Optimising Google Tag Manager (GTM) for speed and performance

Google Tag Manager makes it incredibly easy to add marketing tags to your site. From registering ads conversions and transactions to sophisticated tags that segment users based on the weather in their current location, you can go crazy without having to go back to your development team every time. But that doesn’t mean you should do it all. While your dev and SEO teams are working hard to reach their pagespeed goals, all the marketeers are having a proverbial party in their yard. Here you’ll find a few tips to keep your GTM container lean.

Best Practices

1. Use a (custom) template

Tag manager provides a lot of standard tag templates like the Google Analytics tag or the Hotjar tag, but recently they’ve enabled you to create your own template. This not only helps in terms of a more convenient interface for working with tags and added security benefits, but there is also a performance benefit here. Every time you use a custom HTML tag instead of a template tag the GTM script will have to go through your page again insert the script and evaluate the actual script. A template on the other hand is inserted at the same time as the GTM script itself.

2. Asynchronous everything

Synchronous scripts are executed linearly in the page, meaning that the loading of other scripts is halted until this part of the script is completed. This is good if that part of the script is crucial for loading the rest of the page, it’s not so good if it’s nothing more than dead weight blocking the rendering of your page.

If something is so crucial that other scripts have to wait for it, it shouldn’t be in your Google Tag Manager. In other words: all your GTM script should run a-synchronously. This is the default for GTM itself and for the default and custom templates it runs. You can however screw up in your custom HTML tags and variables.

One use case I often see that is a great example of this is getting a visitor’s IP address using a third party service and mapping that to a list of know (business) IP addresses so you can exclude your own traffic easily. When you call a third party service like that you cannot just request the information as it’ll wait for the information to return and then continue loading the rest of the page. Instead you’ll have to write your request to behave asynchronously.

// DON'T DO THIS
<script scr='random-ip-service.io/get-ip'></script>

// DO THIS INSTEAD
<script>
(function() {
    if (sessionStorage.getItem('ipAddress') === "string") {
        dataLayer.push({
            ip: sessionStorage.getItem('ipAddress')
        }); 
    }
    else {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "random-ip-service.io/get-ip", true);
        xhr.onload = function (e) {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
            dataLayer.push({
                ip: xhr.responseText
            });
            sessionStorage.setItem('ipAddress',xhr.responseText);
            } else {
            console.error(xhr.statusText);
            }
        }
        };
        xhr.onerror = function (e) {
        console.error(xhr.statusText);
        };
        xhr.send(null);
    }
})()
</script>

There are two things going on here. First of all, yes, asynchronous JavaScript is stupidly long, but use it anyway. Secondly, in the first example a request is made on every page again and again. The likelihood of someone’s IP address changing mid-session is near zero as is the business impact of not registering that change. So just save that address in the sessionStorage and don’t call the third party service if you don’t have to.

3. Minimise the use of variables (and tags)

Here’s another easy optimisation trick for you: only fire tags when necessary. This sounds simple enough, but it’s so easy to pollute your tag space and fire all those tags on every page and event. But even when you have set them to fire on specific pages, do you fire them at page view? Why not load them on ‘Window Loaded’? Unless it’s crucial to track visitors that spend less than three seconds on your page, consider using ‘Window Loaded’ instead of ‘Page View’

It’s easy to not fire tags on every page, but did you know that variables are calculated on every page? Especially if you use complex calculations in your Custom JavaScript variables this can become a cumbersome process. A few things you can consider:

  • Store calculations in local or session storage for quick retrieval
  • Use if statements on e.g. document.location to only do the complex calculation when necessary
  • Ask your developer to provide the variable server-side — Yes, I know you don’t like talking to your developer, but do it anyway!

4. Have a process in place for adding and removing tags

Yes, here’s captain obvious again, but tell me, for how many containers do you have a process in place for adding and removing tags? Over time tags will accumulate and leave their waste (unused variables) behind when they’re removed again. Proper documentation and a decision process for adding and removing tags will help you remove that dead weight. For example set a time limit on campaign tags by using the ‘custom tag firing schedule’ in the advanced settings of your tag.

Learn from the best: what your development team does to keep things running smooth

Though broadband connections have allowed us to care less about page speed, mobile use and the ominous Google algorithm have had site builders think about page speed (and thus user experience) for quite some time. And they have a few tricks we can use.

5. Caching: Don’t use what’s already there

Page load time is taken up by two things: waiting for the server to respond and waiting for the browser to render and execute everything on the page. While there’s a lot in your code you can optimise for rendering faster, sometimes the easiest step is to not request anything from the server. How’s that possible? The magic word is ‘cache’. Files are stored in the browser’s memory and if they haven’t changed since the last time they were requested from the server, they’ll be served from the browser cache.

Now you might think that only works for returning visitors, but here’s the trick. A lot of sites use the exact same scripts. They use the same files and javascript libraries, and over the years these are no longer served by individual websites, but by high performance data centers from Google and the like. That means that if you use something like jQuery or Bootstrap, the likelihood of a user already having the latest version of that library on their computer hiding out in their browser cache is very high. To access that file from cache, all you need to do is make a request to the same place it was accessed from before: the Google server. In other words: don’t request from your own server what can be requested from a common server.

6. Minifying and bundling

In the battle for speed every byte counts. That is why developers have something called a build process where certain actions are performed before moving an app or website to production. This can include certain tests to check if code is working properly, but it also includes two actions called bundling and minifying.

Minifying means making your files as small as possible so they’ll load faster. That means not only removing comments out of your code, but also changing variable names from say, productsInCart, to just p, that’s 13 bytes saved right there. The same goes for all those spaces, tabs and blank lines you don’t need. It makes your code unreadable for humans, but hey, the machines don’t care about humans.

Bundling is often combined with minification. Every separate script means a new call to the server. And every call has some amount of overhead. So by bundling all scripts together