Do you also just implement third party code without consideration? Here's a use case where it impacted user engagement and specifically the FCP metric by at least 445ms, based on a Webpagetest analysis.
Table of Contents
- Cookielaw and other CMP implementations
- Loading your CMP without GTM
- A better CMP implementation
It isn't the first time I ran into this situation, so it was time for a blogpost covering this bottleneck to prevent others from making the same mistake.
Cookielaw and other CMP implementations
Although talking about cookielaw.org, this might apply to many other cookie and consent management platforms (CMP). You might be dealing with the following or a similar code-snippet to be implemented on your site:
<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" data-domain-script=uuid></script>
When loaded via Google Tag Manager
When loaded via Google Tag Manager (GTM), the cookielaw.org script would be downloaded and executed with a delay already. That's because GTM is loaded asynchronous by default. Asynchronous means the resource isn't obstructing the browser's critical render path as both GTM and any scripts loaded via GTM typically aren't parse nor render blocking.
In other words, the browser can proceed doing it's work, which increases the chance of a healthy First Contentful Paint (FCP) metric and thus an optimal perceived performance and user engagement.
The GTM dilemma
Loading a CMP via GTM means you're introducing multiple delays. The browser only knows that it should fetch the CMP resource once the GTM resource was downloaded, parsed, compiled and executed.
Although it would improve FCP, it then quickly becomes obstructive and frustrating when users think the page was done loading, but then a modal, interstitial or a large sticky cookie notice is blocking (a large portion of) the page. Not a good experience either.
Example of different cookie placements by web.dev.
Loading your CMP without GTM
So, the next best alternative is loading your CMP without GTM, by simply embedding the snippet directly into your website's HTML source code.
But when looking at the provided code example, we can see there is no
defer attribute. In other words, it is allowed to block the page and thus user experience. But this isn't ideal either when looking at a Webpagetest.org waterfall:
The green vertical line is important. This is representing the First Contentful Paint: the moment where users will start to see something for the first time.
Characteristics of a synchronous setup
In more detail, this is what you see in the above waterfall:
- The HTML file of a requested domain as resource number 1.
As it's the first request, it also involves a DNS lookup and connection + SSL negotiation time. And then waiting plus receiving a response.
- The browser then discovers the main CSS file, resource number 2.
This file is render blocking, as CSS usually is.
- At the same time, the cookielaw.org resource (number 3) was detected and downloaded as well.
This file is also render blocking because of the absense of
The bottleneck of a synchronous setup
This also is where the bottleneck starts. It's downloaded from another domain, involving a delay due to an additional domain lookup and connection + SSL negotiation time. Moreover, next to downloading the file, the browser will also wait for parsing, compiling and executing the contents.
That's what we can see in the waterfall as well when continuing our investigation:
- Resource number 4 and 5 aren't render blocking. But the browser just refuses to find and download them as it's stuck with the cookielaw.org resource. So even downloads of other (maybe important) resources are impacted.
- As a matter of fact, we can see the browser is barely doing anything useful when looking at the marked "Browser main thread" area.
When doing some math, the FCP is delayed by ( 773 - 328 = ) 445ms because of the current implementation. Actually a bit more as the cookielaw JS file is also adding some JS parsing, compiling and execution to the (FCP) mix.
So why was the script implemented in a synchronous and thus blocking way in the first place?
Probably because the Consent Manager Plaform knows that an asynchronous method isn't ideal.And they just had to choose between two evils here when providing merchants or agencies with a code-snippet (and from a perceived performance perspective, they usually make a bad decision here).
A better CMP implementation
So, we don't want a CMP to be blocking the page and thus UX. At the same time, we also want to minimize the delay. Otherwise, users could become frustrated when they already started to read a few sentences or interact with a webpage. But we also don't want to spend too much timing fixing problems of a third party.
Combining async and fetchpriority
Meet async + fetchpriority. That's right, the fetchpriority attribute isn't just for images, allowing us to combine the best of both: high priority without being render blocking. When combining it, you get the following:
In case you like copy and pasting:
<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" async fetchpriority=high data-domain-script=uuid></script>
Scripts required to make some parts of the page interactive are essential but should not block other resources. You can mark these as async with high priorityweb.dev on async + fetchpriority
Fetchpriority browser compatibility for scripts
Consider async + fetchpriority to be progressive enhancement as browser support is still limited, but might improve over time. Based on Mozilla's browser compatibility table, fetchpriority on script elements might actually already work in Opera (just like Google Chrome and Edge, it's a Chromium based browser after all).
I could show another waterfall here, but based on our previous webpagetest run you get a 445ms win within unique pageviews. But at the same time, you minimize risk of frustration as the time duration between FCP and the CMP showing up will be reduced.
Although we tend to think third parties are concerned with the well-being (performance) of the sites and shops that are using their resources, it isn't always the case. And although we can't really change the source code of those third party resources, we can still make a difference with limited effort. In this specific CMP case, we only needed to add two more attributes.
Want to go the extra mile?
There are different ways of going the extra mile. But if you want to keep it simple, then I would at least recommend the following:
- be sure to self-host the cookielaw.org (or any other vendor) file to remove the additional DNS lookup. You could set up a cronjob to periodically (once a day) fetch the latest contents of the cookielaw.org file.
- And prefetch any resources that isn't subject to URL changes.
You wish to do even more as performance has a high priority within your organisation and website? Don't hesitate to reach out!