A site can score well in Lighthouse and still fail Core Web Vitals in Search Console, or the other way around. It is not a bug: Lighthouse loads your page once, on a simulated device; Search Console summarizes what your real visitors experienced over the last few weeks.
Passing is not trivial. According to Chrome's data (CrUX) for September 2026, 55.9% of the 18.4 million origins measured had good Core Web Vitals. LCP fails most often: 68.3% were "good", versus 81.7% for CLS and 85.4% for INP.
This guide explains what they measure, how to measure them, how much they weigh in Search and what to fix first, based on Google and Chrome official documentation reviewed in November 2026.
The three metrics and their thresholds
Metric | What it measures | Good | Needs improvement | Poor |
|---|---|---|---|---|
LCP (Largest Contentful Paint) | When the largest visible element is painted: image, video or text block | up to 2.5 s | up to 4 s | over 4 s |
INP (Interaction to Next Paint) | How long the page takes to respond visually to clicks, taps and key presses | up to 200 ms | up to 500 ms | over 500 ms |
CLS (Cumulative Layout Shift) | How much content moves unexpectedly | up to 0.1 | up to 0.25 | over 0.25 |
Three details that change how to read them:
- They are assessed at the 75th percentile, separately for mobile and desktop. A page passes if all three are "good" at that percentile. Google chose the 75th percentile to reflect the most frustrating experiences, not the average.
- INP is not an average. It is the slowest interaction of the visit, ignoring the highest one for every 50 interactions; since most visits don't reach 50, the worst one is almost always reported. Scrolling, zooming and hovering don't count.
- INP replaced FID on March 12, 2024. FID only measured the first interaction. In September 2024 FID was removed from CrUX, and the
web-vitalslibrary removedonFID()in version 5, released in May 2025. If your dashboard still shows FID, it measures something Google no longer uses.
Did anything change in 2026?
The thresholds did not. According to web.dev, stable metrics don't change more than once per year and every change is announced in their documentation; the CrUX release notes for 2025 and 2026 record no threshold changes. If you read that the good LCP threshold dropped to 2 seconds, ask for the official source: we could not find one.
What is new: on October 13, 2026, CrUX published experimental variants of LCP, INP and CLS that include the "soft navigations" of single-page applications (SPAs). Stable scores don't change while they are evaluated; Google aims to graduate them from experimental in May 2027, and Search Console will then switch to them. If your site is an SPA, review them now.
Field data and lab data
Field data comes from real visits. Google's source is CrUX: PageSpeed Insights shows its data for the previous 28 days, and the Search Console report is also based on CrUX. It only includes Chrome users on desktop and Android who meet certain conditions (not Chrome on iOS or Edge), and the page must be public and have enough visits.
Lab data is a simulated load on a single device and a single network. That is what Lighthouse does, and it is useful for diagnosis.
Why they differ, according to web.dev:
- The lab loads with an empty cache; your returning visitors don't.
- A different screen size or personalized content changes which element is the LCP.
- Pages restored from the back/forward cache (bfcache) load almost instantly and only count in the field.
- In the field people interact and trigger layout shifts that an automated test doesn't.
- Lighthouse cannot measure INP because nobody interacts. It uses TBT (Total Blocking Time), which web.dev considers a reasonable proxy, not a substitute.
The official rule: if you have both, prioritize with field data.
How to measure
PageSpeed Insights
Paste the URL into PageSpeed Insights. Field data is at the top; if the URL doesn't have enough, the tool uses data for the whole origin, so check which level you are looking at. The Lighthouse diagnosis is below: use it to find causes, not to decide whether you pass.
Search Console
The Core Web Vitals report groups similar URLs and assigns them the worst status of their metrics: poor CLS with LCP that needs improvement is labeled "poor". A URL only appears if it has LCP and CLS data. After fixing, click "Start tracking": validation takes 28 days.
The web-vitals library
To measure with your own users, including those on Safari and Firefox, use web-vitals, from Google. As of November 4, 2026 the current version on npm is 6.2.3:
// npm install web-vitals
import {onCLS, onINP, onLCP} from 'web-vitals';
function sendToAnalytics(metric) {
const body = JSON.stringify({
name: metric.name, // 'CLS', 'INP' or 'LCP'
value: metric.value,
rating: metric.rating, // 'good', 'needs-improvement' or 'poor'
id: metric.id, // use it to deduplicate reports
navigationType: metric.navigationType,
page: metric.navigationURL ?? location.href,
});
// sendBeacon sends even while the page is closing
navigator.sendBeacon('/analytics', body);
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);- Call each function only once per page.
- A report can arrive more than once: CLS and INP are sent every time the page goes to the background. Keep the last value per
id. Going back with the back button produces new metrics, with a differentid. - If the values are bad, import from
web-vitals/attribution: each metric carries clues about the cause, such as the LCP element or the script that delayed an interaction. onCLS()only works in Chromium-based browsers; LCP and INP are also measured in Firefox and Safari.
How much do they weigh in Google?
What Google says in its Search Central documentation:
- Its ranking systems use Core Web Vitals. Other page experience aspects don't directly help you rank, and there is no single "page experience signal".
- Google seeks to show the most relevant content even if the page experience is sub-par. But when there is lots of helpful content for a query, a good experience can contribute.
- Good results in Search Console don't guarantee the top spot, and chasing a perfect score just for SEO may not be the best use of your time.
- Evaluation is generally page-specific, although there are some site-wide assessments.
In short: they don't make up for irrelevant content, but among similar results they can matter.
What to fix for LCP
web.dev breaks LCP into four parts: time to first byte (TTFB), delay before the resource starts loading, download duration, and delay before it is painted. Ideally almost all the time goes to TTFB and download, with minimal delays.
- The main image has no priority. Use
fetchpriority="high"on the image that is likely to be the LCP, and on no more than one or two. In a Google test on Google Flights, this attribute lowered LCP from 2.6 to 1.9 seconds. - The LCP image is lazy-loaded. Never use
loading="lazy"on it. - The browser discovers it late. If it is inserted with JavaScript, sits in
data-srcor is a CSS background, put it in the initial HTML or preload it with<link rel="preload">. - Render-blocking resources. Synchronous scripts in the
<head>and unnecessary CSS delay the first paint: defer what is not critical and useasyncordefer. Since Lighthouse 13 this appears as "Render-blocking requests". - Slow server. A high TTFB can make reaching 2.5 s hard or impossible. web.dev suggests 0.8 s or less as a guide: review your hosting, use a CDN with caching and remove chained redirects.
<img src="/img/hero.webp" width="1200" height="630"
alt="Image description" fetchpriority="high">What to fix for INP
An interaction has three phases: input delay, event handler processing, and the delay until the next frame is painted.
- Long tasks. Any task over 50 ms; while it runs, the browser can't respond. Split the work and yield control between parts.
- Third-party JavaScript. Chat widgets, pixels and embeds compete for the same thread. Load them with
asyncordeferunless they are critical, and remove those that don't add clear value. - Heavy handlers. Do the visible work first and defer the rest, such as saving or sending analytics.
- Expensive rendering. A very large DOM or generating lots of HTML on the client lengthens the last phase.
web.dev suggests yielding with scheduler.yield() plus a fallback for browsers without support:
function yieldToMain() {
if (globalThis.scheduler?.yield) {
return scheduler.yield();
}
return new Promise((resolve) => setTimeout(resolve, 0));
}
async function save() {
validateForm();
showSpinner();
await yieldToMain(); // the browser paints before continuing
saveToServer();
sendAnalytics();
}What to fix for CLS
- Images and videos without dimensions. Always include
widthandheight, or useaspect-ratio. - Ads, embeds and iframes. Reserve their space with
min-heightoraspect-ratio. If no ad is returned, leave a placeholder: collapsing the gap also causes a shift. - Content inserted at the top. Banners and notices that push content down: the higher they are, the bigger the shift usually is. Reserve the space or overlay them.
- Web fonts. If the final font has different metrics than the fallback, text jumps. Use
font-display: optional, a suitable fallback font adjusted withsize-adjust, and preload critical fonts. - Animations. Use
transform, nottoporleft.
Shifts within 500 ms after a click, tap or key press don't count, because the user expects them.
Order of work
- Look at field data: which metric fails, on which device and in which group of pages.
- Start with what is "poor" on the templates with the most traffic. A fix in one template improves many URLs at once.
- Install web-vitals with attribution to learn which element, script or interaction causes the problem.
- Apply the cheap fixes: dimensions on images,
fetchpriorityon the LCP image, noloading="lazy"on it, andasyncordeferon third-party scripts. - Tackle the structural issues: TTFB, long tasks, JavaScript weight and fonts.
- Validate in Search Console and wait the 28 days.
Checklist
Check | Metric |
|---|---|
Your dashboards report INP, not FID | INP |
The LCP image is in the initial HTML, with | LCP |
TTFB around 0.8 s or less: hosting, CDN, caching, no chained redirects | LCP |
Third-party scripts with | INP |
Images and videos with | CLS |
Space reserved for ads, embeds and banners | CLS |
Your own measurement with web-vitals, reviewing the 75th percentile by device | All |
If it is an SPA, review of the experimental metrics with soft navigations | All |
Sources
- web.dev · Web Vitals
- web.dev · Largest Contentful Paint (LCP)
- web.dev · Interaction to Next Paint (INP)
- web.dev · Cumulative Layout Shift (CLS)
- web.dev · INP becomes a Core Web Vital on March 12 and INP is officially a Core Web Vital
- web.dev · Experimental soft navigation metrics now available in CrUX
- web.dev · Why lab and field data can be different
- web.dev · Total Blocking Time (TBT)
- web.dev · Optimize LCP
- web.dev · Fetch Priority API
- web.dev · Time to First Byte (TTFB) and Optimize TTFB
- web.dev · Optimize INP and Optimize long tasks
- web.dev · Efficiently load third-party JavaScript
- web.dev · Optimize CLS
- Chrome for Developers · CrUX methodology and CrUX release notes
- Chrome for Developers · Eliminate render-blocking resources
- Google · About PageSpeed Insights
- Google Search Central · Understanding page experience and Core Web Vitals
- Search Console Help · Core Web Vitals report
- GoogleChrome/web-vitals (README and CHANGELOG) and web-vitals on npm
If you want to review your site's metrics and decide what to fix first, let's talk.