Core Web Vitals Optimization: LCP, INP, and CLS in 2026

Core Web Vitals are the three field metrics Google uses to score real-user experience: Largest Contentful Paint (LCP), Interaction to Next Paint (INP), and Cumulative Layout Shift (CLS). They're a soft ranking factor on their own but a strong proxy for the engagement signals that matter more.

Last updated: · By SEO Smart Engine Team

LCP under 2.5s

Almost always image-bound. Preload the hero image, serve it in AVIF or WebP, set explicit width/height, and host it on a CDN with HTTP/3. Defer everything that isn't above-the-fold.

INP under 200ms

INP replaced FID in March 2024. The fix is the same as for long tasks: break up JavaScript work, debounce input handlers, and move heavy logic off the main thread with Web Workers where possible.

CLS under 0.1

Reserve space for every image, embed, and ad. Avoid injecting content above existing content. Use font-display: optional or matched fallback font metrics to prevent FOIT/FOUT shift.

Measure in the field

Lab tools (Lighthouse) lie. Use Chrome UX Report (CrUX) data and a RUM tool like web-vitals.js to capture real visitor metrics segmented by device and country.

The thresholds, in one place

Every metric is judged at the 75th percentile of real visits, split between mobile and desktop. LCP: good under 2.5s, needs improvement 2.5-4.0s, poor above 4.0s. INP: good under 200ms, needs improvement 200-500ms, poor above 500ms. CLS: good under 0.10, needs improvement 0.10-0.25, poor above 0.25. A URL group passes only when all three are in the good band, so the metric closest to its boundary is the one worth fixing first - not the one with the worst-looking chart.

A repeatable diagnosis workflow

1. Open the Core Web Vitals report in Search Console and note which URL group fails and on which device. 2. Take one representative URL and confirm the failure in CrUX rather than Lighthouse. 3. Reproduce it in DevTools with mobile CPU throttled 4x and a Slow 4G profile. 4. For LCP, read the LCP element in the Performance panel and classify the time as TTFB, resource load delay, load time, or render delay - each has a different fix. 5. For INP, record an interaction and look for the long task blocking it. 6. Ship one change at a time and keep a RUM measurement running so you can attribute the improvement.

Worked example: a 4.1s LCP template

A content template failed LCP at 4.1s on mobile. The breakdown was 0.5s TTFB, 1.9s resource load delay, 1.4s load time, 0.3s render delay. The hero was lazy-loaded and discovered only after the CSS parsed, and it was a 1.4MB PNG. Three changes - removing lazy-loading on the hero, adding a preload with fetchpriority=high, and serving a correctly sized AVIF - cut load delay to 0.2s and load time to 0.4s, landing LCP at 1.4s. No framework change and no CDN change was needed; the metric was dominated by discovery, not bandwidth.

Common regressions to watch for

Third-party tags added by marketing are the most frequent INP regression, and consent banners injected above content are the most frequent CLS regression. Guard against both: load tags with async or via a worker-based tag manager, reserve the banner's height, and add a budget check to your deploy process so a regression is caught before it enters the 28-day field window.

A performance budget you can enforce in CI

Thresholds only hold if a build can fail. A budget that works in practice: hero image under 120KB after encoding, total render-blocking CSS under 40KB, total first-party JavaScript under 170KB compressed, zero elements above the fold without explicit dimensions, and no third-party script on the critical path. Wire it to a Lighthouse CI run on one representative URL per template - not every URL - and treat the run as a regression gate rather than a score to optimize. Lab numbers are unreliable as absolute values but very reliable as change detectors between two commits of the same template.

Read the metrics per template, not per site

Site-wide Core Web Vitals averages hide the failure. Group URLs the way your codebase does - home, article, category, product, search results - and pull field data for each group separately. In almost every audit we run, one template accounts for most of the failing URLs, and its fix is a single change applied once. Chasing a site-level score instead produces scattered work with no measurable movement in the 75th percentile.

In-depth guide

A longer, practitioner-level breakdown of core web vitals optimization - written for readers who want the full picture, not just the summary above.

Why Core Web Vitals matter beyond the score

Core Web Vitals are Google's attempt to quantify perceived user experience with three field metrics. On their own they are a modest ranking signal - a tiebreaker at best when two pages are otherwise equal in authority and relevance. But their real value is as a leading indicator for the engagement metrics that do move rankings significantly: dwell time, pages per session, and return-to-SERP rate.

A page that fails Core Web Vitals fails on real user devices, and those users leave. Google reads the leaving. The Web Vitals number is a proxy Google gives you so you can fix the problem before the behavioral penalty compounds. Treat the metrics as diagnostic gifts, not as compliance checkboxes.

There is no 'passing score' that unlocks a ranking boost. There is a continuous relationship where better field metrics correlate with better engagement, which correlates with better rankings. Optimize as far as your engineering budget allows and stop when the marginal minute of engineering time no longer produces a measurable engagement lift.

LCP under 2.5 seconds: the image problem

Largest Contentful Paint is almost always determined by the hero image or the largest above-the-fold text block. In 90 percent of failing cases, it is the image. Compress the hero image to AVIF (fall back to WebP for older browsers), preload it in the head with a fetchpriority=high attribute, set explicit width and height, and never lazy-load it. These four changes together resolve most LCP failures.

Server response time is the second most common LCP contributor. Time-to-first-byte over 600 milliseconds means the LCP metric is already burning budget before your HTML arrives. Cache at the edge (Cloudflare, Fastly, Vercel Edge), use HTTP/3 where supported, and locate your origin near your primary user base. Static rendering (SSG) or edge SSR beats origin SSR for LCP in almost every case.

Render-blocking resources are the third. Every synchronous script and stylesheet in the head delays paint. Inline the critical CSS for above-the-fold content, defer non-critical CSS with media=print + onload, and defer or async every non-critical script. The waterfall in Chrome DevTools shows you exactly which resources are blocking - fix them in priority order.

INP under 200 milliseconds: main thread hygiene

Interaction to Next Paint measures the worst interaction latency across a session, weighted toward the 98th percentile. It is a harsher metric than the old First Input Delay because it captures continued interactions, not just the first one. Failing INP almost always means the main thread is blocked by long JavaScript tasks.

The fix is to break up long tasks. Any function that runs longer than 50 milliseconds should be split with yield points using scheduler.yield() or setTimeout(0). Modern React 18 and beyond include useTransition for exactly this purpose. Audit with Chrome DevTools Performance tab - any task longer than 200ms is a candidate for splitting.

Third-party scripts are the second most common INP killer. Every analytics tag, chat widget, and ad script runs on the main thread by default. Partytown moves them to a Web Worker where they cannot block interactions. Not every script is Partytown-compatible - test individually - but the ones that are usually move INP from 400ms into the 150ms range with no other changes.

CLS under 0.1: reserving space in advance

Cumulative Layout Shift measures unexpected movement of content after the initial render. Every image without width and height attributes causes a shift when it loads. Every ad slot without a reserved container causes a shift when the ad renders. Every font swap from a fallback to a web font causes a shift because the character widths differ.

The fixes are all about reservations. Set width and height (or aspect-ratio) on every image and video. Reserve a minimum height for every ad container. Use font-display: optional to avoid the swap, or match your fallback font's metrics to your web font's metrics using font metric adjustment properties.

Client-side content injection is the CLS trap that bites teams late in the launch cycle. A cookie banner that appears 800ms after paint shifts everything below it. A newsletter modal that pushes the hero down does the same. Either render these immediately in the initial HTML, or overlay them without displacing content.

Field vs lab data: the gap that confuses everyone

Lighthouse runs a lab test on a simulated device with throttled network. It produces a score. Chrome User Experience Report (CrUX) aggregates real Chrome users' field measurements. It produces different numbers. Google's ranking uses field data, not lab data. Optimizing for the Lighthouse score without checking field data can lead you to invest in the wrong problems.

A common pattern: Lighthouse shows 100/100 in a lab test but CrUX shows a 65th percentile LCP of 4.2 seconds. This usually means your users are on slower networks or devices than Lighthouse simulates, or your CDN performs worse in some geographies than the Lighthouse test location. Investigate the CrUX segmentation - device category, connection type, country - to find the failing cohort.

The tools: PageSpeed Insights shows both lab and field data side by side. web-vitals.js instruments your own site to capture real user metrics in your analytics. Search Console's Core Web Vitals report shows CrUX data aggregated per URL group. Use all three. The truth is in the intersection.

The 30-day CWV recovery playbook

Week one: baseline. Pull CrUX data for your top 20 templates (home page, category page, product page, article page, checkout, and so on). Note the 75th percentile LCP, INP, and CLS for each. Screenshot the results so you can measure progress against a fixed reference.

Weeks two and three: image and script optimization. Deploy AVIF/WebP hero images with preloading, defer all non-critical third-party scripts, remove unused JavaScript bundles, and audit render-blocking CSS. This phase alone typically shifts LCP by 30 to 50 percent on failing templates.

Week four: measurement and iteration. Re-pull CrUX data (which lags by 28 days, so the improvements may not fully register yet). Instrument web-vitals.js to see the leading indicator. Any template still failing after phase one needs template-specific investigation - server rendering strategy, JavaScript framework configuration, or third-party integration audit.

Frameworks and CWV: what actually helps

Server-side rendering (SSR) helps LCP by removing the render wait. Static site generation (SSG) helps more by removing the server wait too. Client-side rendering (CSR) frameworks with no SSR fallback typically fail LCP on content-heavy pages because the browser has to download the JavaScript, execute it, fetch the data, and render before the largest paint happens.

Next.js, Nuxt, SvelteKit, TanStack Start, Remix, and Astro all provide SSR or SSG out of the box. Migrating from a CSR-only setup to one of these frameworks is one of the highest-leverage CWV improvements available, and it also fixes JavaScript SEO issues in the same project.

Framework choice matters less than configuration. A poorly configured Next.js app can perform worse than a well-configured CSR app. The magic is in the specific patterns - avoiding client components where server components suffice, using dynamic imports for below-the-fold interactive widgets, using the Image component for automatic responsive images. The framework provides the tools; the team has to use them.

A repeatable measurement workflow (field first, lab second)

Start every Core Web Vitals project in field data, not lab data. Open the Core Web Vitals report in Search Console and note which URL groups are marked poor or needs-improvement, and on which device class. Field data is the 75th percentile of real visits over a rolling 28-day window, which means it lags your deploys by up to a month and it reflects the devices and networks your visitors actually use. That lag is why teams that optimize only against Lighthouse scores keep 'passing' while the report stays red.

Once you know which group is failing and on which metric, switch to lab tooling to find the cause: Chrome DevTools Performance panel with CPU throttling set to 4x and network set to Slow 4G, plus the Web Vitals extension in overlay mode. Reproduce the failing metric locally, capture a trace, and identify the specific element - DevTools names the LCP element and attributes each layout shift to the node that moved. Fix that one element, re-measure, and only then move to the next.

Close the loop with your own field collection so you are not waiting 28 days per iteration. The web-vitals npm library reports LCP, INP, and CLS from real sessions in a few lines of code; send the values to your analytics endpoint with the page path, device type, and connection type attached. With your own histogram you can see a fix land within hours, segment by template, and catch regressions that a sitewide average hides.

Set thresholds explicitly so 'done' is not a judgement call: LCP at or under 2.5 seconds, INP at or under 200 milliseconds, CLS at or under 0.1, each measured at the 75th percentile on mobile. Anything above 4.0 seconds LCP, 500 milliseconds INP, or 0.25 CLS is in the poor bucket and should be treated as a bug with an owner, not as a backlog nice-to-have.

Worked example: a 4.8s LCP article template taken to 1.9s

A typical failing article template we see in audits looks like this: a 1.4 MB JPEG hero at full viewport width, a web font loaded from a third-party host in a blocking stylesheet, a consent banner injected by a tag manager, and an origin server rendering on demand with a 900 millisecond time-to-first-byte. Field LCP sits around 4.8 seconds on mobile and CLS around 0.22 because the banner and the font swap both move the article body.

The fix order follows the waterfall, cheapest first. Convert the hero to AVIF with a WebP fallback and size it to the largest rendered width, which typically cuts 1.4 MB to under 120 KB, then add fetchpriority=high and remove any loading=lazy on that one image. Self-host the font, subset it to the characters used, and load it with font-display: swap plus a size-adjust fallback so the swap does not reflow text. Reserve height for the consent banner with a fixed-height container instead of letting it push content. Finally put the HTML behind an edge cache so time-to-first-byte drops under 200 milliseconds for repeat paths.

In this scenario the individual contributions are roughly: image work removes 1.6 seconds, edge caching removes 0.7 seconds, font and render-blocking cleanup removes 0.6 seconds, and the reserved banner space takes CLS from 0.22 to under 0.05. LCP lands near 1.9 seconds on mobile field data about three weeks after deploy, once the 28-day window has mostly rolled over. INP was already acceptable here because the template ships little JavaScript - on script-heavy templates the equivalent win comes from breaking long tasks with scheduler.yield and deferring third-party tags until after first input.

The lesson from repeating this exercise across templates is that Core Web Vitals failures are rarely mysterious. Four causes - oversized hero media, blocking third-party resources, slow origin responses, and unreserved space for late-arriving elements - account for the large majority of failures. Audit for those four before reaching for exotic optimizations.

Free tools to apply this

FAQ

Do Core Web Vitals affect ranking?

Yes - Google confirmed they're a ranking signal in their Page Experience update, though the effect is small compared to relevance and authority.

What's a 'good' INP score?

Under 200ms at the 75th percentile of real visits. Between 200ms and 500ms is 'needs improvement'.

Why does my Lighthouse score differ from CrUX?

Lighthouse is a lab test on a single device. CrUX is real visitors across all devices and connections - it's the score Google actually uses.

How long after a fix does the Search Console report update?

Field data is a rolling 28-day window at the 75th percentile, so a deployed fix usually shows up partially after about a week and fully after four weeks. Collect your own web-vitals measurements if you need same-day feedback.

Which single fix resolves the most LCP failures?

Right-sizing the hero image and serving it as AVIF or WebP with fetchpriority=high and no lazy-loading. On content templates that one change often removes more than a second of LCP.

Do Core Web Vitals matter for AI search and Bing?

Bing uses its own page experience signals and AI answer engines fetch pages with strict timeouts, so a slow page is likelier to be skipped entirely. Fast, stable pages help every surface, not just Google.

Why do I have no field data for a URL?

CrUX only reports groups with enough real visits. Low-traffic URLs are folded into an origin-level group or omitted entirely, so use your own RUM collection for those pages instead of assuming they pass.

Can failing Core Web Vitals stop a page from being indexed?

Not directly - speed is a ranking signal, not an indexing gate. But a page that times out for the crawler can fail to be fetched, and slow templates crawl less often, which delays how quickly changes are seen.

Does fixing CLS help conversions as well as ranking?

Usually more than it helps ranking. Layout shift causes mis-taps on mobile forms and checkout buttons, so reserving space for images, embeds and banners tends to show up in conversion rate before it shows up in position.

Should I optimize mobile or desktop first?

Mobile, in nearly every case. Google evaluates the mobile group separately and it is almost always the group that fails, because CPU throttling makes JavaScript cost several times more than on desktop.

Is a perfect Lighthouse score worth chasing?

No. Lighthouse 100 on a throttled lab run says nothing about your 75th-percentile field data. Use Lighthouse to detect regressions between commits and CrUX or your own RUM to decide whether a URL group passes.

Related guides

Continue building topical authority with the guides closest to this one.

Recommended for your site

Ranked by topical relevance to this page.

Go deeper

Comparisons, playbooks and use-case breakdowns that build on this topic.