Developer Guide

This document describes details of how to implement Google tag Manager on your site.

Using a Data Layer

To ensure maximum flexibility, portability, and ease of implementation, Google Tag Manager functions best when deployed alongside a data layer. A data layer is an object that contains all of the information that you want to pass to Google Tag Manager. Information such as events or variables can be passed to Google Tag Manager via the data layer, and triggers can be set up in Google Tag Manager based on the values of variables (e.g., fire a remarketing tag when purchase_total > $100) or based on the specific events. Variable values can also be passed through to other tags (e.g., pass purchase_total into the value field of a tag).

Rather than referencing variables, transaction information, page categories, and other important signals scattered throughout your page, Google Tag Manager is designed to easily reference information that you put in this data layer. However, explicitly declaring the data layer is optional and if you choose not to implement the data layer, you can still access values from the page using the Variables feature, but you cannot use events without the data layer. Implementing the data layer with variables and associated values, as opposed to waiting for those variables to load throughout the page, ensures that they will be available as soon as you need them to fire tags.

Adding Data Layer Variables to a Page

To set up your data layer, add the following snippet of code to the head of your page above your container snippet:

  dataLayer = [];

The above snippet is an empty object that can be populated with information to pass to Google Tag Manager. For example, we might want to set data layer variables within the data layer to indicate that the page is a signup page and that the visitor has been identified as being a high-value customer. To do so, we'd populate our data layer as follows:

  dataLayer = [{
    'pageCategory': 'signup',
    'visitorType': 'high-value'

For example, Google Tag Manager can be configured to fire tags on all pages marked as signup and/or on which the visitor has been marked as high-value. It's important that this data layer snippet be set above the container snippet as described in the Quick Start Guide.

If the data layer code is called after the container snippet, any variables declared within will not be available for Google Tag Manager to selectively fire tags on page load. Here are some examples:


<!-- Google Tag Manager -->
<!-- End Google Tag Manager -->
  dataLayer = [{
    'pageCategory': 'signup',
    'visitorType': 'high-value'


  dataLayer = [{
    'pageCategory': 'signup',
    'visitorType': 'high-value'
<!-- Google Tag Manager -->
<!-- End Google Tag Manager -->

Each of the variables declared within the data layer object will persist as long as the visitor remains on the current page. Data layer variables that are relevant across pages (e.g. visitorType) must therefore be declared in the data layer on each page of your website. While you don't need to put the same set of variables in the data layer on every page, you should use a consistent naming convention. In other words, if you set the page category on the signup page using pageCategory, to set a page category on a purchase page, you should do so using pageCategory as well.

Explicitly declaring a data layer is optional. Therefore, if you choose not to implement the data layer code and populate it with variables, the Google Tag Manager container snippet will initiate a data layer object for you.

Using the Data Layer with HTML Event Handlers

Google Tag Manager provides a special data layer variable called an event that is used within JavaScript event listeners to initiate tag firing when a user interacts with website elements such as a button. For example, you may want to fire a conversion tracking tag when a user clicks the Submit button on a newsletter signup form. Events may be called based on user interaction with website elements such as links, buttons, components of a Flash-driven menu system, or based on other JavaScript (e.g. time delays, etc.).

This functionality is accomplished by calling the push API as a method of the data layer on your page (e.g. attached to the particular elements to be tracked). The basic syntax for setting an event, then, is as follows:

dataLayer.push({'event': 'event_name'});

where event_name is a string indicating what the given event or element is.

As an example, to set an event when a user clicks a button, you might modify the button's link to call the push() API as follows:

<a href="#" name="button1" onclick="dataLayer.push({'event': 'button1-click'});" >Button 1</a>

Sometimes, the data you wish to collect or use to trigger certain tags may not load until after the user has interacted with the page. Using a combination of data layer variables and events, you may dynamically push this information to your data layer as necessary.

Data layer variables may be pushed dynamically to the data layer to capture information such as values entered or selected in a form, metadata associated with a video that the visitor is playing, the color of a product (e.g. a car) customized by the visitor, the destination URLs of clicked links, etc.

As with events, this functionality is accomplished by calling the push() API to add or replace data layer variables in the data layer. The basic syntax for setting dynamic data layer variables, then, is as follows:

dataLayer.push({'variable_name': 'variable_value'});

Where variable_name is a string indicating the name of the data layer variable to be set, and variable_value is a string indicating the value of the data layer variable to be set or replaced.

As an example, to set a data layer variable with a color preference when the visitor engages with a car customization widget, you might push the following dynamic data layer variable:

dataLayer.push({'color': 'red'});

One Push, Multiple Variables

Instead of using dataLayer.push() for each variable and event, you can push multiple variables and events at once. Here's an example of how to do this:

  'color': 'red',
  'conversionValue': 50,
  'event': 'customizeCar'

You can use the same technique within a link event handler:

<a href="#"
     'color': 'red',
     'conversionValue': 50,
     'event': 'customizeCar'});">Customize Color</a>

It's important to note that pushing a variable of the same name as an existing variable to the data layer will cause the existing value to be overwritten by the new value. For example, if upon clicking the above link, there were already a variable named color with a value of blue declared within the data layer, that value would be overwritten moving forward with the new value of red.

How the Asynchronous Syntax Works

Google Tag Manager is an asynchronous tag, meaning that when it executes, it does not block other elements from rendering on the page. It also causes the other tags that are deployed via Google Tag Manager to be deployed asynchronously, meaning that a slow loading tag won't block other tracking tags.

The dataLayer object is what makes the asynchronous syntax possible. It acts as a queue, which is a first-in,first-out data structure that collects API calls and tags are fired according to those API calls. To add something to the queue, use the dataLayer.push method. The dataLayer.push method can be used to pass in extra metadata to Google Tag Manager via variables and can be used to specify events.

The creation of the dataLayer object can either be specified before the Google Tag Manager snippet, or it will be created by Google Tag Manager if the dataLayer object hasn't already been defined.

For more information on the asynchronous syntax, read the Tracking Reference for the dataLayer.push method.

Avoiding Common Pitfalls

When implementing Google Tag Manager, keep the following in mind:

Do not overwrite your dataLayer

When you use assignment to assign values to dataLayer e.g. dataLayer = [{'item': 'value'}], it will overwrite any existing values. It is best to declare your dataLayer as high up in your source code as possible, above your container snippet or any Optimize page hiding snippet. After your dataLayer has been declared, you can use dataLayer.push({'item': 'value'}) to add additional values to it later in your scripts.

The dataLayer object name is case-sensitive

If you try to push a variable or event without the proper casing, the push will not work. Examples:

datalayer.push({'pageTitle': 'Home'});    // Won't work
dataLayer.push({'pageTitle': 'Home'});    // Better

Variable names should be enclosed in quotes

While quotes are not strictly required for variable names that consist of only letters, numbers, and underscores, and which are not reserved words (e.g. function, export, native, etc.), to avoid issues, it's recommended that all variable names be enclosed in quotes. Examples:

dataLayer.push({new-variable: 'value'});      // Won't work
dataLayer.push({'new-variable': 'value'});    // Better

Variable names should be kept consistent across pages

If you use different variable names for the same variables on different pages, GTM will be unable to consistently fire tags in all desired locations. Examples:

Won't work
// Homepage:
dataLayer.push({'visitorType': 'low-value'});

// Checkout Page:
dataLayer.push({'visitor_type': 'high-value'});
// Homepage:
dataLayer.push({'visitorType': 'low-value'});

// Checkout Page:
dataLayer.push({'visitorType': 'high-value'});

Any information needed to fire tags on a page load must be declared in the data layer above the container snippet

In order to fire tags on a page load matching some condition (e.g. on pages marked as having a pageCategory of sports), the pageCategory must be defined in the data layer above the container snippet (e.g. 'pageCategory': 'sports'). Variables pushed to the data layer (i.e. using dataLayer.push()) after the container snippet will not be able to fire tags on page loads with a matching condition.

Tags deployed with Google Tag Manager should not be left hard-coded or deployed by another tool as well

Any tags that are fired from Google Tag Manager should be migrated to Google Tag Manager, not just duplicated (for more information about migrating tags, see Migrating Tags to Google Tag Manager). Deploying tags both with Google Tag Manager and through other systems or hard-coded on your site may result in inflation of data (and other data integrity issues) resulting from those tags. For example, if you migrate your Google Analytics tracking code to fire from Google Tag Manager, the hard-coded Google Analytics tracking code should be removed from your site.

Renaming the Data Layer

By default, the data layer initiated and referenced by Google Tag Manager will be called dataLayer. If you'd prefer to use a different name for your data layer, you may do so by replacing the data layer parameter value (highlighted below) in your container snippet with the name of your choice.

<!-- Google Tag Manager -->
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
<!-- End Google Tag Manager -->

Then, all references to your data layer (i.e. when declaring the data layer above the snippet and when pushing events or dynamic Data Layer Variables to the data layer with the push() API) should also be adjusted to reflect your custom data layer name:

  myNewName = [{
    // ...
  myNewName.push({'variable_name': 'variable_value'});

Migrating Tags to Google Tag Manager

In order to gain the most value from Google Tag Manager, we recommend that you migrate most of your existing tags into Google Tag Manager (tags that are not supported should not be migrated). This section describes a best practice migration workflow. The process has 5 main steps:

  1. Map your site (optional)

    To begin your migration, you'll want to think about which tags you currently have deployed on your site and what data you're trying to collect. For data collection think about what actions you want to track (events) and what additional data from the page you'll want to collect (variables). Create a map of tags, the data you want those tags to collect, and which events or pages you want to associate with those tags.

  2. Implement standard Google Tag Manager snippet

    Once you've mapped your site, you'll want to install just the single Google Tag Manager snippet on your site (empty) and deploy it. See Quick Start for more information.

  3. Add Events and Variables

    Customize your Google Tag Manager installation using the methods outlined in the Add Events and Variables section.

  4. Add tags with associated triggers in Google Tag Manager's management interface

    After you've completed setting up the site with the Google Tag Manager snippet and data collection APIs, you should add your site tags to the user interface. DO NOT publish at this time. Simply add and configure the tags from your site in the Google Tag Manager management interface using the appropriate templates and set up the triggers appropriately (more information about how to do this in our Help Center Triggers article).

  5. Final migration swap

    The last step is where you simultaneously swap out your old tags and publish your tags in Google Tag Manager. Within a few minutes of each other, you'll want to:

    • Remove your site tags in a single code push
    • Once you know this push is successful, press the “Publish” button for your container version.

    This method might cause a small gap in data, but once the initial swap occurs, no more data gaps will appear. Alternatively, you could swap the order here and publish shortly before your site changes go live. This might cause minor, one-time data duplication instead of a small data gap.

After you've completed the initial migration to Google Tag Manager, any subsequent tagging needs you have can be handled without site code changes via the Google Tag Manager interface.

Multiple Domains

While you can use the same container for multiple websites it's recommended that each separate web property that you manage be deployed with its own container. This separation will prevent changes specific to one website from having undesired effects on other websites using the same container. In some situations, however, when multiple Top Level Domains or subdomains are considered to be members of the same website, it may be beneficial to manage their tags through the same Google Tag Manager container.

When choosing to use a single container across multiple domains, it's important to carefully configure your tags and triggers within Google Tag Manager. Using the default “All Pages” trigger in Google Tag Manager (i.e. $url matches RegEx .*) will fire tags on all pages of all domains on which your container snippet is deployed. Since some tags have configurations or purposes specific to the domain on which they're deployed, you may need to create custom triggers (or even remove the “All Pages” trigger) to fire tags on all pages of one or each domain individually.

For example, you may choose to deploy your Google Analytics tracking code through GTM with configurations to support GA tracking across multiple domains or subdomains.

Image showing multiple domains

In such a case, you would add a line of code to your GA tracking code to manually set the first-party domain on which to set the GA cookies (e.g. on and, you might set the cookies to the common domain, However, on the secondary site,, you might set the cookies to Therefore, you would want one of two GA tracking code tags (one set to, and one set to to fire on each of the two domains. If both domains were sharing a common GTM container, using the default “All Pages” trigger in Google Tag Manager, would cause each tag to fire on all pages of both domains.

Multiple Containers on a Page

For the best performance of a page, keep the number of Google Tag Manager containers on the page minimal.

If you use more than one container on a page, implement the container snippets with a common data layer object. For example, you may implement two container snippets as follows:

  1. Copy the following JavaScript and paste it as close to the opening <head> tag as possible on the page:
    <!-- Google Tag Manager -->
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    <!-- End Google Tag Manager -->
  2. Copy the following snippet and paste it immediately after the opening <body> tag on the page:
    <!-- Google Tag Manager (noscript) -->
    <noscript><iframe src="//"
    height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <noscript><iframe src="//"
    height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <!-- End Google Tag Manager (noscript) -->

Note that you can use only a single common data layer for all Google Tag Manager containers on a page because using more than one data layer can cause some triggers to stop working and could have other implications. So don't rename the data layer for a subset of containers on the page. You can, if necessary, rename the data layer for all containers on the page.

Avoid implementing a Google Tag Manager container through a custom HTML tag in another Google Tag Manager container because it could add latency in the tags from the secondary container and could have other implications.

Flash / Actionscript

To enable Google Tag Manager to fire tags based on content or interactions in a Flash movie, it is possible to utilize the ActionScript ExternalInterface method to push events and dynamic data layer variables to the data layer on the container page from the SWF movie. To achieve this functionality, the Google Tag Manager container snippet should be implemented within the HTML of the SWF's parent page as described in the Quick Start guide.

Events and dynamic data layer variables may then be pushed from the Flash component to Google Tag Manager by calling the push method via ExternalInterface. For example, to trigger an event upon click of a button mybutton_btn using ActionScript 3, you could implement the following code within your SWF:

import flash.display.*;
import flash.external.*;
mybutton_btn.addEventListener(MouseEvent.MOUSE_UP, onButtonClick);
function onButtonClick( Event:MouseEvent ):void {
  var name:String= "FLASH_EVENT";
  if (ExternalInterface.available) {'dataLayer.push',{'event': name});

For the ExternalInterface method to function properly, please ensure that when embedding your SWF, the allowscriptaccess attribute is set to always:

<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'
        width='300' height='300' id='player1' name='player1'>
  <param name='movie' value='file.swf'>
  <param name='allowfullscreen' value='true'>
  <param name='allowscriptaccess' value='always'>
  <param name='flashvars' value='file=playlist.xml'>
  <embed id='player1' name='player1'
         width='300' height='300'

Adding Data Layer Variables for Devices without JavaScript Support

In order to accommodate visitors who have JavaScript disabled or are visiting from devices that don't support JavaScript, Google Tag Manager includes a <noscript> snippet to deploy non-JavaScript dependent tags even when the primary GTM JavaScript cannot load.

It's important to note, however, that the data layer (containing the data layer variables declared on page load) and any events or dynamic data layer variables pushed to the data layer all rely on JavaScript to function. Therefore, if any of the triggers to fire your non-JavaScript dependent tags (that you want to fire even when JavaScript can't load) depend on data layer variables, you must pass those Data Layer Variables to the <noscript> iframe as query parameters. For example, to fire a tag when the pageCategory is sports and the visitorType is returning, you would modify the container snippet on the given page as follows:

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="//" height="0"
                  width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

Where each data layer variable is appended to the end of the iframe's source URL as plain text query parameters separated by ampersands.


Google Tag Manager incorporates a host of features to help ensure the security of your websites and apps. In addition to the following code-level security features, you may also want to familiarize yourself with Tag Manager's access controls , 2-step verification, and malware detection.

Restricting tag deployment

Although it's not recommended to restrict the types of tags deployed using Google Tag Manager, for various reasons it might be necessary to restrict the tag types deployed on a site. For instance, some site-owners might not want Google Tag Manager users to be able to add certain tags to their site for code stability or data collection reasons. As such, we've added a tag blacklist feature to Google Tag Manager that can be controlled at snippet installation.

To control which tags, triggers, and variables are allowed on a page, use the gtm.whitelist and/or gtm.blacklist keys in your data layer. These keys will override any and all configuration in the container. When properly blacklisted, tags, triggers, and variables will not fire even if they have been configured to fire in the Google Tag Manager UI.

The following example demonstrates how to initialize the data layer with both a whitelist and a blacklist. Both lists are optional, and you can use them separately or at the same time (as shown). Both lists must be of type Array, and the values in the list must be of type String:

dataLayer = [{
  'gtm.whitelist': ['<ID>', '<ID>', ...]
  'gtm.blacklist': ['<ID>', '<ID>', '<ID>', ...]

Each ID in the list corresponds to a specific tag, trigger, or variable type, or to a class of types. Classes represent groups of tags, triggers, and variables that have the same capabilities. For example, all tags that can send pixels to non-Google domains will have the class nonGooglePixels. Classes are useful for blocking capabilities in current and future tags, triggers, and variables.

It's important to understand the rules that govern whitelists and blacklists:

  1. Whitelists
    When a whitelist has been set, relevant tags, triggers, and variables will only execute if they are in the whitelist, either explicitly (by type ID), or implicitly (by having all of their classes in the list).
  2. Blacklists
    When a blacklist has been set, tags, triggers, and variables will only execute if they are not in the blacklist, either explicitly (by type ID), or implicitly (by having any of their classes in the list).
  3. Blacklists Override Whitelists
    When both have been set, blacklists take precedence. You can whitelist a class of tags and blacklist a specific tag in that class, but the reverse is not true. You cannot blacklist a class of tags and whitelist a specific tag in that class.
  4. Classes Have Relationships
    Some classes have relationships with other classes. For example, tags that can run non-Google scripts can (by definition) send non-Google pixels. For this reason, blocking nonGooglePixels will also automatically block nonGoogleScripts. All tags, triggers, and variables that belong to either group will be blocked.

The following table provides a listing of the available tags, triggers, and variables, their types, and the classes that they belong to:

Tag ID Classes
AB TASTY Generic Tag abtGeneric nonGoogleScripts
AdAdvisor Tag ta nonGoogleScripts
Adometry Tag adm google
AdRoll Smart Pixel Tag asp nonGoogleScripts
AdWords Conversion Tracking Tag awct google
AdWords Remarketing Tag sp google
Affiliate Window Conversion Tag awc nonGoogleScripts
Affiliate Window Journey Tag awj nonGoogleScripts
Bing Ads Universal Event Tracking baut nonGoogleScripts
Bizrate Insights Buyer Survey Solution bb nonGoogleScripts
Bizrate Insights Site Abandonment Survey Solution bsa nonGoogleScripts
ClickTale Standard Tracking Tag cts nonGoogleScripts
comScore Unified Digital Measurement Tag csm nonGoogleScripts
Crazy Egg Tag cegg nonGoogleScripts
Custom HTML Tag html customScripts
Custom Image Tag img customPixels
DoubleClick Floodlight Counter Tag flc  
DoubleClick Floodlight Sales Tag fls  
Dstillery Universal Pixel Tag m6d nonGooglePixels
Eulerian Analytics Tag ela customScripts
Google Analytics Tag ga google
Google Consumer Surveys Website Satisfaction gcs google
Google Optimize opt google
Google Trusted Stores Tag ts  
Hotjar Tracking Code hjtc nonGoogleScripts
Infinity Call Tracking Tag infinity nonGoogleScripts
Intent Media - Search Compare Ads sca nonGoogleScripts
K50 tracking tag k50Init nonGoogleScripts
LeadLab ll nonGoogleScripts
LinkedIn Tag bzi nonGoogleScripts
Marin Software Tag ms nonGoogleScripts
Mediaplex - IFRAME MCT Tag mpm nonGoogleIframes
Mediaplex - Standard IMG ROI Tag mpr nonGooglePixels
Message Mate messagemate nonGoogleScripts
Mouseflow Tag mf nonGoogleScripts
Neustar Pixel ta nonGoogleScripts
Nielsen DCR Static Lite Tag ndcr nonGoogleScripts
Nudge Content Analytics Tag nudge nonGoogleScripts
Optimise Conversion Tag omc nonGoogleScripts
Perfect Audience Pixel pa nonGoogleScripts
Personali Canvas pc nonGoogleScripts
Placed placedPixel nonGoogleScripts
Pulse Insights Voice of Customer Platform pijs nonGoogleScripts
Quantcast Audience Measurement qcm nonGoogleScripts
SaleCycle JavaScript Tag scjs customScripts
SaleCycle Pixel Tag scp customPixels
SearchForce JavaScript Tracking for Conversion Page sfc nonGoogleScripts
SearchForce JavaScript Tracking for Landing Page sfl nonGoogleScripts
SearchForce Redirection Tracking Tag sfr nonGooglePixels
Shareaholic shareaholic nonGoogleScripts
Survicate Widget svw nonGoogleScripts
Tradedoubler Lead Conversion Tag tdlc nonGooglePixels
Tradedoubler Sale Conversion Tag tdsc nonGooglePixels
Turn Conversion Tracking Tag tc nonGoogleScripts
Turn Data Collection Tag tdc nonGoogleScripts
Twitter Universal Website Tag twitter_website_tag nonGoogleScripts
Universal Analytics Tag ua google
Ve Interactive JavaScript Tag vei nonGoogleScripts
Ve Interactive Pixel veip nonGooglePixels
VisualDNA Conversion Tag vdc nonGoogleScripts
Xtremepush xpsh nonGoogleScripts
Yieldify yieldify nonGoogleScripts
Trigger ID Classes
Click Listener/Trigger cl google
Form Submit Listener/Trigger fsl  
History Listener/Trigger hl google
JavaScript Error Listener/Trigger jel google
Link Click Listener/Trigger lcl  
Timer Listener/Trigger tl google
Variable ID Classes
1st Party Cookie k  
Auto-Event Variable v google
Constant c google
Container Version Number ctv google
Custom Event e google
Custom JavaScript Variable jsm customScripts
Data Layer Variable v google
Debug Mode dbg google
DOM Element d google
HTTP Referrer f google
JavaScript Variable j google
Lookup Table smm google
Random Number r google
URL u google

The following table provides a listing of the available classes and their relationships to other classes. The Whitelisted Automatically column represents the list of classes that will be implicitly whitelisted when the class from that row is whitelisted. Likewise, the Blacklisted Automatically column represents the list of classes that will be implicitly blacklisted when the class from that row is blacklisted.

Class Description Whitelisted Automatically Blacklisted Automatically
customPixels Capable of sending pixels to URLs defined by the user. nonGooglePixels customScripts
customScripts Capable of running JavaScript code provided by the user. html
google Only capable of running Google hosted scripts and sending pixels to Google.    
html Alias for customScripts. Note that this is also the ID for the Custom HTML tag. This ensures that legacy users also get the benefits of the customScripts class. customScripts
nonGooglePixels Capable of sending pixels to non-Google domains.   customPixels
nonGoogleScripts Capable of running scripts not provided by Google. nonGooglePixels
nonGoogleIframes Capable of injecting iframes from non-Google domains. nonGooglePixels

Using a protocol-relative URL

By default, the Google Tag Manager container snippet always uses https to load containers (i.e., This helps protect your container from malicious parties and snooping, and in many cases, also improves performance.

If you'd prefer to load your Google Tag Manager containers in a protocol-relative manner, you may do so by adjusting the source URL protocol (highlighted below) in your container snippet to be // instead of https://.

<!-- Google Tag Manager -->
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
<!-- End Google Tag Manager -->
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="//"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

When using a protocol-relative URL, the container would be loaded using http on pages with an http:// URL; and, would be loaded using https on pages with an https:// URL.

Older versions of the Google Tag Manager container snippet always used a protocol-relative URL to load containers (i.e., // These older protocol-relative versions of the Google Tag Manager container snippet will continue to work without being updated.

While most of the tag templates in Google Tag Manager are also protocol relative, it's important to make sure that, when setting up custom tags to fire on secure pages, those tags are also either protocol relative or secure.