Glossary/Implementation artifacts
URI redirect mode
Definition
URI redirect mode is a per-link setting on a deep link service that controls whether the link attempts to redirect the browser to a custom URI scheme before falling back, and what it does when that redirect fails.
This setting exists because of a problem the web cannot solve: a page has no reliable way to ask whether an app is installed. Every link service therefore has to guess, and the redirect mode is where you tell it how to guess. On a domain that is properly verified for Universal Links and App Links the guessing is no longer necessary, which makes the correct value for most modern setups the one that does the least.
The three modes
| Mode | App installed | App not installed |
|---|---|---|
| Smart — attempt the scheme only with evidence the app can handle it | Opens the app | Goes straight to the web fallback |
| Forced — always attempt the scheme | Opens the app | Browser error, then the fallback if a timer fires |
| Forced with store fallback — attempt the scheme, then the store | Opens the app | Browser error, then the App Store or Play listing |
Vendors name the setting differently and number the modes differently — Branch exposes it as $uri_redirect_mode, others call it forced redirect or a strict flag — but the behavioural choice is always the same three. What matters is the middle column of the not-installed case, because that is where the setting either produces a clean fallback or an error the user sees.
A forced redirect on iOS shows the user a failure
Navigating Safari to myapp://product/42 when nothing claims myapp produces "Safari cannot open the page because the address is invalid". The user sees a broken link even though your fallback page exists and is fine. On Android the equivalent is ERR_UNKNOWN_URL_SCHEME in Chrome. Neither is recoverable from — the navigation already happened.
Why detection does not work, and what "smart" is really doing
There is no web API that answers "is this app installed". The native check — canOpenURL on iOS, resolving an intent on Android — is only available to another installed app, and iOS additionally requires every scheme queried to be declared in LSApplicationQueriesSchemes. So a link service in smart mode is not detecting anything. It is applying heuristics: the user agent, whether the referrer suggests a surface that blocks scheme navigations, and in most implementations a timer.
// This is what a forced redirect looks like underneath. It is shown
// here to be recognised and removed, not copied.
const FALLBACK = "https://example.com/product/42";
let hidden = false;
document.addEventListener("visibilitychange", () => {
// If the app opened, the page is backgrounded and we must not
// navigate — otherwise the user returns to a store listing they
// never asked for.
if (document.hidden) hidden = true;
});
// Attempt the scheme.
window.location.href = "myapp://product/42";
setTimeout(() => {
if (!hidden) window.location.href = FALLBACK;
}, 2000);
// Four ways this is wrong:
// 1. iOS may show a "Open in app?" confirmation. The timer keeps
// running behind it, so the fallback fires mid-decision.
// 2. A backgrounded tab has its timers throttled, so the flag
// is sometimes read before the event lands.
// 3. Chrome blocks scheme navigation without a user gesture, so
// on a redirect page the first line silently does nothing.
// 4. The 2000 ms is a guess. Slow devices exceed it; fast ones
// make the error visible before it elapses.The third point is the one that quietly invalidates the whole approach on Android. Chrome requires a user gesture for a scheme or intent:// navigation, and an interstitial redirect page has no gesture — the click happened on the previous page. So a forced redirect on Android frequently does nothing at all rather than failing loudly, and the fallback timer becomes the only path that ever runs.
The setting you want, and the one thing that actually breaks
With a verified domain, none of this applies. The operating system intercepts the https:// URL before a browser is involved, so the app opens with no redirect, no scheme, no timer and no error — and when the app is absent, the same URL simply loads as a web page. That is the behaviour smart mode is trying to approximate, achieved properly.
# FORCED. The 302 to a custom scheme is what the browser errors on.
GET /l/abc123 HTTP/1.1
Host: links.example.com
HTTP/1.1 302 Found
Location: myapp://product/42
# → app opens, or "the address is invalid"
# VERIFIED. No scheme anywhere. The OS claims the URL before the
# request is made; if it does not, this is just a web page.
GET /product/42 HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
Content-Type: text/html
Link: <https://example.com/.well-known/apple-app-site-association>; rel="alternate"A same-domain redirect page kills the Universal Link
iOS does not open the app for a Universal Link when the navigation starts on the same domain the link points to, and does not open it for a programmatic window.location change — it needs a genuine link tap from elsewhere. An interstitial on your own domain therefore satisfies both exclusions at once, which is how adding a "smart" redirect page can stop verified links working for users who had them working before.
| Your setup | Mode to use | Why |
|---|---|---|
| Domain verified on both platforms | Smart, or no redirect at all | The OS routes it; a redirect can only interfere |
| Verified on iOS only | Smart | Forced would error for every Android user without the app |
| Legacy app, scheme only, no verification | Forced with store fallback | The error is the price of reaching the app at all |
| Targeting one named Android package | Smart, plus an `intent://` link | The intent declares its own fallback and needs no timer |
| Link opens inside an in-app browser | Smart | Scheme navigation is blocked there regardless |
If you inherited forced mode and cannot yet verify the domain, the pragmatic order is: fix assetlinks.json and the AASA file first, confirm verification on a real device, then switch to smart and delete the interstitial. Changing the mode before the verification lands just moves the failure from an error page to a silent no-op — which is harder to notice and identical from the user's side to a deep link opening the browser instead of the app.
Deep link debugger
Paste the link and the debugger follows every hop, showing whether a custom-scheme redirect is in the chain, where the fallback points, and whether the domain is verified — which together tell you which redirect mode you actually need.
Open the deep link debugger →Frequently asked questions
- What is URI redirect mode?
- It is a per-link setting on a deep link service that controls whether the link tries to redirect the browser to a custom URI scheme such as myapp:// before falling back to the web. The common values are smart, which attempts the scheme only when there is evidence the app can handle it, forced, which always attempts it, and forced with a store fallback.
- What is the difference between smart and forced redirect?
- Forced always navigates to the custom scheme, so a user without the app sees a browser error such as Safari's invalid address message before any fallback runs. Smart only attempts the scheme when heuristics suggest it will succeed and otherwise goes straight to the web fallback, which means no user ever sees the error at the cost of occasionally missing an app open.
- Why does my deep link show "Safari cannot open the page because the address is invalid"?
- The link navigated Safari to a custom URI scheme that no installed app claims, which is what a forced redirect does when the app is absent. The navigation has already happened by the time the failure is known, so it cannot be recovered from. Switching to smart mode, or better, serving a verified Universal Link with no scheme redirect at all, removes the error.
- Do I need a URI redirect mode if my domain is verified?
- No. When a domain is verified for Universal Links and App Links, the operating system intercepts the https URL before any browser handles it, so the app opens with no scheme, no redirect and no timer, and the same URL loads as a normal web page when the app is not installed. Set the mode to smart or remove the interstitial entirely.
- Can a redirect page stop Universal Links from working?
- Yes. iOS deliberately does not open the app when a Universal Link is navigated to from the same domain it points at, or when the navigation is a programmatic location change rather than a user's link tap. An interstitial redirect page hosted on your own domain triggers both exclusions, so adding one can break verified links that previously worked.
Related terms
- Link Fallback Chain — A link fallback chain is the ordered set of destinations a single link resolves to — the app, the app store, or a web page — depending on the user's platform and whether the app is installed.
- Custom URI Scheme — A custom URI scheme is a non-standard URL protocol, such as myapp://, that an app registers with the operating system so that URLs beginning with it open that app.
- Chrome intent — A Chrome intent is a URL using the `intent://` scheme, which encodes an Android Intent — its target package, action, extras and a fallback URL — inside a link so that a web page can launch a specific app and specify what should happen when that app is absent.
- Deep link opens the browser instead of the app — A deep link opens the browser instead of the app when the operating system has not accepted the app as a verified handler for that URL, or when the tap occurred in a context that never offers the app the chance to handle it.
- Deep links in in-app browsers — An in-app browser is an embedded webview inside another app that renders links without handing them to the operating system, which prevents Universal Links and App Links from ever reaching the app that claims the domain.