Skip to content
Dashboard

Usage

import { DetourProvider, type Config } from "@swmansion/react-native-detour";
const config: Config = {
API_KEY: "<REPLACE_WITH_YOUR_API_KEY>",
appID: "<REPLACE_WITH_APP_ID_FROM_PLATFORM>",
shouldUseClipboard: true,
};
export default function RootLayout() {
return (
<DetourProvider config={config}>
<RootNavigator />
</DetourProvider>
);
}

Use values from context - Example with Expo Router

Section titled “Use values from context - Example with Expo Router”

SDK exposes useDetourContext() hook that returns object containing information about deferred link and processing status. Our recommendation is to use the hook before you application renders navigation container.

The SDK only looks for a deferred link during the application’s first launch after installation. Subsequent launches should be handled by Universal Links for iOS and App Links for Android.

import { useDetourContext } from "@swmansion/react-native-detour";
import * as SplashScreen from "expo-splash-screen";
import { Redirect, Stack } from "expo-router";
SplashScreen.preventAutoHideAsync();
export function RootNavigator() {
const { deferredLinkProcessed, deferredLink, route } = useDetourContext();
useEffect(() => {
if (deferredLinkProcessed) {
SplashScreen.hide();
}
}, [deferredLinkProcessed]);
if (!deferredLinkProcessed) {
return null;
}
if (route) {
return <Redirect href={route} />;
}
return <Stack />;
}

Implementation & lifecycle details (important for integrators)

Section titled “Implementation & lifecycle details (important for integrators)”
  • On first app launch after install:
    • provider checks AsyncStorage / persisted flag to determine “first entrance”.
    • provider sets an in-memory flag (so remounts in the same process won’t trigger extra runs).
    • provider will either:
      • use clickId (if Android install referrer is present) → deterministic match
      • or build ProbabilisticFingerprint → probabilistic match
  • The hook (useDetourContext()) exposes the final state. Wait for deferredLinkProcessed before you attempt to route the user.
  • Matching is asynchronous. Show a loading state while it runs, then route to the matched content.
  • Clipboard: including pastedLink improves match accuracy but may surface a paste permission prompt (iOS). Make this configurable in Config.shouldUseClipboard for UX control.

Expo Router handles Universal Links and App Links natively. When it detects that the app was opened by such a link, it redirects to the corresponding route before the SDK can process the link.

If your are not using Expo Router you need to process universal/app link which opened your app manually or upgrade to version 0.4.0 which gives you universal/app link value in same response what is used for deferred links.

Important: Remember that the route detected by Expo Router will contain the necessary hash that Detour uses for link identification. You must either match this route within your navigation structure or implement a catch-all mechanism for unassigned routes in your application.

Example implementation of app/[...unmatched].tsx:

export default function UnmatchedRoute() {
// 1. Get the current path that Expo Router is trying to render
// Example: "/abcd-1234/product/5"
const pathname = usePathname();
// 2. Parse it
const cleanPath = stripHashAndParseUrl(pathname);
// 3. Safety Check:
if (cleanPath === pathname || cleanPath === "/") {
return <Redirect href="/" />;
}
// 4. Immediate Redirect to the clean path
// e.g. Redirects to "/product/5"
return <Redirect href={cleanPath} />;
}