Android Deep Linking Best Practices for App Growth in 2026
One in three deep link attempts fails silently.
Your ad fires. The user clicks. The link opens… a browser. Or a 404. Or the app’s home screen instead of the product page they actually wanted. Your retargeting budget evaporates. Your conversion rate tanks. And most teams don’t even notice because the click registered fine — it’s everything after that’s broken.
If you were using Firebase Dynamic Links before August 2025, there’s a strong chance this is happening to you right now. Google shut the service down. No replacement. No migration path. Just a deprecation notice and a lot of broken links.
About 30% of apps that relied on Firebase Dynamic Links are still seeing deep link failures today. Some teams know it. Most don’t.
This post is about fixing that — and building deep linking the right way so it drives the growth it’s actually capable of.
What You’re Leaving on the Table
Before the technical fixes, let’s talk about what working deep links are actually worth.
Deep links that land users in the right place — not just the app’s front door — drive 2-3x higher conversions compared to standard app links. That’s not a minor optimization. That’s the difference between a campaign that pays for itself and one that bleeds money.
Retention numbers are even more interesting. Apps with properly implemented deferred deep linking see:
- 15% improvement in Day-1 retention
- 13% improvement in Week-1 retention
- 12% improvement in Month-1 retention
After 30 days, that adds up to a 2.5x retention lift versus apps sending users to generic home screens.
The math is brutal: if you’re spending money on user acquisition and your deep links are broken or dumping users at the wrong destination, you’re paying to acquire users you’re immediately losing.
The Firebase Dynamic Links Postmortem
Google deprecated Firebase Dynamic Links, with the service fully shutting down in August 2025. If you haven’t migrated yet, here’s what’s happening to your users:
- Short links that were generated via the FDL API now return errors
- Fallback behavior varies by implementation — some land on a web page, some open the Play Store, some just fail
- Analytics attribution breaks, so you lose visibility into what’s working
- Deferred deep linking (sending new installs to the right in-app destination) stops working entirely
The frustrating part is that this failure is largely invisible. Your crash reporting won’t catch it. Your app won’t throw an error. Users just don’t end up where they should be, and you see it as a vague drop in engagement metrics weeks later.
Alternatives teams are moving to in 2026:
| Provider | Best For | Pricing Model |
|---|---|---|
| Branch | Enterprise, complex attribution | Usage-based |
| AppsFlyer OneLink | MMP + deep linking combined | Per-install |
| Adjust | Privacy-first, granular attribution | Custom |
| ChottuLink | Lightweight, self-hosted option | Free/open source |
| Custom backend | Full control, no vendor lock-in | Infrastructure cost |
There’s no single right answer here. But there is a wrong answer: continuing to use Firebase Dynamic Links or building nothing at all.
Android App Links vs. URI Schemes: Stop Guessing
This is the decision most teams get wrong. They pick one approach, run into problems, and patch the other one on top — ending up with a fragile hybrid that breaks in ways that are hard to debug.
Here’s the actual breakdown:
Custom URI Schemes (myapp://product/123) are easy to implement but have a serious flaw: any app can claim any scheme. If another app on the user’s device claims the same scheme, Android shows a disambiguation dialog — or worse, silently routes to the wrong app. There’s no ownership verification.
Android App Links use verified HTTPS URLs (https://example.com/product/123). They require domain verification via assetlinks.json, but when configured correctly, they open your app directly with no disambiguation dialog. This is what you want.
The intent filter for App Links looks like this:
<activity android:name=".ProductActivity">
<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="example.com"
android:pathPrefix="/product" />
</intent-filter>
</activity>The android:autoVerify="true" attribute is what tells Android to verify your domain ownership automatically on install. Without it, your App Link degrades to a basic intent with a disambiguation dialog.
The assetlinks.json Trap Nobody Warns You About
You’ve set up the intent filter. You’ve created the assetlinks.json file. You’ve deployed it to https://example.com/.well-known/assetlinks.json. App Links still don’t work.
CDN redirect errors are the most common silent killer of App Link verification.
Android’s verification system doesn’t follow redirects. If your CDN rewrites http:// to https://, or if www.example.com redirects to example.com, or if your CDN has aggressive caching that serves a stale version of the file — verification fails. Silently. Android falls back to treating your links as regular intents.
Checklist for assetlinks.json verification:
- No redirects on the path. The exact URL Android requests must return a 200, not a 301 or 302.
- Correct Content-Type header. Must be
application/json. - SHA-256 certificate fingerprint is accurate. Get it fresh:
keytool -list -v -keystore your-release-key.keystore - File is reachable without authentication. No login walls, no rate limiting.
- Test with the Digital Asset Links API:
https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls
Your assetlinks.json should look exactly like this:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.myapp",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:..."
]
}
}
]One wrong character in the fingerprint. One redirect in the chain. That’s all it takes for verification to fail and users to end up in the browser.
Deferred Deep Linking: The Growth Feature Most Teams Skip
Standard deep linking works when the app is already installed. But what about new users?
A user sees your ad for a specific product. They don’t have your app. They click the link, land on the Play Store, install the app, open it — and see the generic onboarding screen. The context from the ad is completely lost.
Deferred deep linking solves this. It stores the deep link intent before the install, then routes the user to the correct destination the first time they open the app. The flow looks like this:
Ad Click → Play Store (app not installed)
↓
App Install
↓
First App Open → Retrieve stored intent → Navigate to /product/123Implementing deferred deep linking without a third-party SDK means you need to:
- Pass the deep link target as a parameter through the Play Store referral URL
- Read it on first launch via the Install Referrer API
- Navigate to the correct destination before showing onboarding
// In your Application class or first Activity
val referrerClient = InstallReferrerClient.newBuilder(this).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
if (responseCode == InstallReferrerResponse.OK) {
val referrerDetails = referrerClient.installReferrer
val referrerUrl = referrerDetails.installReferrer
// Parse your deep link target from referrerUrl
handleDeferredDeepLink(referrerUrl)
}
}
override fun onInstallReferrerServiceDisconnected() {}
})This is also where most cold-start navigation crashes happen. The app tries to navigate to a deep-linked destination before the necessary UI components are initialized. Always guard deep link navigation behind a check that your activity stack is ready.
Handling Deep Links in Your Activity
Once verification is working and your intent filters are set, you need to actually handle the incoming intent. This is simpler than it sounds, but there are a few patterns that cause bugs.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
handleIntent(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent) {
val action = intent.action
val data: Uri? = intent.data
if (Intent.ACTION_VIEW == action && data != null) {
when {
data.pathSegments.firstOrNull() == "product" -> {
val productId = data.lastPathSegment
navigateToProduct(productId)
}
data.pathSegments.firstOrNull() == "promo" -> {
val promoCode = data.getQueryParameter("code")
navigateToPromo(promoCode)
}
else -> navigateToHome()
}
}
}
}The critical thing here: you must handle deep links in both onCreate and onNewIntent. If a user already has your app running in the background, Android calls onNewIntent instead of onCreate. Miss that, and deep links silently fail for active users.
Privacy-First Deep Linking in 2026
The Android Privacy Sandbox has reshaped what data you can collect and use for attribution. As of 2026, you need to think about deep linking with privacy constraints built in from the start — not bolted on after.
The key changes affecting deep linking:
Attribution Reporting API replaces cross-app identifier sharing. Attribution data is aggregated and delayed, not real-time and individual. Your deep link attribution pipeline needs to account for this latency.
IP-based coarse location is now the default, not precise location — which affects geo-targeted deep linking campaigns.
Advertising ID deprecation is ongoing. Don’t build deep link tracking that relies on GAID being available. It won’t be.
Practically, this means:
- Store minimum necessary data from deep link parameters
- Don’t pass PII through deep link URLs (they appear in logs and referrers)
- Use server-side attribution where possible instead of device-side tracking
- Test your attribution flows against Privacy Sandbox behavior, not just legacy behavior
Where App Growth Platforms Fit In
If you’re managing multiple channels — paid social, email, SMS, influencer — the combinatorial complexity of deep link management grows fast. Each channel needs different fallback behavior. Attribution needs to work across web and app. Deferred linking needs to handle both organic and paid installs differently.
This is where platforms focused on app growth pay for themselves. Tools that handle the deep link infrastructure, attribution, and analytics in one place let your team focus on the campaigns instead of the plumbing.
AppBooster is worth checking out if you’re also running growth programs for browser extensions alongside your mobile apps — the cross-surface visibility helps when your users move between platforms.
For pure Android deep linking at scale, Branch and AppsFlyer remain the most battle-tested options, particularly if you need MMP-level attribution accuracy.
The Testing Protocol Teams Skip
Most teams test deep links once at implementation and never again. Then a CDN configuration changes. A certificate rotates. A new Android version ships with different App Link verification behavior. And nobody notices until users start complaining.
Build this into your CI/CD:
# Test App Link verification via ADB
adb shell am start \
-a android.intent.action.VIEW \
-d "https://example.com/product/123" \
com.example.myapp
# Verify assetlinks.json is reachable and correct
curl -H "Accept: application/json" \
https://example.com/.well-known/assetlinks.json
# Check verification status on device
adb shell pm get-app-links com.example.myappRun these in your CI pipeline. Set up monitoring on your assetlinks.json endpoint separately from your main site monitoring — it’s a different failure mode. Alert if the file returns anything other than 200 with the correct content.
Your Next 48 Hours
If you’re reading this because something is broken, here’s the order to fix it:
Right now (< 2 hours):
- Run
adb shell pm get-app-links com.yourapp— if it showsnoneorlegacy, your App Links aren’t verified - Check your
assetlinks.jsonendpoint for redirects and correct content - Audit which links were going through Firebase Dynamic Links and which ones are now dead
This week:
- Pick your Firebase Dynamic Links replacement and start migration
- Implement
onNewIntenthandling if you haven’t - Add deferred deep linking via Install Referrer API for new installs
- Set up monitoring on your
assetlinks.jsonendpoint
This sprint:
- Build deep link testing into your CI/CD pipeline
- Review your attribution pipeline against Privacy Sandbox constraints
- A/B test deep-linked campaigns against non-deep-linked equivalents to quantify the conversion lift for your specific audience
The teams winning on Android growth right now aren’t doing anything exotic. They’re just doing the fundamentals correctly — verified App Links, working deferred deep linking, and continuous testing that catches failures before users do.
The 33% failure rate across the industry is an opportunity. Fix your deep links and you’re already ahead of a third of your competition.
If you found this useful, AppBooster has more resources on driving app and extension growth through technical and marketing optimization.
Share this article
Build better extensions with free tools
Icon generator, MV3 converter, review exporter, and more — no signup needed.
Related Articles
Android Adaptive Layouts: Your App on Foldables, Tablets, and Everything in Between
300M+ large-screen Android devices. Android 17 mandates adaptive support. Window size classes, canonical layouts, and foldable posture handling.
Android App Onboarding UX: 7 Patterns That Cut Churn by 50%
97.9% of Android users churn by Day 30. These onboarding UX patterns from Duolingo, Headspace, and Notion fight back with data-proven results.
Android Bottom Navigation vs Navigation Drawer: How to Choose the Right Pattern
Bottom nav for 3-5 destinations, drawer for 6+. Material Design 3 guidelines, thumb zones, and real examples from Gmail, Instagram, and Maps.