Why Don't My GTM Listeners Work?
Ever so often I come across a Google Tag Manager setup where GTM’s own auto-event listeners don’t perform the task they were supposed to. Listener problems seem to be a hot topic in Google+ and the Product Forums as well.
Let’s explore how listeners work before tackling the problem. You see, when you attach an event listener to an element in your Document Object Model (the collection of all elements on your page), the listener waits for the element to produce the action it is listening for.
With a link click listener, the handler waits for a link (
<a/>) element to fire a click event.
With a click listener, the handler waits for any element to fire a click event.
With a form submit listener, the handler waits for a form (
<form/>) element to fire a submit event.
Now this should still be easy to follow. You set up a link click listener, and when someone clicks a link, the listener pushes the event gtm.linkClick into the dataLayer object. Run-of-the-mill stuff.X
The Simmer Newsletter
Subscribe to the Simmer newsletter to get the latest news and content from Simo Ahava into your email inbox!
Here’s the gist. If you have another listener ALSO waiting for the same event, there’s a chance that it will interrupt the event from ever reaching the GTM listener, meaning that your link click listener never fires.
How is this possible?
The picture below clarifies the difference between a listener on the link node and a listener on the document node. In the example, I have a single link element with a classic onClick=”" attribute. In reality, this attribute is also an event listener. It waits for a click event on this specific tag. Also, I have GTM’s own click listener primed and ready. As you can see, the onClick listener is attached to the link node itself, whereas the click listener is attached to the document node.
A practical example
Let’s say you have a very simple page with a source code that looks something like this:
<html> <head> <title>My Page</title> </head> <body> <!-- Google Tag Manager Container here --> <div id="main"> <a href="http://www.google.com">Google</a> </div> </body> </html>
If I now add a link click listener to my GTM container, it will be attached to the document node, which is a top-level parent to all the elements you see in the code above.
Now, when someone clicks the link, the following happens:
Any listener attached to the
<a/>element itself (e.g. onClick) will be fired first, because it is closest to the event occurrence
Any listener attached to the
<div/>element will fire next, because it is the immediate parent to the element where the event occurred
And so on until the event bubbles up all the way to the top of the DOM tree and reaches the document node where GTM’s link click listener is waiting
Here’s the thing. If at any point during the event’s bubbly journey to the top of the mountain its process is halted by a conflicting script, for example, the event will never reach GTM’s listener!
The most common culprit is a competing jQuery listener which contains the following, ominous line of code:
This effectively halts the progress of the event listener, and returns the action to the link element with a “don’t do what you were supposed to do in the first place” type of statement.
A very common occurrence is when you are using jQuery to animate in-page scrolling to anchor links (i.e. smooth scrolling). I’ve seen a bunch of scripts which hijack the link click event, animate the transition to the correct part of the page, and return false;, because, naturally, they don’t want the link to perform its default action of instantly transporting you to the correct part of the page.
What’s the cure?
You’ll have to talk to your developers about this. Tell them that you need event propagation to work all the way up to the document node. Usually this can be done by replacing
Of course, you’ll need to pass the click event to the handler function as a parameter (event in event.preventDefault();) for this to work. There might also be cross-browser concerns, so do some research before making any changes.
.preventDefault() also prevents the default action of the link click event, but it doesn’t stop event propagation from continuing up the DOM tree. You’ll have to test it, of course, since replacing the code might disrupt the functionality of your script.
NOTE! If you use event.preventDefault(); OR return false;, you’ll need to uncheck the Check validation option in your link click listener. If this is left checked, the listener won’t fire even if the event bubbles up all the way to the document node.
Understanding event propagation and how GTM’s listeners work is one of the things you should not have to worry about when using GTM. After all, tag managers are advertised as a be-all and end-all solution to all your data collection woes with punchlines like: “Forget IT” or “No more development needed”.
The harsh reality is that a tag manager like GTM is just one more library in the client’s often congested resource jungle. Conflicts are bound to happen, especially when external resources like jQuery are used to add functionality to the site.
For one, whenever I work with a complex website, I will never, EVER, disregard the client’s development or IT unit. Rather, I will talk to them about GTM, and work together with them to come up with the best possible implementation plan, without compromising the current front-end deployment.