An auth-gated React Navigation app with @swmansion/react-native-detour. A deep link can arrive at any point in the SignIn → Onboarding → Tabs flow; React Navigation remembers it and replays it once the target screen becomes reachable.
Auth-gated flow. A Detour link arrives while signed out, so the app waits on the sign-in screen (left) → after signing in, a first-time user goes through onboarding (center) → the pending link is replayed and the app lands on Details (right).
- Screen flow:
SignIn→Onboarding(once per install) →Tabs(Home, Explore, Settings) +Details. - Detour feeds URLs via
Detour.getInitialURL()andDetour.addEventListener("url", ...). UNSTABLE_routeNamesChangeBehavior="lastUnhandled"makes React Navigation remember an unresolvable deep link and replay it once the target screen becomes renderable.- All link types handled: Universal/App links, custom scheme, and deferred.
Related examples:
examples/react-navigation— minimal React Navigation integration
How a link survives sign-in and onboarding
- If a deferred link arrives and the user is not signed in, the splash hides and
SignInis shown. React Navigation parses the URL, findsDetailsis not currently rendered, and marks the action as the last unhandled one. - After sign-in, the rendered screen set changes. If onboarding has not been completed yet,
Onboardingis shown —Detailsis still not rendered, so the pending link stays remembered. - After onboarding,
Detailsbecomes part of the rendered stack. React Navigation retries the unhandled action and navigates toDetails(or falls through toNotFound).
Note:
UNSTABLE_routeNamesChangeBehavior="lastUnhandled"is not deep-link-specific. It also captures other unhandled navigation actions — for example a manualnavigation.navigate(...)call or aninitialStatepointing at a screen that isn't currently rendered — and replays them once that screen becomes part of the navigator. See the React Navigation docs for the full behavior.
Expected dev-only warning
When the link arrives while the target screen isn't rendered yet (e.g. on SignIn), React Navigation logs a development-only warning.
This is the dispatch attempt against the current (signed-out) navigator state. UNSTABLE_routeNamesChangeBehavior="lastUnhandled" then stashes the action and replays it once Details is part of the rendered stack. The message is stripped in production builds.
Reference docs:
→ React Navigation deep linking
→ React Navigation auth flow (see UNSTABLE_routeNamesChangeBehavior)
Deferred link
- Follow the Deferred deep link setup to register a pre-install click, then install and launch the app signed out. The deferred match runs only on this fresh first launch.
- You land on
SignIn— Detour has matched the click and is holding the link, so a Link pending banner appears. - Tap Sign in, then tap Get Started on the onboarding screen (shown on the first launch).
- React Navigation replays the held link once
Detailsbecomes reachable, so the app lands onDetailswith the forwarded params visible. - Go back — the same link does not trigger again.
Universal / App link
Same flow as above but don't need to reinstall — the link arrives at runtime. While signed out (tap Logout to get there), trigger a Detour link to /details (see Triggering links). On later launches the onboarding step is skipped.
Custom scheme
Same runtime flow as the Universal / App link, just opened through the app's custom scheme. Trigger the custom-scheme URL (see Triggering links) — it's held through the auth gate and replayed to Details the same way.
You need a Detour account to register this app and generate its credentials. Sign up and open the Detour Dashboard. If you run into issues during setup, the Dashboard Walkthrough covers each step in detail.
Create an organization and add a new app. Detour assigns it a base link URL of the form https://<your-org>.godetour.link/<your-app-hash> visible in Link settings section.
In Link settings, the dashboard asks for a fallback Redirect URL to mark setup as complete. It only controls where web traffic lands — it has no effect on the deferred or Universal/App link flows these examples test, so it can be left empty or filled with a placeholder URL for local development. For production, see Full app configuration.
Dashboard. Create an organization (top-left), create a new app (top-right), and use the generated link (marked with red) in Link settings (bottom).
Open App configuration and fill in the platform details:
- iOS: set Bundle ID to
detourreactnative.reactnavigationadvancedand provide Team ID and App Store ID. The Team ID must be your real Apple Developer Team ID — the one the build is signed with (DEVELOPMENT_TEAMin Xcode › Signing & Capabilities, also shown under Apple Developer › Membership). A placeholder or mismatched Team ID makes the Universal link open in Safari instead of the app. The App Store ID can stay a placeholder for local development. - Android: set package name to
detourreactnative.reactnavigationadvancedand add a SHA-256 certificate fingerprint. The fingerprint must match the keystore that signs the build — a wrong value makes Android open the App link in the browser instead of the app. For local development (npx expo run:android), use the local debug keystore fingerprint. See Testing Android App Links for more info.
The dashboard generates the associatedDomains and intent-filter snippets to paste into app.json (below).
For a production integration, fill all fields with real values. See App configuration for full guidance.
→ Dashboard › App configuration
Dashboard › App configuration. iOS and Android filled configurations with generated integration code snippets ready to copy.
Open API configuration and copy your appID and publishable apiKey into this example's .env.
→ Dashboard › API configuration
Dashboard › API configuration. The API configuration panel with
appIDand the publishableapiKeyready to copy.
Because this example exercises the deferred case through a multi-step gate, you may want to review the Matching settings (threshold and time window) that control how a pre-install click is paired with the first launch.
→ Matching
Dashboard › Link Settings › Matching. The matching panel showing confidence threshold and time-window controls alongside match statistics.
Replace the placeholders in app.json with the values from the dashboard's App configuration section:
<your-org>— your organization slug<your-app-hash>— the path prefix assigned to your app
"ios": {
// ...
"associatedDomains": ["applinks:<your-org>.godetour.link"]
},
"android": {
// ...
"intentFilters": [{
// ...
"data": [{ "scheme": "https", "host": "<your-org>.godetour.link", "pathPrefix": "/<your-app-hash>" }]
}]
}Universal Links not opening the app? Add
?mode=developerto theassociatedDomainsentry:"applinks:<your-org>.godetour.link?mode=developer". This bypasses Apple's CDN and fetches the AASA file directly from your domain on every launch instead of relying on a potentially stale cached version. Requires Settings → Developer → Associated Domains Development to be enabled on the device and a development-signed build. Remove it before submitting to TestFlight or the App Store.
These same values go into the simulator commands in the next section.
Deferred deep link
Follow these steps to test the deferred flow:
- Uninstall the app or clear its data to start from a clean state.
- Open a Detour link in the device's mobile browser.
- Install and launch the app — the SDK resolves the link automatically.
Note: On Android, the install referrer is typically unavailable in development builds, so deferred matching falls back to probabilistic signals (IP, device fingerprint) only. See Limitations & Known Issues.
Alternatively on iOS, you can also copy the link to your clipboard before uninstalling — the SDK reads the clipboard on first launch (shouldUseClipboard: true), so you can skip the browser step. It simulates a link clicked before the app was installed.
Universal / App link
Open a Detour link directly from the terminal:
# iOS simulator
xcrun simctl openurl booted "https://<your-org>.godetour.link/<your-app-hash>/details"
# Android emulator
adb shell am start -a android.intent.action.VIEW -d "https://<your-org>.godetour.link/<your-app-hash>/details"Alternatively, paste the link into Notes or Messages on the device and tap it — this uses the same OS routing path a real user would.
Custom scheme
# iOS simulator
npx uri-scheme open "detour-react-navigation-advanced://details" --ios
# Android emulator
npx uri-scheme open "detour-react-navigation-advanced://details" --androidFor more cases and gotchas, see Testing & Troubleshooting.
- Install dependencies from the repo root:
pnpm install - Configure this app in the Detour Dashboard using identifiers from
app.json(for exampleios.bundleIdentifier,android.package). - Use the values from the dashboard's API configuration section to fill
.envand updateapp.jsonwith the generated integration code. - Run prebuild for this example:
pnpm prebuild - Start the example:
pnpm start - Run on device/simulator:
pnpm iosorpnpm android
- Deferred deep linking blog series — background on the technique
- SDK Usage — how to integrate Detour with your navigation library
- API Reference — full type and method reference
examples/react-navigation— minimal React Navigation integration








