Skip to main content
deep-linking

Deep Linking: The Complete Guide for Mobile Developers

Learn how mobile deep links open specific app screens on iOS and Android. Compare URL schemes, Universal Links, App Links, fallbacks, and install attribution.

WarpLink Team26 min read

Deep linking is the practice of using a URL to open a specific screen inside a mobile app, such as a product, an invite, or a recipe, instead of the app's home screen or a web page. On iOS and Android, one HTTPS link does the job: the operating system opens your app when it is installed, and the same link falls back to the app store or the web when it is not.

iOS and Android mobile app deep linking works through one HTTPS link that each operating system checks against your app: Universal Links on iOS, verified by an apple-app-site-association file, and App Links on Android, verified by an assetlinks.json file. If the app is installed, the link opens the right screen. If it is not, the link falls back to your web page or the app store, and deferred deep linking carries the link's context through the install so a new user still lands on the content they tapped.

Every term in this guide, from Universal Link to deferred deep link, is defined in the deep linking and attribution glossary.

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, every screen in your app gets an address that the operating system can resolve.

A regular URL points to a web page, and a browser loads it. A deep link is a URL the operating system can hand to an installed app, and the app decides which screen to show. Modern deep links are regular HTTPS URLs. What makes https://go.example.com/recipes/lemon-tart a deep link is that the app has proved it owns go.example.com, so iOS and Android open the app instead of the browser.

Why deep linking matters

Without deep linking, a link to a product in an email takes a mobile user through the browser, an "Open in app" banner, and the app's home screen, and then they search for the product by hand. Every step is a chance to give up. With deep linking, the tap opens the app on the product. That makes four things possible:

  • Content sharing. Users share a specific screen, and the recipient lands on it.
  • Campaign measurement. Each link records which campaign or channel drove an open or an install.
  • Personalized onboarding. A user who arrives through an invite sees the team that invited them.
  • Re-engagement. Push notifications and emails reopen a specific screen, not the home screen.

Take one link shared by a recipe app: https://go.example.com/recipes/lemon-tart. The same URL gives each person the best destination their device can open.

Who taps the linkWhat happens
iPhone with the app installediOS matches the path in its stored association file and opens the app on the lemon tart recipe. Safari never loads.
Android phone with the app installedAndroid finds a verified App Link for the domain and opens the app on the recipe.
iPhone or Android phone without the appThe browser loads the URL. The link server sends the visitor to the App Store or Play Store, or to a web version of the recipe.
The same phone after installing the appWith deferred deep linking, the first launch opens the lemon tart recipe instead of the home screen.
Laptop browserThe link server sends the visitor to the recipe's web page.
Messaging or social crawlerThe link server returns a small HTML page with Open Graph tags, so the link shows a title, image, and description in the chat.

That table is the whole job of deep linking: one URL, the right screen in the app when it can open, and a sensible fallback when it cannot.

A deep link is resolved in two places. The operating system gets the first chance to open your app. Only when it declines does the browser load the URL and a link server choose a fallback.

The link is a standard HTTPS URL. It can sit in an email, a text message, a social post, a QR code, an ad, or a web page.

2. The operating system checks for an app

Before any network request, the operating system checks whether an installed app has claimed the link's domain and path.

  • iOS reads the association data it stored for each installed app. That data comes from the apple-app-site-association (AASA) file on your domain, fetched through Apple's CDN when the app was installed or updated.
  • Android reads the domains it verified for each installed app. Verification comes from the assetlinks.json file on your domain, checked when the app was installed or updated.

If an app matches, the operating system opens it and passes the full URL. The link server never sees the tap.

3. The browser loads the URL

If no app claims the link, usually because it is not installed, the browser requests the URL. The link server reads the request's User-Agent header to tell iOS, Android, desktop, and bots apart, then answers:

  • iOS without the app: a redirect to the App Store or to the link's iOS fallback page.
  • Android without the app: a redirect to the Play Store or to the link's Android fallback page.
  • Desktop: a redirect to the web destination.
  • Bot or crawler: an HTML page with Open Graph and Twitter Card tags, so the link renders a rich preview.

4. The app routes to the screen

The app receives the URL and its router maps the path to a screen: /recipes/lemon-tart opens the recipe screen for that ID. The URL arrives through a different callback when the tap launches a closed app (a cold start) than when the app is already running (a warm start). Handle both, or links work while the app is open and fail when it is closed.

There are three ways a URL can open an app. Custom URL schemes are the oldest. Universal Links and App Links are the verified, HTTPS-based replacements that iOS and Android recommend today.

Custom URL Schemes

Custom URL schemes identify the target app with a scheme the app registers, like myapp://, instead of https://.

When the operating system sees myapp://, it looks for an installed app that registered that scheme, launches it, and passes the URL. The app parses the path to choose a screen.

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

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

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.
  • No ownership. Any app can register any scheme. When two apps register the same one, the system picks one and you do not control which.
  • No verification. Nothing proves that the app claiming myapp:// is the app you meant.
  • Blocked in many places. Email clients, social apps, and in-app browsers often strip or refuse custom schemes.

Custom URL schemes still work for app-to-app hand-offs on one device. For links shared on the web, in email, or on social media, use Universal Links and App Links.

Universal Links are Apple's verified deep links, introduced in iOS 9. They are standard HTTPS URLs. When a user taps one and the app is installed, iOS opens the app directly. When the app is not installed, the same URL loads in Safari as a normal web page, so the user always gets the app or the web, never a dead end.

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 apps and which URL paths it covers
  3. Your app declares the domain in its Associated Domains entitlement
  4. When the app is installed or updated, iOS fetches the AASA file through Apple's CDN and stores the association on the device
  5. When the user taps a matching HTTPS URL, iOS opens your app instead of Safari
  6. Your app receives the full URL and routes the user to the correct content

The AASA file looks like this:

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 serves the AASA file over HTTPS with a valid certificate
  • The file is served with Content-Type: application/json
  • The file is reachable without redirects
  • Your app includes the Associated Domains entitlement (applinks:yourdomain.com)
  • The app is signed with a provisioning profile that includes the Associated Domains capability

Common Universal Links pitfalls:

  • CDN caching. Devices read your AASA file from Apple's CDN, and the CDN copy can lag your edits. Fetch https://app-site-association.cdn-apple.com/a/v1/yourdomain.com to see what devices see.
  • Same-domain taps stay in Safari. A tap from a page on yourdomain.com to another page on yourdomain.com is normal navigation. This is one reason link services use a separate short-link domain.
  • The user can turn it off. Choosing "Open in Safari" from a long-press sticks for the whole domain until the user long-presses again and picks the app. No API can detect or reset it.
  • Paste-and-go never opens the app. Typing or pasting a URL into Safari's address bar is navigation, not a link tap.
  • In-app browsers vary. Social apps open links in embedded browsers that handle Universal Links inconsistently. See deep links in Instagram and Facebook in-app browsers.

App Links are Android's equivalent of Universal Links, introduced in Android 6.0. They use verified HTTPS URLs to open your app directly, with the web as the 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, by package name and signing certificate, may handle URLs on your domain
  3. You declare intent filters in your app's manifest with android:autoVerify="true"
  4. When the app is installed or updated, Android fetches the file and verifies the association
  5. Once verified, matching URLs open your app directly

The assetlinks.json file looks like this:

The sha256_cert_fingerprints array contains the SHA-256 hash of your app's signing certificate. If you use Play App Signing, this is the certificate Google signs your release with, not your upload key, and getting that wrong is the most common reason verification fails.

Your Android manifest needs intent filters:

The android:autoVerify="true" attribute tells Android to verify the domain. Without verification, Android 12 and later open the link in the browser. Android 11 and earlier may show a chooser dialog asking which app should open it, unless the user set a default app for the link or only one app can handle it.

Custom URL schemeUniversal Link (iOS)App Link (Android)
URL formatmyapp://pathhttps://domain/pathhttps://domain/path
App not installedError or nothingOpens the web pageOpens the web page
Ownership checkNoneAASA file with Team ID and bundle IDassetlinks.json with SHA-256 fingerprint
Where the device reads itNowhereApple's CDN copy of your fileYour domain, at install or update
When verification failsNot applicableOpens SafariOpens the browser on Android 12 and later; older versions may show a chooser
Another app can claim itYesNoNo
Works from email and social appsOften blockedMostly, with in-app browser exceptionsMostly, with in-app browser exceptions
Carries context through an installNoNoNo
Setup effortLowMediumMedium

None of the three survives an app install on its own. That is a separate layer, deferred deep linking, covered below. Contextual deep linking is a second layer: the link carries extra data, such as a referral code or a campaign name, that the app reads alongside the route.

Setting up deep linking yourself takes a domain you control, two association files, a few lines of app configuration, and a router. Here is the minimum on each platform.

  1. Host the AASA file at https://yourdomain.com/.well-known/apple-app-site-association with your Team ID, bundle ID, and paths, served as JSON with no redirect.
  2. Add the entitlement. In Xcode, open Signing & Capabilities, add Associated Domains, and add applinks:yourdomain.com.
  3. Handle the URL. In a UIKit app with scenes, read the link on both a warm start and a cold start:

In SwiftUI, attach .onOpenURL { url in router.open(url) } to your root view instead, where router is the same URL-to-screen router.

  1. Test on a device. Paste the link into Notes or Messages and tap it. Typing it into the Safari address bar never opens the app, by design. On a simulator, run xcrun simctl openurl booted https://yourdomain.com/product/123.
  1. Host assetlinks.json at https://yourdomain.com/.well-known/assetlinks.json with your package name and the SHA-256 fingerprint of the certificate that signs the installed build.
  2. Add the intent filter with android:autoVerify="true", your host, and your paths, as shown above.
  3. Handle the URL on a cold start and when the activity is already running:
  1. Check verification and test. Run adb shell pm get-app-links com.example.myapp to see whether each domain is verified, then open a link with adb shell am start -a android.intent.action.VIEW -d "https://yourdomain.com/product/123".

For every test command on both platforms, including deferred installs, see how to test deep links on iOS and Android. Cross-platform apps follow the same steps with a framework router: see React Native deep linking and Flutter deep linking.

The files are the fragile part: they must stay valid on every domain your links use and change whenever an app's identifiers do. A link service generates and serves them, resolves each link per platform, and adds fallbacks and analytics. With WarpLink's deep linking for iOS and Android apps, you register the app once, and we generate and host the AASA and assetlinks.json files on our link domains and on every verified custom domain.

What Happens Without the App?

Universal Links and App Links fall back to the browser when the app is not installed. The link server then decides where the visitor goes: usually the App Store or Play Store, or a web page for content that also exists on the web. Custom URL schemes have no fallback at all, which is why a link server sends visitors without your app to the store rather than to myapp://.

The store visit solves the install. It does not solve the context. When the new user opens the app for the first time, the operating system hands it nothing: the link they tapped is gone, and they land on the home screen. Deferred deep linking closes that gap.

A standard deep link opens a screen in an app that is already installed. A deferred deep link delivers the same destination after the user installs the app, on its first launch. The link service records the click, sends the user to the store, and matches the first launch back to that click, so a referral, an invite, or a campaign offer survives the install.

Standard deep linkDeferred deep link
App must be installedYesNo
When the app gets the linkAt the tapAt first launch after install
How the app gets itThe operating system passes the URLAn SDK asks the link service for the matched click
CertaintyExactExact with a store referrer, otherwise a probabilistic match with a confidence score
Typical useSharing, re-engagement, emailReferrals, invites, paid campaigns to new users

For the full mechanism, match confidence, and match windows, see how deferred deep linking works after install. For code, see deferred deep linking on iOS in Swift and deferred deep linking on Android in Kotlin.

How Linking Connects to Attribution and Analytics

A deep link is not just a router. It is also an attribution signal. Every tap carries context about where the user came from, and the same infrastructure that opens the right screen can record which link, campaign, or channel drove that open and the install behind it. Linking, attribution, and analytics are three views of the same event, and treating them as one system is what turns a working deep link into a measurable one.

The hard part is connecting an install back to the click that caused it. There is no identifier that survives the trip from a mobile browser, through the app store, into a freshly installed app. So a link service matches the install to the original click using a cascade of signals, from most reliable to least:

SignalPlatformHow it matchesCertainty
ReferrerAndroidThe Play install referrer passes the original link through the storeDeterministic
Device ID (IDFV)iOSThe vendor identifier recognizes an install that asks again and returns it as first matched, so it never creates a matchCarries the original match's type
Probabilistic matchBothIP address, language, and timezone at the click are compared with the same signals at first launchProbabilistic
Raw signalsBothThe app sends its raw signals and the server adds the request IP, since a device cannot know its own public IPProbabilistic

The first successful match wins, which keeps accuracy high without giving up coverage. The IDFV is scoped to your own apps, so it needs no App Tracking Transparency prompt, and none of these signals uses the advertising identifier. A confidence score and a match window come with every result, so you can see how each install was matched.

Analytics comes from the same event. Each tap records the link and the platform, and each matched install adds the second half of the story. Read together, they show which links produce installs, not just clicks.

WarpLink's install attribution runs this exact cascade, and real-time analytics shows recent clicks within minutes. For confidence scores and the privacy model, see the install attribution concepts page.

Most deep linking failures show up as one of a handful of symptoms, and each has a different cause. Name the symptom first, because "deep links are broken" almost always resolves to a specific, fixable problem.

SymptomLikely causeFirst check
A Universal Link opens SafariiOS has no valid association: AASA file, entitlement, or a remembered "open in Safari" choiceThe CDN copy at app-site-association.cdn-apple.com
An App Link opens the browser or a chooserVerification failed, usually a wrong SHA-256 fingerprintadb shell pm get-app-links with your package
The app opens on its home screenThe URL handler does not route, or misses the cold startLog the URL in both handlers
The link works from Notes but not from a social appThe in-app browser does not hand links to appsTest the same link from Messages
The link works on the web but not from emailClick tracking rewrote the URL to another domainThe final URL after the email redirect
A new user lands on the home screen after installingNo deferred deep link, or the match failedThe link service's attribution result

Most iOS causes are the Universal Links pitfalls listed earlier. On Android, verification is all or nothing per domain: one wrong fingerprint marks every link on it as unverified. Manufacturer browsers and other apps' WebViews can also apply their own link handling, so test on the devices and apps your users actually use.

Where to go for each symptom

If you are not sure which symptom you have, start with the Universal Links triage guide. Its first step sorts "opens Safari" from "opens the app but does nothing".

Frequently Asked Questions

What is deep linking in mobile apps?

Deep linking is a technique that sends users directly to a specific screen or piece of content inside a mobile app, instead of opening the home screen or a browser. Deep links use URLs to encode both the target app and the content path, so emails, ads, and websites can hand off context to the app at launch.

What is an example of deep linking?

A recipe app shares https://go.example.com/recipes/lemon-tart. With the app installed, the tap opens the lemon tart recipe in the app. Without it, the link opens the App Store or Play Store, and on a laptop it opens the recipe's web page.

A regular URL points to a web page that a browser loads. A deep link is a URL the operating system hands to an installed app, which opens a specific screen. Universal Links and App Links are ordinary HTTPS URLs that your app has proved it owns.

Three kinds of URL can open an app: custom URL schemes such as myapp://, Universal Links on iOS, and App Links on Android. Deferred and contextual deep linking are behaviors on top of those URLs: one survives an app install, the other carries extra data such as a referral code.

A deep link is any link that opens a specific screen in an app. A Universal Link is Apple's verified kind: an HTTPS URL that iOS opens in your app because your domain's apple-app-site-association file names the app. A custom-scheme link like myapp://product/123 is a deep link but not a Universal Link.

Universal Links are Apple's iOS mechanism, verified through an AASA file at your domain using Team ID and bundle ID. App Links are Android's equivalent, verified through assetlinks.json using SHA-256 certificate fingerprints. Both use HTTPS URLs and fall back to the web if the app is not installed. If verification fails, iOS opens the link in Safari, Android 12 and later open it in the browser, and older Android versions may show a chooser dialog unless a default app is set.

How does deep linking work on iOS and Android?

When someone taps an HTTPS link, the operating system first checks whether an installed app has claimed that domain and path. iOS checks its stored apple-app-site-association data and Android checks its verified App Links. If one matches, the app opens with the URL and routes to the screen. If not, the browser loads the URL, and a link server sends the visitor to the app store or a web page based on the platform.

What is deferred deep linking?

Deferred deep linking preserves a link's context across an app install. When someone taps a link without the app, they go to the app store, and after they install and open it, the SDK matches the device to the original click and routes them to the intended content. It is essential for referrals and campaigns.

Host an apple-app-site-association file and an assetlinks.json file on an HTTPS domain you control, add the Associated Domains entitlement on iOS and an autoVerify intent filter on Android, and route incoming URLs to screens. A link service can host the files and add fallbacks and analytics.

How do I check if deep linking works on Android?

Run adb shell pm get-app-links with your package name to see whether Android verified your domain, then open a test link with adb shell am start -a android.intent.action.VIEW -d and the URL. On Android 12 and later, an unverified domain opens the browser instead of the app.

Universal Links and App Links are the safer kind, because the operating system checks that your domain names your app. Custom URL schemes have no such check, so another app can claim the same scheme. Either way, treat link parameters as untrusted input and never sign a user in from a link alone.

You register your app once, and WarpLink generates and hosts the association files, so one short link opens your app on iOS and Android and falls back to the store or the web. Open source MIT SDKs for iOS, Android, React Native, and Flutter resolve links in a single method call, and installs are matched to clicks using a cascade of referrer, device ID, probabilistic match, and raw signals.

Getting Started with Deep Linking

Doing deep linking yourself means hosting and maintaining AASA and assetlinks.json files, building a link server that detects each platform, implementing deferred matching, and keeping all of it working as iOS and Android change their rules.

WarpLink is link infrastructure that handles all of it. Register your app with its bundle ID and Team ID, its package name and signing fingerprint, or both, and we generate and host the association files. Then create a link: one short URL opens the app on iOS and Android, falls back to the store or the web, and reports every click in real time. Our open source SDKs for iOS, Android, React Native, and Flutter, all at version 1.1.1, resolve links, run the deferred check on first launch, and report installs in a single method call.

The free plan includes 10,000 clicks a month, and paid plans start at $19 a month. See pricing for every tier, or follow the quickstart guide from app registration to your first working link.

Get your first deep link working today

Deep linking, install attribution, and real-time analytics in one SDK. Free for 10K clicks a month, no sales call.

Stuck on setup? Email support@warplink.app and we will help you get one real link working.

WarpLink Team

Building affordable, reliable link infrastructure for mobile teams. Deep linking, install attribution, and real-time analytics in one SDK.