[UPDATE 02 March 2021]
In this guide, I’ll explain to you the easiest way to track Core Web Vitals (if you don’t know what Core Web Vitas are, click here to read my italian article) i.e. metrics that are the new ranking factor in SEO for Google.
This post is inspired by:
- the web.dev official article that explains several topics about this issue;
- the GitHub link where there’s a script already made to manage the Web Vitals APIs with several tools including Google Tag Manager.
Actually, I was inspired by several sources, but Philip Walton’s post is the most authoritative source for me.
Metrics to focus on are:
- Largest Contentful Paint (LCP)
- First Input Delay (FID)
- Cumulative Layout Shift (CLS)
Are you ready to take advantage of the three Core Web Vitals metrics and create your own Real User Monitoring?
Let’s go!
Thanks to Simo Ahava
For me is an honor to inspired amazing people like Simo Ahava. Indeed, he has created a Core Web Vitals custom template in GTM. Please read his article also: https://www.simoahava.com/analytics/track-core-web-vitals-in-ga4-with-google-tag-manager/
STEP 1 – Create Custom HTML Tag with Web Vitals APIs
You are able to create the Custom HTML Tag just by copying and pasting the script below (integrated by some small changes with the help of the help of Simen Hansen) in 10 seconds.
- Tag > New > Tag Configuration > Custom HTML Tag.
- Copy and paste this script:
<!-- Load 'web-vitals' using a classic script that sets the global 'webVitals' object. --> <script src="https://unpkg.com/web-vitals@1.1.0/dist/web-vitals.umd.js"></script> <script> function sendToGTM(name, delta, id) { // Assumes the global `dataLayer` array exists, see: // https://developers.google.com/tag-manager/devguide dataLayer.push({ event: 'web-vitals', event_category: 'Web Vitals', event_action: name.name, // Google Analytics metrics must be integers, so the value is rounded. // For CLS the value is first multiplied by 1000 for greater precision // (note: increase the multiplier for greater precision if needed). event_value: Math.round(name.name === 'CLS' ? name.delta * 1000 : name.delta), // The 'id' value will be unique to the current page load. When sending // multiple values from the same page (e.g. for CLS), Google Analytics can // compute a total by grouping on this ID (note: requires `eventLabel` to // be a dimension in your report). event_label: name.id, }); } webVitals.getCLS(sendToGTM); webVitals.getFID(sendToGTM); webVitals.getLCP(sendToGTM);
</script>
- Triggering > select “All Pages” Trigger.
- Rename Tag as “Script – Web Vitals”.
- Save and publish.
Some considerations:
- The green parts are comments (you can also delete them)
- The dataLayer object must be initialized. No problem: it’s already like that 🙂
- Since Google Analytics likes integers there’s rounding in the event_value parameter (Math.round), and in the case of the CLS metric a multiple of 1000 is added.
- The event_label parameter contains a unique id of the page
- There are three metrics to add: Largest Contentful Paint (LCP), First Input Delay (FID), Cumulative Layout Shift (CLS)
So this script fires three events called web-vitals in GTM. Let’s intercept metrics.
[WARNING]
The library https://unpkg.com/web-vitals@1.1.0/dist/web-vitals.umd.js the current version (03/02/2021) is 1.1.0 be careful and update it if there will be a new release.
You can find it here: https://unpkg.com/browse/web-vitals/
STEP 2 – Create Trigger for WEB VITALS Custom Event
- Triggers > New > Trigger Configuration.
- Trigger Type: Custom Event.
- Event name: web-vitals.
- Rename Trigger: “Web Vitals”.
- Save.
STEP 3 – Create Data Layer Variables
You have to collect values that are inside dataLayer to send them to Google Analytics.
These values are:
- event_category
- event_action
- event_value
- event_label
You just have to do it for all four values.
Variables > New > Variable Configuration > Data Layer Variable
- Name: dlv – event_category
- Data Layer Variable Name: event_category
- Data Layer Version: Version 2
Do the same for the rest of Variables by changing their name and value:
Variables > New > Variable Configuration > Data Layer Variable
- Name: dlv – event_action
- Data Layer Variable Name: event_action
- Data Layer Version: Version 2
Variables > New > Variable Configuration > Data Layer Variable
- Name: dlv – event_value
- Data Layer Variable Name: event_value
- Data Layer Version: Version 2
Variables > New > Variable Configuration > Data Layer Variable
- Name: dlv – event_label
- Data Layer Variable Name: event_label
- Data Layer Version: Version 2
Great! You just have to send values to Google Analytics (but if you wish, you could send these metrics to any other tool).
STEP 3 – Create and configure Google Analytics Tag for web vitals
- Tag > New.
- Tag Type: Universal Analytics.
- Track Type: Event.
- Category: {{dlv – event_category}}
- Action: {{dlv – event_action}}
- Label: {{dlv – event_label}}
- Value: {{dlv – event_value}}
- Non-Interaction Hit: True
Select Google Analytics Variable on Google Analytics Settings Variable and Enable overriding settings. Insert GA Costant or GA tracking code as Tracking ID.
- Firing Triggers:“Web Vitals”.
- Rename Tag: “GA – Event – Web Vitals”.
- Save.
STEP 5 – Check the correct tag functioning
Before publishing any changes, check the correct tag functioning by activating the Preview and Debug Mode.
Go to your site and refresh the page. You should see a box at the bottom of your current page showing “web-vitals” event triggered three times. Click on Tags Fired On This Event, you’ll find newly created Tag.
This Tag will fire three time, one for each metric. Keep in mind that the event corresponding to the CLS metric will take a little longer to appear in the box.
Therefore, on each event there will be a dataLayer push which will have the parameters of the three metrics:
- Largest Contentful Paint (LCP)
- First Input Delay (FID)
- Cumulative Layout Shift (CLS)
And these following Tags in Google Analytics.
STEP 6 – Publish changes
If the Tags function correctly, then you can publish the changes.
Next step: create your R.U.M.
Now that data are sent to Google Analytics, you should export them and create reports and your Real User Monitoring.
As explained in web.dev official article
“For each of the above metrics, to ensure you’re hitting the recommended target for most of your users, a good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices.”
You have to wait for data (for a few days) and then you can export them by using tools such as Google Sheet, BigQuery, and Data Studio.
Would you like to read a guide explaining how to do it? Let me know in the comments!
Here is an example:
See you in the next article and… Buon Tag 😉
Links
- Defining the Core Web Vitals metrics thresholds
- Getting started with measuring Web Vitals
- Tools to measure Core Web Vitals
- How to measure and monitor site performance with Google’s Core Web Vitals
Altre Guide che potrebbero interessarti
- Guida Avanzata: come tracciare i Core Web Vitals in GA4 con…
- The Data Driven attribution model and the Time Period in the…
- ANALYTIX TALK: il Podcast di Marketing e Digital Analytics
- Glossario: Modello di Attribuzione Data Driven
- Guida Base: come tracciare i click sulle Tab in GA4 con…
- Come prepararsi alla migrazione da GA3 a GA4: il Data Model
Chiedi pure qui sotto, sarò pronto a risponderti!
Google Tag Manager for Beginners
SIMO AHAVA
Latest articles
- Attribuzioni errate in GA4: cause e soluzioni al problema
- Come creare una Dashboard Ecommerce per analizzare i dati degli acquisti Nuovi e di Ritorno
- Caso studio: Greenpeace ottimizza la User Experience, il tasso di conversione e il ROI del suo sito web, landing page e campagne advertising grazie al Server-Side tracking e alla Consent Mode
- Consent Mode v2 e calo dei dati delle audience e del traffico in Google Ads: cause e soluzioni
- Data Leak Google: Chrome e le implicazioni per la Privacy e la Digital Analytics
Looking for something?
Latest comments
- Matteo Zambon su Guida Base: come tracciare i click al link Phone (telefono) in GA4 con Google Tag Manager
- Matteo Zambon su Come gestire la Consent Mode v2 con Iubenda e Google Tag Manager
- Matteo Zambon su Come installare Google Analytics 4 (GA4) con Google Tag Manager
- Matteo Zambon su Glossario: Google Tag Assistant
- Matteo Zambon su Guida Avanzata: come configurare Conversion API di Facebook con l’integrazione nativa per Google Tag Manager
joody
07 07 2023
you are the best! it works
Matteo Zambon
23 10 2023
Oh Thank you 🙂
Hridja
13 09 2022
thanks this was very helpful
Matteo Zambon
19 09 2022
You’re welcome 🙂
Oliver
17 12 2021
Hi Matteo,
thanks for the great article but there’s one question that accurred.
What units do the CWV have
Matteo Zambon
22 12 2021
Hi Oliver, thank you for this feedback. You can see the metrics here: https://web.dev/defining-core-web-vitals-thresholds/
Largest Contentful Paint: ms
First Input Delay: ms
Cumulative Layout Shift: custom metric
Tetsuya
08 10 2021
Hi MATTEO,
I just completed the setup.
It’s working in the GTM preview, but I can’t get the CLS LCP FID values in the GA-UA real-time events.
Does this mean I need to wait a few days?
Matteo Zambon
11 10 2021
Hi Tetsuya, nope. It works immediately.
Let me know
Erik
27 08 2021
Hello Matteo,
I installed the script. What I see is that CLS, LCP and CSP are created, but besides that a lot of hits are registered with event_categry Web Vitals, but wit the event_action as “undiefined”. Do you know how this is created?
Kind regards,
Erik
Matteo Zambon
14 09 2021
Hi Erik,
I should check your configuration to answer your question.
Can you post your problem on our Facebook Group “Fatti di Tag Manager” please?
Add some screenshots too.
Thank you 🙂
Reema
25 06 2021
Hi, Thanks for this article! Could you please show how to shoe the 75th percentile score in Data Studio?
Matteo Zambon
06 07 2021
Hi Reema, I did a payment Italian course to explain how to create your RUM with Google Sheet and Big Query in Data Studio: you can find it here: https://club.tagmanageritalia.it/corso-segni-vitali/
Maybe I will translate this course into English next time.
Laura
25 06 2021
Hi Matteo, thanks for this conclusion.
I’ve learned: 😉
LCP data in GA are seconds
FID data in GA are milliseconds
CLS data is a score multiplied by 1000
My question: The table you’ve shown in this articel contains a LCP value of 518,384. I have similar values. This score means 518 seconds, which mean nearly 10 minutes, am I right?
Kind regards,
Laura
Matteo Zambon
06 07 2021
Hi Laura,
Yes, you’re right, remember that the column “Score” column is a sum.
Best regards 😉
Illia
01 06 2021
Thank you for sharing this amazing guide. I’ve implemented everything according to the guide but this error persists. See this screenshot: https://www.awesomescreenshot.com/image/8883511?key=42ba5a8275dd3cbe65cc5661da80be13
Any help will be highly appreciated😊
Matteo Zambon
16 06 2021
Hi Illia,
can you write a post on our Facebook group “Fatti di Tag Manager”: https://www.facebook.com/groups/TagManagerItalia attaching screenshots of every tag?
Did you try the Simo Ahava template?
Thank you 😉
Sebastian
14 05 2021
Hi together,
Google recently announced, that they have changed the measurement of the Cumulative Layout Shift. So they are now observing layout shift sessions of 5 Seconds and add all values within this time range.
Does changes in the Vital Scoring have an impact on the JavaScript? Or does this script just reads the value, which the chrome browser delivers?
Matteo Zambon
15 05 2021
Hi Sebastian, I think all script or DOM elements can impact the scoring. So I think the answer could be “yes”.
I suggest you ask Philip Walton this question directly.
Bye 🙂
Dave
16 03 2021
Greetings Matteo
I have a couple of questions regarding your reporting:
1.In the table visualization, what aggregation do you use for the values (Score) ?
2.In the scorecard visualization, what aggregation do you use for the values (Score) ? .
Matteo Zambon
16 03 2021
Hide Dave,
1) the score is 75 Percentile. If you mean the column score on the table is a simple sum
2) Average of 75 Percentile 😀
Johnny
09 03 2021
Hey there,
does is make a difference when the JS Library loads pretty slow or the GTM load very slow? Does this have an effect on the measured Core Web Vitals?
Or is the Javascript Library able to gather Core Web Vital information that is collected via your Browser, even before the Library is loaded?
Matteo Zambon
16 03 2021
Hi Johnny, I don’t know exactly, but I’m pretty sure that some parameters are collected via browser and so there are no problems about when the JS library loads.
Ros
05 02 2021
Hi, I have a problem getting the FID value .. In GTM preview mode I can see that the other two values are triggered but this one does not. Is there anyone that had similar problem or know how I can solve this?
Matteo Zambon
09 02 2021
Hi Ros, for me there is no problem. Did you try the Simo Ahava version? https://www.simoahava.com/analytics/track-core-web-vitals-in-ga4-with-google-tag-manager/
Let me know
Sjardo
05 02 2021
HI!
I was following your guide, and everything seems to work besides 1 thingy.
When loading the page, they Web Vitals scripts it fired, yet the events are only tricked after clicking on the page (again). The CLS is only fired after clicking a link.
1 – After page load:
2 – After clicking randomly on a page (LCP &FID)
3 – After clicking on a link (CLS)
Example:
https://ibb.co/nz0qgvf
Other tags trigger: GA & GA4
Total view:
https://ibb.co/mHNJPjw
Would love to get some input how this is happening and what i could do 🙂
Matteo Zambon
09 02 2021
Hi Sjardo, sincerely I don’t know 🙂 The library that I use in this guide is: https://developer.aliyun.com/mirror/npm/package/web-vitals
I can suggest trying the Simo Ahava version. Hhe uses the custom template: https://www.simoahava.com/analytics/track-core-web-vitals-in-ga4-with-google-tag-manager/
Let me know
Tony McCreath
19 03 2021
Hi,
Those delays are deliberate.
FID can’t be calculated until the first input (click).
CLS is an accumalated value so is more accurate the later it is fired. By default it fires when the page is hidden. e.g. a tab switch. The idea is to try and guarantee it finally fires before the page is unloaded. This means it can fire multiple times as a user views a page, so take that into account with your data.
Thom
05 02 2021
Hi Matteo! I’ve just installed this script for a number of my clients. However, I’ve just noticed that Magento 2 webshops have an issue with the script. When it is installed with GTM it appears that the checkout just keeps loading (and never finishes loading). Would you have any idea how to prevent this or how this could happen?
Matteo Zambon
09 02 2021
Uhm I don’t know. You could use the Simo Ahava version with a custom template: https://www.simoahava.com/analytics/track-core-web-vitals-in-ga4-with-google-tag-manager/
Let me know
Thom
18 02 2021
Hi Matteo, just tried Simo Ahava’s template but it gives another issue. With both the script on this page as well as Simo Ahava’s version the data isn’t pushed in a datalayer, and thus cannot be send to UA/GA4. Any idea why this issue is Magento 2 specific? 🙂
Matteo Zambon
02 03 2021
Hi Thom, unfortunately, I can’t help you in deep. Could you share the URL or some screenshot?
Leo Shaw
04 09 2020
Hi, thanks for the great article. I noticed in the code you have “function sendToGTM(name, delta, id) {” – I think you either want brackets in there to destructure the arg, e.g. “function sendToGTM({name, delta, id}) {” or have e.g. “function sendToGTM(metric) {” and reference metric.name, metric.delta etc. below
Matteo Zambon
14 09 2020
Hi Leo and thanks for your feedback.
I don’t understand your point. The function works very well 🙂
Could you explain it better?
Thanks
Alfonso
16 07 2020
Hi Matteo.
I’d love to see how have you made the Data Studio dashboard (without Big Query, directly from GA dataset)
Thanks and congrats for the post!
Matteo Zambon
17 07 2020
Oh, thank you Alfonso. I did an Italian webinar to explain how to create your Data Studio dashboard with Big Query and the other way with GA + Google Sheet.
Maybe I can do it in English version 🙂
Papas
10 07 2020
Thats a great guide and a great work, thanks for that. Would it be possible to write a guide on how you calculate the scores; from GA/BigQuery to GDS.i have done the work and i can caputre the data in GTM, send them over to GA, read the data in GDS, but iam not sure how to represent the data as you.
Matteo Zambon
17 07 2020
Thanks Papas, I did an Italian webinar to explain how to create your Data Studio dashboard with Big Query and the other way with GA + Google Sheet.
Maybe I can do it in English version 🙂
Alfonso
20 07 2020
Thanks for your reponse, Matteo!
Have you got the Italian version to share?
Actually I just don’t know how to make the conditional format with the values of the web vitals events, because columns “score” and “75 percentile” don’t match with my GA events values.
Thanks in advance and congrats for your work! 🙂
Matteo Zambon
21 07 2020
Hi Alfonso, I did a payment Italian course to explain how to create your RUM with Google Sheet and Big Query in Data Studio: you can find it here: https://club.tagmanageritalia.it/corso-segni-vitali/
Maybe I will translate this course in English next time.
Thanks for your feedback, it’s really appreciated.
Paolo
26 06 2020
Ciao Matteo. Non capisco, ho ripetuto l’operazione 3 volte ma mi si attiva sempre un solo tag per una sola metrica (events). Dove potrei aver sbagliato?
Matteo Zambon
26 06 2020
Ciao Paolo, riesci a darmi dettagli sul gruppo: https://www.facebook.com/groups/TagManagerItalia/ con qualche screenshot?
Grazie!
Andres
25 06 2020
This is great, thanks for sharing.
Once it’s all setup in GTM, what are there any other steps in GA to be able to see the data?
Matteo Zambon
26 06 2020
You can use Google Sheet with this addon https://developers.google.com/analytics/solutions/google-analytics-spreadsheet-add-on export and create your report.
Or you can use App+Web and BigQuery.
I will do a webinar in english 🙂
Keep in touch!
Andres
29 06 2020
Thanks.. one last question, what score unit is the is the CLS using? We are aiming for something less than 0.1 but your shows 146 as yellow grade (so I’m guessing this number should be devided by 1000??)
Matteo Zambon
30 06 2020
Hi Andres, you are right. In the step 1: “for CLS the value is first multiplied by 1000 for greater precision”. In the report you could divided by 1000 🙂