Iubenda logo

Documentation

Table of Contents

How to manage cookies for advertising and analytics purposes with Google Consent Mode

To help advertisers manage cookies for advertising and analytics purposes, Google has introduced Consent Mode, a feature that allows you to adjust how your Google tags behave based on the consent status of your users.

Don’t confuse Consent Mode with Additional Consent Mode, a feature that allows you to gather consent for Google ad partners that are not yet part of the Transparency and Consent Framework but are on Google’s Ad Tech Providers (ATP) list.

You can indicate whether consent has been granted for Ads and Analytics cookies. Google’s ad_storage and analytics_storage new keys will dynamically adapt, only utilizing cookies for the specified purposes when consent has been given by the user:

  • when consent is granted, the associated tags will function normally;
  • when consent for ad storage or analytics storage is denied, the associated Google tags deployed via gtag.js or Google Tag Manager will adjust their behavior accordingly.

For example, if a user does not provide consent for ads cookies (and therefore advertising purposes are disabled), but does provide consent for analytics cookies, you’ll still be able to measure site behavior and conversions in Analytics as the analytics_storage setting will be enabled.

Products that support Consent Mode include:

  • Google Ads (including Google Ads Conversion Tracking and Remarketing)
  • Google Analytics
  • Floodlight
  • Conversion Linker

Consent Mode requires gtag.js or Google Tag Manager to run. If you use an older tag like ga.js, analytics.js or conversion.js, you’ll have to update to gtag.js or Google Tag Manager first.

Google Consent Mode and iubenda Cookie Solution Implementation Examples

You may want to use Consent Mode as an alternative to prior blocking. Implementing it with our Cookie Solution requires adding:

  • a few lines of code above your global site tag (gtag.js) or Tag Manager container, and
  • a callback in your Cookie Solution snippet

Let’s see a couple of examples, one asynchronous (with better performances) and the other synchronous.

Asynchronous example

1. Initialize the data layer for Google Tag Manager

You probably have this code in the <head> of your pages:

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
    window.dataLayer = window.dataLayer || [];
    function gtag() {
        dataLayer.push(arguments);
    }
    gtag('js', new Date());
    gtag('config', 'GA_MEASUREMENT_ID');
</script>

It has to become:

<script>
    // Initialize the data layer for Google Tag Manager (this should mandatorily be done before the Cookie Solution is loaded)
    window.dataLayer = window.dataLayer || [];

    function gtag() {
        dataLayer.push(arguments);
    }

    // Default consent mode is "denied" for both ads and analytics, but delay for 2 seconds until the Cookie Solution is loaded
    gtag("consent", "default", {
        ad_storage: "denied",
        analytics_storage: "denied",
        wait_for_update: 2000 // milliseconds
    });

    // Further redact your ads data (optional)
    gtag("set", "ads_data_redaction", true);
    
    // Google Tag Manager
    (function(w, d, s, l, i) {
        w[l] = w[l] || [];
        w[l].push({
            'gtm.start': new Date().getTime(),
            event: 'gtm.js'
        });
        var f = d.getElementsByTagName(s)[0],
            j = d.createElement(s),
            dl = l != 'dataLayer' ? '&l=' + l : '';
        j.async = true;
        j.src =
            'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
        f.parentNode.insertBefore(j, f);
    })(window, document, 'script', 'dataLayer', 'GTM-XXXXXX'); //replace GTM-XXXXXX with the ID of your Google Analytics property
</script>

Redact ads data

As you can see from this line:

gtag("set", "ads_data_redaction", true);

We’ve opted to further redact ads data when ad_storage is 'denied'. In fact, when ads_data_redaction is set to true and ad_storage is 'denied', ad click identifiers sent in network requests by associated Google Ads and Floodlight tags are redacted. Network requests are also sent through a cookieless domain.

Please note that without this optional line, some cookies may be installed.

2. Set the consent settings

After initializing the data layer for Google Tag Manager, you have to set the consent settings:

<script>
    var consentUpdated = false;

    // Update the existing consent
    function updateConsent(ad_storage, analytics_storage) {
        gtag("consent", "update", {
            ad_storage: ad_storage ? "granted" : "denied",
            analytics_storage: analytics_storage ? "granted" : "denied"
        });
        consentUpdated = true;
    }
</script>

3. Add a callback to your Cookie Solution snippet

Finally, you need to add a callback to your Cookie Solution snippet. This way you’ll be able to call the update command when your consent status changes:

<script>    
    var _iub = _iub || [];
    
    _iub.csConfiguration = {
        lang: "en",
        siteId: 12345678, //use your siteId
        cookiePolicyId: 12345678, //use your cookiePolicyId
        ...
        callback: {
            onReady: function() {
                if (!consentUpdated) {
                    // Consent is needed and the user has not expressed his preference yet
                    updateConsent(false, false);
                }
            },
            onPreferenceExpressedOrNotNeeded: function(preferences) {
                var ad_storage = false;
                var analytics_storage = false;
                if (preferences) {
                    // Consent is needed and the user has expressed his preference
                    if (preferences.purposes) {
                        analytics_storage = preferences.purposes[4];
                        ad_storage = preferences.purposes[5];
                    } else {
                        analytics_storage = ad_storage = preferences.consent;
                    }
                    updateConsent(ad_storage, analytics_storage);
                } else {
                    // Consent is not needed
                    updateConsent(true, true);
                }
            }
        }
    };
</script>
<script src="https://cdn.iubenda.com/cs/iubenda_cs.js" charset="UTF-8" async></script>

Wrapping it up:

<!-- Global site tag (gtag.js) - Google Analytics -->
<script>
    // Initialize the data layer for Google Tag Manager (this should mandatorily be done before the Cookie Solution is loaded)
    window.dataLayer = window.dataLayer || [];

    function gtag() {
        dataLayer.push(arguments);
    }

    // Default consent mode is "denied" for both ads and analytics, but delay for 2 seconds until the Cookie Solution is loaded
    gtag("consent", "default", {
        ad_storage: "denied",
        analytics_storage: "denied",
        wait_for_update: 2000 // milliseconds
    });

    // Further redact your ads data (optional)
    gtag("set", "ads_data_redaction", true);
    
    // Google Tag Manager
    (function(w, d, s, l, i) {
        w[l] = w[l] || [];
        w[l].push({
            'gtm.start': new Date().getTime(),
            event: 'gtm.js'
        });
        var f = d.getElementsByTagName(s)[0],
            j = d.createElement(s),
            dl = l != 'dataLayer' ? '&l=' + l : '';
        j.async = true;
        j.src =
            'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
        f.parentNode.insertBefore(j, f);
    })(window, document, 'script', 'dataLayer', 'GTM-XXXXXX'); //replace GTM-XXXXXX with the ID of your Google Analytics property

    var consentUpdated = false;

    // Update the existing consent
    function updateConsent(ad_storage, analytics_storage) {
        gtag("consent", "update", {
            ad_storage: ad_storage ? "granted" : "denied",
            analytics_storage: analytics_storage ? "granted" : "denied"
        });
        consentUpdated = true;
    }
</script>

<!-- iubenda Cookie Solution -->
<script>    
    var _iub = _iub || [];
    
    _iub.csConfiguration = {
        lang: "en",
        siteId: 12345678, //use your siteId
        cookiePolicyId: 12345678, //use your cookiePolicyId
        countryDetection: true,
        perPurposeConsent: true,
        purposes: "1,4,5",
        consentOnContinuedBrowsing: false,
        banner: {
            position: "float-top-center",
            acceptButtonDisplay: true,
            customizeButtonDisplay: true,
            rejectButtonDisplay: true
        },
        callback: {
            onReady: function() {
                if (!consentUpdated) {
                    // Consent is needed and the user has not expressed his preference yet
                    updateConsent(false, false);
                }
            },
            onPreferenceExpressedOrNotNeeded: function(preferences) {
                var ad_storage = false;
                var analytics_storage = false;
                if (preferences) {
                    // Consent is needed and the user has expressed his preference
                    if (preferences.purposes) {
                        analytics_storage = preferences.purposes[4];
                        ad_storage = preferences.purposes[5];
                    } else {
                        analytics_storage = ad_storage = preferences.consent;
                    }
                    updateConsent(ad_storage, analytics_storage);
                } else {
                    // Consent is not needed
                    updateConsent(true, true);
                }
            }
        }
    };
</script>
<script src="https://cdn.iubenda.com/cs/iubenda_cs.js" charset="UTF-8" async></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script>
    // Define the gtag() function prior to your gtag.js or Tag Manager snippet. This should mandatorily be done before the Cookie Solution is loaded
    window.dataLayer = window.dataLayer || [];

    function gtag() {
        dataLayer.push(arguments);
    }

    // Further redact your ads data (optional)
    gtag("set", "ads_data_redaction", true);

    // Prepare Google Tag Manager but don't load it yet (it has to be loaded after the Cookie Solution)
    (window.loadgtm = function(w, d, s, l, i) {
        w[l] = w[l] || [];
        w[l].push({
            'gtm.start': new Date().getTime(),
            event: 'gtm.js'
        });
        var f = d.getElementsByTagName(s)[0],
            j = d.createElement(s),
            dl = l != 'dataLayer' ? '&l=' + l : '';
        j.async = true;
        j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
        f.parentNode.insertBefore(j, f);
    });
    
    var consentCommand = "default";

    // Set the default consent mode or update the existing consent
    function updateConsent(ad_storage, analytics_storage, command) {
        gtag("consent", command || consentCommand, {
            ad_storage: ad_storage ? "granted" : "denied",
            analytics_storage: analytics_storage ? "granted" : "denied"
        });
        consentCommand = "update";
    }
</script>

<!-- iubenda Cookie Solution -->
<script>
    var _iub = _iub || [];

    _iub.csConfiguration = {
        lang: "en",
        siteId: 12345678, //use your siteId
        cookiePolicyId: 12345678, //use your cookiePolicyId
        countryDetection: true,
        perPurposeConsent: true,
        purposes: "1,4,5",
        consentOnContinuedBrowsing: false,
        banner: {
            position: "float-top-center",
            acceptButtonDisplay: true,
            customizeButtonDisplay: true,
            rejectButtonDisplay: true
        },
        callback: {
            onReady: function() {
                if (consentCommand === "default") {
                    // Consent is needed and the user has not expressed his preference yet
                    updateConsent(false, false);
                }
                // Load GTM 
                window.loadgtm(window, document, 'script', 'dataLayer', 'GTM-XXXXXX'); //replace GTM-XXXXXX with the ID of your Google Analytics property
            },
            onPreferenceExpressedOrNotNeeded: function(preferences) {
                var ad_storage = false;
                var analytics_storage = false;
                if (preferences) {
                    // Consent is needed and the user has expressed his preference
                    if (preferences.purposes) {
                        analytics_storage = preferences.purposes[4];
                        ad_storage = preferences.purposes[5];
                    } else {
                        analytics_storage = ad_storage = preferences.consent;
                    }
                } else {
                    // Consent is not needed
                    ad_storage = true;
                    analytics_storage = true;
                }
                updateConsent(ad_storage, analytics_storage, 'update');
            }
        }
    };
</script>
<script src="https://cdn.iubenda.com/cs/iubenda_cs.js" charset="UTF-8" async></script>

To learn more about Consent Mode, take a look at the Google Analytics Help or the gtag.js guide.

See also