Keeping Websites Fast when Loading Google Tag Manager
Google Tag Manager can influence your overall website performance just as any other external 3rd party script. Luckily, there are a couple of things that you can do in that regard.
We love good website performance, not just because it is a big piece of the puzzle of great user experience, but also because it is one of the key factors for page ranking, and it can cut your AdWords prices. Our long list of blog posts on the subject is a testament to that, check out Frontend performance measuring and KPIs, Frontend performance: fast web fonts, or Speeding Up Next JS Websites By Removing JavaScript, as just a few examples on the matter.
External scripts, many of them provided by Google Tag Manager, are often blamed as the reason why a website performs poorly. Let’s investigate why and how we can turn things around and get that sweet high-performance score back while keeping Google Tag Manager.
Google Tag Manager, or just GTM, is one of the most popular services for managing external scripts on websites. It allows you to register all kinds of scripts or tags, as GTM calls it, and it will execute those scripts alongside the rest of your application scripts when the web page loads.
This only works after your alter the source code of the website, and insert a couple of lines of code on the frontend of the website, which looks something in the lines of this:
<!-- 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 -->
These lines of code will download the GTM handler, as well as register a global object, defaulted to “dataLayer”, which you use to talk to GTM. GTM will now load all the scripts that you have defined in our GTM account that should run when the page loads.
Picture this: you and the rest of your team have been working hard on building a fast website site, and the launch date is getting close. Your speed tests show great numbers, and everyone involved is stoked about the website. Here is an example site I made for this blog post:
Now, not long before the site's launch, your team is told to add GTM, pointing to the already existing (and working) set of external scripts. This is done, and immediately the performance scores take a massive hit. Going from top-notch scores to something that no one would ever brag about.
Does this sound familiar?
It certainly does to me. I’ve seen countless sites, often larger enterprise ones, being slowed down by a plethora of scripts that are not managed by the application itself but by GTM.
Why are these scripts bad for performance? Truth be told, not all of them are. Some are just forwarding user behavior, sending tiny payloads to an external service. Others are not so kind.
Take an externally managed cookie disclaimer, for instance. For many websites, it is loaded using GTM and has a negative impact on the LCP Core Web Vital metric, as it tends to be the biggest element on the page and renders very late. Not a good experience for the user, as they often experience a slight period where they can browse the site before a large banner covers the bottom part of their screen.
Another example is A/B testing scripts that change the elements on the page after the script has been downloaded. First off, this is not a good experience for the user, who might see parts of the page that their reading suddenly moves, or disappear, causing a great negative impact on the CLS core web vital metric.
These are just two examples amongst tons of other scripts that impact performance in one way or another. What they all have in common is that none of them are controlled by the team that carefully crafted the website, making them difficult to control, causing both performance issues as well as issues with navigation and layout, because any script can perform any kind of action on the page.
The best solution of them all is to simply load fewer external scripts. Move things in GTM scripts into the application code, the cookie banner, for instance, and reclaim control over the initial layout. If you’re doing A/B testing using GTM scripts, then you should absolutely move them into the application code as well, as it will be better for both user experience and page performance.
Regardless if you can move external scripts into the application code, you should look into claiming more control over what and when GTM scripts are being fired. Very often GTM will execute a script when the page loads, but not all scripts need to be executed simultaneously. You can achieve better script orchestration by defining your custom GTM triggers for the scripts.
A custom trigger is something you set up in GTM and then call from the application code at the appropriate time. It can look like this:
dataLayer.push({
'event': 'pageIsIdle'
});
Here is an example of two simple custom triggers that you can use in your setup:
blockUser
This is essentially the same as the “pageLoad” event and will execute the scripts as soon as the GTM container is ready. This is where you’ll find most scripts in GTM fire today, and it will, as the name suggests, block the user journey. So only the very most critical scripts go here.
doNotBlockUser
This is the game-changer trigger. Scripts that are bad for the performance go here. You need to define a good point in time when this trigger will be active, and I suggest you look into the requestIdleCallback API, which indicates that the client device is not busy with other things to avoid conflict with the application runtime activities.
The naming of these triggers is important. They convey a message beyond when they will trigger, and anyone who wants to put a script in the “blockUser” trigger will then know that adding this script will block the user journey, potentially negatively impacting the conversion rate and user satisfaction.
If you don’t have an existing GTM setup to worry about, then using Partytown to manage GTM might be a good idea. It works by moving all the script execution to its web worker, thus freeing up the main browser thread to only deal with application code. In theory, it will solve most of the performance issues mentioned above, but there is a chance that not all scripts will work out of the box as the scripts are not running in their usual context.
An often overlooked opportunity, but it is possible to track certain things on the server. This works by only executing the simple GTM shell on the client, then forwarding all of the events to your cloud server where you would handle the events.
Segment is another popular player in this space, which can offload client-side work onto its infrastructure.
You want to stay on top of things and ensure that the performance of your website never drops. Check out our advice on Frontend Performance Measuring & KPIs or deep dive with the frontend performance checklist we at Crystallize tend to use.
Performance audits should be part of our automated CI setup and provide appropriate alerts when the performance drops below the desired level. The tests on the CI should target an environment similar to the actual production environment so that you catch all of those tags that might not execute in a development setup.
You should also set up these tests to run at a recurring intervals since changes to the GTM container are not connected to the application code and deployments.
How’s that for performance scores?
Follow the Rabbit🐰
Behind the Scenes of crystallize.com: All the Performance Tricks and Hacks
Putting those frontend performance checklist suggestions to work.
Google Analytics 4 for eCommerce: The Bare Minimum
Google announced Universal Analytics (UA) would no longer process new data in standard properties beginning July 1, 2023, and that you should be moving to Google Analytics 4 (GA4). It’s not like the world is ending, right? But what does that mean for your business?