# Deep linking

> Receive link payloads in your web app with the Grovs SDK.

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

Pass `onDeeplink` to `configure` and the SDK delivers each link's payload. Nothing else is needed.

## Receiving deep link payloads

The SDK reads the link parameter from the page URL, resolves the payload and calls you back:

```javascript
await Grovs.configure({
  apiKey: "your-api-key",
  onDeeplink: (payload) => {
    if (payload.screen === "product") {
      router.push(`/products/${payload.id}`);
    }
  },
});
```

The callback runs when a lookup returns a payload object; a link without a payload doesn't trigger it. With no link parameter in the URL, deferred matching can still return a payload, for a visitor who clicked a link earlier and arrives later.

### What the callback receives

`payload` is the link's custom data: the key-value pairs from the **Data** section when the link was [created in the dashboard](https://docs.grovs.io/docs/links/create-link), or the `data` passed to [`generateLink`](https://docs.grovs.io/docs/sdk/web/link-creation). Keys and values are unrestricted.

### Reading payloads later

```javascript
Grovs.lastReceivedPayload();               // the most recent payload, or null
Grovs.allReceivedPayloadsSinceStartup();   // every payload since the page loaded
```

Both return `[]` or `null` before `configure`.

## Refreshing the page

A refresh with `?Grovs=...` (or legacy `?linksquared=...`) still in the URL resolves the link again and delivers its payload. The SDK consumes the stored token after a successful lookup but leaves the URL unchanged. To handle a link only once, remove the query parameter after handling it and guard actions that mustn't repeat.

## With consent gating

With `requireConsent: true`, `configure` captures the URL's link token in memory, but the lookup and `onDeeplink` wait for `grantConsent()`. A router that cleans the query string while the consent banner is up doesn't lose the link. See [Privacy & Consent](https://docs.grovs.io/docs/sdk/web/privacy).

## Handling SDK errors

Every failure reaches `onError` with a code shared with the iOS and Android SDKs:

```javascript
import Grovs, { GrovsError } from "grovs";

await Grovs.configure({
  apiKey: "your-api-key",
  onError: (code, message) => {
    if (code === GrovsError.authenticationFailed) reportToSentry(message);
  },
});
```

| Code                       | Meaning                                                                                                                                                                           |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `1` `authenticationFailed` | Bad API key, an origin that isn't a linked domain, or another authentication failure.                                                                                             |
| `2` `networkRequestFailed` | A request failed after retries, or the SDK was called during server rendering.                                                                                                    |
| `3` `eventDispatchFailed`  | An event batch was rejected. Events stay queued unless permanently invalid.                                                                                                       |
| `4` `linkGenerationFailed` | Link generation failed.                                                                                                                                                           |
| `5` `inAppDisplayFailed`   | An [in-app message](https://docs.grovs.io/docs/sdk/web/in-app-messages) couldn't be drawn, for example an HTML message blocked by the page's Content-Security-Policy. New in 2.1. |

Errors are informational; the SDK recovers from transient ones. A permanent `authenticationFailed` (bad key, unlinked origin) isn't retried. Fix the cause and call `configure` again.

## Getting link details

Details for a link the SDK generated, by path:

```javascript
const details = await Grovs.linkDetails("abc123");
```

Resolves `null` when the path is unknown.

## Next steps

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