deep-linking

Deep Links in Instagram and Facebook In-App Browsers: The Fixes

A deep link tapped in the Instagram, Facebook, or TikTok in-app browser usually will not open your app. What each one does on iOS and Android, and the fixes.

WarpLink Team··20 min read

TL;DR: A link that opens your app from Safari or Messages often does nothing inside Instagram, Facebook, TikTok, X, LinkedIn, or Gmail. The cause is almost never your association file. Those apps render the page inside an embedded webview they control, and an embedded webview is not the system browser. On iOS, a Universal Link hands off to an app only on a user initiated navigation, so a server redirect or a JavaScript redirect inside a webview never triggers it. On Android, browsers refuse to launch an app from a navigation with no user gesture behind it. The fix is to stop expecting an automatic handoff and design for a tap: land the user on a short page you control, detect the environment, and give them one button that fires the Universal Link, the App Link, or an intent URL with a fallback. For users who do not have the app yet, send them to the store and let a deferred deep link restore the destination after first launch.

The report always sounds the same. The link opens the app when a tester taps it in Messages or Notes. The same link, pasted into an Instagram bio or a TikTok profile, loads a web page and stops there. The assumption is that something is wrong with the apple-app-site-association file or assetlinks.json.

It usually is not. Association files are fetched at install time and cached on the device, and they are the same file no matter who requests the URL. If the link opens your app from the system browser, your association is working.

What changed is who is doing the browsing. Tapping a link in Instagram does not hand the URL to Safari or Chrome. It hands it to a web view Instagram embeds inside its own app, running under Instagram's rules rather than the operating system's. Deep link routing is an operating system feature, and inside someone else's web view the operating system is mostly not in the loop.

That one fact explains every symptom below, so start with the four things an "in-app browser" can actually be.

The Four Webviews Behind Every In-App Browser

An in-app browser is a web view that an app embeds so that links open inside that app rather than in Safari or Chrome.

"In-app browser" is a user-facing word for four very different pieces of technology, two per platform. Which one an app embeds decides whether your deep link has any chance at all.

WKWebView on iOS

WKWebView is a web engine an app embeds and drives. Through its navigation delegate, the host app decides what happens to every navigation: allow it, cancel it, or send it somewhere else.

Apple's own guidance on universal links states the rule directly: "If you instantiate a SFSafariViewController, WKWebView, or UIWebView object to handle a universal link, iOS opens your website in Safari instead of opening your app" (App Search Programming Guide). The same page adds a narrow exception: a universal link the user taps from inside an embedded web view can open the app.

In practice that exception is not something you can rely on in a social app, because the host sits in front of it: when a navigation inside its web view is cancelled and handled by the host, there is no tap left for the system to act on. Assume that a WKWebView based in-app browser will not hand off to another app.

SFSafariViewController on iOS

SFSafariViewController is a different thing entirely. It is Safari, presented inside another app, with Safari's cookie jar and Safari's behaviour, and the host app cannot read or modify the page inside it. Links in it generally behave like links in Safari, including Universal Link routing. That is the good case, and it is less common than it used to be, since a host app gets no analytics from it.

Android WebView

WebView is Android's embeddable engine and the closest analogue to WKWebView. Out of the box it loads http and https in place. It does not verify App Links, and it does not launch other apps. A custom scheme URL or an intent:// URL inside a plain WebView typically produces ERR_UNKNOWN_URL_SCHEME unless the host app has written a shouldOverrideUrlLoading implementation that forwards it to an intent, which many do not.

Chrome Custom Tabs on Android

Custom Tabs are the Android counterpart to SFSafariViewController: a real browser tab, styled by the host app, sharing the browser's cookies and behaviour. Google's documentation is explicit that Custom Tabs support App Links by default, so a verified App Link opens the installed app rather than the tab. One caveat sits in the same document: passing a CustomTabsSession to the intent "will force open the link in a Custom Tab, even if the corresponding native app is installed" (Chrome for Developers). Host apps that warm up a session for speed can suppress App Links without meaning to.

Summarised: SFSafariViewController and Chrome Custom Tabs behave roughly like the system browser. WKWebView and Android WebView do not, and those two are what the large social apps ship.

One mechanism explains most of these failures, including several that have nothing to do with in-app browsers.

On iOS, a Universal Link resolves on a user initiated navigation. Pasting a URL into the address bar does not count. Neither does a 302 from your short domain to your Universal Link domain, and neither does window.location = ... running on page load. The redirect is not a tap, so iOS keeps the user on the web.

Android arrives at the same place from a different direction. Chrome documents that it will not launch an external application when "a JavaScript timer tried to open an application without a user gesture" or when "the Intent URI is initiated without user gesture" (Android Intents with Chrome). Chromium adds more restrictions on top, including refusing launches from a tab that is not visible.

Both platforms are protecting the user from pages that yank them into apps unbidden. The consequence for you is the same on both: an automatic redirect is the one thing that reliably will not open an app. A tap is.

This is also why link wrapping breaks deep links in places that have no in-app browser at all. When a social network or an email service rewrites your URL to its own tracking domain, the domain the user taps is the tracking domain, which has no association file of yours. The hop to your domain is a server redirect, and server redirects do not open apps.

What Each App Does as of September 2026

In-app browser behaviour is the least stable surface in mobile deep linking. Apps swap their embedded browser between releases without announcing it, and a fix that ships in one version can regress in the next. Treat the table as a starting point and verify on the app versions your users run.

AppiOS in-app browserAndroid in-app browserAuto handoff to your appPractical approach
InstagramEmbedded webviewEmbedded webviewNoInterstitial with a tap target
Facebook and MessengerEmbedded webviewEmbedded webviewNoInterstitial with a tap target
TikTokEmbedded webviewEmbedded webviewNoInterstitial with a tap target
XHistorically Safari style, reported to have moved to an embedded webviewEmbedded webviewUnreliable, version dependentInterstitial, and expect link wrapping
LinkedInEmbedded webviewEmbedded webviewNoInterstitial with a tap target
GmailUser configurable, often the system browserCustom Tab by default, toggleableSometimesDeep link normally, keep the interstitial as fallback

Notes worth having in your head, per app.

Instagram, Facebook, Messenger, and TikTok. The hard cases, and they behave the same way. All four render tapped links inside an embedded webview on both platforms, and none of them hand a Universal Link or an App Link off to your app on page load. Reports through 2025 and into 2026 describe Meta's iOS webview also blocking automatic app launches attempted from the page itself, so the redirect tricks are not a plan. Instagram changed its in-app browser again during 2025, a reminder that anything specific you read about these apps has a shelf life. What has held for years is the shape of the fix: a real tap, on a page you control.

X. X wraps every outbound link in its own short domain, so the URL the user taps is never yours, which defeats Universal Link routing on its own. X for iOS historically presented links in a Safari style controller, the friendly case, and developers reported during late 2025 that a client update moved link handling to an internal webview and broke deep links that had worked before. Assume the unfriendly case.

LinkedIn. An embedded webview on both platforms, with an overflow menu that offers to open the current page in the system browser. Same fix as the Meta apps.

Gmail. The most variable of the six, because the user decides. On iOS, Gmail exposes a setting for which browser links open in, so some users are effectively in Safari and get normal Universal Link routing. On Android, Gmail opens links in a Custom Tab by default, with a setting to turn that off, and a Custom Tab does support App Links. Email then adds click tracking on top, which rewrites your URL to the sending service's domain.

Two more worth stating: Slack and Discord also embed webviews, and Apple Mail on iOS opens links in Safari, so Universal Links do work from Apple Mail.

The Strategies That Actually Work

1. An interstitial page with a real tap target

This is the primary fix, and the rest of this list is a variation on it. Instead of pointing your shared link at a deep link, point it at a light page that loads inside whatever webview the user is in and converts that visit into a tap.

The page needs three things: a line telling the user what they are about to open, one prominent button, and a fallback for that button. The button is an ordinary anchor, not a script that navigates on a timer.

The href is your Universal Link and App Link domain. In the system browser or a Custom Tab, tapping it opens the app. Inside a hostile webview the tap at least gives the operating system a user gesture to work with, and where the host still refuses, the hint below the button is the escape hatch.

Use environment detection to change what the button does, never to redirect automatically:

Those tokens are the ones the major clients have used for years, and like everything else here they change. Keep the plain web link working for every user agent you fail to recognise.

2. A custom scheme with a store fallback on iOS

Custom schemes such as exampleapp:// predate Universal Links and are not verified against a domain, which is why they still work in places where Universal Links do not: there is no association for the webview to bypass. Inside an embedded webview, a custom scheme fired from a user tap is often the only thing that opens the app.

The trade is that a custom scheme fails silently, or with a system alert, when the app is not installed, and there is no reliable way to tell which happened. The classic workaround sets a timer and sends the user to the store if the page is still visible when it fires. It is worth knowing, and worth knowing that it is fragile:

Treat this as a fallback for the interstitial button, not as the primary path, and never fire it on page load. A deferred deep link, described below, is a better answer for the not installed case because it does not have to guess.

3. An intent URL with a browser fallback on Android

Android has a first class answer, and it is the one strategy here that handles both outcomes in a single URL. An intent:// URL names the app to open and carries the URL to fall back to when the app is not there:

Written on one line in your href, with the fallback URL percent encoded. If the app is installed, it opens. If not, Chrome loads the fallback URL, and strips the extra so your app never sees it.

Two constraints. The gesture rule applies, so put this in an anchor the user taps: an intent URL fired from a timer or a redirect is blocked. And a raw WebView with no shouldOverrideUrlLoading implementation may reject the scheme outright with ERR_UNKNOWN_URL_SCHEME, so keep an ordinary web link on the page.

4. Ask for the system browser

Every in-app browser in the table has an overflow menu with some form of open in browser, and once the page is in Safari or Chrome the normal routing applies again. A one line hint under your button costs nothing. It is not the whole fix, because most users will not do it, so rank it below the button.

Everything above is about a user who already has your app. For the other half of the traffic the in-app browser question is irrelevant, since they are going to the store either way. What matters is whether the destination survives the install.

That is what deferred deep linking does. The click is recorded before the user leaves for the store, and the first launch of the newly installed app asks which link brought this person here and routes them to it. On Android the match can be deterministic, through the install referrer the store passes along. On iOS a first install has no such channel, so the match is probabilistic and time bounded.

It belongs in a post about in-app browsers because it turns one link into a complete answer: the same URL routes an existing user into the app through the tap, sends a new user to the store, and puts that new user on the right screen. Without it, every install that started inside Instagram lands on your home screen with no context.

The Decision Table

Pick the row that matches where the tap is happening.

SituationWhat to serveWhy
iOS, system browser or Apple MailThe Universal Link directlyNormal routing works, no interstitial needed
iOS, Safari style in-app browserThe Universal Link directlyBehaves like the system browser
iOS, embedded webview such as Instagram, Facebook, TikTok, or LinkedInInterstitial, button pointing at the Universal Link, custom scheme as the fallback, open in browser hintNo automatic handoff exists to rely on
Android, Chrome or a Custom TabThe App Link directlyCustom Tabs support App Links by default
Android, embedded webviewInterstitial, button pointing at an intent URL with S.browser_fallback_urlThe webview will not resolve an App Link, and the intent carries its own fallback
Any platform, app not installedStore URL plus a deferred deep linkThe destination has to survive the install
Any platform, a crawler or an unfurl requestOpen Graph HTML, not a redirectA preview card is not a user and should not be routed like one
DesktopYour web destinationThere is no app to open

What Not to Do

  • Do not redirect automatically and expect the app to open. A 302 is not a tap. A window.location assignment on page load is not a tap. It is the most common design error in this space, and it fails on both platforms for documented reasons.
  • Do not fire a custom scheme on page load. At best it is blocked. At worst the user gets a system alert about a page that cannot be opened before they know what they tapped.
  • Do not fake a tap. Clicking a hidden anchor from script is still not a user gesture, and browsers are getting better at telling the difference.
  • Do not chain redirects before the deep link. Every hop costs time, and only the tapped URL has any chance of triggering the handoff. If you need tracking, do it at the hop that serves the page.
  • Do not point a shared link straight at a store URL. You lose the installed user, who would have been routed into the app, and you lose the deferred destination for everyone else.
  • Do not rely on a timer to detect whether the app opened. It misfires on slow devices and backgrounded pages, and it can dump an existing user into the store on top of the app that just opened.
  • Do not ship user agent sniffing without a default path. Every unrecognised client must still get a working web page.
  • Do not treat a crawler like a user. Social apps fetch your link to build the preview card, and serving that fetch a redirect gives you a bare, unstyled unfurl.

How to Verify This Yourself

There is no simulator for in-app browser behaviour, so the check is manual and short:

  1. Post the link somewhere private in each app that matters, such as a draft message to yourself or a story only you can see.
  2. Tap it on a real device with the app installed. Universal Links are unreliable on the iOS Simulator to begin with.
  3. Tap it again on a device without the app, and confirm the store listing and the first launch destination.
  4. Log the user agent your interstitial receives. It is the only way to know which client you are in. Re-run the pass after any major release of those apps.

Keep the results as a small matrix of app, platform, installed state, and outcome. When behaviour changes under you, and it will, the matrix tells you what changed instead of sending you back into your association files.

Frequently Asked Questions

Why do my deep links not work in the Instagram in-app browser? Instagram renders the page inside an embedded webview it controls, and an embedded webview is not the system browser. The operating system handoff that Universal Links and App Links depend on does not happen there, so the page loads as a web page instead. Your association files are almost certainly fine.

Do Universal Links work in a WKWebView? Not the way they work in Safari. Apple documents that loading a universal link into an embedded web view opens the website rather than the app, and the host app can intercept any navigation inside its own webview and keep it there. Treat a WKWebView based in-app browser as a place where no automatic app handoff will happen.

Can a 302 redirect open my app through a Universal Link? No. Universal Links resolve on a user initiated navigation, not on a server redirect or a JavaScript redirect that arrives afterwards. Android browsers apply the same idea to app launches, which they block without a user gesture. Land the user on a page and give them something to tap.

What is the right way to open an Android app from an in-app browser? Use an intent URL with the S.browser_fallback_url extra, fired from a real tap on an anchor rather than from a timer. Chromium based browsers and Chrome Custom Tabs resolve the intent when the app is installed and load the fallback URL when it is not. Raw Android WebViews often refuse the scheme entirely, so keep a plain web link visible as well.

Should I tell users to open the link in their normal browser? As a secondary path, yes. Every major in-app browser has an overflow menu with an open in browser action, and once the page is in the system browser the normal Universal Link and App Link routing applies again. Make it a hint next to your main button, never the only way forward.

What happens to users who do not have the app installed yet? Send them to the store and let a deferred deep link restore the destination on first launch. The in-app browser problem is a routing problem for people who already have the app, and a deferred deep link is the safety net for everyone else. It also means one link works for both groups.

This post splits into three jobs: route the tap correctly for the platform and the app state, keep the destination alive through an install, and make the shared link look right in the feed it landed in. WarpLink is link infrastructure that does all three from one link.

Linking. A WarpLink URL resolves at the edge in single digit milliseconds globally, and the redirect picks the destination per platform: a Universal Link into the app on iOS, an App Link on Android, the App Store or Play Store when the app is not installed, and your web destination on desktop. Store fallbacks cascade from the link to the app registration. The association files are generated and served when you register an app, which removes the most common reason a tap in the system browser fails to hand off.

Attribution. For everyone without the app, the click is recorded before the user leaves for the store and the SDK asks for it on first launch. The match runs a cascade, from the deterministic install referrer on Android through device level signals and a time bounded fingerprint, and it reports whether the match was guaranteed so you can decide what to trust it with. That is the deferred deep link safety net.

Analytics. Bot user agents are detected on the same request, so a crawler building a preview card gets full Open Graph and Twitter Card HTML while real users get the redirect. Clicks, installs, platforms, and campaigns land in real time, so you can see which surface a share came from.

Read the deep linking concept doc for the full cascade, then create a free WarpLink account and put a link through the Instagram browser yourself.

WarpLink Team

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

Related Posts