Google Tag Manager DataLayer Explained

Updated: June 4th, 2020. The Data layer is one of the key concepts in the world of Google Tag Manager. It ensures maximum flexibility, portability, and ease of implementation. Remember, GTM works best when deployed alongside the data layer (in fact, broken data layer = severely crippled GTM).

At first, Google Tag Manager Data Layer might seem like one of those mysterious concepts that no one really understands (by saying “no one” I mean non-developers). But if you stay focused, it’s a concept that’s definitely possible to grasp on. Understanding and leveraging the data layer is the key to unlocking GTM’s potential so be attentive.

Of course, it takes a while to understand how everything works, but once you get the idea, you’ll start putting puzzle pieces together. It just requires some time. The purpose of this blog post (and entire analyticsmania.com) is to educate non-developers, how they can master GTM, have quite extensive control of Google Analytics, Google Ads, or other implementation. And don’t limit yourself only to those two tools. You can connect GTM with A LOT of other online tools (but we’ll talk about that in other blog posts).

Before we continue: Data Layer is also explained in two of my GTM courses

If you prefer video material over lengthy blog posts, some of my Google Tag Manager courses go deeper into the Data Layer:

Intermediate Google Tag Manager course goes even deeper into the Data Layer (explaining even some technical aspects that are behind the DL). Also, the course teaches some nuances that are not covered in the blog post.

#1. How does Google tag manager Data Layer work?

Before we continue, a quick note: in this article, I will interchangeably use dataLayer and Data Layer. FYI – they are the same thing.

Technically speaking, a Google Tag Manager Data Layer is a JavaScript array that temporarily stores the information you need and then Google Tag Manager uses that data in tag/triggers/variables (later that data can be transferred to other tools, like Google Analytics).

In plain English, a Data Layer like a virtual layer of your website, which contains various data points and GTM uses them (Get it? That’s why it’s called data layer.). Regular visitors don’t see that because it is not something openly displayed. But if you know how, it’s fairly simple to view what’s in it.

Imagine that Data Layer is like a bucket. That bucket can contain little ping pong balls, every ball contains some information, e.g. a user ID, the information about the clicked element, purchase ID, page category, etc. Google Tag Manager heavily relies on what is within that bucket. If click information is added to that bucket, GTM can use it as a triggering condition. Or maybe it can take the Form ID (of the form that was just submitted) and send it further to GA.

Anyone/anything can put those “data balls” in the Data Layer. It might be a 3rd party plugin, some custom code created by your developer, even Google Tag Manager itself can push the information from the Data Layer.

So if for example, you want to track purchase, one of the possible solutions could be to ask a developer to push the order information to the Data Layer once that order/purchase was successfully completed. The information that a developer could push to the Data Layer is (but not limited to):

In many cases (at least from my experience), Data Layer is not commonly known among developers. This is not some standard thing that all websites have. Usually, it is tied to Tag Management tools, like Google Tag Manager. Therefore, if you just tell a developer “add product information to the Data Layer”, there’s a high chance that a developer will have no clue what you’re talking about.

That’s why my philosophy is that digital marketers/analysts should know/understand what Data Layer is and how does it work. This will make communication between you and devs much more fluent.

In further chapters of this blog post, we’ll take a closer look at what Data Layer in Google Tag Manager, how to configure it (if you need that), how to use in your tag management, etc.).

#2. How to implement Data Layer

Once in a while, I see questions online that ask how to create a data layer. If you don’t plan to use any custom data in your tag manager (e.g. user ID, product ID, etc.), you don’t need to do anything additional on your website. Once you place the GTM container’s JavaScript Snippet in your website’s source code and a visitor lands on your site, Data Layer is automatically initiated by Google Tag Manager’s snippet.

You don’t need to add anything additionally. However, if you indeed want to use some custom information, continue reading. I’ll show you how to create/implement a data layer. Just beware that usually, this is the developer’s responsibility.

In fact, it’s just a half of the code. There’s also a noscript part that exists. But since our main topic today is Data Layer, let’s focus only on the <script> part.

The aforementioned <script> GTM code will create a Data Layer on a page. You can even see the dataLayer mentioned in the code. If the Data Layer already exists on a page, this container snippet will adapt to it and will continue using the existing layer.

#2.1. Data Layer declaration vs dataLayer.push

Now let’s talk about actually putting data into the Data Layer. Because by default, if it is created, Data Layer is just an empty bucket. The whole magic starts when someone/something starts putting there useful data/info that later can be used in Google Tag Manager.

There are two ways, how to add data to the Data Layer:

By adding a dataLayer snippet above the GTM container snippet. This is called “Data Layer declaration”

Or by pushing data with dataLayer.push method.

What’s the difference, you ask?

#2.1.1. Data Layer declaration

Thefirst method is very limited and can work only if you add the Data Layer code snippet ABOVE the Google Tag Manager container code. I never use it. But for the sake of science, let’s take a look.

Let’s say that you want to send the page category as a custom dimension to Google Analytics. This is the Data Layer code that must be added above the GTM container:

JavaScript

1

2

3

4

5

6

7

8

9

<script>

dataLayer=[{

'pageCategory':'google-tag-manager-tips'//this value should be replaced with some actual page category

}];

</script>

<!--Google Tag Manager-->

...

<!--EndGoogle Tag Manager-->

If you’re not comfortable with touching the website’s code, a developer should do that (and in most cases, he/she will, in fact, have to do it. Unless you have installed some GTM plugin to your website).

So when the page loads, the Data Layer code will create a Data Layer and it will contain one data point, pageCategory. After that, the Google Tag Manager container code is loaded and you can then use that pageCategory in your tag management. This can be done with the help of the Data Layer Variable.

Another example – transaction or product data. Let’s say, you want to implement Google Analytics Ecommerce Tracking. In this case, your developers should add a dataLayer snippet above the Google Tag Manager container with the following parameters: transactionID, transactionTotal, etc. (you can read the full guide here). Once this information is added to the Data Layer, Google Tag Manager can fetch it and transfer it to Google Analytics.

But there are several reasons why I always advise against using this method.

Sometimes Google Tag Manager beginners confuse which method to use when. I mean, should they use the dataLayer = [] or should they adopt the dataLayer.push (that I will explain next)? It’s much easier to remember and use just one method (see chapter #2.1.2).

All in all, GTM specialists don’t recommend using the Data Layer declaration method (dataLayer = [];). And it’s really weird that Data Layer declaration is still mentioned in the official Google Tag Manager documentation.

#2.1.2. dataLayer.push

The second method (dataLayer.push) is another way how you can add data to the Data Layer. Here are a few examples:

You have a newsletter signup form (which cannot be easily tracked with usual form tracking methods). You should ask your website developer to push a Data Layer event once a new subscriber has entered his/her email on your website. The code of this event should look like this:

JavaScript

1

2

3

4

window.dataLayer=window.dataLayer||[];

window.dataLayer.push({

'event':'new_subscriber'

});

If you wish you can ask your developer for additional information (for example, form location (because you might have more than one form on the same page)).

JavaScript

1

2

3

4

5

window.dataLayer=window.dataLayer||[];

window.dataLayer.push({

'formLocation':‘footer’,

'event':'new_subscriber'

});

When a visitor adds a product to his/her cart, a Data Layer event (containing the product’s information) could be fired.

JavaScript

1

2

3

4

5

6

7

8

9

10

window.dataLayer=window.dataLayer||[];

window.dataLayer.push({

'event':'addToCart',

'products':[{

'id':'123',

'name':'Black T-shirt',

'brand':'balenciaga',

'quantity':1

}]

});

Why is this method better than the first one? It can be placed anywhere in the code (above and below Google Tag Manager container) and it will not break the event tracking within GTM. That is possible thanks to a window.dataLayer = window.dataLayer || []; line.

Also, with it, you can push events to the Data Layer that can be later used as triggering conditions. For example, if someone submits a form, a developer can activate the following code:

JavaScript

1

2

3

4

window.dataLayer=window.dataLayer||[];

window.dataLayer.push({

'event':'formSubmission'

});

Since the code above contains the event key, this dataLayer.push can be used as a triggering condition in Google Tag Manager. Read more about the Custom Event Trigger.

#3. How GTM uses Data Layer’s information/content?

Google Tag Manager uses the information (stored in the data layer) in two ways:

To use certain pieces of data (in the shape of variables). I will explain it in chapter #3.1.

To decide when to fire a tag (in the shape of triggers because you can use Data Layer events as triggers). This part will be explained in chapter #5.

We can achieve the first part with the help of the Data Layer Variable and the 2nd one with triggers.

#3.1. Using the Data Layer Variable

Imagine, there are several authors in this blog:

Me (Julius Fedorovicius)

John Doe

Jack Torrance

etc.

I want to find out which authors write the most engaging content and then segment sessions in Google Analytics. I am using a DurecellTomi WordPress plugin which stores post author name in the Data Layer. If you don’t have WP, ask a developer to add additional data points to the Data Layer. The snippet could look like this:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

<head>

<script>

window.dataLayer=window.dataLayer||[];

window.dataLayer.push[{

pagePostAuthor:'Julius Fedorovicius'

}];

</script>

<!--Google Tag Manager-->

...

<!--EndGoogle Tag Manager-->

</head>

By default, Google Tag Manager does not recognize custom data in the Data Layer thus you cannot use it as variables. Unless you employ the Data Layer Variable. In order to create a variable, you’ll need to specify the Data Layer key of which value you want to retrieve. When the Variable is resolved, it will return whatever was most recently pushed into the key. Easy as that!

If I wanted to fetch pagePostAuthor value, I’d just need to set the pagePostAuthor key in variable settings.

Say, you want to send a Google Analytics event when someone leaves a comment. With every event, you also want to push the full name of the article’s author. This way you’ll see which authors drive the highest reader engagement.

In this example, I will not go into detail on how to create a tag, I will only demonstrate how to pull the author data from the Data Layer and turn it into a variable (within Google Tag Manager).

In GTM account, you should go to Variables and create a new one with the following settings (dlv stands for data layer variable):

It’s important to remember that the “Data Layer Variable Name” field is case sensitive, meaning that only pagePostAuthor will work (not pagepostauthor or Pagepostauthor, etc.).

That’s it! Save this variable, refresh Preview and Debug (P&D) mode, and refresh the website you’re working on. You should then see your newly created variable in the Variables tab of Preview & Debug console.

It’s completely possible (and quite common) to have a bit more difficult data structures stored in the Data Layer, for example:

#4. Example No.1: using data from the Data Layer in GTM and GA

Let’s imagine that I have a website and all registered users are split into two groups:

Paying customers.

Users with a Free plan.

I want to segment these users and all their events/pageviews in Google analytics by their pricing plan. I have already asked my developers to add static information to the Data Layer when the page loads. The Data Layer snippet looks like this:

It’s very important that the Data Layer snippet is placed above Google Tag Manager’s container code in your website’s code. First, you need to send data to Data Layer, then this data is fetched by Google Tag Manager. If the snippet is placed after the GTM container code, Data Layer’s data won’t be fetched by Google Tag Manager.

#4.1. Create a Data Layer Variable in Google Tag Manager

First, you need to create a Data Layer variable in GTM’s account. This way Tag Manager will recognize the parameter. Open Variables > Scroll down to User-defined variables and click New.

#4.2. Enable Preview and Debug mode in Google Tag Manager

When Debug mode is enabled, you should see an orange notification bar:

Go to your website (or refresh a page if you’re already on it). A Google Tag Manager debug console should appear at the bottom of the screen.

Click Variables and look for pricingPlan. Check its value. If pricingPlan is undefined, you should double-check whether you have entered a correct Data Layer Variable name in GTM’s admin panel (by the way, it’s case-sensitive). In my case, pricingPlan variable is defined correctly, because I get the value Free.

#4.3. Create a custom dimension in Google Analytics

pricingPlan is a custom parameter that was defined by you (or your developer) so Google Analytics will not catch it by default. You need to create a custom dimension pricingPlan in order to inform Google Analytics about this new parameter.

Login to your Google Analytics account.

Open your website’s account and then click Admin. You should see something like this.

If you already had a GA Pageview tag in your GTM container, there’s no need to create a new one. Just use the existing one because the most important part (where you need to enter the Custom Dimension) is hiding within the GA Settings Variable.

Since we want to pass this dimension with every Google Analytics hit, go to Variables (in your GTM container), find the Google Analytics Settings Variable, and open it. Go to More Settings > Custom Dimensions and enter the Custom Dimension number you saw in the GA interface (see chapter #4.3) and then enter the Data Layer Variable you created in chapter #4.1.

Save the variable. After you complete these steps, you will start sending user’s pricing plan name with every Google Analytics hit (pageview, event, etc.)

That’s how you can transfer additional data from Google Tag Manager Data Layer to Google Analytics.

#5. Using Data Layer in triggering

The entire concept of the event tracking in Google Tag Manager is based on the Data Layer. If you want to capture interaction and fire a particular tag (e.g. Google Ads conversion tag), the interaction first must be pushed to the Data Layer. Only then Google Tag Manager can catch it and use it as a triggering condition. This applies to both standard (e.g. links, forms) and custom event (e.g. purchase, login) tracking.

In this chapter, I will focus on custom event tracking (if you want to learn more about standard event tracking in Google Tag Manager, check these articles for inspiration: click tracking, using history change trigger).

Back to custom event tracking. If for example, you want to track events when users successfully register on your website and then send such events to Google Analytics, here is one of the possible solutions. You can ask a developer to activate the following code every time a user signs up.

JavaScript

1

2

3

4

window.dataLayer=window.dataLayer||[];

window.dataLayer.push({

'event':'registrationComplete'

});

The key part here is the “event” key. It is necessary if you want to fire tags every time a certain interaction occurs on a page. Also, let’s say that we want to also track pricing plans of the signup (because users can sign up to free or to a premium plan). That’s why we could update the code and add an additional piece of information, plan.

JavaScript

1

2

3

4

5

window.dataLayer=window.dataLayer||[];

window.dataLayer.push({

'event':'registrationComplete',

'plan':'Premium'

});

Once a developer confirms that the above code is implemented, it’s time for you to check whether that’s true.

Enable the Preview and Debug mode in your Google Tag Manager container, register on your website (just like a regular user would do that) and take a look at the debug console. First of all, the “registrationComplete” event must appear in the event stream (left side of the console).

So far so good. Now, let’s check whether the developer passed an additional key you asked for, plan. In Preview and Debug mode, click the registrationCompleted event and go to the Data Layer tab. As you can see from the screenshot below, the developer did a good job as I can see the plan key in the Data Layer.

Please ignore the registrationCountry key in the screenshot above. That’s from another example.

If unfortunately, registrationComplete is missing, contact the developer and tell him/her to properly follow your instructions. Also, this guide is quite useful for developers to better understand how to work with the Data Layer.

#5.1. Custom Event Trigger

So once you reach the point where a developer pushes the interaction data (together with the event key) to the Data Layer, the next step is to catch that .push and turn it into a triggering condition. By default, Google Tag Manager does not care about the pushed events that are happening in the Data Layer (I mean that no tags will be fired unless you specifically instruct GTM to do so).

Since we are interested in tracking successful registrations, we need to tell GTM that registrationComplete events are important to us and we wish to use them as triggers.

In Google Tag Manager, go to Triggers and hit the New button. Choose Custom Event as trigger type and enter the following settings (event name is case-sensitive):

Done. You have just created a Google Tag Manager Custom Event Trigger.

How can you use that in the event tracking? Let’s take a look at the example.

We asked a developer to implement the dataLayer.push code when a user successfully signs up. The value of the event key is registrationComplete

A developer has implemented our request and we checked that in the Preview and Debug mode (Data Layer tab)

We created a Custom Event trigger registrationComplete

So what’s next? Let’s send an event to Google Analytics every time a registrationComplete event is pushed to the Data Layer. Additionally, we’ll pass the value of the plan (pricing plan to which a user signed up).

#6.1. Data Layer Variable

We entered “plan” because that’s the name of the key in the Data Layer (when the registrationComplete event is pushed to the DL).

#6.2. Universal Analytics Event Tag

Now, let’s create a GA event tag that will send the event data to Google Analytics every time a registrationComplete is pushed to the Data Layer). In GTM, go to Tags > New > Universal Analytics. Enter the following settings:

If you’re not familiar with what is Google Analytics Settings Variable, read this guide. The key things here:

Track type: Event. This means that we will send events about successful registrations to GA

Event Action: {{dlv – plan}}. Whenever a registration is completed, Google Tag Manager will take the value of the plan key in the Data Layer and will send it to GA (together with a GA event). That way, you will be able to slice the registrationComplete numbers by the pricing plan.

Assign the trigger, the previously created Custom Event Trigger registrationComplete.

#6.3. Let’s test

Save the GA tag, refresh the preview and debug mode, go to your website (+ refresh it), and complete the registration once again. Once you do that, the registrationComplete Data Layer event will appear in the preview mode. Click it and check whether your GA Event tag is fired.

If the tag has not fired, check whether you have entered the proper event name in the trigger settings. It is super important that you enter the event name precisely as it is displayed in the Data Layer (case sensitive).

If the tag has indeed fired, head over to your GA Real-time reports > Events. Check whether you also see the event there.

If you are still struggling with testing your tags in GTM, read this blog post with 30+ debugging tips.

#6.4. Configure a goal in GA

The final step. Let’s turn the “registration complete” GA event into a GA goal. In your Google Analytics property, go to Admin and in the “View” column of your GA property go to Goals.

With this kind of setup, whenever an event (with event category “registration complete”) is tracked by GA, it a goal completion will also be counted. Just remember that a goal completion applies to the entire session. This means that 5 registrations of the same user during the same session will be counted just as a single goal.

You can also test goals in GA real-time reports. So whenever you save this goal, complete another registration on your website, go to real-time reports > Conversions, and check whether it was displayed there.

Conclusion

If you read the entire article, well done (and thank you)! If you skipped to the summary without reading the entire thing, then I suggest you bookmarking this page so you can come back later. This is not a topic that can be covered by a quick 500-words blog post.

Google Tag Manager Data Layer is a fundamental part of GTM. Without it, event tracking would simply not work. It enables us to capture interactions (+ use them as triggers) and get some additional data about the interaction or the context (+ use it with the help of Data Layer Variables). If you feel that this concept is difficult to master, you’re not alone. It’s perfectly fine to be confused at the beginning. I suggest starting with a few events and then scale up. You’ll become better with time.

17 COMMENTS

Custom Dimension: User Scope
GTM: Passed a custom dimension along with a page view. Also verified the Index Number
Results: Able to see custom dimension to be populated with event trigger and page-view in GTM Preview Mode.

Able to get custom dimension passed in GA via events but not page view?

What I did: I checked Debug Console Mode. I saw that with Page view, the command is being ignored or undefined.

Hey,
Maybe that variable you use for the Custom Dimension is not available on Pageview Trigger? Maybe you should use DOM Ready or Window Loaded triggers, instead? Or maybe you could ask a developer to push that variable to the data layer sooner?

If you want, I can take a look at your implementation. Share a Preview link with me (also, I need this info:
- URL of a website you're working one.
- Which variable are you trying to send as a custom variable.
- It would also help if you could share the access to that GTM container (with "read" permissions).

We can keep this private, you are free to send the information to julius[at] analyticsmania.com

Is there any kind of "lag" before your custom dimensions appear in Google Analytics?

I have a site using the GTM tracking code (and some custom dataLayer variables) but the dimensions in GA are always showing as blank/empty.

I am *not* using any GA tracking snippet (just GTM, with a Google Analytics Tag setup, with the custom variables added as indexed dimensions). I created the Custom Dimensions in GA (using the same Index values).

I have checked the GTM Debugger that all of the values are being passed to GA (with the correct dimension indexes) and I can see "activity" in GA (so the GTM > GA passthrough is clearly working).

Should I have to wait (24 hrs?) before the Dimensions are populated / become active? Or does this suggest that for some reason it isn't working?

Hey, even though we figured this out on Twitter, I'll just reply so that other readers could benefit. From my experience, custom dimensions usually appear within several hours but in Martin's case, it took ~24 hours.

I cannot explain a particular reason for such delay, but in the end, the data found its way to the reports. The best way to check if custom dimensions are properly passed is to use GA Debugger Chrome Extension.

Very good article, thank you. Is the dataLayer session-based? If I make changes to tags in my container, what is the affect on users in a current session? Would they not yet propagate? Would the next page load or screen refresh load them?

Hi Julius, thanks for the awesome article!
I am about to migrate all my hardcoded tags to GTM and find myself a bit confused with the google ads tags already implemented. I already implemented the GTM container and the image tag, and created the google ads remarketing and conversion tags in it, without publishing.
But currently on the website I have this datalayer, which is related to my google ads global site tag, that is being detected by the GTM platform, while I'm in the preview and debug mode.
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

gtag('config', 'AW-9.......6');
</script>

After it I have the event snippet for dynamic remarkting, which pulls the variables I need for that.

The product info it pulls is visible in the gtm debug tool. My question is should I leave it like this or I'd rather create a new datalayer with all the variables I need to set, as I will have multiple other tags to incapsulate in GTM, and remove all the hardcoded tags I cureently have?

I understand "Data Layer" script should be placed before GTM code. However, GTM code is part of template for most of content manager system (such as Drupal or WordPress). How could I implement this data layer script in this type of implementation dynamically?