Centinel AnalyticaCentinel Analytica

Preserve the Referrer

Carry the original visitor source across the interstitial so your analytics still sees where traffic came from.

Overview

When an uncertain visitor passes through the interstitial challenge, the browser reloads into your protected page. That reload erases the original referrer, so analytics on the page attributes the visit to your own site instead of the real source (Google, a newsletter, a partner link).

Centinel preserves the original source in a session-scoped value named _centinel_ref, kept in the browser's sessionStorage. This page explains why the loss happens and how to hand the saved value to your analytics.

Why the referrer is lost

The interstitial is a real page load. To send the visitor on to your content, it calls location.reload(). A reload (like a redirect) does not carry the previous page's referrer forward: after it, both document.referrer and the Referer request header become the interstitial's own URL. The visit looks like a self-referral from your own domain.

JavaScript cannot fix this on its own. document.referrer is read-only, and Referer is a forbidden header that scripts may not set on a top-level navigation. The only document that still holds the true upstream referrer is the interstitial itself, before it reloads.

The _centinel_ref value

While it is still running, the collector script the interstitial loads captures the upstream referrer and writes it to sessionStorage so it survives the reload. sessionStorage is scoped to the tab and origin, so the value is there when your page loads but never travels to your server the way a cookie would.

The entry is keyed _centinel_ref. Four properties decide how you read it:

  • Origin only. The entry holds the referrer's origin (https://www.google.com), never the full path or query. That is all an analytics tool needs for source attribution, and it stays free of personal data regardless of the referring site's Referrer-Policy.
  • Cross-origin only. It is written only when the visitor arrived from a different origin. A same-origin visit leaves nothing behind, so your own URL is never stored as a source.
  • Readable on one origin. Only the origin that served the interstitial can read the entry, so a page on www.example.com will not find a value written on example.com.
  • Cleared on every run. Each interstitial run removes the entry before deciding whether to store a fresh one. A second interstitial in the same tab therefore discards an origin saved earlier, so read the value on the first page view after the challenge.

The value is absent when there was no cross-origin referrer. Always treat it as optional: if it is missing, fall back to the browser's normal behavior.

Restore the referrer

One snippet covers every tool. Most trackers read document.referrer themselves and give you no way to override it, so instead of wiring each one, redefine document.referrer before any of them loads.

<script>
(function () {
  try {
    var ref = sessionStorage.getItem('_centinel_ref');
    if (!ref) return;
    sessionStorage.removeItem('_centinel_ref');
    Object.defineProperty(document, 'referrer', {
      get: function () { return ref; },
      configurable: true
    });
  } catch (e) {}
})();
</script>

document.referrer is a getter on Document.prototype. Defining an own property on document shadows that getter for the rest of the page view, so anything reading the referrer gets the original source instead of your own URL.

Nothing else changes. With no stored value the snippet returns early and every tool sees the browser's own referrer, exactly as it would without this code. That is what makes it safe on the page views that never meet an interstitial, and in browsers that block sessionStorage.

Placement decides whether this works. The snippet has to run before your tag manager and before every analytics loader in <head>. A tracker that has already read the referrer keeps the old value.

If your tags live in Google Tag Manager, the snippet can go in a Custom HTML tag on the Initialization - All Pages trigger, which runs before the container's other tags. That orders only what GTM fires. A tracker installed as its own <script> in the page, as Chartbeat often is, still needs the snippet above it in the markup.

The patch applies to scripts on the page, nothing else. The HTTP Referer header still carries the interstitial URL, so CDN logs and server-side tagging are unaffected. Reporting fed by a server-side export never sees sessionStorage either: forward the origin yourself as a field on an event your page already posts to that pipeline.

When you cannot control load order

A consent manager or a CMS that injects analytics ahead of your own markup leaves nowhere to put the snippet first. Where the tracker exposes a referrer field, read the value and pass it there instead of patching the document. That route does not depend on load order, because you are setting a value rather than racing to shadow a getter.

function centinelReferrer() {
  const ref = sessionStorage.getItem('_centinel_ref');
  if (ref) sessionStorage.removeItem('_centinel_ref');
  return ref || undefined;
}

This is the same read and clear the patch performs, so use one route or the other on a page. Whichever runs first takes the value, and the second finds nothing.

Google Analytics 4 accepts the origin as page_referrer on the config call or in the GA4 tag's Fields to set. Not every tool has such a field. Chartbeat exposes no referrer key in _sf_async_config, so there the document patch is the only route.

Verify

Load a page through the interstitial from an external source, then check what your tracker sends.

For Chartbeat, filter the Network tab on ping? and open a request to ping.chartbeat.net. Two query parameters carry the source:

ParameterCarries
rThe referring URL when the referrer is an external site.
vThe referring URL when the referrer is your own site.

When the restore works, r holds the saved origin and v is absent. Without it the reverse is true: v holds your own URL, because the reload made the visit look like a self-referral.

For Google Analytics 4, open DebugView and read the page referrer on the page_view event, or look for dr= on the request to /g/collect.

Trackers that post JSON rather than a query string carry the value under their own name. A Snowplow collector, for one, sends it as refr in the pv event body.

See also

On this page