A user taps a link, goes to the store, installs the app, and lands exactly on the needed screen. Without this, up to 30% of traffic from ad campaigns is lost. Poorly implemented deep linking costs businesses millions in lost conversions annually. Our team, with 10+ years of iOS and Android experience, delivers a turnkey solution in 2–4 weeks.
Three Types of Deep Links: What to Choose?
| Type | Example | Reliability | Fallback | When to Use |
|---|---|---|---|---|
| Custom URL Scheme | myapp://product/123 |
Low (possible collisions) | None | Internal cross-app communication |
| Universal Links (iOS) / App Links (Android) | https://domain.com/product/123 |
High (system verification) | Browser | Production, any scenario |
| Deferred Deep Link | Link with parameters | Depends on SDK | Store + install | Ad campaigns, new user acquisition |
Custom URL Scheme is the simplest but least reliable. If the app is not installed, the browser shows an error. Multiple apps can register the same scheme — unpredictable which opens. It is only suitable for internal scenarios.
Universal Links (iOS) / App Links (Android) are HTTP/HTTPS links that the system intercepts and opens in the app instead of the browser. If the app is not installed, it falls back to the browser. Reliable, verified, proper fallback. This is the standard for production.
Deferred Deep Links preserve context even if the app is not installed. The user taps → App Store → install → open → correct screen. Implemented via Branch.io, Adjust, or AppsFlyer (Firebase Dynamic Links is no longer supported).
How to Set Up Universal Links on iOS?
A file apple-app-site-association (AASA) is required on the server:
{
"applinks": {
"apps": [],
"details": [
{
"appIDs": ["TEAMID.com.company.app"],
"components": [
{ "/": "/product/*", "comment": "Product pages" },
{ "/": "/profile/*" },
{ "/": "/order/*" },
{ "/": "/promo/*", "?": { "ref": "?" } }
]
}
]
}
}
The AASA must be served with Content-Type: application/json, no redirects, status 200. Apple CDN caches it for up to 48 hours. On iOS 16+, there is a developer mode to speed up updates in debug. In Info.plist, specify domains under com.apple.developer.associated-domains, and handle NSUserActivity in SceneDelegate. More at Apple Documentation.
App Links on Android: Step‑by‑Step Setup
File assetlinks.json on the server:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.company.app",
"sha256_cert_fingerprints": ["AA:BB:CC:..."]
}
}]
SHA256 fingerprint from keystore: keytool -list -v -keystore release.jks. Debug and release fingerprints are different — add both to the production assetlinks.json or use different domains.
In AndroidManifest.xml:
<activity android:name=".MainActivity">
<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"
android:pathPrefix="/product/" />
</intent-filter>
</activity>
android:autoVerify="true" triggers verification on install. To check: adb shell pm get-app-links com.company.app. If STATE_APPROVED — everything works.
Client‑Side Router: Centralized Handling
No more scattered if (url.contains("product")) throughout the code. A single router with a pending deep links queue in case navigation is not yet initialized.
// Android
class DeepLinkRouter {
fun handle(intent: Intent, navController: NavController) {
val uri = intent.data ?: return
val path = uri.path ?: return
val route = when {
path.matches(Regex("/product/(\\d+)")) -> Route.ProductDetail(uri.lastPathSegment ?: return)
path.matches(Regex("/order/(\\w+)")) -> Route.OrderDetail(uri.lastPathSegment ?: return)
path == "/profile" -> Route.Profile
path.startsWith("/promo/") -> {
val ref = uri.getQueryParameter("ref")
Route.Promo(uri.lastPathSegment ?: return, ref)
}
else -> { openInBrowser(uri); return }
}
navController.navigate(route)
}
}
// iOS
final class DeepLinkRouter {
func handle(url: URL) {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return }
let pathComponents = components.path.split(separator: "/").map(String.init)
switch pathComponents.first {
case "product" where pathComponents.count == 2:
navigationManager.push(.productDetail(id: pathComponents[1]))
case "order" where pathComponents.count == 2:
navigationManager.push(.orderDetail(id: pathComponents[1]))
case "profile":
navigationManager.push(.profile)
default:
UIApplication.shared.open(url)
}
}
}
Why Deferred Deep Links Are Critical for Ads?
A regular Universal Link loses context if the app is not installed. Deferred Deep Link remembers parameters (e.g., product id) and passes them after installation. This increases ad conversion by 20–40%. At an average cost per lead of $10, proper deep linking saves up to $3,000 per month on 10,000 installs. For implementation, we use Branch.io or Adjust — they provide SDKs and dashboards for tracking.
What Stages Does Deep Linking Implementation Include?
- Audit of current navigation and URL scheme.
- Design of a router with a pending deep links queue.
- Setup of AASA (iOS) and assetlinks.json (Android).
- Integration of Universal Links / App Links + code handling.
- Connection of Deferred Deep Links via selected SDK.
- Testing on physical devices (iOS and Android).
- Documentation for maintenance and access.
- 30‑day warranty after delivery.
Order a navigation audit — we'll assess the implementation complexity in 2 days.
What Deep Linking Mistakes Are Most Common?
- Redirect to CDN breaks App Links. If the domain redirects to www, AASA is needed on both.
- Wrong Content-Type. AASA must be only
application/json. - Missing
onNewIntenthandling on Android. Deep link on warm start is ignored. - Navigation before NavController is ready. Use a queue.
Comparison of Deferred Deep Link Providers
| Provider | SDK Size | Fingerprinting | Attribution Window | Integration |
|---|---|---|---|---|
| Branch.io | ~2 MB | Yes | 7 days | Simple, single SDK |
| Adjust | ~1.5 MB | No | 30 days | Customizable |
| AppsFlyer | ~1.8 MB | Yes | 30 days | Broad analytics |
| Airbridge | ~1.2 MB | No | 14 days | Lightweight, fast |
Timeline and Cost
Implementation of Universal Links + App Links + router + deferred deep links takes 2 to 4 weeks. The cost is calculated individually after assessing the scope of work. Contact us for a consultation and preliminary estimate.
Deep link is a fundamental concept without which modern mobile apps cannot be imagined. We'll help you implement it correctly and hassle‑free.







