---
title: How to improve Core Web Vitals
description: Improve Core Web Vitals (INP, LCP, CLS) with metric-specific fixes, field-data measurement, and Next.js/Vercel performance best practices.
url: "https://vercel.com/kb/guide/how-to-improve-core-web-vitals"
published: 2025-11-03
last_updated: 2026-10-01
authors: Vercel
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Core Web Vitals are the three metrics Google uses to score a page's loading performance, interactivity, and visual stability during real visits. A page can score well in Lighthouse and still fail the assessment, because Google scores all three from field data rather than lab tests. Largest Contentful Paint (LCP) should occur within 2.5 seconds, Interaction to Next Paint (INP) should stay at or under 200 milliseconds, and Cumulative Layout Shift (CLS) should stay at or below 0.1.

Each metric fails for its own reason and takes its own fix. Identify which one falls outside the good range, trace it to the responsible route and element, apply the fix, then confirm the result in field data rather than a lab score.

## What counts as a good Core Web Vitals score

Each Core Web Vital measures a different part of the experience against its own threshold.

Here's what each one covers:

- **Largest Contentful Paint (LCP):** Measures how long the largest visible element takes to render, timed from when the page starts loading. It should complete within 2.5 seconds.
  
- **Interaction to Next Paint (INP):** Measures how long an interaction takes, timed from input through processing to the next paint. INP should be 200 milliseconds or less.
  
- **Cumulative Layout Shift (CLS):** Measures how far unexpected layout shifts move existing content, scored as a unitless value for the largest burst. It should stay at or below 0.1.
  

Google assesses each metric at the [75th percentile](https://web.dev/articles/vitals), so LCP, INP, and CLS each need to be in the good range for at least 75% of visits. A page passes only when all three do, and the remaining 25% of visits can still include slow or unstable experiences.

Passing won't lift a page on its own. Relevance and content quality are stronger ranking factors, and page experience only decides between pages that Google already rates as comparably relevant. INP replaced First Input Delay (FID) as the responsiveness metric [in March 2024](https://web.dev/blog/inp-cwv-march-12), so a page still tuned for FID is measuring the wrong thing.

## Why Lighthouse and field data disagree on Core Web Vitals

Lab and field data measure different things. Lighthouse loads the page in a fixed, emulated environment and never interacts with it, so it produces no INP score. Google's [Chrome User Experience Report](https://developer.chrome.com/docs/crux) (CrUX) collects real visits from opted-in Chrome users across the devices, networks, and locations your traffic actually comes from, and Google's assessment uses that field data exclusively.

Those two datasets can disagree sharply on the same URL. A page can post a good Total Blocking Time, or a perfect 100 lab score in PageSpeed Insights, while the CrUX field panel on the same report shows failing Core Web Vitals. Total Blocking Time points to main-thread work, but it's not an INP measurement, since the audit performs no real interactions.

Cross-browser field data is now available for two of the three metrics. LCP and INP became Baseline. Newly available when Safari 26.2 shipped on [December 12, 2025](https://web.dev/blog/lcp-and-inp-are-now-baseline-newly-available), so every major browser engine now exposes the APIs needed to measure them. CLS remains a Chromium-only measurement.

Compare the lab and field panels for the same URL, then work from whichever metric fails in the field panel.

## How to improve INP on Vercel

INP captures every discrete interaction across the page lifecycle, including clicks, taps, and key presses. It discards outliers and reports the longest one.

Start with route-level data rather than auditing every component. A slow search-suggestions interaction and a slow checkout action can fail for different reasons on the same site, and [Speed Insights](https://vercel.com/docs/speed-insights) reports real-user INP by page and route, so you can tell which one you're looking at. Reproduce the slow interaction on the affected route, then find which phase holds most of its duration.

The [web-vitals library](https://github.com/GoogleChrome/web-vitals) splits each interaction into three phases:

- **Input delay:** Other work is occupying the main thread before the handler starts, reported as `inputDelay`.
  
- **Processing duration:** The handler, or work it triggers, runs long, reported as `processingDuration`.
  
- **Presentation delay:** Rendering between the handler finishes and the next paint is slow, reported as `presentationDelay`.
  

Each phase takes a different fix, so read the attribution before changing code.

### Reduce input delay

Input delay accumulates when a [long task](https://web.dev/articles/optimize-long-tasks), meaning anything holding the main thread for more than 50 milliseconds, is mid-execution when the user interacts. Hydration that finished four seconds before a click contributes nothing, while a third-party analytics script firing on every scroll does.

Break long tasks into chunks and yield between them with `scheduler.yield()` where it's supported. Safari needs a `setTimeout` fallback. Deferring non-critical scripts until after the page becomes interactive frees the same thread. Yielding can raise total processing time, and net INP still improves.

### Shorten processing duration

Expensive Document Object Model (DOM) reads and writes inside a handler extend the processing duration. Reading a layout property right after writing to the DOM forces a synchronous layout, and the browser has to recalculate before the handler can continue.

Batch DOM mutations, schedule visual updates with `requestAnimationFrame`, and move non-UI calculations to a web worker. For touch and scroll interactions, mark `touchstart`, `touchmove`, and `wheel` listeners as passive when they don't call `preventDefault()`, which lets scrolling start without waiting for the listener.

### Cut presentation delay

Large DOM trees and complex CSS selectors slow the rendering pipeline between the handler finishing and the next paint. Applying `content-visibility: auto` lets the browser skip rendering work for off-screen content while keeping it available to find-in-page and the accessibility tree. Animating with `transform` and `opacity` avoids triggering layout or paint, so those animations run on the compositor thread.

In React applications, a large re-render after an interaction extends the same phase. React's concurrent features let `useTransition` mark a state update as non-urgent in [React 18 and later](https://react.dev/reference/react/useTransition), so the interaction paints before the heavier update lands. None of that helps when an `onClick` handler synchronously flushes analytics, and that work has to move out of the handler itself.

[23% of mobile sites](https://almanac.httparchive.org/en/2025/performance) miss the good INP threshold, and those failures trace back across all three phases rather than clustering in one. For a step-by-step version of this workflow, review the [INP debugging walkthrough](https://vercel.com/blog/demystifying-inp-new-tools-and-actionable-insights).

## How to improve LCP on Vercel

LCP breaks into four stages, and the slowest one tells you which fix to prioritize.

The stages show where the loading budget goes:

- **Time to First Byte (TTFB):** The browser is waiting on the initial response, so nothing else can start.
  
- **Resource load delay:** The browser discovers or prioritizes the LCP resource too late.
  
- **Resource load duration:** The transfer itself is slow.
  
- **Element render delay:** The resource has arrived, and other work prevents the browser from painting it.
  

Measure the stages before changing image formats or infrastructure, since a fix aimed at the wrong stage barely moves the number.

### Lower TTFB with the CDN and fluid compute

Serving requests through [Vercel CDN](https://vercel.com/docs/cdn) puts that first response closer to the visitor, across more than 126 points of presence (PoPs), with request-time code running in the nearest of [20 compute-capable regions](https://vercel.com/docs/regions) behind them. Traffic moves between the two over a private network.

On request-rendered routes, TTFB reflects server work rather than network distance. [Fluid compute](https://vercel.com/docs/fluid-compute) reuses warm instances and runs multiple invocations on a single instance, which reduces cold starts on the routes that render per request.

### Start the LCP resource earlier

The browser discovers the LCP resource late when it has to download HTML, parse CSS, and only then find the image reference. A `preload` hint in the document head starts the fetch immediately and `fetchpriority="high"` upgrades its priority. Keep the number of preload hints small, since competing hints contend for the same bandwidth.

External stylesheets block rendering by default, so the browser won't paint until blocking CSS in the head is downloaded and parsed. Inline the critical CSS for above-the-fold content and load the rest asynchronously. [Never lazy-load](https://web.dev/learn/performance/lazy-load-images-and-iframe-elements) the LCP image, as it is designed to delay the fetch.

### Shrink the LCP file

AVIF compresses [roughly 50% better](https://web.dev/articles/choose-the-right-image-format) than JPEG, with slightly less browser coverage than WebP. Vercel [Image Optimization](https://vercel.com/docs/image-optimization) handles the format negotiation and caches each transformation, and the Next.js [Image component](https://nextjs.org/docs/app/api-reference/components/image) applies [responsive sizing](https://vercel.com/academy/nextjs-foundations/advanced-image-optimization) so a phone doesn't download a desktop-width file.

Verify the same route after each change. If TTFB falls and resource load delay stays high, move to earlier discovery, and if the transfer is still slow, sizing and format negotiation are the next targets. Vodafone [improved LCP by 31%](https://web.dev/case-studies/vodafone) and recorded an 8% increase in sales, a 15% improvement in lead-to-visit rate, and an 11% improvement in cart-to-visit rate.

## How to improve CLS on Vercel

CLS reflects the largest burst of unexpected layout shifts rather than a lifetime sum. The [session window is capped](https://web.dev/articles/optimize-cls) at 5 seconds, and counts shifts less than a second apart.

Each shift multiplies the [impact fraction](https://web.dev/articles/cls) by the distance fraction, so one large shift can consume the budget alone. A banner that pushes the whole viewport down by 22% of its height has an impact fraction of 1.0 and a distance fraction of 0.22, scoring 0.22 on one shift and clearing twice the budget. Shifts [within 500 milliseconds](https://developers.google.com/search/docs/appearance/core-web-vitals) of a user interaction are excluded, since a menu opening shouldn't count against the score.

Replay the largest burst and find what moved the existing content. The usual causes are media without dimensions, content injected after load, fonts that swap at a different size, and layout changes at hydration.

### Reserve space before content renders

Images and videos without `width` and `height` give the browser nothing to reserve, so everything below them shifts once the file loads. Set explicit `width` and `height` on `<img>`, `<video>`, and `<iframe>` elements, or use CSS `aspect-ratio` for responsive media. For content whose size is unknown at render time, such as a third-party widget or an injected banner, a sensible `min-height` bounds the shift as the container grows.

### Match font metrics

With `font-display: swap`, text renders in a fallback font and re-renders when the custom font arrives, reflowing surrounding content when the metrics differ. Matching [fallback font metrics](https://vercel.com/academy/nextjs-foundations/fonts-with-next-font) with `size-adjust`, `ascent-override`, `descent-override`, and `line-gap-override` makes the swap invisible. The Next.js [Font module](https://nextjs.org/docs/app/api-reference/components/font) handles the preloading and metric matching at build time.

### Prevent shifts at hydration and on back navigation

Toggling navigation with `window.innerWidth` inside a `useEffect` snaps the layout after hydration, so use CSS `@media` queries instead and keep both DOM nodes in the initial HTML. Rendering a skeleton of the same dimensions on the server reserves space before client data arrives.

Back and forward navigation can avoid new shifts entirely when the browser restores the page from `bfcache`, because the layout is already final. Pages become ineligible when they attach `unload` listeners, so check eligibility in Chrome DevTools before release.

After applying a fix, replay the same state on a [Preview Deployment](https://vercel.com/academy/svelte-on-vercel/preview-deployments) with the Vercel Toolbar [Layout Shift tool](https://vercel.com/docs/vercel-toolbar/layout-shift-tool) and check the whole session window, since a later insertion can still become the largest burst.

## Core Web Vitals benchmarks for retail storefronts

Storefronts concentrate each metric on a different template, which is why a sitewide average hides the problem.

On a product detail page, the LCP element is typically the main product image, so the 2.5-second budget splits between TTFB and that file's own load duration. Responsive AVIF sizing is what keeps that second half of the budget in range.

Checkout is the likeliest place for a storefront's INP score to be set, since those actions are both frequent and heavy on handler work. Validate the cart and payment handlers separately, because each one can fail at a different phase.

Promotional banners produce the typical storefront CLS regression. A large banner dropped in above the fold without reserved space can consume or exceed the 0.1 budget on its own, so audit those injections before a traffic peak. For the wider operational checklist around peak events, see the [Black Friday preparation](https://vercel.com/kb/guide/black-friday-preparation) guide.

Speculative loading can also shorten navigation between storefront pages by fetching the likely next page before the click. Shopify recorded a [228ms desktop LCP gain](https://performance.shopify.com/blogs/blog/faster-storefront-navigations-with-moderate-speculation-rules) after moving from a conservative to a moderate speculation configuration, and a smaller 24ms gain on mobile.

Confirm that each change improves the affected route without adding a cost elsewhere in the checkout flow.

## How to verify a Core Web Vitals fix in production

Google assesses Core Web Vitals using [field data](https://developer.chrome.com/docs/crux/guides/pagespeed-insights) from real visits, so a lab result never confirms a fix on its own.

The main measurement options differ in the data they return and the questions they answer:

| Tool                                 | Data type                                                         | Real-user CWV data | Best for                                                                                                     | Not best for                          |
| ------------------------------------ | ----------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------ | ------------------------------------- |
| Lighthouse                           | [Lab only](https://developer.chrome.com/docs/devtools/lighthouse) | No                 | Diagnosing loading and main-thread issues                                                                    | Real-user INP or Google's assessment  |
| PageSpeed Insights (lab panel)       | Lab                                                               | No                 | Score checks during development                                                                              | Real-user measurement                 |
| `web-vitals` library                 | Field                                                             | Yes                | [First-party reporting](https://web.dev/articles/vitals-measurement-getting-started) into your own analytics | Google's ranking dataset              |
| Chrome User Experience Report (CrUX) | Field (Google)                                                    | Yes                | The dataset Google assesses, on a [28-day rolling window](https://developer.chrome.com/docs/crux/api)        | Immediate post-deployment feedback    |
| PageSpeed Insights (field panel)     | Field (CrUX)                                                      | Yes                | A single-URL CrUX read                                                                                       | Immediate post-deployment feedback    |
| Speed Insights                       | Field (real user monitoring)                                      | Yes                | Per-page and per-route real-user breakdowns                                                                  | Representing Google's ranking dataset |

Speed Insights collects real-user LCP, INP, and CLS from every deployed environment and filters by route, device type, percentile, time range, and country, defaulting to the P75 view Google assesses against. Route-level detail turns a site-wide number into an actionable one. An INP of 240ms tells you visitors hit a slow response, and attributing it to the search-suggestions handler on `/products` tells the team where to start.

Waiting on CrUX before checking real user monitoring delays feedback by up to a month, so verify the affected route first, then watch CrUX confirm it.

## Next steps

Once all three metrics pass at the 75th percentile, hold them there through each release. [Start a new Vercel project](https://vercel.com/new) and turn on Speed Insights to track LCP, INP, and CLS for real visits by page and route, or [browse the templates](https://vercel.com/templates) for a configuration that already applies image, font, and rendering defaults.

## Read more

- [Speed Insights](https://vercel.com/docs/speed-insights)
  
- [Vercel CDN](https://vercel.com/docs/cdn)
  
- [Vercel Toolbar Layout Shift tool](https://vercel.com/docs/vercel-toolbar/layout-shift-tool)
  
- [Demystifying INP: new tools and actionable insights](https://vercel.com/blog/demystifying-inp-new-tools-and-actionable-insights)
  
- [First Input Delay (FID) vs. Interaction to Next Paint (INP)](https://vercel.com/blog/first-input-delay-vs-interaction-to-next-paint)
  
- [How to prepare your storefront for Black Friday traffic](https://vercel.com/kb/guide/black-friday-preparation)
  

## Frequently asked questions

### Why do Core Web Vitals fail when a page feels fast?

Google assesses Core Web Vitals at the 75th percentile of real visits, across devices, networks, and routes you may never test yourself. One fast visit says nothing about the other 74%. A page can also render its main content fast and still respond slowly to interactions or shift content during load.

### How long does a Core Web Vitals fix take to show up?

Lab tools reflect a deployed change immediately, and real user monitoring starts collecting new visits as soon as the fix ships. CrUX uses a 28-day rolling window updated daily, so Google's field assessment moves gradually as newer visits replace older ones. Use route-level monitoring while that window catches up.

### Are all three Core Web Vitals equally important for ranking?

No. Google assesses the three independently, with no weighting or averaging between them, so one failing metric fails the page however strong the other two are. Push the metric that sits outside its threshold rather than improving one that already passes.

### Should you fix mobile or desktop Core Web Vitals first?

Mobile first. The 2025 Web Almanac reports 97% of desktop websites have good INP against 77% on phones, a 20-point gap that traces to slower CPUs, less memory, and slower networks. Mobile is where most regressions surface, so start with mobile field data for the failing route.

### Does a good Lighthouse score mean a page passes Core Web Vitals?

No. Lighthouse runs one simulated load without interacting, so it reports no INP score and can't represent the devices and networks in field data. A perfect lab score can sit alongside failing Core Web Vitals in CrUX. Use Lighthouse to diagnose loading issues, then confirm with field data.