Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0e11e6d
docs: update readme for expo bare and router examples
piaccho Jun 11, 2026
d4d719e
refactor: improve clarity and conciseness of README examples
piaccho Jun 11, 2026
d703c8c
refactor: update readme deferred flow instructions
piaccho Jun 12, 2026
093e2d4
Revert "refactor: update readme deferred flow instructions"
piaccho Jun 12, 2026
cce7b79
docs: add deferred deep link example
piaccho Jun 12, 2026
31dcac3
docs: update example link handling descriptions
piaccho Jun 12, 2026
58291c0
docs: add screenshots to expo-bare example
piaccho Jun 15, 2026
a2b19be
refactor: update app.json bundle identifiers and domain
piaccho Jun 15, 2026
c46c32f
docs: update screenshot paths in expo-bare example
piaccho Jun 17, 2026
85e6b89
docs: update expo bare example readme
piaccho Jun 17, 2026
947094e
docs: update bare expo readme example
piaccho Jun 17, 2026
59b7889
docs: improve example readme descriptions
piaccho Jun 18, 2026
f0cb899
docs: update readme examples for detour
piaccho Jun 18, 2026
ab6a3a9
docs: update readme with new screenshots and clarify flow
piaccho Jun 19, 2026
dc29f21
refactor: extract LinkTestingCard component
piaccho Jun 19, 2026
c061570
docs: update expo-router native intent example
piaccho Jun 19, 2026
5d7dc8b
chore: update screenshots in intent example
piaccho Jun 19, 2026
0afd3a7
docs: update react-navigation example screenshots and text
piaccho Jun 19, 2026
2e72027
refactor: remove unused screenshot notes
piaccho Jun 19, 2026
aa2d098
docs: clarify link handling in examples
piaccho Jun 19, 2026
ad9c1bf
feat: add bare react native cli example
piaccho Jun 19, 2026
964a90b
docs: add bare react native cli setup instructions
piaccho Jun 22, 2026
1f3e353
refactor: remove bare-react-native-cli example
piaccho Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ npm install react-native-device-info
>
> 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.

### Bare React Native CLI (without Expo)

Detour's peer dependencies are Expo Modules (they ship native code). In a bare React Native CLI project, add Expo Modules once and point Metro at `expo/metro-config`:

```sh
npx install-expo-modules@latest
npx expo install --fix
```

```js
// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { mergeConfig } = require("@react-native/metro-config");

module.exports = mergeConfig(getDefaultConfig(__dirname), {});
```

Then rebuild — `DetourProvider` and the hooks work exactly as in the Expo examples.

See [Expo Modules setup](https://detour.swmansion.com/docs/sdk/react-native/sdk-installation#expo-modules-setup-react-native-cli) for the full walkthrough, and [build issues](https://detour.swmansion.com/docs/sdk/react-native/testing#bare-react-native-cli-build-issues) if you hit setup errors.

## Usage

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.
Expand Down
154 changes: 123 additions & 31 deletions examples/expo-bare/README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,129 @@
# Detour Expo Bare Example

This example demonstrates a simple integration of `@swmansion/react-native-detour` in a React Native app.
The most minimal integration of [`@swmansion/react-native-detour`](https://detour.swmansion.com/docs/sdk/react-native/sdk-installation) — no router, no navigation library. `DetourProvider` is initialized with SDK config and a single screen renders the raw `useDetourContext()` state. No router or navigation.

## Scenario represented
Use this as a quick SDK smoke test or as a base before adding your own routing.

- `DetourProvider` is initialized with SDK config.
- A single screen consumes `useDetourContext()`.
- No router/navigation integration is implemented here.
- The example is focused on exposing Detour link state.
**Related examples:**

## What this example is for
- [`examples/expo-router`](../expo-router) — minimal Expo Router integration
- [`examples/expo-router-advanced`](../expo-router-advanced) — auth-gated Expo Router flow
- [`examples/react-navigation`](../react-navigation) — minimal React Navigation integration

- Quick SDK smoke test in isolation.
- Verifying provider setup and context values.
- Base starting point before adding your own navigation/deep-link routing logic.
## Test flow

If you need more complex routing flows with a specific navigation library, check out the following examples:
Launch the app — once the startup check completes, `isLinkProcessed` turns `true`. With no pending link, `type`, `url`, and `route` are empty.

- `examples/expo-router`
- `examples/expo-router-advanced`
- `examples/react-navigation`
Trigger a Universal/App link (see [Triggering links](#triggering-links)) — `type`, `url`, and `route` populate with the resolved link data.

## Test flow
To test the **deferred** case: follow the [Deferred deep link](#triggering-links) setup before installing. The deferred check only runs once - the SDK writes a persistent flag on first launch, so subsequent launches skip it. Reinstalling is needed to re-trigger the deferred path.

A **custom-scheme** link (`detour-expo-bare://details`) populates the same `type`, `url`, and `route` fields (with `type: scheme`) — see [Triggering links](#triggering-links).

<br>
<img src="assets/screenshots/app-resolved.png" alt="Resolved Detour link state" width="50%"/>
<br>

> _**Resolved link state**. The screen after a Detour link is resolved with `isLinkProcessed: true` and `type`, `url`, and `route` filled in._

## Set up Detour

You need a Detour account to register this app and generate its credentials. [Sign up](https://godetour.dev/auth/signup) and open the [Detour Dashboard](https://godetour.dev). If you run into issues during setup, the [Dashboard Walkthrough](https://detour.swmansion.com/docs/Fundamentals/dashboard) covers each step in detail.

### 1. Register the app

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](https://detour.swmansion.com/docs/Fundamentals/getting-started#4-complete-app-configuration).

→ [Dashboard › Apps](https://detour.swmansion.com/docs/Fundamentals/dashboard#apps)


<div style="display: flex; gap: 10px; margin-bottom: 10px">
<img src="assets/screenshots/dashboard-create-app-a.png" alt="Detour Dashboard organization creator" width="50%"/>
<img src="assets/screenshots/dashboard-create-app-b.png" alt="Detour Dashboard app creator" width="50%"/>
</div>
<img src="assets/screenshots/dashboard-create-app-c.png" alt="Detour Dashboard app link details"/>
<br>

> **Dashboard**. _Create an organization (top-left), create a new app (top-right), and use the generated link (marked with red) in Link settings (bottom)._


### 2. Configure the platforms

Open **App configuration** and fill in the platform details:

- **iOS:** set Bundle ID to `detourreactnative.expobare` and 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_TEAM` in Xcode › Signing & Capabilities, also shown under [Apple Developer › Membership](https://developer.apple.com/account)). 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.expobare` and 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](https://detour.swmansion.com/docs/sdk/react-native/testing#testing-android-app-links) for more info.

The dashboard generates the `associatedDomains` and intent-filter snippets to paste into `app.json` ([below](#configuring-appjson)).

> For a production integration, fill all fields with real values. See [App configuration](https://detour.swmansion.com/docs/Fundamentals/getting-started#app-configuration) for full guidance.

→ [Dashboard › App configuration](https://detour.swmansion.com/docs/Fundamentals/dashboard#app-configuration)

<img src="assets/screenshots/dashboard-app-configuration.png" alt="Detour Dashboard App configuration"/>
<br>

> **Dashboard › App configuration**. _iOS and Android filled configurations with generated integration code snippets ready to copy._

1. Start the app on iOS/Android.
2. Confirm the app renders and `isLinkProcessed` is `false`.
3. Trigger a Detour link.
4. Confirm `isLinkProcessed` flips to `true` and `type`, `url`, and `route` fields are populated on screen.
### 3. Copy your credentials

Open **API configuration** and copy your `appID` and publishable `apiKey` into this example's `.env`.

→ [Dashboard › API configuration](https://detour.swmansion.com/docs/Fundamentals/dashboard#api-configuration-and-key-security)

<img src="assets/screenshots/dashboard-api-configuration.png" alt="Detour Dashboard API configuration"/>
<br>

> **Dashboard › API configuration**. _The API configuration panel with `appID` and the publishable `apiKey` ready to copy._

## Configuring app.json

After registering your app in the [Detour Dashboard](https://godetour.dev), replace the placeholders in `app.json` with values from the **API configuration** section:
Replace the placeholders in `app.json` with the values from the dashboard's [App configuration](https://detour.swmansion.com/docs/Fundamentals/dashboard#app-configuration) section:

- `<your-org>` — your organization slug
- `<your-app-hash>` — the path prefix assigned to your app

```json
"ios": {
"bundleIdentifier": "<your-bundle-identifier",
// ...
"associatedDomains": ["applinks:<your-org>.godetour.link"]
},
"android": {
"package": "<your-package>",
// ...
"intentFilters": [{
"data": [{ "host": "<your-org>.godetour.link", "pathPrefix": "/<your-app-hash>" }]
// ...
"data": [{ "scheme": "https", "host": "<your-org>.godetour.link", "pathPrefix": "/<your-app-hash>" }]
}]
}
```

These same values go into the simulator commands in the section below.
> **Universal Links not opening the app?** Add `?mode=developer` to the `associatedDomains` entry: `"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.

## Triggering links

**Universal / App link** — open a Detour HTTPS link:
<details>
<summary>Deferred deep link</summary>

Follow these steps to test the deferred flow:

1. Uninstall the app or clear its data to start from a clean state.
2. Open a Detour link in the device's mobile browser.
3. 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](https://detour.swmansion.com/docs/Architecture/architecture-limitations).

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.

</details>

<details>
<summary>Universal / App link</summary>

Open a Detour link directly from the terminal:

```sh
# iOS simulator
Expand All @@ -62,17 +133,38 @@ xcrun simctl openurl booted "https://<your-org>.godetour.link/<your-app-hash>/"
adb shell am start -a android.intent.action.VIEW -d "https://<your-org>.godetour.link/<your-app-hash>/"
```

**Deferred link** — simulates a link clicked before the app was installed:
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.

1. Copy a Detour link URL from the Dashboard to your clipboard.
2. Kill or uninstall the app.
3. Relaunch — the SDK reads the clipboard on startup and resolves the link automatically.
</details>

<details>
<summary>Custom scheme</summary>

```sh
# iOS simulator
npx uri-scheme open "detour-expo-bare://details" --ios

# Android emulator
npx uri-scheme open "detour-expo-bare://details" --android
```

</details>

For more cases and gotchas, see [Testing & Troubleshooting](https://detour.swmansion.com/docs/sdk/react-native/testing).

## Quick start

- Install dependencies from the repo root: `pnpm install`
- Configure this app in Detour Dashboard: `https://godetour.dev` using identifiers from `app.json` (for example `ios.bundleIdentifier`, `android.package`).
- Use values from Dashboard from "API configuration" section to fill `.env` and update `app.json` with generated integration code.
- Configure this app in the [Detour Dashboard](https://godetour.dev) using identifiers from `app.json` (for example `ios.bundleIdentifier`, `android.package`).
- Use the values from the dashboard's [API configuration](https://detour.swmansion.com/docs/Fundamentals/dashboard#api-configuration-and-key-security) section to fill `.env` and update `app.json` with the generated integration code.
- Run prebuild for this example: `pnpm prebuild`
- Start the example: `pnpm start`
- Run on device/simulator: `pnpm ios` or `pnpm android`

## See also

- [SDK Usage](https://detour.swmansion.com/docs/sdk/react-native/sdk-usage) — how to integrate Detour with your navigation library
- [API Reference](https://detour.swmansion.com/docs/sdk/react-native/api-reference) — full type and method reference
- [`examples/expo-router`](../expo-router) — minimal Expo Router integration
- [`examples/expo-router-advanced`](../expo-router-advanced) — auth-gated Expo Router flow
- [`examples/react-navigation`](../react-navigation) — minimal React Navigation integration
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 6 additions & 12 deletions examples/expo-bare/src/Screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,16 @@ export const Screen = () => {

<View style={styles.divider} />

<Text style={styles.sectionHeader}>Universal / App Link</Text>
<Text style={styles.bullet}>
Open a Detour link in the browser — iOS/Android will launch the app. Test with the
simulator using:
</Text>
<Text style={styles.code}>npx uri-scheme open {`"detour-expo-bare://"`} --ios</Text>

<Text style={styles.sectionHeader}>Deferred Link</Text>
<Text style={styles.bullet}>
Copy a Detour link to your clipboard, then kill and relaunch the app. Because{" "}
<Text style={styles.accent}>shouldUseClipboard</Text> is enabled, Detour reads the
clipboard on startup and resolves the pending link automatically.
Uninstall the app or clear its data, open a Detour link in the mobile browser, then
install and launch — the SDK resolves the link automatically.
</Text>
<Text style={styles.code}>https://&lt;your-org&gt;.godetour.link/&lt;hash&gt;/</Text>

<Text style={styles.sectionHeader}>Universal / App Link</Text>
<Text style={styles.bullet}>
Make sure <Text style={styles.accent}>Copy link feature enabled</Text> is turned on in
App Configuration in the Detour panel.
Open in browser or paste into Notes/Messages and tap — iOS/Android will launch the app.
</Text>
<Text style={styles.code}>https://&lt;your-org&gt;.godetour.link/&lt;hash&gt;/</Text>

Expand Down
Loading
Loading