Skip to main content
AnalyticsLearner

Module 5

Consent Mode v2 update on banner consent

Fire gtag consent update when a visitor accepts or rejects cookies. Covers both the granted and denied paths.

consent-mode-v2gtmcmpprivacy

What this does

After the visitor interacts with the consent banner, you call gtag('consent','update',...) with the outcome. GTM listens for this update and re-evaluates all consent-gated tags. Tags blocked by the default-deny baseline will fire if the relevant signal is now 'granted'.

Accept path

// Called when visitor clicks "Accept all"
function onConsentAcceptAll() {
  gtag('consent', 'update', {
    ad_storage: 'granted',
    analytics_storage: 'granted',
    ad_user_data: 'granted',
    ad_personalization: 'granted',
  });
 
  // Persist the choice so it survives page reload
  localStorage.setItem(
    'consent_choice',
    JSON.stringify({
      analytics: true,
      advertising: true,
      ts: new Date().toISOString(),
    })
  );
}

Reject path

// Called when visitor clicks "Reject all"
function onConsentRejectAll() {
  gtag('consent', 'update', {
    ad_storage: 'denied',
    analytics_storage: 'denied',
    ad_user_data: 'denied',
    ad_personalization: 'denied',
  });
 
  localStorage.setItem(
    'consent_choice',
    JSON.stringify({
      analytics: false,
      advertising: false,
      ts: new Date().toISOString(),
    })
  );
}

Custom preferences path

// Called when visitor saves granular choices
function onConsentSavePreferences({ analytics, advertising }) {
  gtag('consent', 'update', {
    analytics_storage: analytics ? 'granted' : 'denied',
    ad_storage: advertising ? 'granted' : 'denied',
    ad_user_data: advertising ? 'granted' : 'denied',
    ad_personalization: advertising ? 'granted' : 'denied',
  });
 
  localStorage.setItem(
    'consent_choice',
    JSON.stringify({
      analytics,
      advertising,
      ts: new Date().toISOString(),
    })
  );
}

Restoring consent on page load

On every page load, read the stored choice and fire the update immediately after the GTM snippet:

(function restoreConsent() {
  try {
    const raw = localStorage.getItem('consent_choice');
    if (!raw) return; // No prior choice - banner will show
 
    const choice = JSON.parse(raw);
    gtag('consent', 'update', {
      analytics_storage: choice.analytics ? 'granted' : 'denied',
      ad_storage: choice.advertising ? 'granted' : 'denied',
      ad_user_data: choice.advertising ? 'granted' : 'denied',
      ad_personalization: choice.advertising ? 'granted' : 'denied',
    });
  } catch (e) {
    // localStorage blocked or JSON malformed - proceed with default-deny
  }
})();

GTM verification

In GTM Preview, the Summary tab should show:

  1. consent_default firing first (from the default-deny baseline)
  2. consent_update firing after banner interaction
  3. Consent-gated tags (GA4, Google Ads) firing only on the granted path

Free container for this module

GA4 + Consent Mode v2 Starter Container

A pre-built GTM container that implements the Consent Mode v2 default-deny baseline, region-aware EEA/UK settings, and a GA4 Configuration Tag gated on analytics_storage. Drop it into any GTM account and connect your CMP.

Get the container →