Skip to content

Demystifying Google tag manager for developers

Posted on:March 14, 2024 at 03:22 PM

Table of contents

Open Table of contents

Introduction

I have had to analyze website traffic quite a few times but I never understood how tag management works which is used to manage all the website tracking. So whenever I wanted to track a new event, add new parameters or modify an event for user tracking, I had to rely upon marketing to set it up with Google Tag Manager. Recently, I took some time to understand how Google Tag Manager (GTM) works.

I discovered that almost all the guides online assume a non technical audience and don’t explain how GTM works technically. That is partly because marketing is dominated by non technical folks so naturally the guides and tutorials are written for them. It was also exacerbated by the very confusing terminology Google Tag Manager uses which threw me off sometimes. After some googling around, I found Simo Ahava’s blog which was one of the few technical resources I could find on GTM. He is also very active in #measure slack channel where he responds to almost all questions on Google tag Manager, so I am especially thankful for his guidance. In fact, I asked him to review my first draft and he very graciously reviewed it and found a few problems which I have now rectified. That said, opinions and mistakes in this blog are mine and mine alone.

I am compiling this short guide for technical users to develop a baseline understanding of how various pieces of GTM works together. This is something I wish I had when I started learning about GTM. It is not supposed to be a comprehensive guide but builds up the architectural details of GTM so you should be able to fill in gaps as needed and liaise with your marketing a bit better by understanding their language.

So what is Google Tag Manager?

Google Tag Manager is not a script itself but rather a script loader. It is a JavaScript script that needs to be added to every page of the website. You provide it with your container ID, and it loads your GTM script onto the HTML page. This setup allows marketers to change the configuration of GTM without requiring a full website redeployment, reducing their dependency on developers. However, the downside is that changes made in GTM are not part of your CI/CD setup, meaning bugs can be introduced without proper testing. The script needs to be present on every page because the browser refreshes its global context upon page reload.

This is what the GTM script looks like:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
<!-- End Google Tag Manager -->

So what exactly does GTM do?

As the name suggests it is a tag manager (There are other tag manager solutions besides GTM like Adobe Launch). Here, the name tag threw me off for quite some time, after some digging around I found that a tag is basically a javaScript script. There are a lot of companies out there who provide some functionality through scripts you add to your HTML like chat widgets, A/B testing scripts, web pixels etc. Google Tag Manager is used to add these scripts on the HTML page by dynamically appending HTML5 <script> elements on the page. GTM only appends <script> elements, it does not automatically remove them or manage them in any way. These scripts run within the full context of the browser so they can add their own event listeners, read JavaScript enabled cookies, set their own cookies, create timers and so on. So, these tags usually have a lot of side effects. Misconfigurations in tag triggers (explained below) can lead to memory leaks and duplicate events for tracking.

There is another type of tag which does not work by adding HTML5 script elements on the page. These are tag templates I will explain towards the end of this blog. However, in practice right now most tags work by adding a custom script element on the page.

How does Google Tag Manager decide when to trigger a tag(run the tag script)?

That’s where triggers come into play. We can define various conditions in Google Tag Manager when to run a script (tag) such as current page URL ,custom events (these are not browser events). GTM comes with some default triggers which can be used like form submission trigger, link click, button click etc. Form click and link click triggers have a feature “wait for tags” which can cause problems. It delays firing of page unload events until the tags have been fired or timeout which can make some pages load slower than expected. We can also create our own triggers as well using a combination of events and variables. These are not JavaScript variables or events and are explained below.

How are triggers implemented in JavaScript?

There are two important concepts at play here, variables and the data layer. Let’s start with the data layer first.

Data Layer

Google Tag Manager maintains a javaScript variable named data layer. It is an array of append only javaScript objects and we can push any data inside, using the data layer.push method. This is what it looks like:

Google Tag Manager Data Layer screenshot

As shown,GTM also pushes some default events and configuration parameters. GTM also has an internal data model which is flat in contrast to the data layer which is an array. This internal data model copies all the data from the data layer and in case of duplicate parameters, overwrites the previous value with the most recent one when it is a primitive value and recursively merges the values when the values are arrays and objects. So, if this is our order of inserts in data layer:

Event: page_view page_title: title1

Event: page_view page_title:title2

GTM’s internal model will contain event:page_view and page_title:title2 if we see it after pushing these two events in the data layer. This internal data model also contains data from internal calculations and scripts so it is not just data from the data layer.

Variables

Variables on the other hand contain the most recent or current value of some contextual information like the ID of the most recent HTML form submitted, current cookie values, current page url etc. In order to get the most recent value, variables are resolved when invoked so they act like javaScript functions instead of variables in a programming language.

Variables can also be based on variables in the internal data model of GTM so we can push an arbitrary event parameter in the data layer and define a variable based on it as it defines a new variable in the internal data model.

Triggers

We define triggers based on variables using different types of comparison operators. This is an example of a trigger

Google Tag Manager Trigger screenshot

Click text is a variable which contains the most recent value of text of clicked item. The trigger is fired when it equals “Shop Products”. We can also send variables as custom parameters to the tags. This might sound trivial but I spent a few days trying to wrap my head around how exactly GTM communicates event parameters to custom tags 🙂, the answer is variables which resolve to the most current value.

Whenever a new event is pushed to the data layer (object with “event” as key), GTM updates its internal data model and finds all triggers based on the current state of its internal data model, then for each trigger, it runs all the tags associated with it (well, there are exceptions for triggers but this is an architectural guide so I am not focused on details). Data layer updates aside from events only update the data model, they don’t run tags.

This is what a tag configuration looks like, it contains all event parameters and the trigger condition.

Google Tag Manager Tag screenshot

Tag Template API

Since adding arbitrary scripts on every trigger can cause some problems, Google came up with the idea of a sandbox runtime environment with restricted functionalities. Tag templates only interact with browser APIs by going through the runtime environment. I may be overstretching the definition of runtime environment but it captures the idea very well.

This environment provides a very fine grained permission model for every API. For example logging to the console requires an explicit permission and so does sending an GET request to an endpoint. The endpoint is also part of the permission so a tag cannot send data to a different endpoint than the one it has permission for. It increases transparency as the users can now see exactly what a tag does instead of having to run arbitrary javaScript on all user’s devices.

However, there is a particular API in tag templates which circumvents all the permissions and works outside the sandbox, it is the injectScript API which can be used to inject a script on the page. Tag templates are a good idea in theory but in practice almost all the tag vendors require adding their script via injectScript API right now. Adding your own script on the page offers more flexibility than working in the sandbox runtime but it also exposes the users to all sorts of problems, for example some tags scrape user contact information from contact forms upon form submission automatically. This can lead you into legal trouble

In addition to it, some tags and in particular pixel tags don’t just load a script. They are implemented as script loaders themselves, similar to how GTM is implemented. Your pixel vendor can update their scripts anytime they want so you are allowing third parties to run and update arbitrary code on all of your user’s devices.

Global permissions in Google Tag Manager

GTM provides a mechanism to restrict the use of various tag types, triggers and variables within the entire GTM environment. It ensures that, even if a trigger is activated, any tags associated with that trigger won’t be executed if they’ve been restricted. It can be set by adding a script on the page before the GTM script is loaded.

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  'gtm.allowlist': ['<id>', '<id>', ...],
  'gtm.blocklist': ['<id>', '<id>', '<id>', ...]
});
</script>

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.

From Google’s documentation, see the documentation for details.

It can be a good place to implement organization-wide policies on what sort of tags should not be allowed to deploy for performance, user privacy or compliance reasons. For more information, refer tp Google’s own documentation for it.

Side effects as a feature

Many perceived issues with Google Tag Manager originate from a fundamental problem. Most tags do not expose APIs to be used explicitly; instead, they rely on websites embedding them as scripts on every page to provide functionality. While they do offer APIs for tracking custom events, this is not their core functionality. This script-embedding approach is convenient for non-technical users as it doesn’t require writing JavaScript and may be suitable for certain use cases, such as adding chat widgets or comment sections within iframes on blogs. However, a lot of tags, especially tracking pixels, are designed to be added within the main browsing context outside iframes. Most web pixels (these are scripts or sometimes 1x1 images) are not even scripts themselves but rather script loaders. This is why most web pixels have not adopted the tag template API, as they are meant to run within the full browser context. This requirement for tags to run in the main browsing context is what creates the need for tag management solutions like Google Tag Manager in the first place.

Server Side Tracking

There is a new direction this industry is moving due to performance and privacy concerns. The basic idea is to move the functionality of tags to the server side so instead of adding a script on the page, you collect whatever data you need explicitly and send it to your server which then sends it to the tag vendor. This is a very broad topic and I might write a separate blog on it. It is worth mentioning that Google Tag Manager has a server side solution now which can be used to send data to GTM server side. This is a good direction to move towards but it has some problems, the first being it is not free unlike client side tracking. One interesting side effect of server side tracking is that it can be used to bypass domain based ad blockers as it can be hosted on the same domain as the website and a lot of companies are actively doing it.

Conclusion

Hopefully this guide has given you a basic understanding of how Google Tag Manager works. It is not a comprehensive guide but it should give you a good understanding of the architecture of GTM. It should help you liaise with your marketing team a bit better and understand their language and also help them understand your concerns better.

If you have any questions or feedback, feel free to reach out to me on [email protected]