“Eyes up, this could be a trap!” – How can Google Tag Manager influence your website

What is Google Tag Manager?

Google Tag Manager is a tool provided by Google (thanks, Captain Obvious!), a tag management system that only needs one headshot (single script) in the  of your website for installation.

It has a user friendly interface, it’s web-based and lets you manage and deploy all the marketing tags you need (for tracking, analytics, 3rd party data integrations).

In addition, you can add scripts with which you can manipulate the DOM.

Google Tag Manager has multiple target platforms (web, iOS, Android, AMP and Server) but in this story, we will be focusing on GTM for web.

gtm key elements

What will you be working with?

The key elements are:

  • tags;
  • triggers;
  • variables.

If you could imagine GTM as a person: a tag will be the head (there you have the big information – a script that tells where to send data and how), triggers will be legs and arms to give direction (help the tag trigger on the right moment) and variables are inside components like veins and entrails that help the body (you can use them to collect and send parameters or as an extra condition for triggers – you can’t walk properly if you don’t have blood in one leg, right?).

Variables have different types: navigation (ex: url), page (ex: custom JavaScript, dataLayer), page elements (ex: DOM Element), utilities (ex: custom event, lookup table).

What kind of events* can be tracked?

First of all, let’s define events as actions that a user takes on the website.

So we have the users visit (pageview), scroll on page, click on basically anything, element visibility, form submission, JavaScript Error aaand custom events.

A custom event it’s something that should have some kind of logic. For example, when a user makes a purchase an event should be pushed into a global variable (like the dataLayer) that can be cached by GTM, that is the golden snitch for GTM.

For more information about working with GTM, please use the backlinks.

gtm Javascript lazy load

  1. Custom JavaScript Variable interfere with the page load

I was working on implementing Enhanced Ecommerce for GA4 (the Universal Analytics implementation was already in place). I had all the product data I needed in dataLayer, but I needed to iterate through it and manipulate it to give it the shape it needs.

So, my plan was simple, add the Google Analytics: GA4 Event tags for each event I wanted to track, make the proper configuration settings, choose the appropriate trigger and add the event parameters (items).

The events I was looking for: view item list, view item, select item, add to cart, remove from cart, add to wishlist, begin checkout, purchase, view promotion, select promotion.

For the event parameters, I needed to build some dataLayer variables to pick up the product attributes from the dataLayer and then put them in some custom JavaScript Variables to send the data in the correct object structure for GA4 to read.

Very easy, since I already did that for Universal Analytics object structure, tags etc..

So, like every good kid in town, I wanted to test my implementation in the debug version of GTM: THE PREVIEW MODE.

But the GTM preview mode was not working.

It looked something like this, frozen to the bone (this was the first sign):

Like every naive good kid, I made a mistake: I thought there was a bug or something in GTM and published the container as it was, thinking I can check the collects in the network to be sure that the events with all the parameters are sent to GA4.

When I tried to access the website, the site did not load properly, and if I tried to click on something or scroll, it froze (yes, I’m thinking of Narnia too).

What were the first things I did:

  1. asked the SEO specialist if he had knowledge of any updates or  new changes in the platform;
  2. debugged the network request to see where it ‘hangs’;
  3. restore the GTM version where I knew everything was fine.

Chicken, chicken, 3’s a winner!

OK, now let’s debug the changes that were made in GTM, that could affect the site in such a bad way. Because the bug was as soon as I entered the site, I concluded that it has to be something that triggers very fast like item list view or promotion view so I opened the custom JavaScript variables that were attached to those tags.

Et Voila! In the promotion view, the custom JavaScript variable was an infinite loop.

Watch your typos, guys!

2. Click event listener interferes with the site logic

GA4 has some new features like Enhanced measurement events. You can see them or edit in your data stream details. These don’t need code changes or specific tags in GTM (like for UA).

The Outbound clicks tracks each time a user clicks a link that leads away from the current domain. This sets an event listener on all your anchors.

I stumbled upon one special case:

On the product detail page on a website, if you clicked on the product image, an elegant modal opened so you can see the picture zoomed-in. The logic of the site was listening to the click on the picture, and when that click happened the picture was opened in a modal, on the site domain even if the was holding a link to the CND (content delivery network). After the GA4 configuration tag was implemented, the modal stopped working and the picture of the product was opened on the cdn domain, in the initial href.

After some investigations, we concluded that another click event listener was interfering with the one of the site logic and after we disabled it, the site started to work as expected.

3. GTM didn’t read the dataLayer in live mode

Last chapter of this story. Picture this: a basic implementation of Universal Analytics Enhanced Ecommerce, with some data in the dataLayer, the tags had the ‘use dataLayer’ enabled. All working fine. The same implementation for all the events: product impressions, product click, product detail view, add to cart, checkout, transactions.

We wanted to enhance the measurement and add some custom dimensions to track extra information like price distribution, discount percent etc. Because we didn’t have support from a developer to push that information in the dataLayer, we started implementing with some custom JavaScript variables, like this:

We took some of the information from the dataLayer and some with some querySelectors from the page html. We encountered some issues with the new implementation. The event was sent without parameters in Universal Analytics. We made some changes to try to make it work – removed the new custom dimensions, went back to the simple dataLayer implementation -, but nothing worked.

In the GTM preview mode, the request looked like this:

As you can see, the product impressions event sent all the parameters in the request to Universal Analytics, in the GTM preview mode. So we took this version live but… an error occurred:

After we ran some tests, we concluded that in the live mode, ecommerce.impressions could not be read, so the custom JavaScript or dataLayer enabled could not work. No idea why.

What we did next it’s not something I personally recommend, but it’s a solution we found for the moment. We stopped using a GTM dataLayer variable dataLayer[o].ecommerce.impressions and instead we worked with a Javascript variable, that returned the entire dataLayer:

Then, we parsed it and retrieved the ecommerce impressions data and added it to our initial custom JavaScript.

We did the same thing for product click:

After these changes, the parameters were sent correctly to Universal Analytics, both in preview and live mode.


Google Tag Manager is a complex tool with which you can achieve a lot. You can send data to marketing platforms (like: Google Ads, Facebook Ads, TikTok Ads, Criteo, RTB House, Klaviyo, Analytics etc.), you can track the user’s activity on the site, you can manipulate the DOM, modify meta tags and many more. But it can behave surprisingly and you have to pay attention to the syntax, test all possible cases and be open to out-of-the box solutions.

Good luck!