> ## Documentation Index
> Fetch the complete documentation index at: https://developer.cashbackhive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Click tracking

> Learn how Cashback Hive tracked links attribute purchases to your property, and how to attach your own click IDs, sub-IDs and retailer deep links.

Every offer that supports tracking has a `clickUrl` — a template for a Cashback Hive redirect link. When a shopper follows it, Cashback Hive records the click and forwards them to the retailer, so any resulting purchase is attributed to your property (and to the signed-in member, if there is one).

## `openOffer()` vs `trackingUrl()`

| | `openOffer(offer, opts)` | `trackingUrl(offer, opts)` |
| - | - | - |
| Builds the tracked URL | Yes | Yes |
| Opens it | Yes — new tab by default, or `location.assign` with `newTab: false` | No — returns the URL as a string |
| Emits the `click` event | Yes | No |
| Sends an `offer_click` analytics beacon | Yes | No |
| Use when… | A button or card is clicked | You need the URL for an `<a href>`, QR code, email, or your own redirect |

> [!NOTE]
>
> Prefer `openOffer()` for user-initiated clicks. If you render tracked URLs into `<a>` tags with `trackingUrl()`, Cashback Hive still records the click server-side when the link is followed, but the SDK's `click` event and client-side beacon won't fire.

## Options

Both methods accept the same tracking options.

**clickId** `string`

Your own identifier for this click. Substituted into the `{PublisherClickID}` placeholder. Defaults to a random UUID generated by the SDK. Use this if you want to correlate Cashback Hive's click records with your own logs.

**subId** `string`

Free-form attribution label — a placement, campaign, page section or hashed user ID. Substituted into `{SubId}`. Defaults to an empty string. Appears in your reporting.

**deeplink** `string`

A specific retailer URL (e.g. a product page) to land on instead of the retailer's homepage. Only used when `offer.supportsDeeplinking` is `true`; ignored otherwise. Substituted into `{DeepLink}`.

**newTab** `boolean` (default: true)

`openOffer()` only. Open in a new tab (`window.open` with `noopener`) or navigate the current tab (`location.assign`).

```js theme={null}
sdk.openOffer(offer, {
  subId: "deals-page/hero",
  deeplink: "https://www.nike.com/t/air-max-90",
});
```

## Passing a slug instead of an offer

Both methods accept either an offer object or a slug string. When you pass a slug, the SDK looks it up in its **offer cache**, which is populated by `offers.list()` and `offers.get()`. If the slug isn't cached, the call throws:

```
[CashbackHive] unknown offer "nike"; call offers.list() or offers.get() first
```

So this works:

```js theme={null}
await sdk.offers.get("nike");
sdk.openOffer("nike");
```

But calling `openOffer("nike")` on a fresh page load without fetching first will throw. When in doubt, pass the offer object.

## Offers without tracking

`clickUrl` is `null` for offers that don't support click tracking. `trackingUrl()` and `openOffer()` throw for these:

```
[CashbackHive] click tracking is not available for "some-brand"
```

Check `offer.clickUrl` before rendering a call to action, and disable or hide it when it's `null`.

## Listening for clicks

`openOffer()` emits a `click` event you can use for your own analytics:

```js theme={null}
sdk.on("click", ({ slug, url }) => {
  analytics.track("Offer clicked", { slug });
});
```

See [Events](https://developer.cashbackhive.com/reference/events.md).

## Popup blockers

`openOffer()` with the default `newTab: true` calls `window.open`. Browsers allow this only inside a user gesture (a click handler). If you call it asynchronously after a click — for example after awaiting an API call — the new tab may be blocked. Either fetch what you need before the click, or use `newTab: false`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.