Web-to-App Handoff: Banners, Deferred Links, Routing
The web-to-app handoff comes down to three questions asked in order: does this visitor already have your app, what OS are they on, and does the campaign actually justify pulling them out of the browser? Answer those and the routing writes itself. Get them wrong and you either annoy people who'd have converted on web anyway, or you dump fresh installs onto your generic home screen and lose every scrap of context they arrived with.
Let me start with a mess I had to untangle. A retail client kept celebrating a smart-banner "install lift" of a few thousand a month. Looked great on the dashboard. When I pulled the raw click logs, a good chunk of those banner taps were arriving milliseconds before the install. Classic click-injection timing. The banner wasn't creating installs. It was catching users who were already walking to the App Store and stamping its own name on them. On paper the campaign looked like a hero. In reality maybe 200 to 400 basis points of that "lift" was borrowed credit, and the reallocated budget behind it was real money chasing a number that didn't mean what everyone thought.
So before any of the tactics, hold onto the skeptic's rule: the handoff is worth building because apps genuinely convert better, not because a banner CTR went up.
Why bother pulling people into the app at all
The economics are lopsided, and they've stayed lopsided. Tapcart's 2025 ecommerce breakdown puts mobile app conversion at roughly three times mobile web, with average order value running higher on top of that. UXCam's 2026 benchmarks are more sober about absolute numbers. Retail apps land near a 1.38% install-to-purchase rate, travel apps around 2.41%. But the app-versus-web gap holds across categories. An app user has your push channel, your saved payment, no re-auth friction, and a home-screen icon that costs nothing to re-open.
That's the prize. The catch is that the store visit sits in the middle of the journey like a trapdoor. Someone taps your link on mobile web, gets bounced to the App Store or Play Store, installs, opens... and lands nowhere in particular. Whatever they were looking at (the product, the shared playlist, the referral code) is gone unless you deliberately carry it across. That carrying is the entire job of a deferred deep link.
The routing decision tree
Here's the tree I actually draw on the whiteboard. It's three checks, and each terminal path has a different measurement story.
Check 1: is the app installed? You mostly can't know this reliably from the browser anymore. iOS and Android both killed the old app-detection tricks for privacy reasons. So you design for both outcomes at once: fire a link that opens the app if present and falls through to the store if not. That's what Universal Links (iOS) and App Links (Android) are for. As Airbridge's 2025 cross-platform guide puts it, these are plain HTTPS URLs the OS resolves to a verified app when it's installed, and lets fall back to the browser when it isn't. One URL, both branches, no guessing required.
Check 2: which OS? This decides how the fallback and the match behave, and the two platforms are not equals here. More on that below, but the short version: Android's install-referrer plumbing makes the deferred match dependable, and iOS's does not.
Check 3: does the campaign justify the interruption? This is the one teams skip, and it's the most important. Not every visitor should be shoved toward the app. A user two taps from checkout on mobile web does not need a full-screen interstitial begging them to install and start over. You just added a store round-trip to a conversion that was about to happen. Route by intent: high-commitment, repeat-use, or notification-worthy actions earn the app push. One-off transactional visits stay on web.
| Visitor + intent | Serve | Fallback if no app | What you can measure |
|---|---|---|---|
| Has app, deep-linkable content | Universal/App Link straight into the screen | n/a (app opens) | in-app event, link-attributed open |
| No app, high-intent campaign | Deferred deep link via store | Store, then restore context on first open | click → install → first-open, deferred match rate |
| No app, casual browse | Contextual smart banner, dismissable | Stay on web | banner impression, tap-through, install if tapped |
| Near web conversion | Nothing. Let them finish | Stay on web | web conversion only |
That last row is a feature, not a gap. The most profitable routing decision is often "don't route."
Smart banners: useful, oversold, easy to misread
A smart banner is the polite version of the handoff. A slim bar suggesting the app, dismissable, non-blocking. Apple ships one natively, the apple-itunes-app meta tag, and it costs you a single line of HTML.
Two things nobody tells you until it bites. First, the native iOS Smart App Banner only renders in Safari. Not in-app webviews, not Chrome on iOS, not embedded browsers. Branch's setup guide spells out the second gotcha: Safari reads that meta tag from the initial HTML and doesn't re-check after client-side navigation. On a single-page app, you set the banner on load and it goes stale as the user moves around, showing the wrong deep link, or none, until a hard refresh. If your site is a React or Vue SPA, the native banner is quietly lying to a chunk of your traffic.
That's why the attribution vendors (Branch, AppsFlyer, Adjust) all sell their own JavaScript banners instead. They render across browsers, carry a real deep-link payload through the store, and, not incidentally, let the vendor claim the install. AppsFlyer markets its web-to-app journeys as clearing 30%-plus click-to-install. Treat vendor conversion numbers the way you'd treat a used-car odometer: directionally interesting, measured under their favorite conditions. The number that matters is incremental installs, the ones that wouldn't have happened anyway, and no banner CTR will tell you that on its own. You need a holdout.
Deferred deep linking: the match is the whole game
Deferred deep linking is the trick that survives the store trapdoor. User taps a link for a specific thing, doesn't have the app, installs it, and on first launch the app knows what they came for and takes them there. The magic isn't in the link. It's in reconnecting two events, a click in a browser and a first-open in a brand-new app with no shared identity, across a gap of minutes or hours.
The reliability of that reconnection is where iOS and Android split hard.
Android hands you a real answer. The Play Install Referrer API attaches referrer data to the install itself, so the match is deterministic and holds up well even when the click and open are hours apart. When someone tells me their Android deferred links "just work," this is why.
iOS gives you no equivalent. Post-ATT, there's no clean install-referrer channel, so deferred matching on iOS leans on probabilistic signals (timestamp, IP, device characteristics) that degrade fast as more users sit behind shared IPs and privacy relays. It works, until it doesn't, and it fails silently. The user lands on your home screen, shrugs, and you never see the drop-off as a distinct number. If you're building this and want the trust boundaries drawn properly, our privacy-first attribution reference architecture walks through which signals you're actually allowed to lean on.
And the ground keeps shifting. Adapty's 2026 guide flags the big one: Firebase Dynamic Links shut down on August 25, 2025. Plenty of teams had quietly built their deferred-linking and cross-platform routing on top of it, and that free crutch is gone. If your handoff still references Dynamic Links anywhere, it's already broken.
Measuring each path (so you don't repeat my client's mistake)
Every terminal branch of the tree produces a different signal, and the failure mode is treating them as one funnel. They aren't.
The app-open path, where the user already had the app, should log an attributed open plus the in-app event. Clean. The deferred path is the one to watch: instrument click, install, and first-open-with-restored-context as three separate steps, then track the deferred match rate as its own metric. If matches are quietly falling from 90% toward 60% after an OS update, that's a fire, and it only shows up if you measured the step in the first place. The banner path needs an impression-to-tap rate and, critically, a holdout to separate real lift from borrowed credit.
Once a user is inside the app, what you can observe changes shape entirely. Web session recording and native mobile capture are not the same craft. Native replay reconstructs a rendered view hierarchy rather than a DOM, which is why the in-app leg of the journey needs its own tooling rather than a stretched web setup.
Picking the plumbing
You have real options, and they trade off differently. Branch and AppsFlyer are the heavyweight MMPs, carrying full deferred deep linking, smart banners, and cross-network attribution, with pricing and complexity to match. If you're weighing those two specifically, the head-to-head on how each handles link resolution is worth reading before you sign. Adjust sits in similar territory. Lighter-weight, kixo.cc short links cover deferred deep linking as part of Kixo's broader product-and-attribution stack, which suits teams that want the handoff and the in-app analytics under one roof rather than a dedicated MMP contract. For a straight feature-by-feature read across the dedicated tools, our deep-linking platform comparison lays them side by side.
Whatever you pick, the honest close is this: the tooling is the easy 20%. The hard 80% is discipline about when not to hand off. I've watched more revenue leak from over-eager app interstitials interrupting near-complete web checkouts than from any technical match failure. Build the tree, respect the "do nothing" branch, and measure each path as its own thing. The plumbing will mostly behave. Your routing logic is what earns or burns the money.