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>
);
}

SDK exposes useDetourContext() hook that returns object containing information about 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. Deep links based on uri-scheme are also supported.

import { useDetourContext } from '@swmansion/react-native-detour';
import * as SplashScreen from 'expo-splash-screen';
import { Stack, usePathname, useRouter } from 'expo-router';
SplashScreen.preventAutoHideAsync();
const normalizePath = (route: string) => route.split('?')[0] || '/';
export function RootNavigator() {
const { isLinkProcessed, linkRoute, clearLink } = useDetourContext();
const pathname = usePathname();
const router = useRouter();
useEffect(() => {
if (isLinkProcessed) {
SplashScreen.hide();
}
}, [isLinkProcessed]);
useEffect(() => {
if (!isLinkProcessed || !linkRoute) return;
if (pathname !== normalizePath(linkRoute)) {
router.replace(linkRoute);
return;
}
clearLink(); // avoid redirecting again when returning to this screen
}, [clearLink, isLinkProcessed, linkRoute, pathname, router]);
if (!isLinkProcessed) {
return null;
}
return <Stack />;
}

linkRoute format

linkRoute is a ready-to-use path (including query string if present).

Example:

URL: https://example-organization.godetour.link/Ar8UqUjGzG/segment1?param1=value1
route: /segment1?param1=value1

Short links

If the incoming link path has a single segment (for example https://example-organization.godetour.link/Ar8UqUjGzG), the SDK resolves it to the full link before computing linkRoute.

Custom schemes

For custom scheme links, the route is computed from the host + pathname + query. Example: myapp://promo/123?utm=1 → /promo/123?utm=1.

  • On first app launch after install, the SDK checks whether this is the first entrance and attempts deferred matching once per session.
  • If the app is opened via a Universal/App Link on first launch, the SDK handles that link immediately and skips deferred matching.
  • useDetourContext() exposes the final state. Wait for isLinkProcessed before routing.
  • Matching is asynchronous. Show a loading state while it runs.
  • Clipboard matching (iOS) can be controlled via Config.shouldUseClipboard.
  • After handling a route, call clearLink() to prevent repeated redirects.
  • On subsequent launches the SDK checks only for Universal/App Links and processes them.

Expo Router handles Universal/App Links on its own and may redirect to a route before the SDK finishes processing the link. The detected route can include the hash fragment Detour uses for link identification, so either match such routes in your navigation or add a catch-all.

Links resolve asynchronously, so without a catch-all Expo Router may show Not Found route for unknown paths while Detour resolves the final destination. Use a catch-all route to keep the user on a loading screen until Detour provides linkRoute:

app/[...link].tsx
import { useDetourContext } from '@swmansion/react-native-detour';
import { useEffect } from 'react';
import { useRouter } from 'expo-router';
export default function CatchAllRoute() {
const { isLinkProcessed, linkRoute } = useDetourContext();
const router = useRouter();
useEffect(() => {
if (!isLinkProcessed) return;
if (linkRoute) {
router.replace(linkRoute);
} else {
router.replace('/');
}
}, [isLinkProcessed, linkRoute, router]);
return null;
}

This keeps the UX consistent and avoids a flash of the Not Found screen.

You can log specific user behaviors using the DetourAnalytics module. This allows you to track the user journey through your conversion funnel.

Events are emitted via a global internal system and handled by the DetourProvider.

import { DetourAnalytics } from '@software-mansion-labs/react-native-detour';
// Simple event logging
DetourAnalytics.logEvent("login");
// Event logging with custom metadata
DetourAnalytics.logEvent('purchase', {
item: 'subscription_premium',
currency: 'USD',
});

Check the list of defined events here