Skip to content

Commit d5eaebb

Browse files
committed
docs: update readme
1 parent 8b70135 commit d5eaebb

1 file changed

Lines changed: 138 additions & 58 deletions

File tree

README.md

Lines changed: 138 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,17 @@
66

77
# React Native Detour
88

9-
SDK for handling deferred links in React Native.
10-
11-
## Create an account
12-
13-
You need a Detour account to generate app credentials and configure your links.
14-
Sign up here: [https://godetour.dev/auth/signup](https://godetour.dev/auth/signup)
9+
React Native Detour is an SDK for handling deferred deep links in React Native. A deferred link works like a regular deep link, but survives the App Store or Play Store install — a user who clicks a link before having the app installed is redirected to the right screen on first launch. Detour also handles Universal/App links and custom scheme links in a single unified API.
1510

1611
## Quick links
1712

18-
- Documentation: [https://docs.swmansion.com/detour/docs/](https://docs.swmansion.com/detour/docs/)
19-
- Installation guide: [https://docs.swmansion.com/detour/docs/sdk/react-native/sdk-installation](https://docs.swmansion.com/detour/docs/sdk/react-native/sdk-installation)
20-
21-
## Other Detour SDKs
13+
- Documentation: [https://detour.swmansion.com/docs/](https://detour.swmansion.com/docs/)
14+
- Installation guide: [https://detour.swmansion.com/docs/sdk/react-native/sdk-installation](https://detour.swmansion.com/docs/sdk/react-native/sdk-installation)
2215

23-
Detour is also available for other app stacks:
16+
## Create an account
2417

25-
- Android SDK: [https://github.com/software-mansion-labs/android-detour](https://github.com/software-mansion-labs/android-detour)
26-
- iOS SDK: [https://github.com/software-mansion-labs/ios-detour](https://github.com/software-mansion-labs/ios-detour)
27-
- Flutter SDK: [https://github.com/software-mansion-labs/detour-flutter-plugin](https://github.com/software-mansion-labs/detour-flutter-plugin)
18+
You need a Detour account to generate app credentials and configure your links.
19+
Sign up here: [https://godetour.dev/auth/signup](https://godetour.dev/auth/signup)
2820

2921
## Installation
3022

@@ -48,19 +40,33 @@ npm install expo-device
4840
npm install react-native-device-info
4941
```
5042

51-
> You can override the default persistent storage (@react-native-async-storage/async-storage) by providing an alternative storage implementation. Pass your custom storage object via the configuration settings.
43+
> You can override the default persistent storage (`@react-native-async-storage/async-storage`) by providing an alternative storage implementation via the `storage` config option.
44+
>
45+
> For device info, install either `expo-device` or `react-native-device-info` — at least one is required. If your project already uses one of them, no extra installation is needed.
5246
5347
## Usage
5448

55-
### Initialize the provider
49+
Mount `DetourProvider` at the root of your app and configure it with your credentials. How you consume the resolved link depends on your navigation library.
50+
51+
> The SDK is a no-op on Expo Web — `DetourProvider` mounts but link processing is skipped and `isLinkProcessed` resolves immediately to `true`.
52+
53+
### Expo Router
54+
55+
Wrap your root layout with `DetourProvider`, then use the `useDetourContext` hook to read the resolved link and drive navigation. If your app uses Expo Router's `+native-intent.tsx` to handle Universal/App links, import `createDetourNativeIntentHandler` from `@swmansion/react-native-detour/expo-router` and set `linkProcessingMode: 'deferred-only'` — Detour will only handle deferred links and let the native intent handler take care of the rest. See [`examples/expo-router-native-intent`](./examples/expo-router-native-intent) for a working setup.
56+
57+
<details>
58+
<summary>Expo Router example</summary>
5659

57-
```js
58-
import { DetourProvider, type Config } from '@swmansion/react-native-detour';
60+
```tsx
61+
import { DetourProvider, useDetourContext, type Config } from '@swmansion/react-native-detour';
62+
import { Stack, usePathname, useRouter } from "expo-router";
63+
import * as SplashScreen from "expo-splash-screen";
64+
65+
SplashScreen.preventAutoHideAsync();
5966

6067
const config: Config = {
6168
apiKey: '<REPLACE_WITH_YOUR_API_KEY>',
6269
appID: '<REPLACE_WITH_APP_ID_FROM_PLATFORM>',
63-
shouldUseClipboard: true,
6470
};
6571

6672
export default function RootLayout() {
@@ -70,19 +76,8 @@ export default function RootLayout() {
7076
</DetourProvider>
7177
);
7278
}
73-
```
7479

75-
### Example (Expo Router)
76-
77-
```js
78-
import { Stack, usePathname, useRouter } from "expo-router";
79-
import * as SplashScreen from "expo-splash-screen";
80-
81-
import { useDetourContext } from "@swmansion/react-native-detour";
82-
83-
SplashScreen.preventAutoHideAsync();
84-
85-
export function RootNavigator() {
80+
function RootNavigator() {
8681
const { isLinkProcessed, link, clearLink } = useDetourContext();
8782
const pathname = usePathname();
8883
const router = useRouter();
@@ -99,7 +94,7 @@ export function RootNavigator() {
9994
router.replace({ pathname: link.pathname, params: link.params });
10095
return;
10196
}
102-
clearLink(); // avoid redirecting again when returning to this screen
97+
clearLink();
10398
}, [clearLink, isLinkProcessed, link, pathname, router]);
10499

105100
if (!isLinkProcessed) {
@@ -110,40 +105,70 @@ export function RootNavigator() {
110105
}
111106
```
112107

113-
Learn more about usage from our [docs](https://docs.swmansion.com/detour/docs/SDK/sdk-usage)
108+
</details>
114109

115-
### React Navigation linking integration
110+
### React Navigation
116111

117-
When integrating with React Navigation's custom linking API (`getInitialURL` + `subscribe`), use Detour as the URL source:
112+
#### v2.2.2 and later
118113

119-
```ts
120-
import { DETOUR_LINKING_PREFIX, Detour } from "@swmansion/react-native-detour";
114+
Pass Detour's linking adapter to `NavigationContainer`. React Navigation will handle routing automatically — `useDetourContext` is not needed for basic usage. The splash screen is hidden via `onReady`, which fires after `getInitialURL` resolves.
115+
116+
<details>
117+
<summary>React Navigation example</summary>
118+
119+
```tsx
120+
import { DetourProvider, DETOUR_LINKING_PREFIX, Detour, type Config } from '@swmansion/react-native-detour';
121+
import { NavigationContainer } from '@react-navigation/native';
122+
import * as SplashScreen from 'expo-splash-screen';
123+
124+
SplashScreen.preventAutoHideAsync();
125+
126+
const config: Config = {
127+
apiKey: '<REPLACE_WITH_YOUR_API_KEY>',
128+
appID: '<REPLACE_WITH_APP_ID_FROM_PLATFORM>',
129+
};
121130

122131
const linking = {
123132
prefixes: [DETOUR_LINKING_PREFIX],
124133
async getInitialURL() {
125134
return await Detour.getInitialURL();
126135
},
127136
subscribe(listener) {
128-
const subscription = Detour.addEventListener("url", ({ url }) => {
137+
const subscription = Detour.addEventListener('url', ({ url }) => {
129138
listener(url);
130139
});
131-
132140
return () => subscription.remove();
133141
},
134142
};
143+
144+
export function App() {
145+
return (
146+
<DetourProvider config={config}>
147+
<NavigationContainer linking={linking} onReady={() => SplashScreen.hideAsync()}>
148+
<Navigation />
149+
</NavigationContainer>
150+
</DetourProvider>
151+
);
152+
}
135153
```
136154

137-
`DETOUR_LINKING_PREFIX` is an internal adapter prefix used for Detour-resolved routes.
138-
This API requires `DetourProvider` to be mounted above your `NavigationContainer`.
155+
</details>
156+
157+
#### Before v2.2.2
158+
159+
Use `useDetourContext` and call your navigator imperatively, the same way as the [Expo Router approach](#expo-router) above.
139160

140-
See React Navigation docs:
141-
https://reactnavigation.org/docs/deep-linking?config=static#integrating-with-other-tools
161+
#### Auth-gated apps
162+
163+
The adapter appends `fromDeepLink=true` and `linkType` query params to every URL it emits — you will see these in your route params.
142164

143165
For auth-gated apps, let React Navigation hold the deep link until the right screen is reachable.
144166
Render screens conditionally on auth/onboarding state and opt in to React Navigation's pending-link
145167
behavior on the navigator:
146168

169+
<details>
170+
<summary>Auth-gated navigator example</summary>
171+
147172
```tsx
148173
<Stack.Navigator UNSTABLE_routeNamesChangeBehavior="lastUnhandled">
149174
{isSignedIn
@@ -157,10 +182,13 @@ behavior on the navigator:
157182
</Stack.Navigator>
158183
```
159184

160-
A deep link that arrives while the user is signed-out is parsed, found unreachable (the target
161-
screen isn't currently rendered), and remembered. When the rendered screen set changes — after
162-
sign-in, then again after onboarding — React Navigation retries and lands the user on the target.
163-
See `examples/react-navigation-advanced` for a working setup.
185+
</details>
186+
187+
A deep link that arrives while the user is signed-out is parsed, found unreachable, and remembered. When the rendered screen set changes after sign-in or onboarding, React Navigation retries and lands the user on the target. See [`examples/react-navigation-advanced`](./examples/react-navigation-advanced) for a working setup.
188+
189+
See the [React Navigation deep linking docs](https://reactnavigation.org/docs/deep-linking?config=static#integrating-with-other-tools).
190+
191+
Learn more from our [docs](https://detour.swmansion.com/docs/SDK/sdk-usage).
164192

165193
### Controlling which links Detour processes
166194

@@ -172,7 +200,10 @@ Use `linkProcessingMode` to control which link sources the SDK listens to:
172200
| `'web-only'` ||||
173201
| `'deferred-only'` ||||
174202

175-
```js
203+
<details>
204+
<summary>linkProcessingMode config example</summary>
205+
206+
```ts
176207
const config: Config = {
177208
apiKey: '<REPLACE_WITH_YOUR_API_KEY>',
178209
appID: '<REPLACE_WITH_APP_ID_FROM_PLATFORM>',
@@ -182,8 +213,32 @@ const config: Config = {
182213
};
183214
```
184215

216+
</details>
217+
185218
Use `'deferred-only'` when Expo Router's `+native-intent.tsx` handler is already resolving runtime Universal/App links — this prevents double-processing.
186219

220+
### Clearing handled links
221+
222+
If your app redirects based on `link` (especially in entry screens), call `clearLink()` after handling the route. This prevents repeated redirects when the user returns to the same screen.
223+
224+
## Analytics
225+
226+
The SDK includes a built-in analytics module. `DetourProvider` automatically tracks app opens for retention. You can also log custom events using the predefined `DetourEventNames` enum:
227+
228+
<details>
229+
<summary>Analytics example</summary>
230+
231+
```ts
232+
import { DetourAnalytics, DetourEventNames } from '@swmansion/react-native-detour';
233+
234+
DetourAnalytics.logEvent(DetourEventNames.Purchase);
235+
DetourAnalytics.logRetention('week_1');
236+
```
237+
238+
</details>
239+
240+
See the [analytics docs](https://detour.swmansion.com/docs/) for the full event list and retention tracking setup.
241+
187242
## Examples
188243

189244
All example apps with Detour SDK integrated live in `examples/`:
@@ -231,10 +286,6 @@ pnpm android
231286

232287
> Running `pnpm ios` / `pnpm android` produces a development build. This is recommended over Expo Go for testing deep linking flows on a real device.
233288
234-
## Clearing handled links
235-
236-
If your app redirects based on `link` (especially in entry screens), call `clearLink()` after handling the route. This prevents repeated redirects when the user returns to the same screen.
237-
238289
## Types
239290

240291
The package exposes several types to help you with type-checking in your own codebase.
@@ -243,7 +294,10 @@ The package exposes several types to help you with type-checking in your own cod
243294

244295
This type is used to define the configuration object you pass to the DetourProvider.
245296

246-
```js
297+
<details>
298+
<summary>Config type</summary>
299+
300+
```ts
247301
export type Config = {
248302
/**
249303
* Your application ID from the Detour dashboard.
@@ -257,7 +311,8 @@ export type Config = {
257311

258312
/**
259313
* Optional: A flag to determine if the provider should check the clipboard for a deferred link.
260-
* Note: This feature is iOS-only. On Android, clipboard is never accessed regardless of this setting.
314+
* Note: This feature is iOS-only. On Android, the SDK uses the install referrer for deterministic
315+
* link matching instead; clipboard is never accessed regardless of this setting.
261316
* When enabled on iOS, it may display a permission alert to the user.
262317
* Defaults to true if not provided.
263318
*/
@@ -279,11 +334,16 @@ export type Config = {
279334
};
280335
```
281336

337+
</details>
338+
282339
### DetourContextType
283340

284341
This type represents the object returned by the `useDetourContext` hook, containing the resolved link and its processing status.
285342

286-
```js
343+
<details>
344+
<summary>DetourContextType type</summary>
345+
346+
```ts
287347
export type DetourContextType = {
288348
/**
289349
* Boolean indicating if the initial link (deferred, Universal/App Link, or scheme) has been processed.
@@ -303,11 +363,16 @@ export type DetourContextType = {
303363
};
304364
```
305365

366+
</details>
367+
306368
### DetourLink
307369

308370
The resolved link object, or null if no link was found.
309371

310-
```js
372+
<details>
373+
<summary>DetourLink type</summary>
374+
375+
```ts
311376
export type DetourLink = {
312377
/** The original link URL as received by the SDK. */
313378
url: string | URL;
@@ -331,9 +396,14 @@ export type DetourLink = {
331396
} | null;
332397
```
333398

399+
</details>
400+
334401
### React Navigation adapter types
335402

336-
```js
403+
<details>
404+
<summary>React Navigation adapter types</summary>
405+
406+
```ts
337407
export const DETOUR_LINKING_PREFIX: string; // "detour://"
338408

339409
export type DetourUrlEvent = {
@@ -345,11 +415,21 @@ export type DetourUrlSubscription = {
345415
};
346416
```
347417

348-
```js
418+
```ts
349419
Detour.getInitialURL(): Promise<string | undefined>
350420
Detour.addEventListener("url", (event: DetourUrlEvent) => void): DetourUrlSubscription
351421
```
352422

423+
</details>
424+
425+
## Other Detour SDKs
426+
427+
Detour is also available for other app stacks:
428+
429+
- Android SDK: [https://github.com/software-mansion-labs/android-detour](https://github.com/software-mansion-labs/android-detour)
430+
- iOS SDK: [https://github.com/software-mansion-labs/ios-detour](https://github.com/software-mansion-labs/ios-detour)
431+
- Flutter SDK: [https://github.com/software-mansion-labs/detour-flutter-plugin](https://github.com/software-mansion-labs/detour-flutter-plugin)
432+
353433
---
354434

355435
## License

0 commit comments

Comments
 (0)