ShieldPage
← All articles
Guides · · 11 min read

Google Consent Mode v2, Explained Properly (Including the Bug Almost Everyone Ships)

What Consent Mode v2 actually does, how to implement it correctly, and the dataLayer mistake that silently breaks it on a surprising number of sites — including how to verify yours works.

Since March 2024, Google requires Consent Mode v2 for websites using its advertising features — audience building, remarketing, conversion measurement — with visitors from the EEA and UK. Plenty of articles repeat that sentence. Far fewer explain what Consent Mode actually does, and almost none mention the implementation mistake that makes it silently do nothing — one we've seen in the wild repeatedly, and one that standard testing won't catch. This guide covers all three.

What Consent Mode v2 actually is

Consent Mode is a signaling layer between your consent banner and Google's tags. Instead of deciding whether to load Google's scripts, it tells the scripts what they're allowed to do. Four signals matter: ad_storage (advertising cookies), ad_user_data (sending user data to Google for advertising), ad_personalization (personalized ads), and analytics_storage (analytics cookies). The "v2" additions are ad_user_data and ad_personalization — without them, Google's EU User Consent Policy considers your setup incomplete and features like audience building degrade.

The flow has two steps. First, a default command sets every signal to denied *before any Google tag loads* — this is the part that protects visitors. Then, when the visitor makes a choice in your banner, an update command flips the granted signals. If consent is denied, Google's tags can send cookieless "pings" instead of full measurement — that's what enables conversion modeling without tracking individuals.

The bug: array pushes are silently ignored

Here is the detail that catches even experienced teams. Consent commands must be pushed to the dataLayer as an arguments object, via the canonical gtag function:

window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('consent', 'default', {...});

A plain array push — dataLayer.push(['consent', 'default', {...}]) — looks identical in the browser console, appears in the dataLayer when you inspect it, and is completely ignored by gtag.js. Google's library only processes consent commands delivered as arguments objects. To be clear: this is not a Google bug. It's documented behavior — Google's own setup guide (developers.google.com/tag-platform/security/guides/consent) prescribes exactly the gtag() shim above, and consent commands are simply not part of the plain-array API. The bug lives in implementations that bypass the shim, and it's an easy one to write because array pushes *do* work for many other dataLayer uses. The failure is invisible: no error, no warning, your dataLayer looks right, and your consent signals never reach Google. We know this one intimately because our own widget shipped exactly this bug — our test suite inspected the dataLayer contents and passed, while Google ignored every signal. We found it in a line-by-line audit, not in testing. If you take one thing from this article: inspecting the dataLayer is not verification.

How to verify Consent Mode actually works

  • Use Tag Assistant, not the console. Open tagassistant.google.com, connect your site, and look for the Consent tab. You should see "Default" consent states registered before any tag fires, then an "Update" after you interact with the banner.
  • Check the ordering. The default command must execute before gtag.js or GTM loads. If your consent script loads async after the Google tag, you have a race — the tag can fire with no consent state at all.
  • Test the denied path, not just the granted one. Reject everything in your banner, then confirm in Tag Assistant that signals stay denied and (in basic mode) no cookies like _ga appear in devtools → Application → Cookies.
  • Watch for the wait. The default command accepts a wait_for_update value (in milliseconds) that holds tags briefly so a returning visitor's stored consent can be applied — without it, tags may fire denied pings before your banner has read the stored choice.

Basic vs. advanced mode — an honest note

In "advanced" mode, Google tags load even when consent is denied and send cookieless pings. Google argues this is privacy-safe; some EU regulators and privacy professionals are skeptical of any pre-consent communication with ad servers. The conservative implementation — the one we default to — is to combine Consent Mode with actual script blocking: denied categories mean the tag doesn't load at all, and Consent Mode signals whatever Google needs when consent *is* granted. You lose conversion modeling on rejected traffic; you gain a setup no regulator will argue with. Which trade-off is right for you is a business decision worth making consciously rather than by default.

Checklist

  • Consent default set to denied for all four signals, as an arguments-object push, before any Google tag
  • Update pushed on every consent change, mapped from your banner categories (marketing → ad_*, analytics → analytics_storage)
  • Verified in Tag Assistant: Default appears, Update appears, denied stays denied
  • Decision made consciously between basic mode (block tags) and advanced mode (cookieless pings)
  • Re-verified after any tag manager or banner change — this breaks quietly

ShieldPage's widget does this automatically when Google Consent Mode is enabled — including the arguments-object detail, which is covered by an automated test suite that checks behavior, not just dataLayer contents. But whichever CMP you use, run the Tag Assistant verification yourself. It takes five minutes and it's the only way to know.

*This article explains technical implementation, not legal obligations — for what your specific site must do, consult qualified counsel.*