
December 1, 2022
Quick Guide: dataLayer.push with examples
Updated: December 1st, 2022.
This quick guide was born after getting multiple questions from Google Tag Manager beginners/intermediate users: when should I use dataLayer.push() and when Data Layer declaration (dataLayer = [{}])?
The reason why this question is raised at all is that Google Tag Manager’s official documentation is a bit misleading in some parts. Continue reading and I’ll show you where.
dataLayer.push?
So what is dataLayer.push in the first place? It’s a code that enables one to add/update data that is stored in the Data Layer, for example:
<script> window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'new_subscriber', 'formLocation': 'footer' }); </script>
But what does it mean? Well, let’s have a quick refresher on what the Data Layer is. P.S. If (after reading this blog post) the topic still looks confusing, consider enrolling in my Google Tag Manager course for Beginners where I explain what dataLayer.push is in much greater detail.
What is Data Layer?
Data Layer is one of the main Google Tag Manager concepts, which ensures maximum flexibility, portability, and ease of implementation. Without it, GTM would not work. It is what keeps your tag management running properly. It is the key to unlocking Google Tag Manager’s potential.
I’ve already covered Data Layer in my other guide, Complete Data Layer Guide, but to save you some time, here’s the TL;DR version.
Simply put, a Data Layer is like a bucket that stores certain information. It’s a central place (virtual layer) of a website where you, your developers, or 3rd-party-tools tools can temporarily store data (about user, page content, etc.). From there, Google Tag Manager reads that information, uses it in tags/triggers/variables, or sends it further to other tools, Google Analytics, Google Adwords, Facebook/Meta, you name it.
Once you place the Google Tag Manager container’s JavaScript Snippet in your website’s source code, the Data Layer is automatically created. You don’t have to add anything more. However, if you want some more custom data, like userID, Product price, Order total, etc. (and use that in Google Tag Manager), additional configurations will be needed. And that’s where dataLayer.push plays the role.
Store/update data in the data layer
There are two ways how the data can be pushed to the Data Layer. Actually, there is only one that you should be using, but for the sake of knowledge, I’ll mention both:
- By adding a Data Layer snippet above the Google Tag Manager container snippet ( dataLayer = [] ). This method is also mentioned in the official GTM documentation. It’s called Data Layer declaration.
- Or by pushing data with dataLayer.push method.
What’s the difference, you ask?
Data Layer declaration (not recommended)
This method of inserting data into the Data Layer could be used if you want to add any data right when the page loads, for example, user ID. As a result, you could utilize the user ID variable in the All Pages trigger.
In this case, your developers should add a Data Layer snippet above (this is important!) GTM tracking container with the actual user ID. Once this information is added to Data Layer, you can start working with it in Google Tag Manager. Here’s a code example:
<script> dataLayer = [{ 'userID': '123456' }]; </script> <!-- Google Tag Manager --> // this is where your Google Tag Manager container snippet should be placed <!-- End Google Tag Manager -->
Although this method is mentioned in the official Google Tag Manager documentation, you should not use it. Why?
If a developer places this snippet below the Google Tag Manager container, it will break things. One of the consequences will be broken All Pages trigger. Also, Google Tag Manager will not be able to track various website interactions, such as clicks, form submissions, etc.
Even Google’s documentation is inconsistent here. For example, in the Standard Ecommerce (for GTM) documentation (for Universal Analytics, a.k.a. GA3), they were offering another way to place the data, and it’s dataLayer.push (which is explained in the next paragraph).
Simo Ahava also recommends using only dataLayer.push, and never dataLayer = [].
Why? Because by using the syntax dataLayer = [], you are resetting the dataLayer variable to a new Array (read: you clear the bucket), thus overwriting anything that was in it before (such as Google Tag Manager’s customizations needed for tracking to work). Since you overwrite the dataLayer, it no longer works properly with Google Tag Manager, and the typical symptom is that GTM’s triggers don’t work anymore, either.
dataLayer.push (recommended)
The second method of how to put data in the Data Layer is dataLayer.push, which is recommended and should be your only choice of yours. Regardless of where you place it (below or above the Google Tag Manager container), dataLayer.push will work properly. Here are a few examples:
- You have a newsletter signup form (which cannot be easily tracked with a default GTM’s form listener), so you decided to ask a website developer to fire a Data Layer event once a new subscriber has successfully entered his/her email on your website:
<script> window.dataLayer = window.dataLayer || []; window.dataLayer.push({'event': 'new_subscriber'}); </script>
If you wish you can ask your developer for additional information (e.g. form location (because you might have more than one form on the same page)).
<script> window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'formLocation': 'footer', 'event': 'new_subscriber' }); </script>
- When a visitor adds a product to his/her cart, a Data Layer event (containing the product’s information) could be fired.
One more thing. Suppose you compare code snippets in this blog post to those explained in the official Google Tag Manager documentation for developers. In that case, you’ll notice that my code examples also have the “window” prefix (instead of dataLayer.push, I use window.dataLayer.push). After using Google Tag Manager for a while and seeing other professionals talking, I’ve noticed that they recommend one more thing (as a rule of thumb): adding a prefix window to the dataLayer.push. As a result, the final dataLayer.push code snippet could look like this:
<script> window.dataLayer.push({ 'formLocation': 'footer', 'event': 'new_subscriber' }); </script>
By the way, the dataLayer name is case-sensitive. This means that only the letter L must be uppercase:
- DataLayer.push will not work (because D is uppercase)
- datalayer.push will also not work (all letters are lowercase, although L should have been uppercase).

More dataLayer.push examples
Previously mentioned dataLayer.push examples are pretty basic but if you need, you can also push data as objects or arrays. A good example would be a Universal Analytics Standard E-commerce transaction code:
<script> window.dataLayer = window.dataLayer || []; dataLayer.push({ 'transactionProducts': [{ 'sku': 'DD44', 'name': 'T-Shirt', 'category': 'Apparel', 'price': 11.99, 'quantity': 1 },{ 'sku': 'AA1243544', 'name': 'Socks', 'category': 'Apparel', 'price': 9.99, 'quantity': 2 }] }); </script>
What happened here is that with one dataLayer.push we also pushed an array (transactionsProducts) containing two objects. Each object contains the same set of keys (sku, name, category, price, quantity), but their values differ. And that’s logical because two different products will usually have different characteristics.
Enhanced E-commerce Data Layer pushes also use a bit more difficult data structures:
<script> window.dataLayer.push({ 'ecommerce': { 'promoView': { 'promotions': [ { 'id': 'JUNE_PROMO13', // ID or Name is required. 'name': 'June Sale', 'creative': 'banner1', 'position': 'slot1' }, { 'id': 'FREE_SHIP13', 'name': 'Free Shipping Promo', 'creative': 'skyscraper1', 'position': 'slot2' }] } } }); </script>
With this dataLayer.push, we added an ecommerce object which contains the promoView object, which contains a promotions array that contains two objects of two promotions displayed on a page. Each promotion has four keys, id, name, creative, and position.
OK, now what?
After the data/events are pushed into the Data Layer, it’s time to start working with them:
- Do you want to use a Data Layer event as a trigger? Do it with the Custom Event Trigger.
- Do you wish to access some data (e.g. userID) and insert it in the Universal Analytics tag? Create a Data Layer Variable for each data point you want to access from the Data Layer.
dataLayer.push: Final Words
DataLayer.push is a way for you/developers/3rd-party-plugins to pass some useful data to the Data Layer. And from there, you can “play with it” in Google Tag Manager and use it in your tag management.
dataLayer.push should be the only way how you should add data. Even though Google Tag Manager’s official documentation still mentions/recommends using a regular Data Layer declaration (dataLayer = [{}]), you should not fall for that. Remember, always push to the dataLayer.
53 COMMENTS
If I push an event to the dataLayer before GTM is loaded in what order do things happen once GTM loads? Say I have GA set for 'all pages' and another GA set for this specific event... would all pages always 'run' before the event trigger or because the event was pushed before GTM loads it would happen immediately?
Tag Sequencing makes it seem like that tag would be fired 'again' or in addition to the tag you add it. If I have GA set to fire once per event on all pages then on another tag choose GA as the setup tag (fire before)... it seems like GA would be fired twice or just once if it already had - right? Isn't ordering of the tags what Tag Firing Priority is for?
Hey, if you push event + data before the GTM snippet, then that event will occur before the Pageview event.
As for your second question, a tag might fire once, it might fire twice. It depends.
Imagine there are 2 tags:
- Event tag
- Some other tag.
If:
- "Some other tag" fires on All pages
- AND you also set Event tag as its setup tag
- AND also Event tag is set to fire on All pages, then Event tag will fire only once because everything is happening within the boundaries of "Pageview" event.
If you set event tag to fire on DOM Ready, then Event tag will fire twice per page:
- On All pages
- And on DOM Ready
Hi Julius can you help me with setup of datalayer for my opencart e-commerce store
Hey, I recommend reading the following guides for you to better understand how to implement Ecommerce tracking:
- Standard Ecommerce tracking https://www.analyticsmania.com/post/ecommerce-tracking-with-google-tag-manager/
- Enhanced Ecommerce tracking https://www.simoahava.com/analytics/enhanced-ecommerce-guide-for-google-tag-manager/
What if you want to preload some data, in the meaning that load some data before someone has the 1st contact with our website? (1st pv)
Is it better to already load the page with the preloaded dataLayer or to load the page normally and perform a push?
It depends on how accurate do you want your data to be. The sooner you'll preload dataLayer with some data points (even on the first pv), the better.
If you push some data later, it won't be available on Page View event thus some tags will not access it and you'll miss it in, say, Google Analytics (of course, this one depends on a scope)
So you're saying I have to declare this window.dataLayer = window.dataLayer || []; even when I push an event right?
window.dataLayer.push({
'event': 'Button clicked'
});
It's enough to have this code added once but "just in case" I fire it before every dataLayer.push. this code isn't heavy and does not have negative impact.
Hi Julius,
Thanks for sharing all the great posts. These are really helpful for people like me to get an understanding. We are working on a task to track user login and account creation on our website; however, we handle login and account creation process through Centralized account / sub-domain. i.e. if I try to login from a landing page --> it takes to the sub-domain --> after authentication, user returns back to the landing page.
Looking for your suggestion, what will be the best approach to track login using data layer in multi domain cases.
Thanks!
Tracking visitors across the main domain and its subdomains is not a "multi-domain tracking". It's still happening on the same domain. Just keep the "cookieDomain: auto" in your GA Settings Variable and you're good to go.
Hi,
We use Oracle Infinity as Analytics tool. I have added Oracle Infinity tag to GTM and data is being correctly sent to tool for standard variables.
We have custom variables we need added. I have added a Custom HTML Tag in GTM to trigger on a button click which is clicked after a user makes specific selections. Developer added code to site to push data(user selections) to dataLayer.
When I test, GTM has current dataLayer values but what is sent when tag fires( dcs call ) is always previous data (previous user selections).
Is triggering tag on button click wrong solution?
here is code:
//Oracle Infinity UDO testing
dataLayer.push({'o_filteraction':'AdvancedSearch'});
dataLayer.push({'o_filtertype':checkTypes.join(';')});
dataLayer.push({'o_filterfeature':checkFeatures.join(';')});
dataLayer.push({'o_filtercategory':checkCategory.join(';')});
dataLayer.push({'o_filteraccommodation':checkAccommodation.join(';')});
dataLayer.push({'o_filterlocation':checkLocation.join(';')});
dataLayer.push({'o_filterdates':checkDates.join(';')});
dataLayer.push({'o_filterprice':checkPrice.join(';')});
Hi, if you want to use the latest data from the data layer in your tags, your dataLayer.push codes need to have 'event' key).
E.g.
dataLayer.push({
'event' : 'some_event_name', //this could be the same for all the pushes that you listed in your comment
'o_filteraction':'AdvancedSearch'
});
Then create a custom event trigger that will be activated on "some_event_name". That way you will get the latest data in your tags.
Read more about the custom event trigger - https://www.analyticsmania.com/post/google-tag-manager-custom-event-trigger/
Hey Julio, alright? I have some custom variables that are used for standard GA events ... For example:
window.dataLayer.push ({
'event': 'dataevent',
'mycategory': "Group",
'myaction': "Clik",
'mylabel': "button x"
});
Now in a single push I need to send multiple events at once.
Is that what I should do?
window.dataLayer.push({
'event': 'dataevent',
'mycategory': {[“Grupo”]}, // this is the string unique for all
'myaction': {[”Click one, Click two”]}, // these change
'mylabel': {[“button x, buton y”]} // these change
});
Thank you for your help
You should better send separate events, not everything at once. This means separating dataLayer.push as well. Category, action and label accept only strings, not arrays or objects.
Hi Julius,
I'm currently trying to push data into squarespace Post-submit HTML. Due to the event is gtm.submit, and the formID is unknown (From google tag manager, variable tab can be seen). I have addded the following code to push the formID. So it can be added into Google tag manager to track form.
<script>
console.log('THIS IS FIRING');
dataLayer.push({
'event': 'formSubmission',
'formType': 'contactUs',
'formPosition': 'contactPage',
'formID': 'contact001'
})
</script>
I'm in a lost of why it can't push the data in. What should I do?
Thanks for your help
Do you see the console.log in the console? If yes, then here are some fixes:
- semicolon is missing after the dataLayer.push.
- also, I've added an additional line in the beginning to initiate the dataLayer (because maybe at that moment it is still not created by the GTM).
Here's the code:
<script>
console.log('THIS IS FIRING');
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'event': 'formSubmission',
'formType': 'contactUs',
'formPosition': 'contactPage',
'formID': 'contact001'
});
</script>
If you don't see the console.log in the console, then maybe squarespace does not allow custom js? I don't know its limitations.
Thanks for the reply, I can't see the console.log in the console. maybe I should delete it instead?
Cause when I choose to click on a button as 1 submission it works. but dropdown menu requires a formID and i can't locate it. That is why I uses JS script to add-in.
According to what I know, squarespace allow custom js. That's why I have such a doubt that why it cant be fired.
Thanks for your help :)
If you cannot see the console.log, this means that the entire code is not activated (including the dataLayer.push). I would contact squarespace suport, maybe they will give you some hints (because this looks like something squarespace-specific).
For subscription based affiliate tracking (ex. I want to track an affiliate that generated usd5 every month.) The trigger only fires once from the client. Is there a way to fire the trigger from the server (from a callback to the payment gateway) instead?
If you want to send the data from the backend when the user is not logged in, then GTM won't help you. A developer must directly send the data to GA via a thing called Measurement protocol.
Hi Julius and others.
The website I work for has a search field and the client needs the list of search queries, since the dev's do ajax call, we don't have track on the searches.
I tried the below-
<script>window.dataLayer = window.dataLayer || [];window.dataLayer.push({'searchQuery': 'value'});</script>
and created an event, whenever earch button is clicked, value from searchQuery will be sent to GA, but since the variable will be null, I cant track the searches correctly.
Now, how can I delay the tag and wait for the searchQuery variable to get the search value and then send the value to GA?
Thanks in Advance,
Thomas
You can use the following code:
<script>window.dataLayer = window.dataLayer ||[];
window.dataLayer.push({
'searchQuery': 'value',
'event' : 'searchComplete'
});</script>
Then create a custom event trigger that activates on "searchComplete" event and only then fire the tag.
Hi Julius,
Is there a way to use the info in a Data Layer variable set via website1, in a different portal(website2)?
The task: the user perform an action in website1 and as a result we set a value in a variable ("true"). We need to read that value in website2 before executing some code (via a GTM tag).
We can not use cookies for this, as apparently you can not (not allowed) to access cookies set in other websites.
Many thanks
You could try passing the variable via URL. When the visitor goes from website1 to website2, the URL should be decorated with the value of the variable.
Hey Julius
Great article, but I have a question too:
How can I push a parent class into the data layer?
nav class
ul class
li class
a class
In gtm.linkclick events I got the a class, but I need the nav class as well, to distinguish between different navigations.
any idea?
Hey, use this https://www.simoahava.com/analytics/capturing-the-correct-element-in-google-tag-manager/
Thanks for article Julius.
What if I wanted to pass a variable via a URL. For instance, for a specific URL I wanted to display a list of products (associated with article). The data would come from database, Google sheets, etc.
Any suggestions would be greatly appreciated.
For that, you can use URL variable in GTM, also Custom Javascript variable is useful if you know how to code.
Hi Julius,
Need a small help. I have created a custom event. The label has a variable which captures the search (a section search not internal site search) phrases. Used DLV type for creating a variable to capture the value.
Event is also firing perfectly. In preview mode, under tags, the label value is firing as undefined. However, under datalayer tab, I can see the value passing to DLV variable. But this data is not being pushed to analytics. Here is the code placed on website
window.dataLayer = window.dataLayer || [];
window.dataLayer.push
({
'event': 'Ideas Search'
‘dlv_ideas_search_term’: ‘value’
})
Kindly assist.
Regards,
Swapna
This means that your data layer variable is incorrect. Check the grammar error.
Swapna, I had the same problem. We had to change the trigger to Window Loaded rather than Page View because PV fired too early to actually capture the data.
Once we changed to WL, the data started making it into Analytics.
Good luck!
This will work is dataLayer.push occurs very late. If dataLayer.push was above the GTM container (in the code), then All Pages trigger would work well.
I have one question regarding the push function. If I want to push my custom event before any gtm.start or load or error. How can I achieve that?
Place your code above GTM container.
This makes no sense.
"Although this method is mentioned in the official Google Tag Manager documentation, you should not use it. Why?"
You never actually explain this statement, you just babble on about what is written on the GA site.
Please explain why this is bad? Especially since this (the snippet of code on your and the official GA site) will be at a page level
The explanation is literally in the next paragraphs after what you quoted.
dataLayer.push ( { "event": "newsletter_unsubscribe"} )
Can we use above one without quote
dataLayer.push ( { event: newsletter_unsubscribe} )
No. Unless that newsletter_unsubscribe refers to some variable in that function.
Hi Julius,
I have read many of your tutorials but stuck in one common scenario. I have following data structure to push using dataLayer:
{
event: 'loginSuccess',
category: 'Login',
action: 'loginSuccess',
noninteraction: false, // Optional
loginType: 'Google',
userID: dataObj.user_id
userEmail: dataObj.user_email.
}
I have created the variables in GTM and while creating a loginSuccess event tag to send data to GA I am not able to figure out how to send all the other variables as most of the example show one variable that too they pass in the "label" mapping of GA in the GTM.
I need to send all the variables and track in GA this is one sample there are many such events with 4-5 data variables in each of them.
I am so confused as not able to figure out this small issue.
Thanks in advance.
You need to create datalayer variables for each data point. And then it's up to you how you can to send them. It can be event action, category, label, custom dimensions, etc.
Hello Julius,
how does the dataLayer object is sent to GTM?
when I use the push method the navigator behaves as if I'm just updating a local js array/object and the web browser dev tools doesn't show any network request. Using the push method shouldnt be generating some kind of network movement? (or maybe I'm just missunderstunding the datalayer behavior...)
Thanks!
Based on dataLayer.push,GTM updates its internal model stored in the google_tag_manager object
Great article👏I am confused about one thing, I am assuming that the data layer would be empty at first.
E.g. I am making a purchase event and I pass amount, this amount is moved to data layer, on a button click.
So what code should be present on the button? Should there be any code on the button?
Depends on how the website is coded. For example, a developer could write the listener that checks clicks of a particular button and then dispatches data to the dataLayer.
Hi Julius,
Can we send user Data Such as Email and User Name through Data Layer. if user Auto logged in Via Some Articles to our Homepage can Push his Email and other Deatails when he performs each Actions
Yes, talk to the website's developer about this
Can I push data into GTM/GA in code? Basically, I want to have the user submit an order then I'll wait for the response, when/if the response comes back as successful, I want to push the data into GTM/GA before sending the user to the Thank You page. I have having issues with the Thank You page so I'd like to capture the data sooner using this method.
Is it even possible?
Then do the dataLayer.push before the redirect
Thanks for article Julius.
I want to implement the
1.
window.dataLayer.push
({
'event': 'Apply Now Click'
})
2.
window.dataLayer.push
({
'event': 'Sign In Click'
})
Where should I put this script on the page?
You could just use the built-in click tracking in GTM https://www.analyticsmania.com/post/google-tag-manager-click-tracking/
Its Tej again,
Could you suggest the tool to keep track on this click events.
I see my dataLayer variables in GTM, but how do I see these in Google Analytics?
Bu including them in GA tags within GTM