cookieowl

Chapter IV of IX

Google Consent Mode v2 setup, step by step

Consent Mode tells Google tags what the visitor allowed. Here is how the four v2 signals work, basic versus advanced mode, and a setup that sends them right.

By Updated 8 min read

The four signals of Consent Mode v2

Consent Mode is a small protocol between your page and Google tags. Before a tag reads or writes cookies, it checks a set of consent types, each either granted or denied. Version 2, introduced for the Digital Markets Act, added two signals to the original two, and all four are now expected for traffic from the European Economic Area:

  • ad_storage: cookies and identifiers for advertising.
  • ad_user_data: sending user data to Google for advertising.
  • ad_personalization: personalized advertising and remarketing.
  • analytics_storage: cookies for analytics, such as the Google Analytics client id.

There are also functionality_storage, personalization_storage and security_storage. cookieowl maps them all to categories: the three ad signals follow marketing, analytics follows analytics, functionality and personalization follow preferences and security is always granted.

Order matters: default, then update

The default command must run before any Google tag, and the update must follow every choice. Getting the order wrong is the most common Consent Mode bug: if gtag.js reads the dataLayer before the default exists, the first hit goes out as if consent were granted. That is why cookieowl must be the first script in the head. It writes this before anything else can run:

what cookieowl sends
gtag('consent', 'default', {
  ad_storage: 'denied',
  ad_user_data: 'denied',
  ad_personalization: 'denied',
  analytics_storage: 'denied',
  functionality_storage: 'denied',
  personalization_storage: 'denied',
  security_storage: 'granted',
  wait_for_update: 500,
});
gtag('set', 'ads_data_redaction', true);

// later, when the visitor accepts analytics only
gtag('consent', 'update', { analytics_storage: 'granted', ad_storage: 'denied' });

wait_for_update tells tags that load before the visitor's stored choice is applied to wait that many milliseconds for an update. Returning visitors get their update in the same tick as the default, so tags never see a wrong state.

Setup with gtag.js

Turn Consent Mode on with one attribute. Keep your gtag snippet as it is, but mark it so it waits for analytics (basic mode):

index.html
<head>
  <script src="https://cdn.jsdelivr.net/npm/cookieowl@0.1.0/dist/cookieowl.js"
    data-policy-url="/privacy" data-consent-mode></script>

  <script type="text/plain" data-cookieowl="analytics" async
    src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
  <script type="text/plain" data-cookieowl="analytics">
    window.dataLayer = window.dataLayer || [];
    function gtag() { dataLayer.push(arguments); }
    gtag('js', new Date());
    gtag('config', 'G-XXXXXXX');
  </script>
</head>

For advanced mode, load the Google tags normally (no text/plain) and set data-consent-mode="advanced". The auto blocker then leaves gtag.js and Tag Manager alone, while still holding the Meta Pixel, Hotjar and the rest.

Setup with Google Tag Manager

With Tag Manager you have two choices. In basic mode, hold the whole container until analytics is accepted: mark the GTM snippet with type="text/plain" data-cookieowl="analytics", or let data-auto-block catch gtm.js. Nothing inside the container runs before consent, which is the simplest setup to audit.

If you prefer to let the container load and decide per tag, use data-consent-mode="advanced". Tags with built in consent checks (Google Analytics, Google Ads, Floodlight) read the consent state themselves. For other tags, turn on Require additional consent in their settings, or fire them from the cookieowl_consent event that cookieowl pushes to the dataLayer on every choice, reading the categories from the cookieowl variable it carries.

dataLayer after a choice
{
  event: 'cookieowl_consent',
  cookieowl: { necessary: true, preferences: false, analytics: true, marketing: false }
}

Region specific defaults

If you serve visitors outside the EEA and want different defaults there, list regions with ISO 3166-2 codes. Region commands are sent before the global default, and the most specific region wins:

consent.js
cookieowl.init({
  consentMode: {
    waitForUpdate: 500,
    regions: [
      { region: ['US-CA', 'US-CO'], analytics_storage: 'denied', ad_storage: 'denied' },
      { region: ['US'], analytics_storage: 'granted' },
    ],
    urlPassthrough: true,
  },
});

Questions

Is Google Consent Mode v2 mandatory?

Since March 2024 Google requires the ad_user_data and ad_personalization signals for advertisers who use Google Ads measurement, remarketing or audiences with traffic from the European Economic Area. Without them those features stop working for EEA users.

What is the difference between basic and advanced mode?

In basic mode Google tags do not load at all until consent. In advanced mode they load with everything denied and send cookieless pings, which Google uses for modeling. cookieowl uses basic mode by default and switches with advanced: true.

Does Consent Mode replace a cookie banner?

No. Consent Mode only passes the visitor's choice to Google tags. You still need a banner that collects the choice and blocks the other trackers.

How do I check that Consent Mode works?

Open Tag Assistant or the browser console and inspect window.dataLayer. You should see a consent default command before any config or event, then a consent update right after each choice.

Hoot suggests

Nothing here. Hoot looked under every cookie jar.