# Attribution Tag (/docs/attribution-tag)

GA4 keeps only the *host* of a referrer, as `sessionSource`. That is usually enough - `chatgpt.com` is `chatgpt.com`. But the moment GA4 re-attributes a session, the referrer is gone and the visit lands in **(direct)**, indistinguishable from someone typing your URL.

The RankZero attribution tag captures the full referrer and the full landing query string on the visitor's **first hit**, keeps them for the visit in a first-party cookie, and attaches them to every GA4 event. Once it is installed, RankZero folds that captured referrer into your AI Traffic figure automatically - no setting to switch on.

## What it recovers, and what it cannot

**Recovers.** Sessions where a referrer genuinely existed but GA4 dropped it:

* the session timed out mid-visit and restarted as direct
* a redirect, interstitial, or consent gate stripped the header along the way
* a cross-domain hop broke the chain
* the visitor came back later in the same visit from a different tab

**Cannot recover.** Sessions where the browser never sent a referrer at all:

* links opened from the ChatGPT desktop and mobile apps, which use an embedded browser that drops the `Referer` header
* URLs the visitor copied and pasted
* links marked `rel="noreferrer"`

That information does not leave the other side, so nothing running on your page can reconstruct it. Anything claiming to attribute those clicks is guessing. The **Unattributed traffic** card on your Traffic page shows how much of that bucket is at least *consistent* with AI - it is labelled an estimate because that is what it is.

<Callout type="warn">
  The tag cannot see Google AI Overviews or AI Mode either. Google classifies both as Organic Search by its own definition and sends no marker to the destination. Brave is the same story: `search.brave.com` sends `strict-origin-when-cross-origin`, so its AI answers and its web results arrive under one identical referrer.
</Callout>

## 1. Add the tag

Place this **after** your gtag.js or Google Tag Manager snippet, on every page:

```html
<script src="https://www.rankzero.io/rz-attribution.js" defer></script>
```

It sets no identifiers, reads no storage other than its own cookie, and sends nothing to RankZero - the values travel to your own GA4 property, on your own measurement ID.

## 2. Register the custom dimensions in GA4

The tag writes three event parameters. GA4 discards event parameters that are not registered, so this step is required - nothing is reported until it is done.

In GA4: **Admin → Data display → Custom definitions → Create custom dimension**. Create one for each, all **event-scoped**:

| Dimension name   | Event parameter    | What it holds                                                                  |
| ---------------- | ------------------ | ------------------------------------------------------------------------------ |
| RZ Referrer      | `rz_referrer`      | Full referring URL at first touch, `(none)` if there was none                  |
| RZ Landing Query | `rz_landing_query` | Landing page query string, so `utm_source=chatgpt.com` survives re-attribution |
| RZ First Seen    | `rz_first_seen`    | ISO timestamp of the first hit of the visit                                    |

Only `rz_referrer` is required for AI attribution; the other two are what make the data readable when you go looking.

## 3. Nothing else

RankZero checks each connected property for the `rz_referrer` dimension and starts using it the moment it appears. There is no toggle and no per-brand configuration.

<Note>
  GA4 does not backfill. The dimension only carries data from the moment both the tag and the custom dimension are live, so give it a few days before comparing.
</Note>

## Verifying it works

1. Open your site from another site (any external link will do) in a fresh browser profile.
2. In GA4, go to **Reports → Realtime** and find your session.
3. Or check the cookie directly: in the browser console, `document.cookie` should contain an `rz_attr` entry holding the referrer you arrived from.

If `rz_attr` is present but GA4 shows nothing, the custom dimensions have not been registered - GA4 drops unregistered parameters silently.

## Privacy

The tag stores one first-party cookie, `rz_attr`, for six hours. It contains the referring URL, the landing query string, and a timestamp - no identifiers, no fingerprinting, nothing read from other storage. It is the same information the browser already handed your server in the `Referer` header, kept for the length of the visit so a re-attributed session does not lose it.

Because it writes to your GA4 property, it inherits whatever consent gating you already apply to GA4. If you load it only after consent, it captures the referrer at that point instead.
