Site Landing & Site Referrer Preservation
Site Landing Page & Site Referrer to Cookies in Google Tag Manager — A Complete Recipe Without Custom JavaScript
Persist the user's landing page host, landing page path, and referral source into session or long-lived persistent cookies using only GTM sandboxed Custom Templates. No Custom HTML tags. No new CSP hashes.
Where did this user first land on your site — and what referred them there? Those two pieces of information are foundational to understanding any user journey. But they only exist at the moment of the first page load. Navigate to a second page, return in a new browser session, or submit a form three days after the original visit, and the browser's native referrer is gone and the landing URL has long since changed. Without a persistence layer, you are flying blind.
This recipe solves that problem cleanly. On the very first Initialisation event — before any other
tag fires — it captures the site landing host, landing page path, and referral host, and writes
them into browser cookies. Session cookies cover the current visit; persistent cookies with a
_1 suffix survive for up to 730 days, recording the user's first ever
landing and referral. Both cookie sets flow automatically into every GA4 hit via Shared Event
Settings and GA4 User Properties. No Custom HTML tags. No new Content Security Policy SHA-256
hashes required.
The Core Problem: Landing Context Vanishes After the First Page
A visitor arrives at https://example.com/pricing referred from a partner site at
https://partner.example.org/blog/recommended-tools. GA4 records the referral for
the session. But the user does not convert. They return three days later by typing the URL directly.
GA4 now attributes that second session to direct. The referral source that actually
initiated the relationship is invisible.
The same problem applies to your own site's landing pages. Knowing that a user's first ever
landing was /pricing versus /blog/use-case-study gives you a completely
different picture of their intent and where they are in the funnel — information that is lost the
moment they navigate away from that first page.
Cookies are the browser's built-in persistence mechanism for exactly this purpose. This recipe writes the landing and referral context on Initialisation (the very first GTM event) and makes those values available across every subsequent page view, event, and session.
utm_source is a free-text field — there is
nothing enforcing that it contains an actual traffic source. A campaign tagged
utm_source=spring-promo tells you nothing about where traffic originated. The site
referrer, by contrast, is set by the browser and reflects the actual page the user navigated from.
Capturing the referral host independently of UTM tagging gives you a ground-truth signal of traffic
origin that is not subject to marketer naming conventions.
<script> block. Any such
script requires its SHA-256 hash to be listed in your Content-Security-Policy
header's script-src directive. Every time the script changes — even whitespace —
the hash changes and must be redeployed. This recipe uses only GTM sandboxed Custom Templates,
which execute inside GTM's own sandbox and require zero additions to your CSP. The cookie-writing
logic runs entirely within the GTM runtime — no new hashes, no security team review cycles.
What's Inside the Container
The exported container (site-landing-and-referrer-2-cookies-recipe.json) is organised
into three folders, plus the existing Analytics infrastructure and sandboxed Custom Templates.
Folders
| Folder | Contains |
|---|---|
| Analytics | GA4 configuration tag, shared settings variables, environment and stream routing variables, and client ID and timestamp utilities. |
| Process site landing & site referrer 2 cookies | Two tags (session and user/persistent), plus eight Cookie Variable variables reading the landing host, landing path, referral host, and referral path for each track. Fires on Initialisation — the earliest possible GTM event — to capture the landing context before any other tag can fire. |
| Extend Cookie Life | One tag and two supporting variables. Rewrites the persistent cookies on every page visit to refresh their expiry date, ensuring the 730-day window resets on each visit rather than counting from first write. |
Tags
| Tag | Type | Purpose |
|---|---|---|
Google Analytics Configuration |
Google Tag (googtag) |
Standard GA4 configuration tag. Shared Event Settings and User Properties automatically forward landing and referral cookie values on every GA4 hit. |
Write site landing & site referrer 2 cookies user |
Custom Template — Write site landing & site referrer 2 cookies | Fires on Initialisation, but only if the landing host and referral host persistent cookies do not already exist (trigger condition: both {{site Referral Host user}} and {{site Landing Host user}} match the empty/null regex). Writes four persistent cookies expiring in 730 days, with the _1 suffix: landHost_1, landPath_1, referHost_1, referPath_1. Because the trigger only fires when the cookies are absent, these values are set exactly once — on the user's first ever visit — and never overwritten. |
Write site landing & site referrer 2 cookies session |
Custom Template — Write site landing & site referrer 2 cookies | Fires on Initialisation, but only if the session-level cookies are absent (both {{site Referral Host session}} and {{site Landing Host session}} are empty). Writes four session cookies — landHost, landPath, referHost, referPath — that expire when the browser closes. Refreshed on each new browser session. |
Extend Cookie Life Tag |
Custom Template — Cookie Rewriter | Fires on DOM Ready, guarded by the _arrewr sentinel cookie. Rewrites the persistent landing and referral cookies with a refreshed expiry of 720 days from now, without altering their values. |
Triggers
| Trigger | Type | Condition | Purpose |
|---|---|---|---|
Write site landing & site referrer 2 cookies user |
Initialisation | {{site Referral Host user}} AND {{site Landing Host user}} both match ^(undefined|null|0|false|NaN|)$ |
Fires the persistent-cookie write tag on the very first page load of the user's first ever visit. The Initialisation event type ensures this runs before GA4 configuration and before any other tag fires. The double condition ensures the write only happens once — when both persistent cookies are still absent. |
Write site landing & site referrer 2 cookies session |
Initialisation | {{site Referral Host session}} AND {{site Landing Host session}} both match ^(undefined|null|0|false|NaN|)$ |
Fires the session-cookie write tag on the first page load of each new browser session. Because session cookies expire when the browser closes, the condition will be true at the start of each new session, refreshing the session-level landing context. |
Extend Cookie Life Trigger |
DOM Ready | {{Extend Cookie Life Already Ran Cookie Value}} matches ^(undefined|null|0|false|NaN|)$ |
Fires the Cookie Rewriter tag once per page load. The sentinel cookie _arrewr prevents the tag firing more than once per page even if DOM Ready fires multiple times. |
Custom Templates
| Template | Author | Purpose |
|---|---|---|
Write site landing & site referrer 2 cookies |
drewspen | Reads the current page's host, page path, document referrer host, and document referrer path, and writes them to browser cookies with configurable expiry (session or persistent), a cookie name suffix, root domain scoping, and optional URI decoding. Runs entirely within the GTM sandboxed template runtime — no Custom HTML, no CSP implications. |
Cookie Rewriter |
drewspen | Rewrites a specified list of existing cookies with a refreshed expiry date, converting static expiry windows into rolling windows that extend on each visit. |
If Else If — Advanced Lookup Table |
Sublimetrix | Powers coalesce and routing logic elsewhere in the container. |
Timestamp |
Sublimetrix | Reads Unix timestamps from GA4 session and client cookies for shared event parameters. |
Get Root Domain |
drewspen | Extracts the registrable root domain for cookie scoping, ensuring cookies are accessible across subdomains (e.g. www.example.com and app.example.com). |
Two Tracks: Session Cookies and Persistent Cookies
The recipe deliberately writes each landing and referral value twice — once as a session cookie and once as a persistent cookie. This gives you two distinct attribution windows with a single implementation: what happened in this session, and what happened on the user's first ever visit.
Session Cookies — Current Visit Context
Session cookies expire automatically when the browser is closed. They record the landing page
and referral source for the current visit only. This is ideal for within-session attribution:
if a user arrives from a partner site, browses three pages, and completes a download, the session
cookie carries the referral host through the entire session — even though document.referrer
changes on every page navigation.
| Cookie Name | Type | Content |
|---|---|---|
landHost | Session | Hostname of the first page the user landed on this session (e.g. example.com) |
landPath | Session | Page path of the first landing page this session (e.g. /pricing) |
referHost | Session | Hostname of the referring site at session start (e.g. partner.example.org) |
referPath | Session | Full referrer path at session start (URI-decoded) |
Persistent Cookies — First-Touch Attribution Across Visits
Persistent cookies survive browser restarts and are retained for up to 730 days (2 years) from
initial write. The _1 suffix is the distinguishing convention — these cookies hold
the values from the user's very first visit. Because the user-level trigger only fires
when both cookies are absent, the values are written exactly once and never overwritten by
subsequent visits. When the Cookie Rewriter runs on later visits, it refreshes the expiry without
touching the values, preserving the original first-touch context.
| Cookie Name | Type | Expiry | Content |
|---|---|---|---|
landHost_1 | Persistent | 730 days (rolling) | Hostname of the user's first ever landing page |
landPath_1 | Persistent | 730 days (rolling) | Page path of the user's first ever landing page |
referHost_1 | Persistent | 730 days (rolling) | Hostname of the referring site on the user's first ever visit |
referPath_1 | Persistent | 730 days (rolling) | Full referrer path on the user's first ever visit (URI-decoded) |
The Rolling Expiry: How the Cookie Rewriter Works
A persistent cookie written once with a 730-day expiry will expire 730 days after it was first written, regardless of how often the user returns. For most use cases, a rolling expiry is preferable — active users should never lose their first-touch attribution simply because they have not visited in 730 days since acquisition.
The Extend Cookie Life Tag achieves rolling expiry by running the Cookie Rewriter
template on every page visit. It reads each of the four persistent landing and referral cookies
and rewrites them with the same value but a new expiry date set 720 days from the current time.
The first-touch values are preserved; only the expiry date changes.
The Sentinel Guard: Firing Exactly Once Per Page
To avoid the Cookie Rewriter firing multiple times per page load, the recipe uses a sentinel
cookie named _arrewr. The Extend Cookie Life Trigger condition checks
{{Extend Cookie Life Already Ran Cookie Value}} against the regex
^(undefined|null|0|false|NaN|)$. The tag fires only when the sentinel is absent or
empty. The Cookie Rewriter template sets _arrewr on its first run, preventing any
subsequent firing within the same page load.
Cookie Variables: Reading the Values Back
Eight Cookie Variable variables are included in the
Process site landing & site referrer 2 cookies folder, one
for each cookie. These use GTM's built-in First-Party Cookie variable type and require no custom
code. The landPath and referPath variables are configured with URI
decoding enabled; the host variables are not, as hostnames do not require decoding.
| Variable Name | Cookie Read | Decode | Track |
|---|---|---|---|
site Landing Host session | landHost | No | Current session |
site Landing Page Path session | landPath | Yes | Current session |
site Referral Host session | referHost | No | Current session |
site Referral Page Path session | referPath | Yes | Current session |
site Landing Host user | landHost_1 | No | First touch (persistent) |
site Landing Page Path user | landPath_1 | Yes | First touch (persistent) |
site Referral Host user | referHost_1 | No | First touch (persistent) |
site Referral Page Path user | referPath_1 | Yes | First touch (persistent) |
How Landing and Referral Data Flow Into Every GA4 Hit
The cookie variable values are wired into the Google Tag Shared Event Settings variable as event-scoped parameters and into the GA4 User Properties block. This means the values are forwarded on every GA4 event sent by the container — page views, scroll events, clicks, form submissions, and conversions alike — without any need to touch individual tag configurations.
Shared Event Settings — Landing and Referral Parameters
| GA4 Event Parameter | GTM Variable | Attribution Track |
|---|---|---|
e_cur_landing_host | {{site Landing Host session}} | Landing hostname for the current session |
e_cur_landing_path | {{site Landing Page Path session}} | Landing page path for the current session |
e_cur_referral_source | {{site Referral Host session}} | Referral hostname for the current session |
e_1st_landing_host | {{site Landing Host user}} | Landing hostname on user's first ever visit |
e_1st_landing_path | {{site Landing Page Path user}} | Landing page path on user's first ever visit |
e_1st_referral_source | {{site Referral Host user}} | Referral hostname on user's first ever visit |
GA4 User Properties — Landing and Referral
In addition to event-scoped parameters, the Shared Event Settings variable also populates GA4 User Properties. User Properties persist at the user level in GA4 and are available in audience definitions, Explorations, and BigQuery exports.
| GA4 User Property | GTM Variable | Attribution Track |
|---|---|---|
u_cur_landing_host | {{site Landing Host session}} | Landing hostname for the current session |
u_cur_landing_path | {{site Landing Page Path session}} | Landing page path for the current session |
u_cur_referral_source | {{site Referral Page Path session}} | Referral page path for the current session |
u_1st_landing_host | {{site Landing Host user}} | Landing hostname on user's first ever visit |
u_1st_landing_path | {{site Landing Page Path user}} | Landing page path on user's first ever visit |
u_1st_referral_source | {{site Referral Page Path user}} | Referral page path on user's first ever visit |
Architecture: How a Landing Becomes a Cookie Becomes a GA4 Parameter
- User lands on the site for the first time. GTM fires the Initialisation event — the very earliest event in the GTM lifecycle, before page view, before DOM Ready, before any other tag.
- Both user-level persistent cookie triggers evaluate. Because
landHost_1andreferHost_1do not yet exist, both Cookie Variable variables return empty strings matching the null regex. The trigger fires. - The user-level write tag runs. The Write site landing & site referrer 2 cookies user tag reads the current page hostname, current page path, document referrer hostname, and document referrer path, and writes them as persistent cookies scoped to the root domain (e.g.
.example.com), expiring 730 days from now. These values are permanently set for this user. - The session-level write tag also runs. If the session cookies are also absent (new session), the Write site landing & site referrer 2 cookies session tag writes the same four values as session cookies (no expiry — browser-close expiry).
- GTM fires DOM Ready. The
Extend Cookie Life Triggerchecks the_arrewrsentinel. If absent, the Extend Cookie Life Tag rewrites the four persistent cookies with a new 720-day expiry from now. - Cookie Variable variables are evaluated on every GTM event. The eight cookie variables read the current values from the browser for every subsequent event.
- Shared Event Settings deliver values to GA4. The six event parameters (
e_cur_*ande_1st_*) and six User Properties (u_cur_*andu_1st_*) are included in every GA4 hit automatically. - Days or weeks later, the user returns directly. Their persistent cookies still hold the original first-touch landing and referral values. The session cookies are absent (browser closed), so the session-level write tag fires again, capturing the new session's landing context. The persistent cookies are extended by the Cookie Rewriter but their values are unchanged.
- A conversion event fires. GA4 receives both the current-session landing context and the first-ever landing context on the same event hit, allowing multi-session journey analysis in a single query.
Why Sandboxed Templates Do Not Require New CSP Hashes
GTM's sandboxed Custom Template runtime accesses browser APIs through GTM's own internal permission
model — not through Content Security Policy. A template that writes a cookie uses GTM's
setCookie sandbox API, which executes within code already authorised by the GTM
container's existing CSP allowance (the allowance granted to googletagmanager.com).
In contrast, a Custom HTML tag writes a literal <script> element into the DOM.
CSP's script-src directive applies to every inline script element. Unless you have
unsafe-inline enabled (which defeats much of CSP's purpose) or a matching SHA-256
hash in your CSP header, the browser blocks execution. Every change to that script — adding a
comment, reformatting a line, changing a cookie name — changes the hash and requires a CSP header
redeployment and typically a security team review cycle.
With sandboxed templates, your CSP never changes when GTM tag logic changes. The entire landing and referral cookie implementation in this recipe is CSP-transparent.
Real-World Use Cases
Identifying the True Referral Source When utm_source Is Not Reliable
Google's convention is that utm_source should identify the actual traffic source —
the platform, publisher, or channel that sent the visitor. In practice, many campaigns use
utm_source as a free-text label: utm_source=spring-promo,
utm_source=email-footer, utm_source=sales-team. These values describe
the campaign intent, not the origin of the traffic.
The referral host cookie, set by the browser from document.referrer, reflects where
the user actually navigated from — independent of any UTM tagging. A visit tagged
utm_source=spring-promo that shows referHost=email.mailprovider.com
tells you it was an email campaign. A visit tagged utm_source=newsletter with
referHost=t.co tells you the link was actually shared on X (Twitter). The referral
host provides a ground-truth origin signal that complements — and sometimes corrects — the UTM
source value.
First-Touch Landing Page Analysis for User Journey Mapping
The user's first ever landing page is one of the most predictive signals of their intent and
their position in the funnel. A user whose first landing was /pricing is on a
fundamentally different journey from one whose first landing was /blog/what-is-x.
But without persistent cookies, you can only know the first landing page if the user converted
in the same session — which is rare in B2B and considered-purchase categories.
With landPath_1 persisted for up to two years, you can join any downstream event —
a contact form submission, a free trial activation, a purchase — to the user's original entry
point. In GA4 Explorations or BigQuery, this enables cohort analysis by first landing page,
funnel analysis by acquisition path, and lifetime value modelling by initial intent signal.
B2B Multi-Session Lead Attribution
A prospect clicks a LinkedIn post, lands on /case-studies/enterprise, reads for
ten minutes, and leaves. The referral host and landing path are stored in persistent cookies:
referHost_1=linkedin.com, landPath_1=/case-studies/enterprise.
Two weeks later, they return directly, read the pricing page, and submit a demo request form.
Your CRM receives hidden form fields populated from the cookie values — and your sales team
knows the lead came from LinkedIn via the enterprise case study page, not from direct traffic.
How to Import
- Download the JSON file from the Google Drive link.
- In GTM, go to Admin → Import Container.
- Upload
site-landing-and-referrer-2-cookies-recipe.json. - Choose Merge (not Overwrite) to preserve your existing tags and triggers.
- Update
Measurement Stream ID ProductionandMeasurement Stream ID Developmentconstant variables to your actual GA4 Measurement IDs. - Verify that
{{Root Domain}}resolves correctly for your site — this controls the cookie's domain scope. Check its value in GTM Preview mode on your site before publishing. - In GA4, register the following as custom event-scoped dimensions under Admin → Custom definitions → Custom dimensions:
e_cur_landing_host,e_cur_landing_path,e_cur_referral_source,e_1st_landing_host,e_1st_landing_path,e_1st_referral_source. - Register the six User Properties under Admin → Custom definitions → Custom dimensions (selecting User scope):
u_cur_landing_host,u_cur_landing_path,u_cur_referral_source,u_1st_landing_host,u_1st_landing_path,u_1st_referral_source. - Open GTM Preview mode on a URL with an external referrer and confirm the cookie variables populate in the Tag Assistant panel under the Initialisation event.
- Navigate to a second page and confirm that the session and persistent cookie values persist (the landing host should remain the first page URL, not the current page URL).
- Close the browser, reopen, and revisit the site directly. Confirm the session cookies are absent (triggering a new session write) and the
_1persistent cookies still hold the original first-visit values.
What You Can Do With It
- Attach first-touch landing page and referral source to CRM lead records via hidden form fields — link pipeline and revenue to the user's original entry point without server-side infrastructure
- Compare
e_cur_referral_source(this session's referrer) againste_1st_referral_source(first-ever referrer) in GA4 Explorations to identify multi-channel journeys and mid-funnel referral sources - Segment GA4 audiences by
u_1st_landing_pathto create intent-based audiences (e.g. users whose first landing was/pricing) for remarketing and personalisation - Build BigQuery attribution models joining on
e_1st_referral_sourceto compare first-touch referral attribution against GA4's session-based default attribution - Identify referral traffic where
utm_sourcedoes not match the actualreferHost— a powerful quality signal for your UTM hygiene audits - Measure cohort differences in conversion rate, session depth, and time-to-convert between users by first landing page — enabling landing page optimisation based on downstream outcome data rather than session-level metrics
- Use
e_1st_landing_pathas a dimension in GA4 Explorations funnels to understand which entry points drive users towards high-value conversion paths
The full source — including the container JSON and the drewspen sandboxed Custom Templates — is available on GitHub and via the Google Drive download below. If you extend the implementation with additional cookie naming conventions or add complementary UTM cookie tracks, open a pull request or issue.
⬇ Download GTM Container JSON
Comments
Post a Comment