Core Web Vitals: The Chrome UX Report (CrUX) Explained

Hendrik

Hendrik

December 18, 2023 · 9 min read
Core Web Vitals metrics cover image

Debugging:

  • Featured Image URL: https://seo-experiments.net/assets/core-web-vitals.png
  • Alt-Text:

Introduction

In today's digital landscape, the performance of a website is not just about its content or design, but significantly about its core functionality and user experience. This is where Google's Core Web Vitals come into play, serving as crucial factors in the search engine's ranking algorithm. These metrics, which focus on the speed, responsiveness, and visual stability of a webpage, are pivotal in determining a website's visibility and user engagement. As Google increasingly emphasizes user experience, the importance of optimizing for Core Web Vitals cannot be overstated.

Acknowledging this shift, our focus is to provide you with practical, actionable insights and tools to optimize your website in alignment with Core Web Vitals. This article leverages the extensive data and insights from the Chrome UX Report (CrUX), a rich resource that sheds light on real user experiences across millions of websites. By the end of this guide, you will have a clearer understanding of Core Web Vitals and how to use CrUX data to enhance your website's performance, ensuring a superior user experience and improved search engine rankings.


Understanding Core Web Vitals

At the heart of website performance are Core Web Vitals, a set of metrics designed by Google to quantify key aspects of a user's experience on a website. These vitals are integral components of Google's ranking algorithm, emphasizing the importance of a seamless user experience. Core Web Vitals consist of three primary metrics, each focusing on a distinct facet of website usability.

  1. Largest Contentful Paint (LCP): This metric measures the loading performance of a website. Specifically, it tracks the time taken to render the largest content element visible in the viewport, typically an image or a block of text. LCP is a critical indicator of how quickly a user perceives the page's main content to be available, with faster LCP times leading to a better user experience.

  2. Cumulative Layout Shift (CLS): CLS assesses the visual stability of a webpage. It quantifies the amount of unexpected layout shift during the lifespan of the page. High CLS scores indicate a jarring experience for users, as content moves around the screen unpredictably, often leading to accidental clicks or difficulty in reading text.

  3. First Input Delay (FID): Focusing on interactivity, FID measures the time from when a user first interacts with your site (i.e., when they click a link, tap on a button) to the time when the browser is actually able to begin processing event handlers in response to that interaction. A low FID is essential for a website to feel responsive and to engage users effectively.

Understanding and optimizing these Core Web Vitals are key to improving the overall user experience of a website, which in turn can positively impact its ranking in search engine results.


What is the Chrome UX Report (CrUX)?

As the official dataset for the Web Vitals program, CrUX includes all of the user-focused core Web Vitals metrics. The Chrome UX Report, commonly known as CrUX, stands as a pivotal resource in the world of web performance analysis. It offers an extensive collection of real user experience data gathered from millions of Chrome users worldwide. This report is instrumental in providing a realistic and broad perspective on how users interact with websites across different devices and geographical locations. The CrUX Dashboard is a Looker Studio (formerly Data Studio) dashboard that links to the raw origin-level CrUX data.

CrUX's role extends far beyond mere data collection. It offers vital insights into the actual performance of websites as experienced by real users. This includes data on key metrics like the Core Web Vitals, enabling webmasters and SEO professionals to understand and analyze the user experience on their websites more accurately. With CrUX, professionals can see how their site performs across different conditions and use this information to make data-driven decisions. This user-centric approach to performance analysis makes CrUX an invaluable tool in optimizing websites to meet and exceed the expectations of today's web users, ultimately leading to improved user engagement and higher search engine rankings.

CrUX Core Web Vitals

Utilizing CrUX for Website Optimization

The Chrome UX Report (CrUX) serves as a treasure trove of data for website owners seeking to enhance their site’s performance, particularly in the realm of Core Web Vitals. By leveraging the comprehensive user experience data provided by CrUX, website administrators can delve deep into how real users interact with their sites. This data includes detailed insights on metrics like Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS), which are crucial for understanding a website's performance from a user's perspective.

The analysis of user engagement metrics from CrUX is invaluable in targeted website optimization. It offers a real-world view of how users experience a website, differing significantly from controlled test environments. This approach allows website owners to pinpoint specific areas that need improvement, whether it's enhancing loading times, reducing layout shifts, or improving interactivity. By focusing on these real user metrics, webmasters can implement more effective optimizations that directly address the issues impacting their visitors. In turn, this leads to a more engaging and user-friendly website, which not only satisfies visitors but also aligns with Google's emphasis on user experience in its ranking algorithms.


CrUX Dashboard and API

The Chrome UX Report (CrUX) Dashboard is a user-friendly interface that provides access to the vast array of raw, origin-level CrUX data. This dashboard simplifies the process of analyzing user experience metrics across different web domains. Additionally, the CrUX API offers a more granular approach, allowing webmasters to perform detailed analyses and automate reporting on Core Web Vitals metrics for specific URLs or domains.

CrUX FCP

Script for Google Sheets / Apps Script

To further streamline the process, a custom script for Google Sheets/Apps Script can be utilized. This script allows website owners to automatically pull Core Web Vitals data from the CrUX API directly into a Google Sheet. Simply insert the script into the script editor of a Google Sheet, replace Your-API-Key with your own API key from the Google Cloud Console, and run the function to fetch Core Web Vitals data for a list of URLs. This provides an easy and efficient way to monitor and analyze website performance. Below is the first step script for Desktop + Phone + Tablet - these are the dimensions by which the CrUX data is distinguished.

Desktop + Phone + Tablet

function importCoreWebVitals() {

const sheet = SpreadsheetApp.getActiveSheet();

const urls = sheet.getRange("A2:A").getValues();

// Add headers

sheet.getRange(1, 2).setValue("Largest Contentful Paint");

sheet.getRange(1, 3).setValue("Cumulative Layout Shift");

sheet.getRange(1, 4).setValue("First Input Delay");

sheet.getRange(1, 5).setValue("LCP Status");

sheet.getRange(1, 6).setValue("CLS Status");

sheet.getRange(1, 7).setValue("FID Status");

for (let i = 0; i < urls.length; i++) {

if (urls[i][0] === "") break;

const url = urls[i][0];

const CrUXApiUtil = {};

CrUXApiUtil.API_KEY = 'Your-API-Key';

CrUXApiUtil.API_ENDPOINT = `https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=${CrUXApiUtil.API_KEY}`;

CrUXApiUtil.query = function (requestBody) {

if (CrUXApiUtil.API_KEY === '') {

throw 'API_KEY must be set before making a query.';

}

try {

const options = {

method: 'POST',

contentType: 'application/json',

payload: JSON.stringify(requestBody),

};

const response = UrlFetchApp.fetch(CrUXApiUtil.API_ENDPOINT, options);

const result = JSON.parse(response);

const metrics = result.record.metrics;

const largestContentfulPaint = metrics.largest_contentful_paint.percentiles.p75;

const cumulativeLayoutShift = metrics.cumulative_layout_shift.percentiles.p75;

const firstInputDelay = metrics.first_input_delay.percentiles.p75;

const lcpStatus = largestContentfulPaint <= 2500 ? "Good" : largestContentfulPaint <= 4000 ? "Needs Optimization" : "Slow";

const clsStatus = cumulativeLayoutShift <= 0.1 ? "Good" : cumulativeLayoutShift <= 0.25 ? "Needs Optimization" : "Slow";

const fidStatus = firstInputDelay <= 100 ? "Good" : firstInputDelay <= 300 ? "Needs Optimization" : "Slow";

sheet.getRange(i + 2, 5).setValue(lcpStatus);

sheet.getRange(i + 2, 6).setValue(clsStatus);

sheet.getRange(i + 2, 7).setValue(fidStatus);

sheet.getRange(i + 2, 2).setValue(largestContentfulPaint);

sheet.getRange(i + 2, 3).setValue(cumulativeLayoutShift);

sheet.getRange(i + 2, 4).setValue(firstInputDelay);

} catch (error) {

console.error(error);

}

};

CrUXApiUtil.query({

url: url,

});

Utilities.sleep(500);

}

}

Google Cloud CrUX API dashboard interface screenshot

Next is the script for the CrUX data for desktop.

Desktop

function importCoreWebVitals() {

const sheet = SpreadsheetApp.getActiveSheet();

const urls = sheet.getRange("A2:A").getValues();

// Add headers

sheet.getRange(1, 2).setValue("Largest Contentful Paint");

sheet.getRange(1, 3).setValue("Cumulative Layout Shift");

sheet.getRange(1, 4).setValue("First Input Delay");

sheet.getRange(1, 5).setValue("LCP Status");

sheet.getRange(1, 6).setValue("CLS Status");

sheet.getRange(1, 7).setValue("FID Status");

for (let i = 0; i < urls.length; i++) {

if (urls[i][0] === "") break;

const url = urls[i][0];

const CrUXApiUtil = {};

CrUXApiUtil.API_KEY = 'Your-API-Key';

CrUXApiUtil.API_ENDPOINT = `https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=${CrUXApiUtil.API_KEY}`;

CrUXApiUtil.query = function (requestBody) {

if (CrUXApiUtil.API_KEY === '') {

throw 'API_KEY must be set before making a query.';

}

try {

const options = {

method: 'POST',

contentType: 'application/json',

payload: JSON.stringify(requestBody),

};

const response = UrlFetchApp.fetch(CrUXApiUtil.API_ENDPOINT, options);

const result = JSON.parse(response);

const metrics = result.record.metrics;

const largestContentfulPaint = metrics.largest_contentful_paint.percentiles.p75;

const cumulativeLayoutShift = metrics.cumulative_layout_shift.percentiles.p75;

const firstInputDelay = metrics.first_input_delay.percentiles.p75;

const lcpStatus = largestContentfulPaint <= 2500 ? "Good" : largestContentfulPaint <= 4000 ? "Needs Optimization" : "Slow";

const clsStatus = cumulativeLayoutShift <= 0.1 ? "Good" : cumulativeLayoutShift <= 0.25 ? "Needs Optimization" : "Slow";

const fidStatus = firstInputDelay <= 100 ? "Good" : firstInputDelay <= 300 ? "Needs Optimization" : "Slow";

sheet.getRange(i + 2, 5).setValue(lcpStatus);

sheet.getRange(i + 2, 6).setValue(clsStatus);

sheet.getRange(i + 2, 7).setValue(fidStatus);

sheet.getRange(i + 2, 2).setValue(largestContentfulPaint);

sheet.getRange(i + 2, 3).setValue(cumulativeLayoutShift);

sheet.getRange(i + 2, 4).setValue(firstInputDelay);

} catch (error) {

console.error(error);

}

};

CrUXApiUtil.query({

url: url,

formFactor: 'DESKTOP', // specify the form factor as DESKTOP

});

Utilities.sleep(500);

}

}

Next is the script for the CrUX data for Phone.

Phone

function importCoreWebVitals() {

const sheet = SpreadsheetApp.getActiveSheet();

const urls = sheet.getRange("A2:A").getValues();

// Add headers

sheet.getRange(1, 2).setValue("Largest Contentful Paint");

sheet.getRange(1, 3).setValue("Cumulative Layout Shift");

sheet.getRange(1, 4).setValue("First Input Delay");

sheet.getRange(1, 5).setValue("LCP Status");

sheet.getRange(1, 6).setValue("CLS Status");

sheet.getRange(1, 7).setValue("FID Status");

for (let i = 0; i < urls.length; i++) {

if (urls[i][0] === "") break;

const url = urls[i][0];

const CrUXApiUtil = {};

CrUXApiUtil.API_KEY = 'Your-API-Key';

CrUXApiUtil.API_ENDPOINT = `https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=${CrUXApiUtil.API_KEY}`;

CrUXApiUtil.query = function (requestBody) {

if (CrUXApiUtil.API_KEY === '') {

throw 'API_KEY must be set before making a query.';

}

try {

const options = {

method: 'POST',

contentType: 'application/json',

payload: JSON.stringify(requestBody),

};

const response = UrlFetchApp.fetch(CrUXApiUtil.API_ENDPOINT, options);

const result = JSON.parse(response);

const metrics = result.record.metrics;

const largestContentfulPaint = metrics.largest_contentful_paint.percentiles.p75;

const cumulativeLayoutShift = metrics.cumulative_layout_shift.percentiles.p75;

const firstInputDelay = metrics.first_input_delay.percentiles.p75;

const lcpStatus = largestContentfulPaint <= 2500 ? "Good" : largestContentfulPaint <= 4000 ? "Needs Optimization" : "Slow";

const clsStatus = cumulativeLayoutShift <= 0.1 ? "Good" : cumulativeLayoutShift <= 0.25 ? "Needs Optimization" : "Slow";

const fidStatus = firstInputDelay <= 100 ? "Good" : firstInputDelay <= 300 ? "Needs Optimization" : "Slow";

sheet.getRange(i + 2, 5).setValue(lcpStatus);

sheet.getRange(i + 2, 6).setValue(clsStatus);

sheet.getRange(i + 2, 7).setValue(fidStatus);

sheet.getRange(i + 2, 2).setValue(largestContentfulPaint);

sheet.getRange(i + 2, 3).setValue(cumulativeLayoutShift);

sheet.getRange(i + 2, 4).setValue(firstInputDelay);

} catch (error) {

console.error(error);

}

};

CrUXApiUtil.query({

url: url,

formFactor: 'PHONE', // specify the form factor as PHONE

});

Utilities.sleep(500);

}

}

Google Sheets CrUX Data Walmart
Walmart homepage PageSpeed Insights report analysis

Source: https://pagespeed.web.dev/analysis/https-www-walmart-com/utm1v0wu42?hl=en&form_factor=mobile

Finally, the script for the CrUX data for tablet

Tablet

function importCoreWebVitals() {

const sheet = SpreadsheetApp.getActiveSheet();

const urls = sheet.getRange("A2:A").getValues();

// Add headers

sheet.getRange(1, 2).setValue("Largest Contentful Paint");

sheet.getRange(1, 3).setValue("Cumulative Layout Shift");

sheet.getRange(1, 4).setValue("First Input Delay");

sheet.getRange(1, 5).setValue("LCP Status");

sheet.getRange(1, 6).setValue("CLS Status");

sheet.getRange(1, 7).setValue("FID Status");

for (let i = 0; i < urls.length; i++) {

if (urls[i][0] === "") break;

const url = urls[i][0];

const CrUXApiUtil = {};

CrUXApiUtil.API_KEY = 'Your-API-Key';

CrUXApiUtil.API_ENDPOINT = `https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=${CrUXApiUtil.API_KEY}`;

CrUXApiUtil.query = function (requestBody) {

if (CrUXApiUtil.API_KEY === '') {

throw 'API_KEY must be set before making a query.';

}

try {

const options = {

method: 'POST',

contentType: 'application/json',

payload: JSON.stringify(requestBody),

};

const response = UrlFetchApp.fetch(CrUXApiUtil.API_ENDPOINT, options);

const result = JSON.parse(response);

const metrics = result.record.metrics;

const largestContentfulPaint = metrics.largest_contentful_paint.percentiles.p75;

const cumulativeLayoutShift = metrics.cumulative_layout_shift.percentiles.p75;

const firstInputDelay = metrics.first_input_delay.percentiles.p75;

const lcpStatus = largestContentfulPaint <= 2500 ? "Good" : largestContentfulPaint <= 4000 ? "Needs Optimization" : "Slow";

const clsStatus = cumulativeLayoutShift <= 0.1 ? "Good" : cumulativeLayoutShift <= 0.25 ? "Needs Optimization" : "Slow";

const fidStatus = firstInputDelay <= 100 ? "Good" : firstInputDelay <= 300 ? "Needs Optimization" : "Slow";

sheet.getRange(i + 2, 5).setValue(lcpStatus);

sheet.getRange(i + 2, 6).setValue(clsStatus);

sheet.getRange(i + 2, 7).setValue(fidStatus);

sheet.getRange(i + 2, 2).setValue(largestContentfulPaint);

sheet.getRange(i + 2, 3).setValue(cumulativeLayoutShift);

sheet.getRange(i + 2, 4).setValue(firstInputDelay);

} catch (error) {

console.error(error);

}

};

CrUXApiUtil.query({

url: url,

formFactor: 'TABLET', // specify the form factor as TABLET

});

Utilities.sleep(500);

}

}

As you can see, the last scripts just changed the formFactor. For phone (except for B2B websites) usually the most data is available, for tablet the least. Here is the Google documentation about the CrUX API: https://developer.chrome.com/docs/crux/api


Practical Tips for Core Web Vitals Optimization

Optimizing for Core Web Vitals is essential for enhancing user experience and improving website performance. Here are detailed tips for optimizing each of the Core Web Vitals: Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), and First Input Delay (FID).

Largest Contentful Paint (LCP) Optimization:

  • Optimize Server Response Times:

    • Use a reliable web hosting service.

    • Implement caching solutions for faster content delivery.

    • Optimize your server configuration.

  • Compress and Optimize Images:

    • Utilize modern, efficient image formats like WebP.

    • Implement lazy loading for images.

    • Reduce image file sizes without compromising quality.

  • Defer Non-Critical CSS and JavaScript:

    • Use the "defer" attribute in script tags.

    • Identify and prioritize critical CSS needed for above-the-fold content.

    • Inline critical CSS and defer the rest.

  • Additional Strategies:

    • Minimize render-blocking resources.

    • Optimize content delivery networks (CDN) usage.

    • Implement preloading for key resources.

Cumulative Layout Shift (CLS) Optimization:

  • Define Dimensions for Images and Embeds:

    • Specify width and height attributes for media elements.

    • Use aspect ratio boxes to reserve space for elements.

  • Avoid Inserting New Content Above Existing Content:

    • Dynamically injected content should be placed below current view.

    • Reserve space for ad elements to prevent layout shifts.

  • Optimize Fonts and Animations:

    • Preload web fonts.

    • Use transform properties for animations instead of properties that trigger layout changes.

  • Additional Strategies:

    • Use CSS containment to limit layout recalculations.

    • Monitor and optimize dynamic content like carousels or accordions.

First Input Delay (FID) Optimization:

  • Minimize JavaScript Execution Time:

    • Break up long tasks into smaller, asynchronous tasks.

    • Defer unused JavaScript.

    • Optimize and reduce JavaScript bundle size.

  • Remove Non-Essential Third-Party Scripts:

    • Audit and remove unnecessary third-party scripts.

    • Delay loading of third-party scripts until necessary.

  •  

  • Additional Strategies:

    • Implement code splitting to only load what's needed.

    • Optimize event listeners and debouncing for user interactions.

    • Review and refine your JavaScript parsing and execution.

By implementing these focused optimizations, you can significantly enhance the Core Web Vitals scores for your website, leading to a better user experience and potentially higher search engine rankings.

Conclusion

Core Web Vitals and the Chrome UX Report are pivotal in the realm of SEO, offering a clear pathway to understanding and improving user experience. These tools and metrics are not just technical checkpoints; they represent real-world user interactions and satisfaction levels. By utilizing the CrUX Dashboard, API, and the provided Google Sheets script, website owners and SEO professionals can gain valuable insights and effectively optimize their websites. Embrace these tools and tips to ensure your website not only ranks well but also delivers an exceptional experience to every visitor.

Similiar Posts

October 04, 2023

2 min read
Hendrik
Hendrik

December 10, 2023

38 min read

Copyright © 2025 SEO Experiments

Don't be evil

Legal Notice