Because I was bored, I did a quick test to sort out the firing order of competing GTM listeners. If you’ve done your homework (i.e. read my article on GTM listeners), you’ll remember that GTM listeners are set up on the document node of the document object model (DOM). I wanted to test what the firing order is if you have multiple competing listeners on the same page.
I tested with the following listeners (make sure you read up on auto-event tracking if you are completely baffled at this point):
-
Form Submit Listener - listens for a submit event on a form
-
Click Listener - listens for a click event on any element
-
Link Click Listener - listens for a click event on a link element
-
History Listener - listens for changes in browser history
The Simmer Newsletter
Follow this link to subscribe to the Simmer Newsletter! Stay up-to-date with the latest content from Simo Ahava and the Simmer online course platform.
The premise
I had a very simple HTML page, with just two buttons. One was the submit button of an empty form, the other an HTML5 button element, wrapped in a link.
To make things more interesting, I wrapped the submit button of the form in a link as well, because I wanted to see what happens. It’s not like you’ll ever come across a silly implementation like that in real life. I hope.
Here’s what the code looked like:
<!DOCTYPE html>
<html>
<head>
<title>Just testing</title>
</head>
<body>
<!-- GOOGLE TAG MANAGER CONTAINER WAS HERE -->
<form action="#form">
<a href="?formlink">
<input type="submit" value="Form test"/>
</a>
</form>
<a href="?buttonlink">
<button>Link test</button>
</a>
</body>
</html>
Very simple, right? I used query parameters in links simply because I wanted to see what happened to the {{url}} macro when different listeners fired.
I created a Custom HTML tag for each listener, with just a simple alert dialogue. Here’s what my click tag looked like:
<script>
alert("Click occurred on " + {{url}});
</script>
And ditto for all the other listeners. So every time a listener fires, an alert is shown. Just by following the sequence of these alerts, I should always see what the firing order is.
Outcome
Here’s what happened on Chrome and Safari:
Click on “Form test”
-
Alert: Link click occurred on (current URL)
-
Alert: Click occurred on (current URL)
-
Alert: Form submit occurred on (current URL)
-
Alert: History event occurred on (current URL + ?#form)
So the order is:
Link Click -> Click -> Form Submit
The History Listener fires because the form transports me to the URL ?#form (it’s in the action attribute of the form element), and in Chrome and Safari this triggers a popstate event.
Click on “Link test”
-
Alert: Link click occurred on (current URL)
-
Alert: Click occurred on (current URL)
-
Alert: History event occurred on (current URL + ?buttonlink)
And the order is:
Link Click -> Click
The History Listener fires this time as well upon popstate, because the active history entry is changed to ?buttonlink thanks to the link’s default action.
With Firefox, the History Listener won’t fire upon page load, so you won’t get an alert for the history event changes. Otherwise, the sequence is the same.
Conclusions
The result of this simple test is that your GTM listeners fire in the following order:
Link Click -> Click -> Form Submit
Remember that any other listeners you might have set up on the element nodes themselves (e.g. onClick) will be fired first. For example, if you have a pushState() call sent upon clicking a navigation link, this will change the URL (if you pass it as a parameter) before your link click listener fires. This, in turn, means that if you have an event sent to GA with gtm.linkClick as the event firing rule, you will see the URL set in pushState() as the page where the link click occurred!
Make sure that you understand how listeners compete with each other. GMT listeners are last of the line because they’re set up on the document node, not the elements themselves.
I haven’t come across a single case yet where having multiple GTM listeners active at the same time would cause any problems in data collection. However, it’s not inconceivable, and you should really try to keep things simple with your listener tags (among other things).