Three metrics still drive how Google evaluates user experience: LCP, INP and CLS. Their “good”, “needs improvement” and “poor” thresholds haven’t changed since the last update to web.dev’s official documentation, despite persistent rumors of a tightening sometime in 2026. What has changed is how easily a poorly run audit produces a wrong diagnosis — and sends optimization effort in the wrong direction.
The three metrics and their official thresholds
Each metric is evaluated at the 75th percentile of page loads, measured separately for mobile and desktop. A site only counts as “good” on a metric if 75% of its real visits fall under the “good” threshold, not just its average.
| Metric | Good | Needs improvement | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤ 2.5 s | 2.5 s – 4 s | > 4 s |
| INP (Interaction to Next Paint) | ≤ 200 ms | 200 ms – 500 ms | > 500 ms |
| CLS (Cumulative Layout Shift) | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |
INP replaced FID (First Input Delay) as the official responsiveness metric in March 2024. Unlike FID, which only measured the delay before the first interaction started processing, INP looks at every interaction in a session and keeps the worst representative value — a far stricter calculation for JavaScript-heavy interfaces.
Measuring: field data versus lab data
The most common mix-up is auditing a site with Lighthouse or PageSpeed Insights in “lab” mode only, then announcing a score, while Google actually ranks pages on field data from the Chrome User Experience Report (CrUX) and real users who opted into telemetry reporting.
- Lab data (Lighthouse, WebPageTest): a reproducible simulation on a standardized machine and network. Useful for debugging, not for judging ranking impact.
- Field data (Search Console’s “Core Web Vitals” report, PageSpeed Insights’ “real user experience” tab, CrUX directly): only this reflects what Google actually uses for ranking.
A site can show an excellent local Lighthouse score while still scoring “poor” on INP in production, simply because its real visitors are on entry-level devices or a degraded mobile connection that the lab test never reproduces.
For teams that want to track both sources without juggling three separate dashboards, the PageSpeed Insights API returns lab data (a fresh Lighthouse run) and field data (the latest CrUX snapshot for that URL and its origin) in a single JSON response, which makes it straightforward to feed a weekly report or an internal dashboard without manually exporting anything from Search Console.
Reducing LCP
LCP measures how long it takes to render the largest visible element in the initial viewport — usually a hero image, a headline, or a text block. The most effective levers, roughly in order of typical impact:
- Preload the critical resource with
<link rel="preload">instead of letting the browser discover it late. - Serve pre-sized, compressed images in AVIF or WebP, with
fetchpriority="high"on the LCP element. - Cut server response time (TTFB), often overlooked even though it sets the starting point for the entire timeline.
- Remove render-blocking resources (synchronous CSS and JavaScript) above the fold.
Reducing INP
INP degrades when the main thread stays busy too long after an interaction — a click, a keystroke, a tap — before the browser can paint the result. The fix is almost never “speeding up” one isolated function, but breaking work into chunks so the main thread can breathe:
import {onINP} from 'web-vitals';
onINP((metric) => {
// Logs each measured interaction, with the culprit element
console.log('INP:', metric.value, metric.attribution.interactionTarget);
navigator.sendBeacon('/analytics/web-vitals', JSON.stringify(metric));
});
The official web-vitals library exposes an attribution field that identifies the DOM element responsible for the slowest interaction — often more useful for real debugging than an isolated Lighthouse score. Common fixes include breaking up long tasks with scheduler.yield(), deferring non-critical JavaScript until after the user’s first interaction, and cutting the rendering work triggered by each state update.
Stabilizing CLS
CLS penalizes unexpected layout shifts after the first render: an image with no reserved dimensions, a font swap that lands late, an ad banner injected above content the user has already started reading. Reserving space ahead of time, through explicit width/height attributes or a CSS Subgrid layout with pre-sized tracks, avoids most regressions. For animations, stick to transform and opacity, which never trigger a layout recalculation — a principle central to the best practices covered in the guide on scroll-driven CSS animations, where even a small layout shift breaks the effect as much as the score.
A site can show an excellent local Lighthouse score while still being ranked “poor” in production: only field data counts toward ranking.
Prioritizing with CrUX data
Before launching a rebuild, it helps to know whether a problem touches the whole site or a single template. The public CrUX dataset, queryable for free through BigQuery or the CrUX History API, tracks the monthly evolution of all three metrics by origin or by URL, segmented by effective connection type (4G, 3G) and form factor. Comparing a site’s own trend against a direct competitor’s, over the same period, helps separate a site-specific regression from a broader seasonal effect (a shift in device behavior, load on a shared CDN, and so on).
To keep a regression from slipping by unnoticed between two monthly audits, a performance budget set directly in continuous integration remains the most reliable approach: the build fails if the simulated LCP exceeds a fixed threshold, before the change ever reaches production.
{
"ci": {
"assert": {
"assertions": {
"largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
"total-blocking-time": ["warn", {"maxNumericValue": 300}]
}
}
}
}
This Lighthouse CI configuration doesn’t replace field measurement — it stays a lab-level safety net — but it keeps a crude regression (an uncompressed image slipped into a commit, a third-party script added without async) from reaching production unnoticed.
What to remember
The thresholds themselves are stable and well documented; what actually makes the difference is measurement discipline. Audit on field data, isolate the specific page template actually at fault before acting, and treat LCP, INP and CLS as three distinct problems, with three distinct technical levers, rather than one score to push up.
The habit I recommend to every client: stop running Lighthouse in a loop and open the Search Console report once a month, no more. Core Web Vitals optimization is one of those topics where you can easily burn entire days chasing a lab score that never reflects what real visitors experience — a structural fix (sized images, self-hosted fonts, chunked JavaScript) beats a string of micro-tweaks guided by an audit that isn’t measuring the right thing. — Simon Janvier
To go further: the official documentation and full methodology are available on web.dev.
