Create a consent mode template

This article is for developers that maintain a consent management solution on websites that use Google Tag Manager (GTM).

This page introduces consent types in Google Tag Manager and shows you how to integrate them with your consent management solution.

When you provide a tag template, your users can integrate your consent solution in a codeless way, saving significant time and effort.

Users can set default consent states using a consent mode template and communicate visitor consent choices to Google Tag Manager. This ensures optimal functioning of Google and third-party tags that support consent mode.

As a template creator, you can implement consent mode templates for internal use or publish them in the Community Template Gallery to make them publicly available. Consent Management Platform (CMP) providers who offer consent mode templates have the opportunity to be listed in our consent mode documentation and have the Template Gallery picker feature their templates.

Google and third-party tags adjust their storage behavior based on a consent state of either granted or denied. They can have built-in consent checks for any of the following consent types:

Consent Type Description
ad_storage Enables storage, such as cookies, related to advertising.
ad_user_data Sets consent for sending user data to Google for online advertising purposes.
ad_personalization Sets consent for personalized advertising.
analytics_storage Enables storage, such as cookies, related to analytics (for example, visit duration).
functionality_storage Enables storage that supports the functionality of the website or app such as language settings.
personalization_storage Enables storage related to personalization such as video recommendations.
security_storage Enables storage related to security such as authentication functionality, fraud prevention, and other user protection

Consent mode keeps track of visitor consent choices and tag consent checks ensure that tag behavior adjusts accordingly. When creating a new consent template, follow the best practices:

  • Use the Tag Manager consent mode APIs setDefaultConsentState and updateConsentState instead of gtag consent.

  • Set default consent states immediately upon firing using the Consent Initialization - All Pages trigger.

  • The CMP has to prompt the visitor as soon as possible to grant or deny consent for all applicable consent types.

  • When a visitor indicates their consent choice, the CMP has to pass the updated consent state.

1. Create a new template

This implementation approach uses one field in the template to hold the default consent state. The implementation code reads that field to set the default consent state at runtime. For the update command, your code attempts to read a cookie set by the consent solution to store visitor consent choices. You will also set up a callback for updateConsentState to handle the case where a visitor has yet to make their consent selections or decides to change their consent.

  1. Log into your Google Tag Manager account.
  2. In the left navigation, select Templates.
  3. In the Tag Templates pane, click New.
  1. Select the Fields tab, click Add Field > Param table.
  2. Change the name to defaultSettings.
  3. Expand the field.
  4. Update the Display name to Default settings.
  5. Click Add column, choose Text input, change the name to region and check the Require column values to be unique box.
  6. Expand the column, and change the display name to Region (leave blank to have consent apply to all regions). The statement in parenthesis is documentation for your template users. Learn more about setting up consent defaults for different regions.
  7. Click Add column, choose Text input, change the name to granted.
  8. Expand the column and change the display name to Granted Consent Types (comma separated).
  9. Click Add column, choose Text input, change the name to denied.
  10. Expand the column and change the display name to Denied Consent Types (comma separated)

Optional: To add support for ads data redaction:

  1. Click Add Field, choose Checkbox, and change the field name to ads_data_redaction.
  2. Update the Display name to Redact Ads Data

Learn more about cookie behavior with ads data redation

Optional: To add support for passing through URL parameters:

  1. Click Add Field, choose Checkbox, and change the field name to url_passthrough.
  2. Update the Display name to Pass through URL parameters

Learn more about passing through URL parameters

To add the implementation code:

  1. Open the Code tab in the template editor.
  2. In the code sample below, edit the placeholder fields.
  3. Copy the code and replace the boilerplate code in the template editor with it.
  4. Save the template.
// The first two lines are optional, use if you want to enable logging
const log = require('logToConsole');
log('data =', data);
const setDefaultConsentState = require('setDefaultConsentState');
const updateConsentState = require('updateConsentState');
const getCookieValues = require('getCookieValues');
const callInWindow = require('callInWindow');
const gtagSet = require('gtagSet');
const COOKIE_NAME = 'Your_cookie_name';
/*
 *   Splits the input string using comma as a delimiter, returning an array of
 *   strings
 */
const splitInput = (input) => {
  return input.split(',')
      .map(entry => entry.trim())
      .filter(entry => entry.length !== 0);
};
/*
 *   Processes a row of input from the default settings table, returning an object
 *   which can be passed as an argument to setDefaultConsentState
 */
const parseCommandData = (settings) => {
  const regions = splitInput(settings['region']);
  const granted = splitInput(settings['granted']);
  const denied = splitInput(settings['denied']);
  const commandData = {};
  if (regions.length > 0) {
    commandData.region = regions;
  }
  granted.forEach(entry => {
    commandData[entry] = 'granted';
  });
  denied.forEach(entry => {
    commandData[entry] = 'denied';
  });
  return commandData;
};
/*
 *   Called when consent changes. Assumes that consent object contains keys which
 *   directly correspond to Google consent types.
 */
const onUserConsent = (consent) => {
  const consentModeStates = {
    ad_storage: consent['adConsentGranted'] ? 'granted' : 'denied',
    ad_user_data: consent['adUserDataConsentGranted'] ? 'granted' : 'denied',
    ad_personalization: consent['adPersonalizationConsentGranted'] ? 'granted' : 'denied',
    analytics_storage: consent['analyticsConsentGranted'] ? 'granted' : 'denied',
    functionality_storage: consent['functionalityConsentGranted'] ? 'granted' : 'denied',
    personalization_storage: consent['personalizationConsentGranted'] ? 'granted' : 'denied',
    security_storage: consent['securityConsentGranted'] ? 'granted' : 'denied',
  };
  updateConsentState(consentModeStates);
};
/*
 *   Executes the default command, sets the developer ID, and sets up the consent
 *   update callback
 */
const main = (data) => {
  /*
   * Optional settings using gtagSet
   */
  gtagSet('ads_data_redaction', data.ads_data_redaction);
  gtagSet('url_passthrough', data.url_passthrough);
  gtagSet('developer_id.your_developer_id', true);
  // Set default consent state(s)
  data.defaultSettings.forEach(settings => {
    const defaultData = parseCommandData(settings);
  // wait_for_update (ms) allows for time to receive visitor choices from the CMP
    defaultData.wait_for_update = 500;
    setDefaultConsentState(defaultData);
  });

  // Check if cookie is set and has values that correspond to Google consent
  // types. If it does, run onUserConsent().
  const settings = getCookieValues(COOKIE_NAME);
  if (typeof settings !== 'undefined') {
    onUserConsent(settings);
  }
  /**
   *   Add event listener to trigger update when consent changes
   *
   *   References an external method on the window object which accepts a
   *   function as an argument. If you do not have such a method, you will need
   *   to create one before continuing. This method should add the function
   *   that is passed as an argument as a callback for an event emitted when
   *   the user updates their consent. The callback should be called with an
   *   object containing fields that correspond to the five built-in Google
   *   consent types.
   */
  callInWindow('addConsentListenerExample', onUserConsent);
};
main(data);
data.gtmOnSuccess();

Next, configure permissions for accessing consent state and for accessing cookies.

  1. Select the Permissions tab and click Accesses consent state.
  2. Click Add consent type.
  3. Click the box and select ad_storage from the drop-down menu.
  4. Check Write.
  5. Click Add
  6. Repeat steps 2-5, for ad_user_data, ad_personalization, and analytics_storage. If you need additional consent types, add them in the same way.
  7. Click Save.

To add permissions for accessing cookies:

  1. Select the Permissions tab and click Reads cookie value(s).
  2. Under Specific, enter the names of each of the cookies your code needs to read to determine the user's consent choices, one name per line.
  3. Click Save.

2. Create unit tests

See Tests for information on creating tests for your template.

The following code shows one example of how this template could be integrated with the code for your consent management solution by adding a listener:

// Array of callbacks to be executed when consent changes
const consentListeners = [];

/**
 *   Called from GTM template to set callback to be executed when user consent is provided.
 *   @param {function} Callback to execute on user consent
 */
window.addConsentListenerExample = (callback) => {
  consentListeners.push(callback);
};

/**
 *   Called when user grants/denies consent.
 *   @param {Object} Object containing user consent settings.
 */
const onConsentChange = (consent) => {
  consentListeners.forEach((callback) => {
    callback(consent);
  });
};

After a website visitor has indicated their consent choices, typically through interacting with a consent banner, the template code should update consent states accordingly with the updateConsentState API.

The following example shows the updateConsentState call for a visitor that indicated they consent to all storage types. Again, this example uses hardcoded values for granted, but in practice, these should be determined at runtime using the visitor’s consent that is collected by the CMP.

const updateConsentState = require('updateConsentState');

updateConsentState({
  'ad_storage': 'granted',
  'ad_user_data': 'granted',
  'ad_personalization': 'granted',
  'analytics_storage': 'granted',
  'functionality_storage': 'granted',
  'personalization_storage': 'granted',
  'security_storage': 'granted'
});

About region-specific behavior

To set default consent states that apply to visitors from particular areas, specify a region (according to ISO 3166-2) in the template. Using region values enables template users to comply with regional regulations without losing information from visitors outside those regions. When a region is not specified in a setDefaultConsentState command, the value applies to all other regions.

For example, the following sets default status for analytics_storage to denied for visitors from Spain and Alaska, and sets analytics_storage to granted for all others:

const setDefaultConsentState = require('setDefaultConsentState');

setDefaultConsentState({
  'analytics_storage': 'denied',
  'region': ['ES', 'US-AK']
});
setDefaultConsentState({
  'analytics_storage': 'granted'
});

Most specific takes precedence

If two default consent commands occur on the same page with values for a region and subregion, the one with a more specific region will take effect. For example, if you have ad_storage set to 'granted' for the region US and ad_storage set to 'denied' for the region US-CA, a visitor from California will have the more specific US-CA setting take effect.

Region ad_storage Behavior
US 'granted' Applies to users in the US that are not in CA
US-CA 'denied' Applies to users US-CA
Unspecified 'granted' Uses the default value of 'granted'. In this example, that applies to users who aren't in the US or US-CA

Additional metadata

You can use the gtagSet API to set following optional parameters:

These APIs are only available within the GTM template sandbox environment.

Pass through ad click, client ID, and session ID information in URLs

When a visitor lands on an advertiser's website after clicking an ad, information about the ad might be appended to the landing page URLs as a query parameter. To improve conversion accuracy, Google tags usually store this information in first-party cookies on the advertiser's domain.

However, if ad_storage is denied, Google tags won't save this information locally. To improve ad click measurement quality in this case, advertisers can optionally pass ad click information through URL parameters across pages using a feature called URL passthrough.

Similarly, if analytics_storage is set to denied, URL passthrough can be used to send event and session-based analytics (including conversions) without cookies across pages.

The following conditions must be met to use URL passthrough:

  • Consent-aware Google tags are present on the page.
  • The site has opted in to using the URL passthrough feature.
  • Consent Mode is implemented on the page.
  • The outgoing link refers to the same domain as the current page's domain.
  • A gclid/dclid is present in the URL (Google Ads and Floodlight tags only)

Your template should allow the template user to configure whether or not they would like to enable this setting. The following template code is used to set url_passthrough to true:

gtagSet('url_passthrough', true);

Redact ads data

When ad_storage is denied, no new cookies are set for advertising purposes. Additionally, third-party cookies previously set on google.com and doubleclick.net won't be used. Data sent to Google will still include the full page URL, including any ad click information in the URL parameters.

To further redact your ads data when ad_storage is denied, set ads_data_redaction to true.

When ads_data_redaction is true and ad_storage is denied, ad click identifiers sent in network requests by Google Ads and Floodlight tags will be redacted.

gtagSet('ads_data_redaction', true);

Developer ID

If you are a CMP vendor with a Google-issued developer ID, use the following method to set this as early as possible in your template.

You only need a developer ID when your implementation will be used across multiple websites by unrelated companies or entities. If the implementation will be used by one site or entity, don't apply for a developer ID.

gtagSet('developer_id.<your_developer_id>', true);

Provide documentation for your users

Your users will use your consent template to set up a tag that collects user consent. Provide documentation for your users that explains the following best practices:

  • How to set consent defaults in the Settings table.
  • How to set up consent defaults for different regions by adding additional table rows.
  • Trigger the tag on the Consent Initialization - All Pages trigger.

Next steps

If you want to provide your template to all Tag Manager users, upload it to the Community Template Gallery.