Skip to main content
Version: 2.0.0

SDK Usage

Initialize provider in app root

import { DetourProvider, type Config } from '@swmansion/react-native-detour';

const config: Config = {
apiKey: process.env.EXPO_PUBLIC_DETOUR_API_KEY!,
appID: process.env.EXPO_PUBLIC_DETOUR_APP_ID!,
shouldUseClipboard: true,
// linkProcessingMode: 'all' // default
};

export default function RootLayout() {
return (
<DetourProvider config={config}>
<RootNavigator />
</DetourProvider>
);
}

Use exactly one DetourProvider in your app tree.

On Expo Web, DetourProvider is disabled: it returns a no-op context (isLinkProcessed: true, link: null) and does not process links.

If you want complete, runnable integrations for each navigation style, go to Examples.

import { useDetourContext } from '@swmansion/react-native-detour';
import { useEffect } from 'react';
import { useRouter } from 'expo-router';

export function RootNavigator() {
const { isLinkProcessed, link, clearLink } = useDetourContext();
const router = useRouter();

useEffect(() => {
if (!isLinkProcessed || !link) return;

router.replace({
pathname: link.pathname,
params: link.params,
});

clearLink();
}, [clearLink, isLinkProcessed, link, router]);

if (!isLinkProcessed) {
return null;
}

return <AppStack />;
}

useDetourContext() returns a link object (or null):

  • link.route: full in-app route with query string (e.g. /details?utm=1)
  • link.pathname: path without query (e.g. /details)
  • link.params: parsed query params record
  • link.url: original URL or raw value
  • link.type: 'deferred' | 'verified' | 'scheme'

Use clearLink() after handling navigation to avoid repeated redirects.

Choose linkProcessingMode

Config.linkProcessingMode controls which link sources are handled by the SDK:

ValueDeferredUniversal / AppCustom scheme
'all' (default)YesYesYes
'web-only'YesYesNo
'deferred-only'YesNoNo

Use 'deferred-only' when Expo Router +native-intent.tsx already handles runtime and initial URLs.

Expo Router integration

Recommended for Expo apps

If you use Expo Router, we strongly recommend using our dedicated createDetourNativeIntentHandler API in a +native-intent.tsx file. This intercepts URLs at the router level before any screen renders, avoiding flash-of-wrong-screen issues and providing the smoothest deep-linking experience.

Expo Router's +native-intent.tsx file lets you intercept and transform incoming system URLs before the router processes them. The Detour SDK provides createDetourNativeIntentHandler — a factory that creates a handler pre-configured for Detour link resolution.

Basic setup

Create a +native-intent.tsx file in your app directory (e.g. src/app/+native-intent.tsx):

import { createDetourNativeIntentHandler } from '@swmansion/react-native-detour/expo-router';

export const redirectSystemPath = createDetourNativeIntentHandler();

This uses intercept mode: any URL matching a Detour host is caught and the user is routed to the home screen (default fallbackPath). Deferred links are still handled separately by DetourProvider.

Resolve mode

To resolve Detour short links to their full destination URLs at the router level, pass a config object:

import { createDetourNativeIntentHandler } from '@swmansion/react-native-detour/expo-router';

export const redirectSystemPath = createDetourNativeIntentHandler({
config: {
apiKey: process.env.EXPO_PUBLIC_DETOUR_API_KEY!,
appID: process.env.EXPO_PUBLIC_DETOUR_APP_ID!,
},
});

In resolve mode, when a user taps a Detour short link (e.g. https://abc123.godetour.link/xyz), the handler resolves it to the full destination URL and routes directly to the correct screen — all before the first render.

See API Reference — Expo Router helper for the full list of options (custom hosts, fallback path, timeout, route mapping, etc.).

Configure DetourProvider for native intent

When using +native-intent.tsx to handle Universal Links and App Links, configure the provider to only process deferred links:

const config: Config = {
apiKey: process.env.EXPO_PUBLIC_DETOUR_API_KEY!,
appID: process.env.EXPO_PUBLIC_DETOUR_APP_ID!,
linkProcessingMode: 'deferred-only',
};

This avoids double-processing: +native-intent.tsx handles runtime and initial URLs, while DetourProvider handles deferred deep links only.

Advanced examples

The SDK repository includes examples for common native intent scenarios:

  • expo-router-native-intent — Full resolve mode setup with a custom mapToRoute function and scheme URL handling. Use this as a starting point when you need to transform resolved URLs before routing (e.g. stripping path prefixes) or when you want to handle custom scheme links alongside Detour links.

  • expo-router-advanced — Demonstrates how to coexist Detour's native intent handler with your own custom routing logic. The handler first delegates to Detour; if the URL isn't a Detour link, it falls through to custom rules (e.g. routing third-party deep links to a dedicated screen). Use this when your app handles links from multiple sources beyond Detour.

For all runnable examples, see Examples.

Alternative: catch-all route without +native-intent.tsx

If you prefer not to use +native-intent.tsx, you can handle all incoming links through DetourProvider with linkProcessingMode: 'all' (the default) and implement a catch-all route in your navigation stack.

In this approach, DetourProvider processes all link types (deferred, Universal/App Links, and custom scheme). You consume the resolved link via useDetourContext() in a top-level component and navigate programmatically:

const { isLinkProcessed, link, clearLink } = useDetourContext();

useEffect(() => {
if (!isLinkProcessed || !link) return;
router.replace({ pathname: link.pathname, params: link.params });
clearLink();
}, [isLinkProcessed, link]);

This was the primary integration pattern before the SDK introduced native intent support (pre-1.x). It still works but the +native-intent.tsx approach provides better UX by resolving links before the first screen renders.

Analytics module

DetourAnalytics emits events that are sent by the active DetourProvider.

import {
DetourAnalytics,
DetourEventNames,
} from '@swmansion/react-native-detour';

DetourAnalytics.logEvent(DetourEventNames.Purchase, {
item: 'subscription_premium',
currency: 'USD',
});

DetourAnalytics.logRetention('home_screen_opened');