FIRST-PARTY FORTRESS/ARCHITECTURE BLUEPRINT

Architecture
Blueprint

The four-phase mental model. Consent-aware frontend capture, real-time GTM signal, CRM vault, and a server-side API loop that bypasses the browser entirely.

SYSTEM OVERVIEW

CAT. · THE BRAND CATALYSTTHE FIRST-PARTY FORTRESSARCHITECTURE OVERVIEW · v2.0brand-catalyst.comBROWSER-DEPENDENTCONSENT-INDEPENDENT ↗PHASE 01 · FRONTEND CAPTUREConsent Mode · UUID · gclidPHASE 02 · WEB GTMReal-time GTM signalPHASE 03 · CRM VAULTFirst-party data anchorPHASE 04 · API LOOPServer-side · Consent-immuneLAYER 1 · CONSENT MODEConsent Mode v2denied defaults · url_passthroughads_data_redaction · EU/UK/CHLAYER 2 · FRONTEND TRACKS (3 parallel)UTM StashsessionStorageno consentrequiredCookieWriter_gads cookiead_storageHiddenField_gcl_awgclid chainUUIDgclid lookup: URL → lt_gclid → ft_gclid → sessionStorage → _gcl_awLAYER 3 · FORM SUBMITCMS FormUUID + gclid injected into hidden fieldsLAYER 4 · THANK-YOU PAGEThank-you PageGTM fires conversion tag hereGoogle Tag ManagerWeb container · consent-gatedGoogle Ads Conversion TagTransaction ID = UUID variableUser-Provided Data TagSHA-256 hashed email · ECLConversion LinkerWrites _gcl_aw cookie⚠ WP Rocket: exclude GTM from JS deferServer GTM (optional)events.domain.com — stillconsent-gated for ads via x-ga-gcsCRMHubSpot / OnePageCRM / etc.Custom Fieldsfpf_order_idUUID from hidden fieldgclidraw click IDUTM source/mediumfrom sessionStorageEmail (hashed)SHA-256 on webhookContact Created Webhookn8n / Make.com triggern8n (preferred)Contact Created only · error alertsowned infrastructureMake.com (alt.)scope to Contact Createdavoid duplicate uploadsROUTING LOGICPATH A · CLICKgclid presentuploadClickConversionsUPLOAD_CLICKS action→ Primary goal (bidding)PATH B · ECLno gclid · email presentuserIdentifiersSHA-256 hashed email25–45% match · 24–48hPATH C · NO ATTR.no gclid · no emailorganic / direct trafficlog only · no uploadexpected · no actionGOOGLE ADS · CONVERSION ACTIONSPRIMARY · BIDDING ENGINEImport → UPLOAD_CLICKSUsed for bidding optimisationConsent-independent · 90%+ reachcustomers/{customer_id}/conversionActions/{ctId}SECONDARY · DIAGNOSTICWebsite pixel · GTM tagNot used for biddingConsent-gated · ~65% EU reachEnhanced Conversions enabled ✓CONVERSION ACCURACY COMPARISONBrowser pixel only~65%First-Party Fortress (API loop)90%+Remaining gap: organic/direct traffic with no Google click attribution — not a tracking failure.KEY PITFALLS01 · Pixel as Primary goal — corrupts Smart Bidding in EU markets02 · Contact Updated trigger — causes duplicate API uploads03 · WP Rocket JS defer — GTM never fires on thank-you page04 · ECL toggle off — rejects all userIdentifiers uploads05 · Wrong conversionAction format — use full resource name, not AW-XXXX© Cat. The Brand Catalyst · brand-catalyst.com · First-Party Fortress Architecture v2.0honold@brand-catalyst.com
PHASE 01

Frontend Capture & Consent

Consent Mode denies all ad and analytics storage by default for EU/UK/CH visitors. Any system that depends solely on cookies granted after consent will miss 30–40% of conversions before the loop even starts. The frontend layer handles this in three parallel tracks.

TRACK A

UTM Stash

Fires before consent is resolved

Saves all UTM params + click IDs to sessionStorage

No consent required — survives page reloads

TRACK B

Cookie Writer

Fires when ad consent is granted

Writes first-touch (180d) and last-touch (90d) cookies

Extends attribution beyond the current session

TRACK C · CORE

Hidden Field Setter

Fires on DOM Ready — no consent requirement

Resolves gclid via priority chain: URL → cookies → sessionStorage → _gcl_aw

Generates UUID, injects into hidden order_id field

On form submit: saves email + UUID to sessionStorage

The _gcl_aw Conversion Linker cookie is consent-immune — written by GTM regardless of consent status. It is the last-resort gclid fallback in Track C.

PHASE 02

Real-Time Signal — Web GTM

Google Tag Manager fires on the thank-you page, sending an immediate conversion signal to Google Ads via the browser. This registers the click-to-conversion path in Smart Bidding without waiting for the CRM loop.

Three tags fire: a Google Ads Conversion Tracking tag (UUID as Transaction ID), a User-Provided Data Event tag (hashed email for Enhanced Conversions), and a GA4 event routed to the server container.

These tags are consent-gated. In EU markets expect 60–70% of visitors to grant ad consent. The pixel signal is intentionally partial — Phase 4 provides the consent-independent layer.

JS deferral tools (WP Rocket, LiteSpeed Cache) wrap GTM in a deferred loader. On thank-you pages, users read the confirmation and close the tab — GTM never loads, the pixel never fires. Exclude GTM's domain from all deferral rules.

PHASE 2b · SERVER GTM (OPTIONAL UPGRADE)

A server container on events.yourdomain.comintercepts the GA4 event before it reaches Google's servers. This extends the first-party cookie lifetime and improves signal quality for consenting users. It does not make conversion tracking consent-independent.

PHASE 03

The CRM Vault

The CRM is the secure first-party anchor — the source of truth the API loop reads from. Every new lead record must store gclid, the UUID, and email as structured fields, not just the form submission data.

FIELDSOURCEPURPOSE
gclidHidden field (Track C)Primary API upload identifier
gbraid / wbraidHidden field (Track C)iOS campaign click IDs
gads_order_idHidden field (Track C)UUID — deduplication key
emailForm field (standard)ECL fallback — hashed in automation
UTM paramsHidden fields (Track C)Campaign attribution context

Configure the CRM webhook to fire on Contact Created only — not on updates. Every update re-triggers the pipeline and risks uploading duplicate conversions to Google Ads.

PHASE 04

The API Loop — n8n / Make.com

The only layer that is genuinely consent-independent. n8n or Make.com reads the CRM contact record and uploads a conversion directly to the Google Ads API — bypassing the browser and its consent state entirely.

PATH A · PRIMARY

gclid present

uploadClickConversions endpoint

Uses gclid (or gbraid / wbraid)

Primary UPLOAD_CLICKS goal

Immediate — 90%+ EU lead coverage

PATH B · FALLBACK

No gclid — email present

Same endpoint — ECL path

userIdentifiers: SHA-256 hashed email

Probabilistic identity match

25–45% match rate · 24–48h delay

PATH C · NO ATTRIBUTION

No gclid · no email

Organic / direct traffic

No Google click to attribute

Log and notify — no upload

Expected — not a tracking failure

n8n is preferred: Contact Created trigger is explicit, built-in error alerting, owned infrastructure. Make.com works — verify trigger scope is Contact Created only, check the hardcoded conversion value, and add a manual error notification branch.

ARCHITECTURE

Conversion Action Hierarchy

The most commonly misconfigured element. Two conversion actions, two distinct roles. If the website pixel is set as Primary, Smart Bidding trains on a systematically biased subset of your leads.

ACTIONSOURCEGOAL TYPEREACH (EU)

Primary — CRM Feed

Import → UPLOAD_CLICKS

n8n / Make.com via Google Ads APIPRIMARY · BIDDING90%+

Secondary — Web Pixel

Website (GTM tag)

Google Tag Manager — thank-you pageSECONDARY · DIAGNOSTIC~65%
PITFALLS

Key Failure Points

01

JS deferral tools (WP Rocket, LiteSpeed, etc.)

Performance plugins that defer JavaScript prevent GTM from loading on thank-you pages where users close the tab immediately. GTM's domain and your server container domain must be excluded from all deferral rules.

02

Server container SSL

The server container runs on a custom subdomain. If the SSL certificate expires, GTM tags fail silently. Verify: GET https://events.yourdomain.com/gtm.js must return HTTP 200. Check after every infrastructure change.

03

CRM webhook trigger scope

"Contact Updated" re-fires on every CRM edit. Scope the webhook to "Contact Created" only — every update-triggered upload is a potential duplicate conversion in Google Ads.

04

UPLOAD_CLICKS ≠ Enhancement

The UPLOAD_CLICKS endpoint (uploadClickConversions) uploads a new conversion using a gclid. The RESTATEMENT adjustment endpoint modifies an existing conversion's value. The primary API loop always uses uploadClickConversions.

05

Server-side GTM is still consent-gated for ads

The server container's Google Ads tag reads the consent signal forwarded from the browser. If the user declined ads consent, the server-side pixel does not fire either. Server GTM is an accuracy upgrade, not a consent bypass.

06

Double-counting

Do not fire an additional server-side conversion tag from the same web event that already fires a browser-side pixel for the same conversion action. Each conversion should be recorded by exactly one path.

07

Google Ads API version sunset

The API version in the upload URL (/v20/) is periodically deprecated. When Google sunsets a version, all uploads silently fail. Monitor the deprecation schedule and update the endpoint URL before the cutoff.