Consent Mode v2 debugging guide
last verified · against Google Consent Mode v2 docs as of 2026-07
Field reference for Consent Mode v2 debugging: decode gcs and gcd signals, verify default and update in Tag Assistant, and fix the common failures.
What this is
Consent Mode v2 debugging is the task of confirming that a page sends the four
consent signals — ad_storage, analytics_storage, ad_user_data,
ad_personalization — in the correct default-then-update order before any
Google tag fires, and reads them back from the network request or Tag
Assistant. This card maps each signal, network parameter, and Tag Assistant
surface to the misconfiguration it exposes and the fix.
The four signals to verify
| Signal | Sets consent for | Version | Value |
|---|---|---|---|
ad_storage |
Storage of advertising cookies / device identifiers | v1 | 'granted' or 'denied' |
analytics_storage |
Storage of analytics cookies | v1 | 'granted' or 'denied' |
ad_user_data |
Sending user data related to advertising to Google; required for enhanced conversions and tag-based conversion tracking | added in v2 | 'granted' or 'denied' |
ad_personalization |
Personalized advertising | added in v2 | 'granted' or 'denied' |
By default, no consent mode values are set — unset is not the same as
'denied'. If nothing is configured, GA4 treats ad_storage and
analytics_storage as 'granted', so data still flows and masks the
misconfiguration.
All seven consent types
| Type | Group |
|---|---|
ad_storage, analytics_storage, ad_user_data, ad_personalization |
Core advertising / analytics signals — what v2 debugging targets |
functionality_storage, personalization_storage, security_storage |
Other privacy storage types, not the four core signals |
What each network parameter carries
| Parameter | Encodes | Always sent? | Client key | Server-side key |
|---|---|---|---|---|
gcs |
The ad_storage and analytics_storage consent choice only |
No — reflects consent-mode state when tags fire | gcs |
x-ga-gcs in Event Data |
gcd |
All four signals plus how each signal was generated (default vs update) | Yes — sent to Google services whether or not consent mode is active | gcd |
Not specified in the sources |
Because gcd is always sent, its presence alone is not proof consent mode is
configured. Use an explicit default Consent event (and non-l gcd letters)
as the real test. Because gcs carries only two of the four signals, a
“green” gcs can hide missing ad_user_data / ad_personalization.
gcs value decode (community-documented)
Google does not publish a gcs value table; it confirms only that gcs
transmits ad_storage and analytics_storage. The mapping below is
community-documented (CookieHub, dumbdata, owntag, Simo Ahava). Verify live
against a known consent state.
Format G1xy: x = ad_storage, y = analytics_storage, where 1 is
granted and 0 is denied.
gcs |
ad_storage |
analytics_storage |
Reading |
|---|---|---|---|
G100 |
denied | denied | Both denied (advanced mode, no update fired) |
G110 |
granted | denied | ad_storage granted, analytics_storage denied |
G101 |
denied | granted | ad_storage denied, analytics_storage granted |
G111 |
granted | granted | Both granted |
Unverified: a dashed / partial gcs (reported as G1--) is claimed by some
practitioners to mean “no default set / consent mode not configured,” but no
official page confirms it. The leading digit is described in community sources
as 1 = signal sent; alternate leading digits are not officially documented.
gcd letter decode (community-documented)
Google does not publish the gcd letter table either; the letters are
reverse-engineered by practitioners. The four letters appear in the order
ad_storage, analytics_storage, ad_user_data, ad_personalization.
| Letter | State |
|---|---|
l |
Signal not set with consent mode |
p |
Denied by default (no update) |
q |
Denied both by default and after update |
r |
Denied by default, granted after update |
t |
Granted by default (no update) |
u |
Granted by default, denied after update |
v |
Granted both by default and after update |
m |
Denied after update (no default) |
n |
Granted after update (no default) |
Sources disagree on some letters: an alternate mapping in some references reads
q as denied-then-granted, r as granted-then-denied, and adds s for
granted-both. Treat exact letter semantics as approximate and verify live
against a known consent state.
gcd = 11 [ad_storage] 1 [analytics_storage] 1 [ad_user_data] 1 [ad_personalization] 5example: 11l1p1u1v5 (starts 11, a 1 separates each signal, terminator digit 5)GA4 behavior by consent state
| State | GA4 behavior |
|---|---|
| No defaults ever set | Treated as ad_storage: 'granted' and analytics_storage: 'granted' — data flows, hiding the missing config |
analytics_storage: 'denied' |
Will not read or write first-party analytics cookies; cookieless pings are sent for future measurement / modeling |
ad_storage: 'denied' with ads_data_redaction: 'true' |
GCLID / DCLID in consent and key-event pings are redacted |
Basic vs advanced implementation
Knowing which mode the CMP deployed decides what “correct” looks like before consent.
| Basic | Advanced | |
|---|---|---|
| Tags before consent | Blocked until banner interaction | Load on page open with defaults (denied unless configured) |
| Data before consent | None sent — not even the default consent status | Consent state plus cookieless pings |
| Expected pre-consent request | No request (this is expected, not a bug) | Cookieless ping carrying gcs=G100 (community-asserted; not stated in official docs) |
Required command order
The single most common failure. If the consent code runs out of order, defaults do not work.
| Order | Action |
|---|---|
| 1 | Load the Google tag with the default consent call |
| 2 | Load the consent solution (CMP) |
| 3 | Call update after the user consents |
For gtag, the gtag('consent','default') / gtag('consent','update')
commands must fire before any gtag('config') command. wait_for_update
(illustrated as 500 ms; no documented default or maximum) holds tags so an
async CMP can send its update first.
Region-scoped defaults
| Behavior | Rule |
|---|---|
| Scope | The region key limits a default to listed regions / subregions |
| Precedence | Most specific parameter takes precedence over a broader default |
| Failure mode | A region-scoped 'denied' default can apply to users the banner never prompts — align banner and default to the same regions |
Tag Assistant surfaces
Tag Assistant (tagassistant.google.com, with the Companion Chrome extension) is Google’s sanctioned tool.
| Check | Event to select | Where to read | Expected |
|---|---|---|---|
| Default state | Earliest Consent event in the Summary | API Call section, or the On-page Default column | Denied, all four parameters present |
| Update state | Most recent Consent event in the Summary | API Call section, or the On-page Update column | Granted, all four parameters moved |
| Tag Assistant message | Meaning |
|---|---|
| “A tag read consent state before a default was set” | Ordering bug — a tag read consent before any default was set. Move the default commands above every tag snippet |
| Empty Consent tab | Consent mode is not implemented on the page, or the Google tag was blocked from loading |
For measurement that looks correct on-page but still excludes EEA users, check
the server-side surface: GA4 Admin > Consent settings, per data stream
(Advertising related consent signals, Behavior analytics consent signals).
Notifications there may lag on-page signals by 48-72 hours.
Gotchas
gcsstaysG100after “Accept all,” and data remains modeled / low → the banner’s update handler never firesgtag('consent','update',...), so state never leaves its default → select the most recent Consent event in Tag Assistant; if the four signals did not move to granted, wire the accept action to the update command (or, for a CMP, confirm Google consent mode is enabled).- Tag Assistant shows “A tag read consent state before a default was set” → the default runs after a tag already read consent — an async CMP, or the default sits below the tag snippet / below
gtag('config')→ move every default command above all tag snippets, do not load it async, and addwait_for_update(e.g.500) so an async banner’s update can land first. gcsis missing / empty in the network request → consent mode is not firing before Google’s tags, OR the site runs basic mode (no request before consent), OR the Google tag is blocked from loading → an empty Tag Assistant Consent tab means not-implemented or tag-blocked; confirm the tag loads, a default precedes it, and identify basic (expect no request) vs advanced (expect agcs=G100cookieless ping).- EEA users are silently denied / low consent rate without ever seeing a banner → region mismatch — the banner and the region-scoped default target different regions → align both to the same regions, audit overlapping region defaults (most specific wins), and test with Chrome location simulation.
- Remarketing / enhanced conversions / audiences stop for EEA users even though
gcslooks fine →ad_user_dataand/orad_personalizationwere never set;gcscarries onlyad_storage+analytics_storage, so a greengcshides them → check thegcdstring (or Tag Assistant API Call) for all four, set defaults and updates for the two v2 signals, and verify GA4Admin > Consent settings. - In server-side GTM you filter for
gcsand find nothing → sGTM renames the field tox-ga-gcsin Event Data → readx-ga-gcs, then apply the same decode logic. - A site with no consent mode still reports GA4 data normally, so nobody notices → with defaults never set, GA4 treats both storage signals as granted → do not treat “data is flowing” as proof; verify an explicit default Consent event (earliest event) with all four parameters set.
- Consent mode looks correct but Google Ads shows no impact / modeling results → data thresholds and minimum run time are not met yet — not an implementation bug → keep the implementation running at least 7 full days and meet the data thresholds; do not “fix” a working setup.
Quick recipes
window.dataLayer = window.dataLayer || [];function gtag() { dataLayer.push(arguments); }gtag('consent', 'default', { ad_storage: 'denied', analytics_storage: 'denied', ad_user_data: 'denied', ad_personalization: 'denied', wait_for_update: 500, // ms to let an async CMP send its update first});gtag('consent', 'update', { ad_storage: 'granted', analytics_storage: 'granted', ad_user_data: 'granted', ad_personalization: 'granted',});// Narrow default, scoped to two regions...gtag('consent', 'default', { analytics_storage: 'denied', region: ['ES', 'US-AK'],});// ...and a broader default for everywhere else.gtag('consent', 'default', { ad_storage: 'denied',});// Most specific parameter takes precedence.// Paste a captured Google request URL (the collect / Ads request).const url = new URL('PASTE_REQUEST_URL');const gcs = url.searchParams.get('gcs'); // e.g. "G111"// Community decode of G1xy (Google does not publish this table):console.log({ gcs, ad_storage: gcs && gcs[2] === '1' ? 'granted' : 'denied', analytics_storage: gcs && gcs[3] === '1' ? 'granted' : 'denied',});// In server-side GTM the signal is exposed as x-ga-gcs, not gcs.const getEventData = require('getEventData');return getEventData('x-ga-gcs'); // e.g. "G111"// With ad_storage denied, GCLID / DCLID in consent and key-event pings are redacted.gtag('set', 'ads_data_redaction', true);Related
- Hub: Privacy & consent guides
- Lateral: Consent Mode v2 parameter reference · sGTM consent forwarding patterns
Sources
- Consent mode overview — Tag Platform (read 2026-07-20)
- Set up consent mode on websites — Tag Platform (read 2026-07-20)
- Troubleshoot consent mode with Tag Assistant — Tag Platform (read 2026-07-20)
- Consent mode — GA4 Analytics Help (read 2026-07-20)
- Verify and update consent settings in GA4 — Analytics Help (read 2026-07-20)
- Verify consent mode implementation — Tag Manager Help (read 2026-07-20)
- Troubleshoot consent mode — Tag Manager Help (read 2026-07-20)
- Consent Mode troubleshooting for Google Ads — Tag Assistant Help (read 2026-07-20)
- About consent mode — Google Ads Help (read 2026-07-20)
- Updates to consent mode for EEA traffic — Google Ads Help (read 2026-07-20)
- Consent mode reference — Google Ads Help (read 2026-07-20)
Community references (unofficial gcs / gcd decodings, not attributable to Google):
- Consent Mode V2 for Google Tags — Simo Ahava (read 2026-07-20)
- Read and use GCS values in server-side GTM — dumbdata (read 2026-07-20)
- Consent mode v2 signals — CookieHub Docs (read 2026-07-20)
- What the gcs parameter means in GA4 — owntag (read 2026-07-20)
Changelog
- — Initial version, verified against official documentation.