ChangelogPricing
DocsIntegrationsAttribution Tag

Attribution Tag

Recover AI referrals that GA4 files as direct, by capturing the first-touch referrer on your own site.

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.

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.

1. Add the tag

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

<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 nameEvent parameterWhat it holds
RZ Referrerrz_referrerFull referring URL at first touch, (none) if there was none
RZ Landing Queryrz_landing_queryLanding page query string, so utm_source=chatgpt.com survives re-attribution
RZ First Seenrz_first_seenISO 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.

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.

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.