Every hit a Google tag fires - a GA4 collect request, a Google Ads or Floodlight ping, a syndication request - carries its consent state in the query string through the Google Consent Mode gcs/gcd parameters: gcs as the short status code, gcd as the detailed one. Reading gcs takes one official table; gcd is another story: Google explains what the parameter is for but does not publish its encoding, so the layout below comes from reverse-engineering work by analytics engineers, cross-checked against a public decoder. This guide gives you both parameters, value by value, and shows where manual decoding should stop.
What gcs and gcd encode in consent mode
Google tags attach both parameters to outgoing requests. You will see them on /g/collect hits from GA4, on Google Ads and Floodlight measurement pings, and on syndication requests - anywhere a Google tag reports an event. In server-side GTM the same values arrive inside event data under the prefixed names x-ga-gcs and x-ga-gcd, next to dma and dma_cps, the two parameters that carry DMA consent for Google services.
The two parameters do different jobs, and mixing them up is the most common reading mistake:
| Parameter | What it encodes | Documented by Google | Length |
|---|---|---|---|
gcs | effective state of ad_storage + analytics_storage only | yes, format and values | 4 characters |
gcd | all four signals: ad_storage, analytics_storage, ad_user_data, ad_personalization, plus how each state was set | purpose yes, encoding no | 10 or 12 characters |
Because gcs covers only two signals, a page can send gcs=G100 while the same hit's gcd shows ad_user_data granted after an update. The full consent picture lives in gcd; gcs is the legacy-compatible short status that consent mode has reported since version 1.
What Google documents about gcs and gcd
Three official statements anchor everything else. First, the consent debugging guide gives the gcs format and the full value table: "Check for the gcs= parameter on URLs for consent status. The gcs parameter has the following format: gcs=G1 [ad_storage][analytics_storage]" - Google, Consent debugging guide. Second, the consent mode overview states that the gcd parameter "is always sent to Google services regardless of whether consent mode is implemented" - Consent mode overview. Third, the same overview warns: "Google tag fields may be encoded to improve transmission efficiency. These fields may be subject to change."
That third sentence is why a reverse-engineering scene exists at all. Google never published the gcd alphabet, so the layout in the next sections was recovered by Markus Baersch (and published in English by Simo Ahava), refined by David Vallejo's parsing template, and verified against Vallejo's public decode API. Throughout this guide each claim carries its source: official, reverse-engineered, or hypothesis.
How to read gcs: the G1-- matrix
The official table, from the current consent debugging guide:
| Value | What it reports |
|---|---|
G100 | Consent denied for both signals |
G101 | Analytics granted, ads denied |
G110 | Ads granted, analytics denied |
G111 | Consent granted on both signals |
G1-- | Site did not require consent for these two signals |
Two more cases sit outside the table. No gcs parameter at all means consent mode is not implemented or the tags are blocked before they fire - the basic consent mode setup, where denied tags simply do not load. And a lowercase prefix such as g110 shows up in real traffic; parsers normalize the prefix case because only the two digits after G1 carry meaning.
The parameter reports the effective state, the default merged with any update - a user who declines the banner keeps G100, and one who accepts moves the same hit to G111. Regional consent decisions fold into the same effective value.
How gcd is built: 12 characters of consent state
The layout below is the reverse-engineered consensus, documented by Vallejo's template and consistent with the public decoder's answers:
1 3t 3t 3t 3t 5 l1
version ad_storage analytics_storage ad_user_data ad_personalization marker tailPosition by position:
| Positions | Content | Meaning |
|---|---|---|
| 1 | version digit | 1 on every string observed so far |
| 2-9 | four consent pairs | one pair per signal, in order: ad_storage, analytics_storage, ad_user_data, ad_personalization |
| 10 | marker digit | 5 in most traffic; 6 and 1 also occur |
| 11-12 | optional tail | "container scoped defaults" in Vallejo's reading; present in current-format strings, absent in older ones |
Each consent pair is two characters: the first is an implicit-consent marker, the second is the state letter that carries default and update. So 13t3t3t3t5l1 reads as "implicit granted, granted by default, no update" on all four signals. The public decoder accepts 12-character strings; 10-character values from 2023 traffic are the same layout without the implicit markers in a separate position and without the tail, and they still decode by hand with the letter table below.
What the letters in gcd mean: nine states
Each state letter sits at even positions 2, 4, 6, and 8 of the string. Baersch published the full set in his guest post on Simo Ahava's blog, and every row below comes with a real-world example:
| Letter | Reads as | Default | Update | Typical string |
|---|---|---|---|---|
l | signal not configured via consent mode | not set | not set | 11l1l1l1l1 - consent mode absent |
p | denied by default, banner untouched | denied | none | 11p1p1p1p5 - advanced mode before a banner click |
q | declined and confirmed | denied | denied | 13q3q3q3q5 - user rejected all |
r | accepted after a denied default | denied | granted | 13r3r3r3r5 - user accepted all |
t | granted by default | granted | none | 13t3t3t3t5 - no banner interaction needed |
u | consent withdrawn | granted | denied | 11u1u1u1u5 - user revoked |
v | granted and confirmed by update | granted | granted | 13v3v3v3v5 |
m | update denied without a default | not set | denied | 11p1m1p1p5 - only one signal configured |
n | granted by update alone | not set | granted | 11n1n1n1n5 - site never set a default |
The grouping makes the table computable rather than memorizable. Each letter is a position in the base64url alphabet, and the low four bits split into two fields: (index >> 2) & 3 gives the default and index & 3 gives the update, where 2 means denied and 3 means granted:
l = index 21: low four bits 0101 - default 1, update 1: not set
p = index 25: low four bits 1001 - default 2, update 1: denied, no update
q = index 26: low four bits 1010 - default 2, update 2: denied, denied
r = index 27: low four bits 1011 - default 2, update 3: denied, granted
t = index 29: low four bits 1101 - default 3, update 1: granted, no updateA three-by-three mnemonic from the community articles compresses the same table: alphabet row gives the default (l-m-n none, p-q-r denied, t-u-v granted), position inside the row gives the update (first none, second denied, third granted).
What the odd positions mean: implicit consent markers
Through 2023 most strings looked like 11p1p1p1p5 - implicit position 1, which the decoder reports as unset. In 2024 Google tags started sending 13t3t3t3t5 en masse: the same layout with implicit 3. The public decoder's implicit field per signal confirms the mapping: 1 decodes to unset, 3 to granted, 2 to denied. A string like 13r3r3r2r5 therefore shows a user who accepted everything while ad_personalization carries implicit denial - the pattern community sources link to Global Privacy Control opt-outs and derived signals.
What "implicit granted" means semantically is the least documented part of the whole format. Vallejo's template reads position 10 as a Global Privacy Controls marker and the tail as container scoped defaults; comment threads on the Baersch material read the tail the other way around. Treat both readings as hypotheses - the decoder exposes global_privacy_control and containerDefaults fields, and both stayed empty on the strings tested for this guide.
How gcs and gcd describe the same state
Take a site with denied-by-default consent mode where the visitor accepts the banner. The hit then carries gcs=G111 and gcd=13r3r3r3r5l1-type values: the r letters mean "denied by default, granted by update", which merges to granted - exactly what G111 says. Before the banner click the same site sends gcs=G100 with gcd=11p1p1p1p5: p is denied with no update, and G100 agrees. A site that requires no consent sends G1-- while gcd still details the four signals with l letters where nothing is configured.
No official text states the correspondence, so it stays a reverse-engineering result - but it holds on every string this guide checked against the decoder, and it gives you a fast sanity check: if gcs and the first two gcd pairs disagree on a hit, something is off in the consent setup itself.
How to decode gcd in a minute
Common values and their readings, each verified through the decoder:
| gcd | Reading |
|---|---|
11l1l1l1l1 | consent mode not configured; tail digit 1 marks the old version |
11p1p1p1p5 | everything denied by default, no update - advanced mode, banner untouched |
13r3r3r3r5 | user granted everything after a denied default |
13q3q3q3q5 | user confirmed the rejection of a denied default |
13t3t3t3t5 | everything granted by default, no update needed |
13v3v3v3v5 | default grant confirmed by update |
11u1u1u1u5 | default grant withdrawn by the user |
11r1r1l1l5 | only ad_storage and analytics_storage configured, both accepted |
11l1p1l1l5 | only analytics_storage denied by default |
13q3v3q3q5 | mixed: rejection on three signals, analytics granted by default and update |
13r3r3r2r5 | user granted everything, but ad_personalization carries implicit denial |
13t3t3t3t5l1 | current 12-character format with the tail present |
Tools, in the order you should reach for them:
- Tag Assistant - the officially recommended debugger; it shows consent state without any string reading. Google's debugging guide warns against calling the consent command from a custom HTML tag, so when the on-page state looks wrong, suspect the setup before the parameters.
- The public decode endpoint - one request per string:
curl -s "https://openapi.analytics-debugger.com/v1/google/consent/decode/13r3r3r3r5l1?mode=full"- A server-side GTM variable template for local decoding - Analytics Debugger's parser or dpezrez's consent-state template, which decodes without outbound requests; Lukas Wojcik's toolbox offers the same in the browser for
gcsandgcdseparately.
How to check gcs and gcd in server-side GTM
Server-side tracking moves the inspection point from the browser to your own endpoint, and both parameters ride along with every forwarded event - the same values the browser tag put on the outgoing request. In a server-side tracking container, event data carries them under prefixed names, so a quick check looks like this:
- Open the affected client in the server container preview, or log event data with a temporary variable.
- Look up
x-ga-gcs- expectG100before a banner decision andG111after acceptance; a missingx-ga-gcson GA4 hits usually means the request never passed through the web tag's consent state. - Look up
x-ga-gcdand decode it with the letter table above - this is where you catch the case the banner test misses:ad_user_dataorad_personalizationin a different state thanad_storage. - Compare against the migration checklist in the server-side GTM migration guide if the values differ between the web container and the server container, and see server-side tracking versus the browser pixel for why the two layers can legitimately disagree.
Community templates, including the stape ones, expose the same prefixed fields as variables - the prefix is the only difference from the query-string names. Without a server container you can read both parameters straight from the browser network tab on any /g/collect request, which is usually enough for a banner test; the fuller consent context behind cookieless measurement is covered in the cookieless attribution guide.
Why you should not parse gcd in production logic
The format has already changed twice: the 2023 strings were 10 characters, the 2024 strings added implicit markers and the 12th-character tail, and the marker digit grew variants beyond 5. Baersch's guide states it plainly: "These are internal parameters used by Google. Their values can change without warning." A parser that ships in a production tag, a template you sell, or a compliance report will break silently on the next format shift.
Three more gaps keep the string unfit as a source of truth. functionality_storage, personalization_storage, and security_storage never appear in either parameter, so a parsed gcd cannot prove full consent coverage. The semantics of implicit markers and the tail are consensus, not documentation. And regional consent variants produce strings the community tables do not cover yet.
For anything with compliance consequences, use the instruments built for it: Tag Assistant for on-page consent state, and your own captured consent state as the delivery gate - the discipline of storing what the visitor agreed to and shipping only what matches is the subject of the first-party data consent guide. The parameters are for verification, and your consent platform is for enforcement.
Frequently asked questions about gcs and gcd
Frequently asked questions
Sources
Sources
- Consent debugging guide - Google Tag Platform
- Set up consent mode on websites - Google Tag Platform
- Consent mode overview - Google Tag Platform
- Consent Mode V2 For Google Tags - Markus Baersch at Simo Ahava
- Consent Mode 2.0 FAQ - Markus Baersch
- GTM server-side Google consent parser - Analytics Debugger
- Public gcd decode endpoint - Analytics Debugger
- gtm-consent-state - dpezrez
- GA4 gcd Parameter Decoder - Lukas Wojcik
- What the gcd parameter of Google Analytics 4 means - ROIANALYTICS
- See what leaves your stack: Pixel Activator sends verifiable test events so you can inspect every consent field your delivery transmits.
- Gate delivery on real consent state: Most carries the captured consent state with every event and holds what should not ship.
