> This document 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.

#### Why use a tag template for consent?

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](https://developers.google.com/tag-platform/tag-manager/templates/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.
Don't create templates that use the `gtag consent` command. Instead, use the Tag Manager API `updateConsentState`. `gtag` commands are queued after all other pending messages and may not be processed before the next event begins. For more information, see [How data layer information is processed](https://developers.google.com/tag-platform/tag-manager/datalayer#how_data_layer_information_is_processed).

> [!IMPORTANT]
> Consent Management Platform (CMP) commonly refers to a consent management solution provided by a vendor. This page uses the abbreviation CMP to refer to both third-party and in-house solutions.

## Consent state and consent types

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 |

> [!NOTE]
> **Note:** If you offer consent options that don't map to these consent types, you can also provide custom consent types by providing your own consent type key.

## Create a new consent template

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](https://developers.google.com/tag-platform/tag-manager/templates/api#setdefaultconsentstate) and
  [updateConsentState](https://developers.google.com/tag-platform/tag-manager/templates/api#updateconsentstate) instead of `gtag consent`.

  > [!IMPORTANT]
  > **Important:** `gtag` commands are queued after all other pending messages and may not be processed before the next event begins. For more information, see [How data layer information is processed](https://developers.google.com/tag-platform/tag-manager/datalayer#how_data_layer_information_is_processed).

- 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.

#### To create a consent template:

1. Log into your [Google Tag Manager](https://tagmanager.google.com) account.
2. In the left navigation, select **Templates**.
3. In the **Tag Templates** pane, click **New**.

#### To set default consent states:

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](https://developers.google.com/tag-platform/tag-manager/templates/consent-apis#regional-behavior).
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](https://developers.google.com/tag-platform/tag-manager/templates/consent-apis#data-redaction)

#### 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](https://developers.google.com/tag-platform/tag-manager/templates/consent-apis#url-passthrough)

#### 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.

> [!NOTE]
> **Note:** When you first save the code, a validation error will occur. It will be resolved when you add your cookie names later in the **Permissions** tab.

    // 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 JSON = require('JSON');
    const COOKIE_NAME = 'Your_cookie_name';
    /*
     *   Splits the input string using comma as a delimiter, returning an array of
     *   strings
     */
    const splitInput = (input) => {
      if (!input) return [];
      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). Add optional chaining to safely handle cases
      // where defaultSettings might be null or undefined.
      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 cookieValues = getCookieValues(COOKIE_NAME);
      if (cookieValues && cookieValues.length > 0) {
        try {
          const settings = JSON.parse(cookieValues[0]);
          if (settings) {
            onUserConsent(settings);
          }
        } catch (e) {
          // Log an error if the cookie value is not valid JSON.
        }
      }
      /**
       *   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.

#### To add permissions for managing consent states:

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](https://developers.google.com/tag-platform/tag-manager/templates/tests) for information on creating tests for your template.

### 3. Integrate the template with the consent solution

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);
      });
    };

### Update the consent state

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](https://developers.google.com/tag-platform/tag-manager/templates/api#updateconsentstate) API.

> [!NOTE]
> **Note:** The `updateConsentState` call should be executed as early as possible on pages after the one where the user interacts with the consent banner. If possible, it is preferable to use the template's sandboxed code to read the user's consent directly from the cookie(s) that store it instead of using external code to do this. If it is necessary to make network requests or perform other asynchronous tasks before calling `updateConsentState` you should specify a wait time of at least 500 milliseconds in the **wait_for_update** field when calling `setDefaultConsentState`. This will allow those tasks time to complete before Google tags fire. For more information, see [Integrate with asynchronous consent
> management platforms](https://developers.google.com/tag-platform/security/guides/consent#async).

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](https://en.wikipedia.org/wiki/ISO_3166-2#current-codes)) 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](https://developers.google.com/tag-platform/tag-manager/templates/api#gtagset) API to set following optional parameters:

- [`url_passthrough`](https://developers.google.com/tag-platform/tag-manager/templates/consent-apis#url-passthrough)
- [`ads_data_redaction`](https://developers.google.com/tag-platform/tag-manager/templates/consent-apis#data-redaction)
- [`developer_id`](https://developers.google.com/tag-platform/tag-manager/templates/consent-apis#developer-id)

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);

> [!NOTE]
> **Note:** If you add the option to set URL passthrough in your template it still needs to be configured inside conversion linker tags (if in use) to work as expected. For more information on best practices when using URL passthrough, see [Manage consent settings](https://developers.google.com/tag-platform/security/guides/consent#passthroughs).

### 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](https://developers.google.com/tag-platform/tag-manage).