deep-linking

Deep Linking: The Complete Guide for Mobile Developers

What is deep linking? Learn how universal links, app links, and deferred deep links work. Covers iOS, Android, and cross-platform implementation.

WarpLink Team··17 min read

TL;DR: Deep linking routes users directly to specific content inside a mobile app instead of the app's home screen. There are four types: standard deep links (custom URL schemes), Universal Links (iOS), App Links (Android), and deferred deep links. Each solves a different piece of the mobile linking puzzle. This guide covers how they all work, when to use each, and how to implement them.

What Is Deep Linking?

Deep linking is a technique that sends users directly to a specific screen or piece of content inside a mobile app, rather than opening the app's home screen or a web browser. When someone taps a deep link, they land exactly where you intended: a product page, a user profile, an article, a checkout flow, or any other in-app destination. Deep links use URLs to encode both the target app and the content path within it, allowing external sources like emails, social media posts, ads, and websites to hand off context to the app at launch time.

For developers building mobile apps, deep linking is the bridge between the open web and the closed world of native apps. Without it, every link sends users to a browser, the app store, or the app's home screen. With it, you can build connected experiences that feel instant and intentional.

Why Deep Linking Matters

Mobile apps live in sandboxes. Unlike the web, where any URL can link to any page on any site, native apps are isolated by design. There is no universal address bar for app content. Deep linking solves this by giving every screen in your app a URL that the operating system can resolve.

Without deep linking, the typical user journey looks like this:

  1. User sees a link to a product in an email
  2. User taps the link
  3. Browser opens to a mobile web page
  4. Web page shows a banner saying "Open in app"
  5. User taps the banner
  6. App opens to the home screen
  7. User manually navigates to find the product

That is seven steps for something that should take one. Each step is a drop-off point. Industry data consistently shows that conversion rates decrease with every additional tap or redirect in a mobile flow.

With deep linking:

  1. User taps the link
  2. App opens directly to the product page

Two steps. No friction. No wasted time. The user gets what they wanted, and you keep the engagement.

The Developer Case for Deep Linking

Beyond user experience, deep linking unlocks several technical capabilities that are difficult or impossible to achieve otherwise:

  • Content sharing. Users can share specific screens from your app, not just the app itself. The recipient lands on the exact content.
  • Marketing attribution. You can track which links, campaigns, and channels drive app opens and installs.
  • Onboarding personalization. New users who arrive through a specific link can see tailored first-run experiences based on the link's context.
  • Re-engagement. Push notifications and emails can route users back to specific content, not just relaunch the app.
  • Cross-platform continuity. A link works whether the user has the app installed, needs to install it, or is on a device where the app is not available.

Not all deep links work the same way. The technology has evolved significantly over the past decade, and there are now four distinct types, each with different capabilities and trade-offs.

Standard deep links use custom URL schemes to identify the target app. Instead of https://, they use a scheme registered by the app, like myapp:// or example://.

For example:

myapp://product/123
myapp://profile/jane
myapp://settings

When the operating system sees a URL with the myapp:// scheme, it checks whether any installed app has registered that scheme. If one has, it launches the app and passes the URL. The app then parses the path to determine which screen to show.

On iOS, you register a custom URL scheme in your app's Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>

On Android, you declare an intent filter in your AndroidManifest.xml:

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="myapp" />
</intent-filter>

Limitations of custom URL schemes:

  • No fallback. If the app is not installed, the URL goes nowhere. The user sees an error or nothing happens. There is no graceful degradation to a web page or app store listing.
  • No uniqueness guarantee. Any app can register any scheme. Two apps registering the same scheme creates undefined behavior. On iOS, the system picks one arbitrarily.
  • No verification. There is no proof that the app claiming myapp:// actually owns the domain myapp.com. This is a security gap.
  • Blocked in many contexts. Many email clients, social media apps, and in-app browsers strip or block custom URL schemes entirely.

Custom URL schemes were the first generation of deep linking and are now considered legacy. They are still useful for app-to-app communication on the same device, but they are not reliable for links shared across the web, email, or social media.

Universal Links are Apple's modern deep linking mechanism, introduced in iOS 9. They use standard HTTPS URLs instead of custom schemes. When a user taps a Universal Link, iOS opens the associated app directly. If the app is not installed, the same URL loads in Safari as a normal web page.

This solves the biggest problem with custom URL schemes: Universal Links always work. The user either gets the app experience or the web experience. No dead ends.

How Universal Links work:

  1. You host an Apple App Site Association (AASA) file at https://yourdomain.com/.well-known/apple-app-site-association
  2. The AASA file declares which URL paths your app handles
  3. When a user installs your app, iOS downloads the AASA file from your domain
  4. iOS stores the association locally on the device
  5. When the user taps a matching HTTPS URL, iOS checks the local association and opens your app
  6. Your app receives the full URL and routes the user to the correct content

The AASA file looks like this:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["ABCDE12345.com.example.myapp"],
        "components": [
          { "/": "/product/*", "comment": "Product pages" },
          { "/": "/invite/*", "comment": "Invitation links" },
          { "/": "/share/*", "comment": "Shared content" }
        ]
      }
    ]
  }
}

The appIDs value combines your Apple Team ID (ABCDE12345) and your app's bundle identifier (com.example.myapp). The components array defines which URL paths your app handles.

Requirements for Universal Links:

  • Your domain must serve the AASA file over HTTPS with a valid certificate
  • The AASA file must be served with Content-Type: application/json
  • The AASA file must be accessible without redirects (Apple's CDN fetches it directly)
  • Your app must include an Associated Domains entitlement (applinks:yourdomain.com)
  • The app must be signed with a provisioning profile that includes the Associated Domains capability

Common Universal Links pitfalls:

  • AASA caching. Apple's CDN caches your AASA file aggressively. After updating it, changes can take hours or days to propagate. During development, you can use Apple's AASA validator to check the cached version.
  • Same-domain taps do not trigger Universal Links. If the user is already browsing yourdomain.com in Safari and taps a link to another page on yourdomain.com, iOS treats it as normal web navigation. Universal Links only trigger from cross-domain contexts. This is why many deep linking services use a separate short-link domain.
  • Long press reveals the choice. If a user long-presses a Universal Link, iOS shows options to open in Safari or the app. If they choose Safari, iOS remembers that preference for the entire domain. The user must long-press again and choose "Open in App" to re-enable the behavior.
  • In-app browsers bypass Universal Links. Links opened inside apps like Twitter, Facebook, or Instagram often load in an in-app SFSafariViewController or WKWebView. These embedded browsers handle Universal Links inconsistently. Some respect them, others do not.

App Links are Android's equivalent of Universal Links, introduced in Android 6.0 (Marshmallow). They use verified HTTPS URLs to open your app directly, with web fallback for users who do not have it installed.

How App Links work:

  1. You host a Digital Asset Links file at https://yourdomain.com/.well-known/assetlinks.json
  2. The file declares which apps are authorized to handle URLs from your domain
  3. You declare intent filters in your app's manifest with autoVerify="true"
  4. At install time, Android verifies the association by fetching the assetlinks file
  5. Once verified, matching URLs open your app automatically

The assetlinks.json file looks like this:

[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.myapp",
      "sha256_cert_fingerprints": [
        "AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90"
      ]
    }
  }
]

The sha256_cert_fingerprints array contains the SHA-256 hash of your app's signing certificate. This cryptographically verifies that only your app can claim URLs from your domain.

Your Android manifest needs intent filters:

<intent-filter android:autoVerify="true">
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="https" android:host="yourdomain.com" />
  <data android:pathPattern="/product/.*" />
</intent-filter>

The android:autoVerify="true" attribute tells Android to verify the domain association at install time. Without it, Android treats the link as a regular intent and shows a disambiguation dialog ("Open with...") instead of opening your app directly.

Key differences from Universal Links:

  • Android uses SHA-256 certificate fingerprints for verification. iOS uses Team ID and bundle ID.
  • Android verifies at install time and periodically re-verifies. iOS caches the AASA via Apple's CDN.
  • Android intent filters support regex-like path patterns. iOS AASA components support wildcards and exclusions.
  • If verification fails on Android, the link still works but shows a disambiguation dialog. On iOS, the link falls through to Safari silently.

Deferred deep links solve the hardest problem in mobile linking: what happens when a user taps a link but does not have the app installed yet?

With standard deep links or even Universal Links and App Links, the best you can do for a new user is redirect them to the app store. After they install and open the app, the original link context is gone. The user lands on the home screen with no idea how to find the content they originally wanted.

Deferred deep links preserve the link context across the app install. The word "deferred" refers to the fact that the deep link is delivered to the app after a delay, not at the moment the user tapped it.

How deferred deep links work:

  1. User taps a link (e.g., https://links.example.com/product/123)
  2. The link service records the click context: destination path, UTM parameters, timestamp, and a device fingerprint based on IP address, user agent, and other signals
  3. The user does not have the app, so they are redirected to the app store
  4. The user installs the app and opens it for the first time
  5. The app's SDK sends device signals to the link service
  6. The link service matches the install to the original click using a cascade of matching strategies
  7. The SDK returns the matched deep link data to the app
  8. The app navigates the user to the intended content

The matching step is the core technical challenge. Since there is no persistent identifier that survives the journey from browser to app store to app (cookies do not cross that boundary, and Apple restricts device tracking), the system must use indirect signals.

Common matching strategies, in order of reliability:

StrategyMechanismAccuracy
ReferrerGoogle Play install referrer (Android only)Deterministic
Device IDIDFV on iOS, deterministic re-engagement matchingDeterministic
FingerprintIP + User Agent + screen size + other signalsProbabilistic (~90-95%)

The best implementations use a cascade approach: try deterministic matching first, fall back to probabilistic matching only when needed. This maximizes accuracy while maintaining coverage across platforms.

Deferred deep link use cases:

  • Referral programs. Alice shares a referral link. Bob taps it, installs the app, and Alice gets credit. The deferred deep link carries Alice's referral code through the install.
  • Content sharing. A user shares a recipe link on social media. A follower taps it, installs the cooking app, and lands directly on that recipe.
  • Marketing campaigns. An ad links to a specific in-app promotion. New users who install through the ad see the promotion on first launch.
FeatureCustom URL SchemesUniversal Links (iOS)App Links (Android)Deferred Deep Links
URL formatmyapp://pathhttps://domain/pathhttps://domain/pathhttps://domain/path
Works if app not installedNoFalls back to webFalls back to webRedirects to store, delivers context after install
Domain verificationNoneAASA fileassetlinks.jsonDepends on link service
SecurityLow (no verification)High (Apple-verified)High (certificate pinning)Varies by implementation
Works in all contextsNo (blocked by many apps)Mostly (some in-app browser issues)MostlyYes (uses HTTPS URLs)
Preserves context through installNoNoNoYes
Implementation complexityLowMediumMediumHigh

How Deep Linking Works: The Full Flow

Understanding the complete flow helps when debugging issues or building a custom implementation. Here is what happens step by step when a user taps a deep link.

The link is a standard HTTPS URL, like https://links.example.com/abc123. This URL could appear in an email, a text message, a social media post, a QR code, or a web page.

The link service receives the HTTP request. It looks up the slug (abc123) to find the link configuration: the target app, the in-app destination path, fallback URLs, and metadata. It also inspects the User-Agent header to determine the user's platform (iOS, Android, or desktop) and whether the request comes from a bot (for social media preview cards).

Step 3: Platform Routing

Based on the platform:

  • iOS user: The service returns a redirect to the Universal Link URL, or directly to the app store if no Universal Link is configured
  • Android user: The service returns a redirect to the App Link URL, or to the Play Store
  • Desktop user: The service redirects to a web fallback URL
  • Bot/crawler: The service returns an HTML page with Open Graph and Twitter Card meta tags so the link renders a rich preview on social media

Step 4: OS Resolves the App Association

If the user's platform supports it and the app is installed:

  • iOS checks its local AASA cache. If the URL matches a registered path, iOS opens the app and passes the URL.
  • Android checks its verified App Links. If the URL matches a verified intent filter, Android opens the app and passes the URL as an intent.

If the app is not installed, the URL loads in the browser (which may show a web page or redirect to the app store).

The app receives the URL and parses it to determine which screen to show. On iOS, this happens in application(_:continue:restorationHandler:) for Universal Links or scene(_:continue:) for SceneDelegate apps. On Android, it happens in the activity's onCreate or onNewIntent by reading the intent data.

Step 6: Content Routing

The app's router maps the URL path to an internal screen. For example, /product/123 maps to the product detail screen with ID 123. The app fetches the necessary data and renders the screen.

Deep Linking Challenges

If deep linking sounds straightforward in theory, the implementation reality is considerably more complex. Here are the most common challenges developers face.

iOS Quirks

Universal Links are fragile in practice. The AASA file must be served perfectly. Any issue with SSL certificates, redirects, content types, or caching breaks the entire flow silently. There is no error message. The link just opens in Safari instead of the app.

Paste-and-go bypasses Universal Links. If a user copies a URL and pastes it into Safari's address bar, iOS treats it as direct navigation, not a link tap. Universal Links do not trigger. This catches many developers off guard during testing.

In-app browsers are inconsistent. Each social media app handles links differently. Some apps open links in SFSafariViewController (which supports Universal Links), others use WKWebView (which does not), and the behavior can change between app versions without notice.

The user can break it. If a user long-presses a Universal Link and chooses "Open in Safari," iOS remembers that preference for the entire domain. The user must manually reverse this choice. There is no API to detect or reset it.

Android Fragmentation

Verification failures are common. App Link verification depends on Android fetching your assetlinks.json at install time. If the fetch fails (network issues, server downtime, DNS problems), the app falls back to showing a disambiguation dialog instead of opening directly. Some Android OEMs (particularly in China) block the verification request entirely.

OEM customizations break standard behavior. Device manufacturers like Samsung, Xiaomi, and Huawei modify Android's default link handling. Samsung Internet has its own app linking behavior. Xiaomi's MIUI sometimes overrides verified App Links with its own browser.

Chrome's intent system adds complexity. When an App Link is tapped in Chrome, Android handles the routing. But if the link is tapped in a WebView inside another app, the behavior depends on how that app configured its WebView.

Cross-Platform Consistency

Building deep links that work identically on iOS and Android requires handling two completely different systems (AASA vs. assetlinks, Universal Links vs. App Links, different URL handling APIs) and presenting a single consistent experience to users and marketers who just want "one link that works everywhere."

Attribution Accuracy

Matching an app install to the link that caused it is an inherently lossy process. There is no cross-boundary identifier between the mobile browser and the app store. Since Apple removed access to IDFA (Identifier for Advertisers) without explicit user consent in iOS 14.5, and both platforms continue tightening privacy restrictions, probabilistic fingerprinting is becoming less accurate over time. The industry is moving toward server-side referrer passing and privacy-preserving attribution models.

Deep Linking Use Cases

Content Sharing

The most common use case. A user shares a link to a specific item, article, recipe, listing, or profile. The recipient taps the link and lands directly on that content in the app. If they do not have the app, they see the web version or get directed to the app store.

Good content sharing links also include Open Graph metadata so the link renders with a title, description, and image when shared on social media or messaging apps.

Referral Programs

Referral links encode the referrer's identity so that both parties receive credit when the new user installs and signs up. Deferred deep links are essential here because the referral code must survive the app install flow. Without deferred deep linking, you lose attribution for every new user who did not already have the app.

Marketing Campaigns

Email campaigns, paid ads, social media posts, and influencer partnerships all benefit from deep links that route users to specific in-app content. UTM parameters attached to the link provide campaign attribution data. Deep links with analytics tell you not just that someone clicked, but whether they opened the app, which content they saw, and whether they converted.

Re-engagement

Users who installed your app weeks ago but have not opened it recently can be re-engaged through email or push notifications containing deep links. Instead of a generic "Come back!" message that opens the home screen, you can link to new content, a personalized recommendation, or a time-limited offer. The specificity of the deep link dramatically improves tap-through and re-engagement rates.

Onboarding Flows

When a new user arrives through a specific context (an invitation to a team workspace, a shared document, a promotional offer), deferred deep links let you customize the onboarding experience. Instead of a generic sign-up flow, the user sees an onboarding screen that acknowledges why they are here and gets them to the relevant content faster.

Getting Started with Deep Linking

Implementing deep linking from scratch requires hosting and maintaining AASA and assetlinks.json files, building a link resolution service, handling platform detection, implementing deferred deep link matching, and keeping everything working as iOS and Android change their requirements.

WarpLink handles all of this. You get Universal Links, App Links, deferred deep links, and install attribution through a single dashboard and API. The open source SDKs for iOS, Android, and React Native handle link resolution in a single method call.

If you are migrating from Firebase Dynamic Links, the migration guide walks through the process step by step.

To see how WarpLink fits into the bigger picture, read Introducing WarpLink or jump straight to the quickstart guide to create your first deep link in under five minutes.

WarpLink Team

Building the open deep linking platform for developers and small teams.