What are Core Web Vitals? LCP, INP, CLS and the UX of page speed
Core Web Vitals are three user experience metrics that web.dev defines for all web pages. LCP measures loading, INP responsiveness to interactions, and CLS visual stability. The good thresholds are 2.5 seconds for LCP, 200 milliseconds for INP and 0.1 for CLS. What is assessed is the 75th percentile of page loads, segmented across mobile and desktop.
In short
Core Web Vitals describe, with three numbers, how a page behaves for the user. web.dev defines these three metrics as the subset of Web Vitals that apply to all web pages.
- LCP (Largest Contentful Paint): the moment the largest image or text block in the viewport has been painted. Measures loading.
- INP (Interaction to Next Paint): how quickly the screen responds after clicks, taps and key presses. Measures interactivity.
- CLS (Cumulative Layout Shift): how much content shifts unexpectedly. Measures visual stability.
These metrics look like they come from a developer report. To me, each one is a measured user complaint: “The page won’t load”, “I pressed it, but nothing happened”, “I clicked the wrong thing”.
Thresholds for LCP, INP and CLS
web.dev gives two limits for each metric. If the value is at or below the good limit, it counts as good; if it’s above the poor limit, as poor. In between is the “needs improvement” range.
| Metric | Good | Needs improvement | Poor |
|---|---|---|---|
| LCP | up to 2.5 s | 2.5 s to 4 s | over 4 s |
| INP | up to 200 ms | 200 ms to 500 ms | over 500 ms |
| CLS | up to 0.1 | 0.1 to 0.25 | over 0.25 |
The table comes from the web.dev article on thresholds, last updated May 7, 2025. The main Web Vitals page (last updated October 31, 2024) gives the same good limits.
The 75th-percentile rule
The thresholds don’t apply to a single measurement. web.dev recommends looking at the 75th percentile of page loads and assessing mobile and desktop separately.
In practice, you read it like this: if at least 75 percent of page views meet the good limit, the result is good. If at least 25 percent of page views fall in the poor range, the result is poor.
I like this rule because it makes visible the user the average hides. On a fast office network, everything can look good. Someone with an old phone and a weak connection sees a very different page.
Enter your own values below. The labels use the limits from the table above.
Good
Good
Good
Move a slider and read the result here.
This tool needs JavaScript. The thresholds are in the table above.
The labels use the web.dev thresholds: a value exactly on the good limit counts as good, a value above the poor limit as poor. I chose the slider ranges. Don’t enter a single measurement here; enter the 75th percentile of visits.
LCP: when does the page look ready?
LCP is the moment the largest image, video or text block in the viewport has been painted. It’s the moment the user says, “The page is here.” On a product page, this might be the product photo; in an article, the heading or the first paragraph.
According to web.dev, img elements, image elements inside an SVG and video elements can be LCP candidates. Background images loaded with the CSS url() function and block-level elements containing text count too. Gradient backgrounds don’t.
In my audit experience, some LCP problems start at the design table. A heavy video on the first screen or a heading that depends on a late-loading font are examples.
web.dev recommends for LCP:
- The hero image is in the HTML source itself, so the browser finds it without waiting for JavaScript.
- The hero image doesn’t get lazy loading (
loading="lazy"). According to web.dev, this always leads to unnecessary delay. - The hero image gets
fetchpriority="high". web.dev recommends giving this priority to only one or two images. - If the LCP element is text in a web font, the font is loaded in the HTML with
rel="preload", so the browser discovers it early.
These points sound like developer work. But which element becomes the LCP is decided in design. A single, clear hero image on the first screen makes the developer’s job easy.
INP: I pressed it. Did anything happen?
INP measures how a page responds to user interactions overall. Mouse clicks, taps on touchscreens and key presses are counted. Hovering, zooming and scrolling aren’t.
web.dev defines INP as the successor to the FID (First Input Delay) metric. FID only measured the input delay of the first interaction on the page.
In its announcement, web.dev wrote that INP would become a Core Web Vital on March 12, 2024, replacing FID. A note added to the page later says that INP has officially replaced FID.
From the user’s side, INP answers a simple question: did what I pressed work? If the screen doesn’t respond, people press a second time or assume the page has frozen.
The Doherty threshold complements INP well. The Doherty threshold looks at the system’s response time, INP at the screen’s first reaction. My lesson from both is the same: show users right away that you’re making them wait.
Long tasks
According to web.dev, any task that takes longer than 50 milliseconds is a long task. While it runs, it blocks the main thread.
web.dev recommends breaking long tasks into small pieces and yielding to the main thread between them. That way, the browser can respond much sooner to more important work, such as a user interaction.
The designer’s job is to define that first reaction. Design a state that changes immediately after the press, or a loading indicator. While the heavy work runs in the background, the screen tells the user: “Got it.”
CLS: the sliding page and the misclick
CLS measures the largest burst of unexpected layout shifts while the page is open. web.dev puts it like this: a shift is only bad if the user doesn’t expect it. Shifts within 500 milliseconds of user input can be excluded from the calculation.
According to web.dev, unexpected shifts usually happen when resources load asynchronously or new elements are added to the page above existing content. The article names these causes:
- Images and videos with unknown dimensions.
- Web fonts that render larger or smaller than the fallback font.
- Third-party ads and widgets that dynamically resize themselves.
For the user, CLS means a lost reading position and misclicks. On a checkout page, clicking an ad or Cancel instead of the confirm button is the most expensive kind of shift.
Below, first load the ad with “Reserve space” off and get ready to click “Confirm order” before the ad appears. Then turn “Reserve space” on and do it again.
Cart
2 items, total incl. shipping $89.90
This example needs JavaScript. Without JavaScript, no ad loads and the buttons stay where they are.
The cart, the ad and the amounts are made up. The ad arrives with a 2-second delay so you can see the shift. I move the buttons with CSS transform and keep the box height fixed, so this page itself doesn’t shift.
Reserving space is often a single line of code: giving the ad area a min-height. web.dev names this as one approach for ads and embeds. It also recommends placing late-loading content lower in the viewport so it affects CLS less.
Fixes on the design side
Some of these metrics are won or lost in the design file. These are the points I look at in audits.
Image sizes
Set the aspect ratio for every image and video in the design. web.dev recommends using the width and height attributes on every image and video element. The other way is to reserve the space with CSS aspect-ratio.
For images that users upload or that come from the admin area, the ratio varies. Define a fixed frame and a cropping rule for them in the design.
Skeleton screens
For late-loading content, design a skeleton the same size as the content that’s coming. web.dev recommends reserving space for loaded-in UI in advance with a placeholder or skeleton UI. When the content arrives, the page doesn’t shift, and the user sees what’s coming.
What I watch for: the skeleton must have the same height as the real content. If a five-line text arrives instead of a three-line skeleton, the page shifts anyway.
Font loading
While a custom font loads, the browser may show the fallback font first. If the metrics differ, the lines change and the page shifts. Choose a fallback font whose metrics are close to the custom font.
web.dev recommends font-display: optional to avoid re-layouts, and preloading critical fonts. I also reduce the font weights in the design, because each weight is a separate file.
A first reaction for heavy interactions
For interactions such as filtering, adding to cart or submitting a form, design the first reaction on its own. The button switches to the pressed state right away; the result follows. Ask the developer to paint this reaction before the heavy work.
Who fixes what?
When I hand the report out to the team, I split the work like this. This table isn’t from web.dev; it shows my own way of working.
| Metric | In design | In code |
|---|---|---|
| LCP | One hero image on the first screen, a light choice of fonts | Image in the HTML, priority, no lazy loading |
| INP | Pressed state, loading indicator, optimistic update | Break up long tasks, paint the first reaction first |
| CLS | Fixed image ratios, skeletons, space for banners | Size attributes, min-height, font-loading setting |
Animations
When you design motion, don’t move elements with top or left; use transform. web.dev recommends transform animations to translate, scale, rotate and skew. That’s why I built the demo above with transform too.
How do you measure it?
Core Web Vitals are assessed with real user data. The Chrome User Experience Report (CrUX) collects anonymized data from real users for each metric. This data powers PageSpeed Insights, Chrome DevTools and the Core Web Vitals report in Search Console.
As lab tools, web.dev names Chrome DevTools and Lighthouse. Lighthouse can’t measure INP because there is no user input. In the lab, Total Blocking Time (TBT) serves as a proxy for INP.
To collect your own measurements, web.dev names the web-vitals JavaScript library as the easiest way. I use both sources together: field data shows whether there is a problem, and lab measurements show the cause.
My note
I read Core Web Vitals like a counter for three user complaints. If I see a poor LCP in the report, I look at the first screen first. What does the user see there first, and why does it arrive so late?
The most common cause of shifts in my audits is banners that appear afterwards. A cookie notice or a promo strip slides in at the top and pushes everything down. Reserving space for them from the start, or pinning them to the bottom of the screen, is usually enough.
On this site, I keep a stricter mobile budget than the web.dev good limits: at the 75th percentile, LCP under 2 seconds, INP under 150 milliseconds, CLS under 0.05. If you stay just under the limit, you quickly go over it on slow devices.
A fast page doesn’t rescue a bad flow. The form opens in a second, and the user still gets stuck on the error message. That’s why I treat Core Web Vitals as part of a flow review.
In ecommerce UX work, I look at the checkout page and the product detail page first. If you want to see these three metrics together with design decisions, the UX audit looks at them too. I describe how the process works in the UX audit guide.
Questions
What are Core Web Vitals?
Core Web Vitals are three metrics that web.dev defines for all web pages. LCP measures loading, INP responsiveness to interactions and CLS visual stability.
What are good values for LCP, INP and CLS?
According to web.dev, LCP up to 2.5 seconds, INP up to 200 milliseconds and CLS up to 0.1 are good. If LCP is over 4 seconds, INP over 500 milliseconds or CLS over 0.25, the value is poor.
When did INP replace FID?
In its announcement, web.dev wrote that INP would become a Core Web Vital on March 12, 2024, replacing the First Input Delay (FID) metric. A note added later says that INP has officially replaced FID.
What does the 75th percentile mean?
The threshold applies not to a single measurement but to the distribution of visits. If at least 75 percent of page views meet the good limit, the result is good. Mobile and desktop are assessed separately.
Does the designer or the developer fix Core Web Vitals?
Both together. Image sizes, skeleton screens, font choices and the first reaction to an interaction are set in design. Prioritization, loading order and breaking up long tasks happen in code.
Sources (9)
- Philip Walton, Web Vitals, web.dev. May 4, 2020; last updated October 31, 2024; accessed November 4, 2026; three metrics, 75th percentile, measurement tools, TBT
- Bryan McQuade, Barry Pollard, Defining the Core Web Vitals metrics thresholds, web.dev. May 21, 2020; last updated May 7, 2025; accessed November 4, 2026; good, needs improvement and poor thresholds
- Philip Walton, Barry Pollard, Largest Contentful Paint (LCP), web.dev. August 8, 2019; last updated September 4, 2025; accessed November 4, 2026
- Jeremy Wagner, Barry Pollard, Interaction to Next Paint (INP), web.dev. May 6, 2022; last updated September 2, 2025; accessed November 4, 2026; counted interactions, successor to FID
- Milica Mihajlija, Philip Walton, Cumulative Layout Shift (CLS), web.dev. last updated April 12, 2023; accessed November 4, 2026; causes of shifts, 500 ms rule
- Jeremy Wagner, Rick Viscomi, Interaction to Next Paint becomes a Core Web Vital on March 12, web.dev Blog. last updated January 31, 2024; accessed November 4, 2026; announcement that INP replaces FID on March 12, 2024, and the note added later
- Addy Osmani, Barry Pollard, Optimize Cumulative Layout Shift, web.dev. May 5, 2020; last updated February 7, 2025; accessed November 4, 2026; size attributes, min-height, skeleton, fonts, transform
- Philip Walton, Barry Pollard, Optimize Largest Contentful Paint, web.dev. April 30, 2020; last updated March 31, 2025; accessed November 4, 2026; discoverability in the HTML, lazy loading, fetchpriority
- Jeremy Wagner, Brendan Kenny, Optimize long tasks, web.dev. September 30, 2022; last updated December 19, 2024; accessed November 4, 2026; definition of a long task as 50 ms