How to Improve Core Web Vitals: A Practical Guide for Faster Websites
A practical guide to LCP, INP and CLS: what the thresholds mean, how to measure with field and lab data, concrete fixes with code, and how to keep performance from regressing.
⚡ Key takeaways
- Core Web Vitals are LCP (loading), INP (responsiveness) and CLS (visual stability); INP replaced FID in March 2024.
- Google assesses the 75th percentile of real-user visits, so field data matters more than a single Lighthouse score.
- Most wins come from a few fixes: prioritizing the hero image, shipping less JavaScript, breaking up long tasks and reserving space for content.
- Performance regresses quietly; budgets, CI checks and real-user monitoring keep it fixed.
If you want to improve Core Web Vitals, start by understanding what each metric measures and where your real users are struggling. Chasing a perfect lab score without that context often leads to effort spent on the wrong problem, while the pages that drive revenue stay slow.
This guide covers the three metrics and their thresholds, how to measure them correctly, concrete fixes for each one (with code), notes for Next.js and React teams, and how to stop performance from regressing after you have fixed it.
What Core Web Vitals measure
Core Web Vitals are Google’s user-centric metrics for page experience. Each one targets a different part of how a page feels to a visitor. Google’s web.dev guide to Web Vitals is the authoritative reference for definitions and thresholds.
| Metric | What it measures | Good | Needs improvement | Poor |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | Time until the largest image or text block in the viewport renders | ≤ 2.5 s | 2.5 – 4.0 s | > 4.0 s |
| INP (Interaction to Next Paint) | Delay between a user interaction and the next visual update, across the visit | ≤ 200 ms | 200 – 500 ms | > 500 ms |
| CLS (Cumulative Layout Shift) | How much visible content moves unexpectedly while the page is in use | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |
A page passes when at least 75% of visits meet the “good” threshold for all three metrics, measured separately for mobile and desktop. That 75th percentile rule is why a fast experience on your office laptop says little about a mid-range phone on a patchy connection.
Why INP replaced FID
First Input Delay (FID) only measured the delay before the browser started handling the first interaction. Interaction to Next Paint (INP) became a Core Web Vital in March 2024 and looks at interactions throughout the visit, including the time to process them and paint the result. Pages that passed FID easily can fail INP if they run heavy JavaScript after load.
How to measure Core Web Vitals: field vs lab data
There are two kinds of data, and you need both.
- Field data comes from real users. The Chrome UX Report (CrUX) aggregates it from opted-in Chrome users over a rolling 28-day window. This is what Google uses for page experience.
- Lab data comes from a simulated load in a controlled environment, such as Lighthouse. It is repeatable and great for debugging, but it cannot fully reproduce real devices, networks or interactions.
Tools to use
- PageSpeed Insights shows CrUX field data for a URL or origin alongside a Lighthouse lab run. Start here.
- Search Console’s Core Web Vitals report groups URLs with similar issues across your whole site, so you can prioritize templates rather than single pages.
- Chrome DevTools Performance panel lets you record loads and interactions to find long tasks, layout shifts and the LCP element.
- Real-user monitoring (RUM) with the open-source
web-vitalslibrary sends metrics from your own visitors to your analytics, with attribution data that points to the element or script responsible.
Lab tools cannot measure INP directly because there is no real user interacting. Total Blocking Time (TBT) in Lighthouse is a useful proxy, but confirm INP with field data.
How to fix LCP (Largest Contentful Paint)
LCP breaks down into four parts: time to first byte, resource load delay, resource load duration and element render delay. Find which part is largest before choosing a fix.
- Reduce server response time: cache HTML at the edge, use a CDN, and avoid slow database queries or API waterfalls during server rendering.
- Make the LCP image discoverable early: use a real
<img>in the HTML, not a CSS background or a JavaScript-injected element. - Prioritize it: add
fetchpriority="high"and never lazy-load the LCP image. - Shrink the file: serve modern formats such as AVIF or WebP with responsive
srcsetsizes. - Remove render-blocking resources: inline critical CSS, defer non-critical scripts and self-host fonts.
<!-- Preload a hero image that is set via CSS or discovered late -->
<link rel="preload" as="image" href="/img/hero.avif" fetchpriority="high">
<!-- Or prioritize the hero <img> directly -->
<img src="/img/hero.avif" width="1200" height="600"
fetchpriority="high" alt="Product dashboard overview">
How to fix INP (Interaction to Next Paint)
INP suffers when the main thread is busy. Any task longer than 50 milliseconds blocks the browser from responding to clicks, taps and key presses.
- Ship less JavaScript: audit bundles, remove unused dependencies, code-split by route and defer third-party scripts such as chat widgets and tag managers.
- Break up long tasks: yield to the main thread between chunks of work so the browser can handle input.
- Keep event handlers light: update the UI first, then do heavy work such as analytics calls or data processing afterwards.
- Avoid layout thrashing: batch DOM reads and writes, and keep the DOM size manageable.
// Yield to the main thread between chunks of work
function yieldToMain() {
if (globalThis.scheduler?.yield) return scheduler.yield();
return new Promise((resolve) => setTimeout(resolve, 0));
}
async function processItems(items) {
for (const item of items) {
renderRow(item);
await yieldToMain(); // lets pending clicks and taps run
}
}
web-vitals library to log which element and event caused your slowest interactions. It turns “INP is poor” into “the filter dropdown on the category page is slow”, which is something a developer can fix.How to fix CLS (Cumulative Layout Shift)
Layout shifts happen when content appears or resizes after surrounding content has rendered. The fix is almost always to reserve space in advance.
- Set dimensions on media: add
widthandheightattributes or a CSSaspect-ratioto images, videos and iframes. - Reserve slots for ads, embeds and banners: give them a minimum height instead of letting them push content down.
- Tame web fonts: use
font-displaywith metric-matched fallback fonts so text does not jump when the web font loads. - Animate with transforms: use
transformandopacityrather than properties that trigger layout, liketoporheight. - Avoid inserting content above existing content unless it responds to a user action.
/* Reserve space before media and embeds load */
.card-media { aspect-ratio: 16 / 9; width: 100%; object-fit: cover; }
.ad-slot { min-height: 250px; }
Is a slow frontend costing you users?
We run Core Web Vitals audits, bundle analysis and fixes for React and Next.js products, then set up monitoring so gains stick.
Framework notes: how to improve Core Web Vitals in Next.js and React
Modern frameworks give you good defaults, but they also make it easy to ship too much JavaScript.
Next.js
- Use the built-in image component for automatic sizing, modern formats and lazy loading, and mark the hero image as a priority or preload image (the exact prop depends on your Next.js version).
- Use
next/fontto self-host fonts with automatic fallback metrics, which reduces font-related layout shift. - Prefer server rendering, static generation or incremental static regeneration for content pages so HTML arrives complete.
- Load third-party scripts with
next/scriptand a non-blocking strategy.
React
- Keep components that do not need interactivity as React Server Components where your framework supports them, so their code never ships to the browser.
- Wrap non-urgent state updates in
startTransitionso typing and clicks stay responsive. - Virtualize long lists and memoize expensive computations to cut render work.
- Hydration cost counts: large client-side trees delay interactivity, which shows up in INP.
How to keep performance from regressing
It is one thing to improve Core Web Vitals once; keeping them good over the next dozen releases is harder. A new marketing script, an unoptimized image or a heavy dependency can undo months of work.
- Set performance budgets: define limits for JavaScript size, image weight and key metrics per page template.
- Add CI checks: run Lighthouse CI or similar on pull requests and fail the build when budgets are exceeded.
- Monitor real users: track LCP, INP and CLS by template, device and country, and alert on regressions.
- Govern third-party scripts: require a review before any new tag or widget goes live.
- Review Search Console regularly: field data lags, so check trends monthly after major releases.
Treat Core Web Vitals as a product requirement with owners and budgets, not a one-off SEO project.
Where to start: a prioritized checklist
If you have limited engineering time and need to improve Core Web Vitals quickly, work through the problem in this order.
- Check PageSpeed Insights and Search Console to see which metric fails and on which templates.
- Focus on templates with the most traffic or revenue, such as home, category, product and landing pages.
- Fix LCP on those templates first, since it is often the quickest win.
- Profile interactions on key flows to find the long tasks behind poor INP.
- Audit layout shifts on mobile, where ads, banners and fonts usually cause them.
- Put budgets and monitoring in place before moving on.
For online stores, these fixes connect directly to revenue; our guide to eCommerce conversion rate optimization covers related technical improvements.
Frequently asked questions
What are good Core Web Vitals scores?
A good score is LCP of 2.5 seconds or less, INP of 200 milliseconds or less and CLS of 0.1 or less. Google assesses these at the 75th percentile of page visits, separately for mobile and desktop.
Do Core Web Vitals affect SEO rankings?
Core Web Vitals are part of Google’s page experience signals. Relevant, helpful content still matters most, but when pages are similar, a better experience can help, and faster pages usually convert and retain users better.
Why is my PageSpeed Insights score different from my Core Web Vitals?
The performance score comes from a single lab test with simulated conditions. Core Web Vitals assessment uses field data from real Chrome users over 28 days. A page can score well in the lab and still fail in the field, or the reverse.
How long does it take to see Core Web Vitals improvements?
Lab results change as soon as you deploy. Field data in CrUX and Search Console uses a rolling 28-day window, so expect it to take several weeks for improvements to show fully.
What replaced First Input Delay?
Interaction to Next Paint (INP) replaced First Input Delay as a Core Web Vital in March 2024. INP measures the responsiveness of interactions across the whole visit, not just the first one.
Next steps
The fastest way to improve Core Web Vitals is to find the failing metric on your highest-value templates and fix the root cause, then protect the gains with budgets and monitoring. If you want experienced help, explore our frontend engineering and web and platform engineering services, or contact our team to discuss a performance audit.


