Context
A premium skincare brand with significant UK and EU revenue had implemented a GDPR-compliant cookie consent banner. They’d done the right thing: all analytics and advertising tags were properly gated behind consent. Users who declined (55% of EU visitors) generated no tracking data whatsoever.
This is ethically correct. It was also making their Google Ads campaigns increasingly ineffective.
The core problem with consent-only tracking: When 55% of EU converters generate no conversion signal, Google Ads smart bidding algorithms are training on half the conversions. The algorithm under-bids for the audience segment that doesn’t consent — which is typically privacy-aware users, often higher-income demographics in Germany and the Nordics. Campaign efficiency degrades not just in proportion to the data loss — it compounds, because the algorithm actively deprioritises audiences it can’t measure.
The brand’s EU Google Ads ROAS had declined 31% over 18 months since implementing the consent banner. Their UK campaigns (pre-Brexit, using UK-specific standards) were performing fine. The correlation with consent implementation was clear.
The challenge was recovering signal without violating the consent decisions users had made. That’s the needle Consent Mode v2 is designed to thread.
Challenge
Challenge 1: Consent Mode v2 requires server-side for full benefit. Consent Mode v2’s Advanced mode fires cookieless pings that GA4 and Google Ads can use for modelling — but these pings are third-party requests from the browser, subject to ITP (Intelligent Tracking Prevention) on Safari and blocking by privacy extensions. To get the full modelling benefit, the pings need to go through a first-party domain.
Challenge 2: Browser-based first-party cookies expire after 7 days on Safari (due to ITP). A customer who browses on Thursday and buys on the following Wednesday is unmeasurable. Server-side cookies set via HTTP response headers last up to 400 days — preserving the attribution chain.
Challenge 3: Existing GTM setup was client-side only. The brand had no server-side infrastructure. We were building this from scratch alongside the Consent Mode configuration.
Challenge 4: Meta Pixel and Google Ads running simultaneously. Both platforms needed to benefit from the server-side infrastructure. Both needed proper Consent Mode signals. The setup needed to be clean enough for both to work without conflicting.
Action
Phase 1 — Consent Mode v2 in Advanced Mode
The critical distinction: Basic Consent Mode fires no tags until consent is granted. Advanced Consent Mode fires all tags immediately but in a cookieless, non-identifying mode — sending consent state signals that Google uses for modelling.
The brand was running Basic mode. Moving to Advanced mode is the first step.
In the CMP (OneTrust): Configured the consent state to fire a dataLayer.push with consent signals on page load — before any tags fire — and again on consent state change:
// Fires before GTM tags — default denied state for EU visitors
window.dataLayer = window.dataLayer || [];
window.dataLayer.push('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
wait_for_update: 500, // ms to wait for consent signal
});
// Fires when user makes a choice
window.dataLayer.push('consent', 'update', {
analytics_storage: userAccepted ? 'granted' : 'denied',
ad_storage: userAccepted ? 'granted' : 'denied',
ad_user_data: userAccepted ? 'granted' : 'denied',
ad_personalization: userAccepted ? 'granted' : 'denied',
});
In GTM: Updated all GA4 and Google Ads tags to have Consent Check enabled (the built-in Consent Mode integration in GTM). Tags fire in restricted mode when denied — sending cookieless pings with consent signals but no PII.
Phase 2 — Server-Side GTM on Google Cloud
We deployed a server-side GTM container on Google Cloud Run. The container runs at collect.brand.com — a subdomain on the brand’s own domain.
# Deploy server-side GTM container
gcloud run deploy gtm-server \
--image gcr.io/cloud-tagging-10302018/gtm-cloud-image:stable \
--set-env-vars CONTAINER_CONFIG=<container_config_encoded> \
--platform managed \
--region europe-west1 \
--allow-unauthenticated \
--min-instances 1 \
--max-instances 10
DNS: Added collect.brand.com CNAME pointing to the Cloud Run service URL. SSL certificate handled automatically by Google Cloud.
In client-side GTM: Updated the GA4 Configuration tag to send events to the server container instead of Google’s servers:
Server container URL: https://collect.brand.com
All events now flow: Browser → collect.brand.com (owned domain) → Google’s servers.
Phase 3 — Server-Side First-Party Cookies
The most impactful technical change. The server-side container sets the GA4 client ID cookie via HTTP Set-Cookie header — bypassing Safari’s ITP restriction entirely.
In the server-side GTM container, we added a custom Variable that reads the _ga cookie from the request and a Tag that sets it as a server-side response cookie:
Set-Cookie: _ga=GA1.1.XXXXXXXXXX; Max-Age=34560000; Path=/; Domain=.brand.com; SameSite=Lax; Secure
Max-Age=34560000 = 400 days. For Safari users who previously had attribution windows of 7 days, this extended the measurable conversion window by 57x.
Phase 4 — Meta Conversions API via Server Container
We added a Meta CAPI client to the server-side GTM container. Purchase and AddToCart events from the client container flow through to Meta’s Conversions API server-side — deduped with browser Pixel events using the event_id parameter.
This gave Meta higher-quality conversion signals for the same consent-declined segment that Consent Mode handles for Google.
| Signal Type | Consent Required | Data Quality |
|---|---|---|
| Browser Pixel only | Yes | Lost for 55% of EU users |
| Consent Mode v2 pings | No (cookieless) | Used for modelling, no PII |
| Server-side CAPI | No (aggregated) | High quality, no user-level PII |
Phase 5 — Enhanced Conversions for Google Ads
For users who did consent, we implemented Enhanced Conversions — hashing first-party customer data (email) at purchase time and sending to Google Ads for improved identity matching:
// GTM tag — Enhanced Conversions (fires only with ad_storage: granted)
window.gtag('set', 'user_data', {
email: sha256(purchaseEmail), // hashed client-side
phone_number: sha256(purchaseMobile),
});
This improved match rates for consented users from 61% to 84%.
Result
Three months post-implementation:
34% of previously lost EU conversion data recovered. This isn’t data that wasn’t collected — it’s modelled data that Google and Meta’s algorithms now use to reconstruct the full conversion picture. The 55% decline rate didn’t change; we’re not re-identifying declined users. The modelling fills the gap.
Google Ads EU ROAS improved 28% over the subsequent 90 days. Smart bidding algorithms recovered as conversion signal density increased. Campaigns that had been spending conservatively on German and Nordic audiences (where decline rates are highest) returned to previous efficiency levels.
Attribution coverage for high-value Safari users restored. The 7-day vs 400-day cookie lifetime gap was closing 38% of purchase journeys for Safari users who had browse sessions more than a week before buying. That attribution is now captured.
An important caveat: Consent Mode modelling is an estimate, not a measurement. The 34% recovery figure represents modelled conversions, not individually identified users. For clients with strict “no modelling” policies, this approach isn’t appropriate. For brands that need to make ad spend decisions based on the best available signal — this is the state of the art.
The uncomfortable truth about GDPR compliance and advertising is that you can be legally correct and commercially blind at the same time. Consent Mode v2 + server-side is the industry-accepted solution for recovering signal within the legal framework — but only if it’s implemented properly. Most implementations we audit are still running Basic mode, leaving the modelling benefit on the table entirely.