Instantiating & Using The Google Tag Manager dataLayer – Data Layer Best Practices Pt 1



We’ve collected a series of technical best practices designed to help you successfully interoperate with the Google Tag Manager Data Layer. These best practices are designed to help eliminate some of the peskier and harder-to-debug issues we run into when working with clients. This part will discuss the proper way to instantiate and work with the dataLayer.

Always Use .push()

Google documentation frequently demonstrates populating values in the data layer by simple instantiation, e.g.:

However, in certain circumstances, directly instantiating the dataLayer like this is dangerous. Why? If the above code were placed below the Google Tag Manager snippet on the page, something not-so-nice would happen, e.g.:

By moving the dataLayer = [{}] statement below our Google Tag Manager snippet, we actually destroy the true dataLayer. Any subsequent .push()‘s will seemingly have no effect, never appearing in our Debug Panel. And it would extremely hard to debug, since events prior to the overwrite will appear in Debug Mode, while events fired after will not.

The problem is that our initialization code doesn’t check if there’s already a variable named dataLayer. Because of this, it effectively overwrites whatever is already associated with the namespace dataLayer when it’s executed.

Making things worse, Google Tag Manager is still using the now-un-namespaced dataLayer, so if we .push() additional events into the new dataLayer, Google Tag Manager misses them completely. The Debug Panel is no help, either, as it still will show whatever events were caught up until that point. It’s only by manually polling dataLayer in the console that you’ll discover the issue.


Proper dataLayer Instantiation

To fix this, copy the big G. In Google’s scripts and snippets, they frequently have to interact with globals that may or may not be ready and available when the code is executing. To get around this issue, they use the following pattern:

Look familiar? You might remember this snippet of the Classic tracking code:

This pattern is incredibly useful in JavaScript. Literally translated, it says “set the value of the variable named someArray to whatever is already named someArray, or, if someArray doesn’t exist yet, set it to an empty array”. This pattern lets us sprinkle in commands to various services throughout the code, to be executed when the service is ready to go.

Google isn’t alone in using this pattern, either; Facebook and many others employ the same strategy for managing asynchronous resource loading and command queueing and execution.

We take it one step further in our best practice; although the above method is good for 99.99% of the time, our instantiation syntax is 100% bulletproof. Whenever we’re interacting with the dataLayer, we use this syntax:

By using this syntax, you’ll always reference or instantiate the global dataLayer, and scope the variable dataLayer locally to prevent any funky hoisting or scope collisions.

The reason you should take this approach is simple: over time, other development teams will add their own dataLayer code, or shift your code around. If you use the dataLayer = [{}]; style of instantiation, you’ll end up with some hard-to-debug issues whenever this happens (and trust me, it will).

Using var dataLayer = window.dataLayer = window.dataLayer || []; dataLayer.push({ ... }); ensures you’ll never run the risk of these issues popping up. Making this the standard syntax also prevents two teams from accidentally overwriting/deleting another teams dataLayer values when they add their own code later on.

Join us for Part 2 of this series, where we’ll discuss how to push values into the dataLayer within Google Tag Manager Custom HTML Tags.

What are your thoughts on dataLayer interaction? Have you developed another clever solution to this issue? Share with us in the comments below.

Dan Wilkerson is a former LunaMetrician and contributor to our blog.

  • Simo Ahava

    Hey Dan 🙂

    Thanks for the series, great stuff!

    As a data geek, I have to take issue with your “100% Bullet-proof” and counter it with a use case where dataLayer isn’t an Array. Surprisingly, I’ve now run into this in three different enterprise setups, each dealing with a similar custom stack. They used dataLayer as a plain object, so you could do simple lookups to it (obviously had nothing to do with GTM). A generic one-liner wouldn’t be elegant in this case, so in a situation like this it’s just prudent to rename dataLayer for GTM.

    Another issue might be with a renamed dataLayer. You can get the name of dataLayer by parsing the google_tag_manager object, and looking for the key which holds a plain object with keys gtmDom and gtmLoad. That is, if you want to take the geeky, generic path, and who wouldn’t?!

    But I’m just nit-picking, love the series 🙂


    • Dan Wilkerson

      Hi Simo,

      That’s fair; I should reword the post to specifically say I’m referring to the default GTM Data Layer, and not the broader concept of a dataLayer or a custom implementation. There would be nothing wrong with var dataLayer = window.dataLayer = window.dataLayer || {}; in that case, though, no?

      Didn’t know about parsing out the DL name in that manner! Thanks for sharing 🙂 You could get bit if someone was using two different dataLayer names, though, although that’s not best practice.

      Thanks for the feedback!


    • Kemen Paulos Plaza

      Hi Simmo, yes i have the same problem with the declaration of the DataLayer.

      i’m trying to look depeer the way to avoid this error of the dataLayer initialization, but i cant detect when it’s an array and when is not, do you have more information about this?

  • Tom

    Hi Dan,

    overwriting the dataLayer object is sometimes very hard to debug.
    Also if you reinitialize the object somewhere in the code. The GTM will lose track of the “push” option for the dataLayer Array. Good post. Looking forward for more insights.


    • Dan Wilkerson

      Yes, I’ve run into that particular issue more than a few times. Thanks, Tom!


  • ilnar

    Another 100% bullet proof code 🙂
    var dataLayer = window.dataLayer || (window.dataLayer = []);

  • Andrea Lyn Van

    Great series! A follow-up, and somewhat basic question, if I may. If you are just starting out with the data layer (like me), and have minimal coding experience, what coding knowledge do you recommend acquiring? Thanks!

    • Dan Wilkerson

      Hi Andrea,

      JavaScript! I’d recommend starting with the codecademy course:

      And then I’d recommend picking out a thing you’d like to do with code, and hacking at it until you get it working.


  • Kalashri

    @simoahava:disqus I have one question related tp data persistence in gtm data layer.
    I have many events in my one page application , and i am pushing data in every event, issue is , after every event click , old data persist in the dataLayer. I am doing below solution , please let me know is it proper or not.
    export function setGTMDataLayer(data) {
    let gtmEvent = {
    ‘event’: ‘’,
    ‘action’: data.action,
    ‘actionValue’ : data.actionValue

    let gtmClearEvent = {
    ‘event’: undefined,
    ‘action’: undefined,
    ‘actionValue’ : undefined


    setTimeout(function() {
    }, 300);

Contact Us.

Follow Us



We'll get back to you
in ONE business day.
Our Locations
THE FOUNDRY [map] LunaMetrics

24 S. 18th Street
Suite 100

Pittsburgh, PA 15203


4115 N. Ravenswood
Suite 101
Chicago, IL 60613


2100 Manchester Rd.
Building C, Suite 1750
Wheaton, IL 60187