# Deep linking

> Handle incoming deep links in your React Native app with the Grovs SDK.

Source: https://docs.grovs.io/docs/sdk/react-native/deep-linking

Register `onDeeplinkReceived` once and route the user from its payload.

## Listening for deep links

The listener gets the link that opened the app and its custom payload:

```typescript
import Grovs from 'react-native-grovs-wrapper';

const listener = Grovs.onDeeplinkReceived((response) => {
    console.log('Link:', response.link);
    console.log('Data:', response.data);

    // Route the user based on payload
    if (response.data?.screen === 'product') {
        navigation.navigate('Product', { id: response.data.productId });
    }
});

// When you no longer need the listener
listener.remove();
```

It fires for links that open the app, links delivered while it runs, deferred links matched after a fresh install (by fingerprint or clipboard), and tapped Grovs [push campaigns](https://docs.grovs.io/docs/sdk/react-native/push-notifications#what-your-app-receives) (3.1). `response.data` holds the `data` passed when [generating the link](https://docs.grovs.io/docs/sdk/react-native/link-creation). The event also carries the link's `tracking` metadata on both platforms, though `DeeplinkResponse` doesn't type it.

From 3.1.0, `response.link` is optional: a push campaign without a link arrives with `data` only. Check `link` before using it.

### When to register

Register once, in your root component or entry point. No race: the launch link is held natively and delivered when the first listener registers. iOS holds only the most recent link.

On Android each new registration restarts the native subscription and re-delivers the latest link to every listener. Registering in several components can navigate twice.

Links only arrive with the URL scheme, intent filters, Associated Domains, and `AppDelegate` and `MainActivity` forwarding from the [Quick Start](https://docs.grovs.io/docs/sdk/react-native/quick-start).

### When the lookup fails

If the lookup fails (phone offline, backend unavailable), the native SDK keeps the link and retries after a widening wait, on return to foreground, and when the network comes back. The listener fires once it succeeds.

### While the SDK is disabled

Links aren't resolved while `setSDK(false)` is in effect. On Android, `setSDK(true)` forwards `onStart` again, so a launch link is delivered then. On iOS it isn't replayed. See [Privacy & Consent](https://docs.grovs.io/docs/sdk/react-native/privacy#re-enabling).

## Clipboard-assisted deferred deep linking

When a copy-to-clipboard link opens in a browser, the preview page copies it to the clipboard before sending the visitor to the store. On first launch after install, if fingerprint matching found nothing, the native SDK reads the clipboard and attributes the install deterministically. The link arrives through `onDeeplinkReceived`, possibly several seconds after launch.

No JavaScript is needed. The check is skipped when the backend reports no recent clicks on your clipboard-enabled links. Only links on Grovs hosts or your configured domains are sent. Platform details (the iOS paste notice, the Android 12+ "pasted from your clipboard" toast) are on the [iOS](https://docs.grovs.io/docs/sdk/ios/deep-linking#clipboard-assisted-deferred-deep-linking) and [Android](https://docs.grovs.io/docs/sdk/android/deep-linking#clipboard-assisted-deferred-deep-linking) pages.

If your links use a custom domain, list it. With the Expo config plugin, set `clipboardDomains`:

```json
["react-native-grovs-wrapper", {
  "apiKey": "your-api-key",
  "scheme": "your_app_scheme",
  "clipboardDomains": ["links.yourdomain.com"]
}]
```

In a bare project, pass it to the native `configure` calls:

```swift
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: false, autoTrackScreenViews: false, clipboardDomains: ["links.yourdomain.com"], enabled: GrovsWrapperSwift.isSDKEnabled(), delegate: GrovsWrapperSwift.shared)
```

```kotlin
Grovs.configure(this, "your-api-key", useTestEnvironment = false, baseURL = null, autoTrackScreenViews = false, clipboardDomains = listOf("links.yourdomain.com"), enabled = GrovsConsent.isEnabled(this))
```

Enable copy-to-clipboard per link with [`copyToClipboardIos` and `copyToClipboardAndroid`](https://docs.grovs.io/docs/sdk/react-native/link-creation), or set the project default in the dashboard. Flow, settings and limits: [Copy to Clipboard](https://docs.grovs.io/docs/links/copy-to-clipboard).

## Looking up a link

To read a link's details by path, use [`linkDetails`](https://docs.grovs.io/docs/sdk/react-native/link-creation#inspecting-a-link) (3.1).

## Next steps

- [Generate smart links →](https://docs.grovs.io/docs/sdk/react-native/link-creation)
- [Track events and screens →](https://docs.grovs.io/docs/sdk/react-native/analytics)
- [Full API reference →](https://docs.grovs.io/docs/sdk/react-native/api-reference)
