# Deferred deep linking

> What happens when a link is clicked before the app is installed, and why the payload sometimes doesn't arrive on first launch.

Source: https://docs.grovs.io/docs/troubleshooting/deferred-deep-linking

Deferred deep linking delivers a link's payload to a user who tapped it **before installing your app**. The link sends them to the store or your fallback. After install, Grovs matches the click to the install and delivers the payload on first launch. It's automatic: there's no separate API.

## How the payload arrives

Through the **same callback** as a regular deep link, on the first launch after install:

| Platform     | Callback                                                                                                                                                              |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| iOS          | `grovsReceivedPayloadFromDeeplink(link:payload:tracking:)` on your `GrovsDelegate`. See [iOS Deep Linking](https://docs.grovs.io/docs/sdk/ios/deep-linking).          |
| Android      | The `Grovs.setOnDeeplinkReceivedListener` listener, or the `openedLinkDetails` flow. See [Android Deep Linking](https://docs.grovs.io/docs/sdk/android/deep-linking). |
| Flutter      | The `onDeeplinkReceived` stream. See [Flutter Deep Linking](https://docs.grovs.io/docs/sdk/flutter/deep-linking).                                                     |
| React Native | The `Grovs.onDeeplinkReceived` callback. See [React Native Deep Linking](https://docs.grovs.io/docs/sdk/react-native/deep-linking).                                   |

Handle deferred and direct opens the same way.

## Common pitfalls

### Installing before tapping the link

If you install the build first and tap the link afterwards, that's a _direct_ deep link. The deferred path never runs. This is the most common testing mistake.

Test in this order:

1. **Uninstall** the app from the test device.
2. **Tap the Grovs link** on that device. It redirects to the store page or fallback URL.
3. **Install and launch** the app on the same device. A development build from Xcode or Android Studio is fine here: what matters is that the tap came first.
4. The payload arrives in your delegate or listener shortly after the SDK initializes.

### Listener registered too late

The deferred payload arrives early in the first launch. A delegate or listener set up later, for example on a deeper screen, misses it.

Register the handler at app entry:

- **iOS:** set `Grovs.delegate` at app startup. Recover missed payloads with `Grovs.lastReceivedPayload` or `Grovs.allReceivedPayloadsSinceStartup`. See [Retrieving past payloads](https://docs.grovs.io/docs/sdk/ios/deep-linking#retrieving-past-payloads).
- **Android:** register the listener in your launcher activity.
- **Flutter and React Native:** subscribe in your root component.

### Click and install in different environments

A test-environment link opened before installing a production build (or the reverse) records the click and the install in different environments, so they never match. Match the link's environment to the build's `useTestEnvironment`. See [Test vs production environment mismatch](https://docs.grovs.io/docs/troubleshooting/sdk-configuration-issues#test-vs-production-environment-mismatch).

### Click and install on different devices

Matching connects a click to an install on the **same device**. Tapping on your laptop and installing on your phone produces no payload. Run the whole flow on one device.

> **Tip:** If direct deep links don't work either, fix those first: see [Deep link doesn't open the app](https://docs.grovs.io/docs/troubleshooting/deep-link-not-opening-app). Deferred delivery uses the same SDK setup.
