Decompose the metric, not the checklist

A 420 ms INP is three timings, and only one of them is worth your effort.

Do not optimize what a lab tool flags. Optimize what your field data proves is failing at the 75th percentile, and here is exactly how much each fix is worth. INP is input delay plus processing plus presentation. Attribute the overshoot to one subpart, then pull one lever.

Core Web Vitals optimization 2026, diagnosed from field data

Do not optimize what a lab flags. Read your field data at p75, attribute the failure to one subsystem, pull the one fix, then measure the millisecond delta and the revenue it moves.

Why start from field data instead of a 20-item checklist?#

Search this topic and every top result hands you the same list. What that list never asks is whether your page needs any of it. You apply generic fixes and hope one lands. In practice, that is expensive guessing.

This guide inverts the genre, turning Core Web Vitals optimization 2026 into a diagnostic loop rather than a prescription. You read the field, attribute the failure to one subsystem, then pull the one fix, measure the delta, and model the revenue. Branching on data means you never spend effort a metric did not ask for.

The diagnosis-first loop from a field reading to a modeled revenue impactRead the field at p75, attribute the failure to one subsystem, apply the single fix that moves that metric, quantify the millisecond delta, then model the revenue on your own traffic. Re-read the field and repeat, fixing only what still fails.

Read the loop as an order, not a menu. It starts from the field, never the lab, and forces attribution before action. The fix that survives is always the one your numbers demand.

Prescription-first vs diagnosis-first: why the generic list wastes your time#

A checklist is prescription-first. It lists fixes with no link to your data, so you cannot tell which item is your bottleneck. Most items will not apply to your page at all.

Diagnosis-first flips the order. It asks which metric fails in the field, then which subsystem owns that metric. A slow first byte is a server problem, so backend query bottlenecks that inflate server response time matter more than any image trick. Attribute first and you stop pulling levers that were never loose.

The 75th percentile is the only number that decides#

Core Web Vitals pass or fail at the 75th percentile. Seventy-five percent of real visits must clear the good line. An average hides your failing quartile, and a single lab run hides it completely. p75 is the grade that ships.

Chrome exposes this in the Chrome User Experience Report, so read your metric there before you act. The CrUX documentation explains how the field dataset is collected from real Chrome users. Being real-user data, it is the verdict that counts.

The routing table: which fix does your failing metric actually need?#

Attribution needs a reference. This is where Core Web Vitals optimization 2026 turns into a routing engine competitors skip. Read down to your failing subpart, then across to the one fix, the typical millisecond delta, and the effort it takes.

Failing subpart to the single highest-leverage fix, with a typical ms delta and effort
Failing metric and subpartMost likely causeThe one fixTypical ms deltaEffort
LCP: TTFBSlow server or origin round-tripCache or render at the edge400 to 1200 msMedium
LCP: load delayLCP image discovered latePreload with fetchpriority=high200 to 600 msLow
LCP: load durationOversized or legacy-format imageAVIF or WebP at the rendered size300 to 900 msLow
LCP: render delayRender-blocking CSS or JSInline critical CSS, defer the rest150 to 500 msMedium
INP: processingOne long main-thread taskYield after ~50 ms, break the task up80 to 300 msMedium
CLS: shift sourceUnsized media or a late bannerReserve space with aspect-ratioscore to ~0Low

Read the effort column as a tie-breaker. Two low-effort levers clear most LCP problems, so you rarely start with the medium ones. Exhaust the cheap moves, then re-measure the field.

INP: the core web vitals optimization 2026 centrepiece#

INP replaced FID as the responsiveness metric in March 2024. Most guides still explain it as a single number, which misses the mechanics entirely. It is the least explained Core Web Vital, and the one most driven by third-party scripts and hydration cost.

The web.dev launch note marks the change from FID to INP. Measuring the full interaction rather than just the first input makes INP harder to fake and harder to fix. This section owns the mechanics.

Input delay + processing time + presentation delay: 420ms, broken apart#

INP is three timings, not one. Input delay runs while the thread is busy with other work. Processing time runs while your handler executes. Presentation delay runs while the next frame renders. Together they make the number.

Consider a real 420 ms INP, the one in the hero above. It splits into 120 ms of input delay, 250 ms of processing, and 50 ms of presentation. The processing chunk is the largest and the most reducible, which makes it the subpart to attack. Presentation delay, by contrast, is a near-fixed frame cost. The web.dev INP guide defines all three phases in full.

The INP Task Lab: insert yield points and watch INP fall#

A decomposition is easier to feel than to read. Fire a synthetic interaction, then drag the slider to insert scheduler.yield() breakpoints. As breakpoints rise, the long task splits into shorter chunks. The measured INP falls from about 420 ms toward about 180 ms, live, split across the three subparts.

INP Task Lab: split a long task and watch each subpart fall

The 340 ms handler, split into 1 chunk

Each yield ends a task, so the browser can accept the next interaction and paint between chunks. Shorter chunks mean a shorter wait and a shorter path to the next frame.

420 msestimated INP
Needs improvement

Good line: 200 ms. Poor above 500 ms.

Estimated INP as scheduler.yield() breakpoints rise (illustrative)
YieldsInput delayProcessingINP total
0120 ms250 ms420 ms
180 ms145 ms275 ms
267 ms110 ms227 ms
360 ms93 ms203 ms
456 ms82 ms188 ms
553 ms75 ms178 ms
651 ms70 ms171 ms
750 ms66 ms166 ms
849 ms63 ms162 ms

0 yield points: the 340 ms handler runs as 1 chunk, longest about 340 ms. Estimated INP 420 ms, made of input delay 120 ms, processing 250 ms, presentation 50 ms. Verdict Needs improvement.

An illustrative planning model, not a benchmark. It assumes each yield point splits the handler into one more chunk, that shorter tasks cut both the input delay and the processing before paint, and that presentation delay is a fixed frame cost. Real numbers move with your device, your other scripts, and your hydration cost. Show 420 ms here, then attribute your own slow interaction with the Long Animation Frames API before you ship a fix.

Fire the interaction, then add scheduler.yield() breakpoints. The chunk strip shows the handler splitting, the stacked bar shows input delay, processing, and presentation, and the verdict flips from needs-improvement to good as INP crosses the 200 ms line. The total, the subparts, the verdict, and the data table are the accessible source of truth. Every figure is illustrative planning math, never a benchmark.

Notice which subparts move. Yielding shortens the longest task, so input delay and processing fall together while presentation delay holds near its floor. The lever is scheduling, not a faster function.

Mapping each INP component to its code fix#

Each phase maps to a distinct change. Here is the causal chain in code. Switch tabs to compare the monolithic long task, the yielded version, and the deferred version. Each panel is the exact pattern that moves one subpart.

inp-monolith.js · js
// One click handler doing ~340 ms of synchronous work on the main thread.
button.addEventListener('click', () => {
  const parsed = parsePayload(raw);   // ~90 ms
  const items  = buildResults(parsed); // ~180 ms
  renderList(items);                   // ~70 ms of DOM writes
});

// The browser cannot paint or accept a new interaction until this
// returns. So INP = input delay + this whole 340 ms + presentation.
// Under load the measured INP lands near 420 ms, past the 200 ms line.

Read the tabs as a progression. Chunk the task first, and the interaction starts and paints sooner. Defer whatever the user does not wait on next. Analytics and prefetch never affect the visible result, so moving them off the interaction path drops them out of INP entirely.

LCP: what actually moves it in 2026#

LCP is the load metric. It marks when the largest element paints. Generic advice stops at "optimize images" and moves on. This section is concrete about what moves LCP now.

Find the LCP element, then make it arrive first#

Attribution comes before action here too. Identify the LCP element from field data, since it is often not the element you assume, then trace which subpart holds it back. A large share of the budget is usually spent before the browser paints anything at all, on the first byte. To see where that byte comes from, read the request lifecycle behind every page load. For the rendering side of that first byte, edge rendering that cuts Time to First Byte on Cloudflare attacks the largest LCP subpart directly.

fetchpriority, preload, and modern image delivery#

Two low-effort moves clear most LCP problems. Preload the LCP image and mark it high priority, so the browser starts it early. Then serve a modern format at the rendered size, so you download only the bytes you paint.

lcp-image-delivery.html · html
<!-- Preload the LCP image and mark it high priority, so the browser
     starts it in the first flight, not after CSS and layout settle.
     This attacks resource load delay, the discovery gap. -->
<link rel="preload" as="image" href="/hero.avif" fetchpriority="high" />

<!-- Serve a modern format at the rendered size, so load duration is
     bytes you actually paint, not a full-resolution PNG. -->
<img
  src="/hero.avif"
  srcset="/hero-800.avif 800w, /hero-1200.avif 1200w"
  sizes="(max-width: 800px) 100vw, 1200px"
  alt="Product hero"
  width="1200"
  height="630"
  fetchpriority="high"
/>

Discovered and prioritised early, the image shrinks its resource load delay, and the AVIF at the rendered size cuts load duration. The web.dev fetch priority guide covers the priority-hints API, and the optimize LCP guide covers the full subpart split.

CLS: eliminating layout shift at the source#

CLS is the stability metric. It scores how much visible content jumps while the page settles. A shift only counts when visible content moves, so the fix is almost always to reserve space up front.

Reserved space, font-display, and late-injected content#

Read the pattern behind all three. In every case, the shift happens because a box arrives without a reservation. Reserving the box removes the cause, not just the symptom.

The critical rendering path, and exactly what blocks it#

LCP render delay and much of load delay trace to one thing: the critical rendering path. It runs from the first byte through parse, style, layout, and paint. Some resources block that path, and the first pixels wait on them.

The critical rendering path with render-blocking CSS and JS called outHTML parses into the DOM, then render-blocking CSS and synchronous JS both hold up the render tree before layout and paint. Deferred and async scripts run off the critical path, so they do not block the first paint.

Notice the two red nodes. Render-blocking CSS and synchronous JS both sit between parse and paint, which pushes out every load-side metric. Deferred scripts run afterward and never block the first frame.

Render-blocking CSS and JS, and how to unblock each#

Each blocking node has a matching move. Inline the critical CSS and load the rest asynchronously, so the render tree does not wait on a full stylesheet. Add defer or async to scripts, so parsing is not paused mid-document. Code-split the bundle, so a route ships only the JavaScript it needs. Each move clears one blocking node, and the first paint arrives sooner. For the perceived-speed side of this, progressive web app patterns that improve perceived performance cover instant navigation and offline shells.

Why Lighthouse says 98 while your users are failing#

A green Lighthouse score is not a passing grade. A lab tool runs one synthetic load, so it misses the range of real devices and networks. A lab pass can sit right next to a field failure. Step through why.

  1. Lighthouse runs one throttled load

    The lab test uses a single synthetic device and network profile. It is reproducible, but it is one sample, not your audience.

  2. It has no real user to interact

    A lab tool cannot click, type, or scroll like a person. Therefore it cannot measure INP honestly, because INP needs a real interaction.

  3. CrUX reads 75 percent of real visits

    The field dataset aggregates real Chrome users at p75. So it captures the slow devices and busy main threads the lab never saw.

  4. The verdict is the field, every time

    When lab and field disagree, trust the field. A Lighthouse 98 with a failing CrUX INP means real users are waiting, so the field is where you act.

Read the INP step as the key case. A lab has no real input, so it cannot grade responsiveness. Field data is the only honest source for INP.

Measuring for real: CrUX for the verdict, RUM for attribution#

Two field sources do two jobs. CrUX and PageSpeed Insights give the p75 pass or fail verdict. Your own RUM gives the attribution, since it can tag the exact element or script. Read the verdict in CrUX, then attribute the cause in RUM.

For INP attribution, the Long Animation Frames API names the script that held the main thread. For CLS, the Layout Instability API logs each shift source. These tie a number to a line of code, turning a failing metric into a specific fix. The Core Web Vitals overview explains the lab and field split in full.

What a Core Web Vitals win is actually worth#

Speed is not vanity. Rakuten 24 ran a controlled test to prove it, which makes the payoff measurable rather than a slogan. The chart shows the business deltas from that test as scannable magnitudes.

Show data table
Rakuten 24: business deltas from the Core-Web-Vitals-optimized variant (web.dev case study)
Item Change against the unoptimized variant
Revenue / visitor 53.37%
Conversion rate 33.13%
AOV 15.2%
Time spent 9.99%
Exit rate cut 35.12%

On one landing page split 50/50 for a month, the Core-Web-Vitals-optimized variant moved revenue per visitor by 53.37 percent and conversion by 33.13 percent, with no visual or functional change beyond the performance work. These are the published web.dev Rakuten 24 figures, not a benchmark of your page.

Figure Rakuten 24: business deltas from the Core-Web-Vitals-optimized variant (web.dev case study) web.dev, Rakuten 24 Core Web Vitals case study

Read the numbers as leverage, not a promise. The only change was the performance work, so the deltas are attributable to it. Core Web Vitals optimization 2026 is a conversion lever, not just a lab score.

The Rakuten 24 controlled test, in real numbers#

The setup was clean. Rakuten 24 split one high-traffic landing page 50/50 for a month. Version A was optimized for Core Web Vitals. Version B was the original, with no visual or functional difference beyond the performance work.

The field result was concrete. Version A finished loading 0.4 seconds earlier on the mobile test and showed no significant layout shift. That single change crossed the line, and the business outcome followed. Correlating field vitals against revenue separately, a good LCP bucket was associated with up to a 61.13 percent higher conversion rate versus the site average. The web.dev Rakuten 24 case study documents the full method and figures.

Model your own page: the budget + revenue calculator#

A published case study is not your page, so enter your own numbers instead. Set your traffic, your average order value, and your current LCP and INP subpart timings. Read which subparts overshoot budget, and the revenue a crossing to good would model on your inputs.

Budget + revenue modeler: your subparts against budget, and the money at stake
Your traffic and order economics
Current LCP subpart timings
Current INP phase timings
LCP subparts vs budget3300 ms of 2500 ms . Needs improvement
TTFB1100 ms / 800 msover by 300 ms
Load delay300 ms / 250 msover by 50 ms
Load duration1400 ms / 1000 msover by 400 ms
Render delay500 ms / 450 msover by 50 ms
INP phases vs budget420 ms of 200 ms . Needs improvement
Input delay120 ms / 50 msover by 70 ms
Processing250 ms / 100 msover by 150 ms
Presentation50 ms / 50 ms

If this page crossed to good, on your own numbers

Modeled conversion uplift
8.7%
Extra revenue / month
$20,045
Extra revenue / year
$240,538

Current modeled revenue is about $230,400 a month. The uplift scales with how far LCP and INP sit over budget, capped at 30.0%. For context, Rakuten 24's controlled test moved revenue per visitor by 53.37% on a single optimized page, so this cap stays deliberately conservative.

Subpart timings against budget (illustrative)
SubpartCurrentBudgetOver budget?
TTFB1100 ms800 msyes, by 300 ms
Load delay300 ms250 msyes, by 50 ms
Load duration1400 ms1000 msyes, by 400 ms
Render delay500 ms450 msyes, by 50 ms
Input delay120 ms50 msyes, by 70 ms
Processing250 ms100 msyes, by 150 ms
Presentation50 ms50 msno

LCP total 3300 ms (Needs improvement), INP total 420 ms (Needs improvement). 6 of 7 subparts are over budget. Modeled conversion uplift if you cross to good: 8.7%, worth about $20,045 a month and $240,538 a year on 120,000 monthly visits at $80 order value.

An illustrative planning model, not a benchmark. Budgets are the published good ceilings (LCP 2.5 s, INP 200 ms) split across subparts; the revenue model applies a conservative, capped conversion uplift to your own traffic and order value. Real outcomes depend on your audience, funnel, and pricing, so read your own p75 in CrUX and run a controlled test before you bank any figure here.

Enter your traffic, AOV, and current LCP and INP subpart timings. Each subpart fills a budget bar and flags its overshoot, the totals roll up with a good, needs-improvement, or poor verdict, and the revenue card models a conservative, capped conversion uplift on your own numbers. The totals, the overshoot flags, the revenue figures, and the data table are the accessible source of truth. Every figure is illustrative planning math, never a benchmark.

Notice how the money tracks the overshoot. The uplift scales with how far LCP and INP sit over budget, so the worst subpart is worth the most to fix. Tuning a subpart already inside budget models nothing. Read your own p75 in CrUX before you fund any lever.

When NOT to reach for these fixes#

There is one more limit to name. Sometimes the real problem is not a subpart at all. A page that ships a megabyte of unused third-party script cannot be rescued by any single lever. What it needs is a script budget and a hard look at what each tag earns. Core Web Vitals optimization 2026 tunes the critical rendering path; it does not excuse a bloated page. Set a budget first, then run the loop.

Talk to us about a Core Web Vitals audit

Keep reading