Core Web Vitals are three numbers Google measures from real visitors to your site, and they feed into ranking. Not heavily — content and relevance dominate — but they are a genuine tiebreaker between comparable pages, and they are also just a decent proxy for whether your site is pleasant to use.

The three, and what each actually means:


Measures

Good

Poor

LCP — Largest Contentful Paint

How long until the main content appears

≤ 2.5s

> 4.0s

INP — Interaction to Next Paint

How long the page takes to respond when tapped

≤ 200ms

> 500ms

CLS — Cumulative Layout Shift

How much things jump around while loading

≤ 0.1

> 0.25

You need to hit "good" on all three, for 75% of visits, to pass. And in 2026 the one most sites fail is INP.

Start here: field data, not your Lighthouse score

The single most common mistake is optimising the wrong number.

Lab data — Lighthouse, PageSpeed Insights' score, your local audit — is a simulation on a synthetic device and network. Useful for diagnosis. It is not what Google uses.

Field data — the Chrome UX Report — is real Chrome users on real devices on real networks. That is what counts for ranking.

They routinely disagree, and in a specific direction: your Lighthouse score is generated by a simulated page load that never touches anything. It cannot produce a meaningful INP at all, because nobody interacted with the page.

So: open PageSpeed Insights and read the top section, "Discover what your real users are experiencing". If it says there is not enough data, your site has too little traffic for CRUX, and Vitals are not currently a ranking concern for you — spend the effort on content instead.

INP: the one that fails

INP replaced FID in March 2024, and it is a much harder test. FID measured only the delay before an event handler started. INP measures the whole thing: input delay, handler execution, and the rendering of the next frame. It reports roughly the worst interaction of the visit.

A site could pass FID with 30 ms and fail INP at 600 ms, because FID never measured the 570 ms of work that happened after the handler began.

What causes bad INP, in order of how often it is the culprit:

  1. Too much JavaScript on the main thread. The browser is single-threaded for JS and rendering. A long task blocks the tap.
  2. Third-party scripts. Analytics, chat widgets, heatmaps, ad scripts, tag managers. These are usually the biggest single contributor and the least examined.
  3. Expensive event handlers. A click that triggers a large re-render, or a scroll handler doing layout work on every frame.
  4. Large DOM. Tens of thousands of nodes make every style recalculation expensive.

What actually fixes it:

  • Remove third-party scripts you cannot justify. Not defer — remove. Audit what is on the page and what each one is for. Most sites are running at least one tag nobody remembers adding.
  • Defer what is left. Anything not needed for the first interaction loads after it.
  • Break up long tasks. Yield to the main thread between chunks of work rather than doing it all at once.
  • Ship less JavaScript. On React, that means moving work to the server — Server Components exist substantially for this reason.
  • Give immediate visual feedback. Even when work is genuinely slow, painting a pressed state or a spinner in the next frame improves the measured interaction and, more importantly, the felt one.

LCP: the one most people already work on

LCP is when the biggest element above the fold finishes rendering — usually the hero image, sometimes a heading block.

It decomposes into four parts, and knowing which one is yours saves a lot of guesswork:

  1. Time to First Byte. The server. If TTFB is 800 ms you cannot have a 2.5 s LCP without heroics. Fix the host first — speeding up WordPress and choosing shared hosting both cover this.
  2. Resource load delay. The gap between the HTML arriving and the browser starting to fetch the LCP image. Almost always because the image is discovered late — in CSS, in JavaScript, or lazily.
  3. Resource load time. The image download itself. Size and format.
  4. Render delay. The image is downloaded but blocked from painting by a render-blocking stylesheet or font.

The fixes, in order of effect:

  • Never lazy-load the LCP image. This is the most common self-inflicted LCP failure. loading="lazy" on a hero image directly delays the metric.
  • Preload it, so the browser fetches it immediately rather than after parsing CSS.
  • Serve modern formats — WebP or AVIF, sized for the actual display width.
  • Fix TTFB if it is the dominant component. No front-end work compensates for a slow origin.
  • Watch fonts. font-display: swap prevents an invisible-text period; a heading rendered in a fallback and then swapped is far better for LCP than nothing rendered at all.

CLS: the easiest to fix, the most annoying to experience

CLS measures content jumping while the page loads. It is the one users complain about without knowing its name — the tap that lands on the wrong thing because an ad loaded.

Four causes, and all four have the same shape of fix: reserve the space in advance.

  1. Images without dimensions. Always set width and height, or an aspect-ratio. The browser then reserves the box before the file arrives.
  2. Ads and embeds. Give the container a fixed minimum height. An ad slot that appears from nothing pushes everything below it down — this is exactly why the ad units on this site reserve their height before the script runs.
  3. Web fonts. A fallback with different metrics reflows the text on swap. size-adjust and the ascent-override descriptors reduce it.
  4. Content injected at the top. Cookie banners, promotional strips, notification bars. Either reserve space or overlay rather than insert.

A caution from experience. This site once shipped a particle-animation container that briefly grew to a full viewport before its canvas became position: fixed, pushing the entire page down and then snapping back. Measured CLS: 1.05 — ten times the failing threshold. The fix was one line sizing the container to zero, and it took the page to 0.02. The lesson generalises: anything that mounts after paint should occupy its final space from the start.

A practical order of work

Do not optimise all three at once. Work the field data.

  1. Get field data. No CRUX data means no ranking impact yet; go and write content instead.
  2. Find the failing metric. Usually INP.
  3. For INP: audit third-party scripts first. It is the biggest lever and the least fun, which is why it gets skipped.
  4. For LCP: check whether the hero image is lazy-loaded, then check TTFB. Those two are most of it.
  5. For CLS: add dimensions to images and reserve space for anything that appears late.
  6. Re-measure after 28 days. CRUX is a rolling 28-day window, so a fix deployed today does not show fully for four weeks. This is where people panic and change five more things.

What is not worth your time

  • Chasing a Lighthouse score of 100. It is a lab simulation with weights that do not match the field thresholds. A site at 100 can fail Vitals, and a site at 70 can pass comfortably.
  • Micro-optimising past the threshold. These are pass/fail bands, not a continuous ranking scale. LCP at 1.2 s ranks no better than LCP at 2.4 s.
  • Rewriting your site "for performance" before measuring which metric is failing and why. Most Vitals problems are three specific things, not an architecture.

If the measurement and the fixing are not a good use of your week, we do this as a service too, in both English and Bangla.

Measuring your own visitors, not Google's sample

Field data from the Chrome UX Report is what Google ranks on, but it has two limits: it is a 28-day rolling average, and it only covers Chrome users on sites with enough traffic. That makes it a poor debugging tool — by the time it moves, you have forgotten what you changed.

The fix is to measure your own, with the same API browsers report from:

html
<script type="module">
  import { onLCP, onINP, onCLS } from 'https://unpkg.com/web-vitals?module'
  const send = m => navigator.sendBeacon('/vitals', JSON.stringify({
    name: m.name, value: m.value, rating: m.rating, path: location.pathname,
  }))
  onLCP(send); onINP(send); onCLS(send)
</script>

That gives you three things CRUX cannot:

Per-page numbers. CRUX reports at origin level and, for popular pages, per URL. Your own data tells you that one template is dragging the average down, which is usually the whole answer.

Immediate feedback. You see the effect of a deploy the same day rather than in four weeks.

The attribution. The web-vitals library's attribution build reports which element was the LCP and which interaction was the worst INP. That converts "INP is 480ms" into "the filter dropdown on the listing page takes 480ms", which is something you can actually fix.

Send it wherever you already send analytics. The volume is small, and it turns Core Web Vitals from a quarterly report card into an ordinary engineering metric you can act on.

Frequently asked questions

What is a good INP score in 2026? 200 milliseconds or less at the 75th percentile of real visits. Above 500 ms is poor. INP replaced FID in March 2024 and is considerably harder to pass, because it measures the full interaction including the next paint rather than only the initial delay.

Why is my PageSpeed score high but Core Web Vitals failing? Because they measure different things. The score is a lab simulation; Core Web Vitals assessment uses field data from real Chrome users. Lab tests also cannot measure INP meaningfully, because nothing interacts with the page.

Do Core Web Vitals actually affect rankings? Yes, as part of the page experience signals — but modestly. Relevance and content quality dominate. Treat them as a tiebreaker between comparable pages, and as a genuine user-experience measure in their own right.

How long until fixes show up? Field data is a rolling 28-day window, so a fix deployed today takes about four weeks to be fully reflected. Deploy, then wait, then re-measure — do not stack five more changes in between.

What causes bad CLS? Images without width and height, ads and embeds that appear without reserved space, font swaps that reflow text, and content injected above existing content. All are fixed by reserving the space before the element arrives.

Does my site have enough traffic to be measured? If PageSpeed Insights shows no field data, your site is below the threshold for the Chrome UX Report. Core Web Vitals then have no measurable ranking effect for you, and your effort is better spent on content.