Lakshya

Software Engineering · Chapter 16 of 31

Web performance, measured on real users

The three metrics, the numbers the whole web is failing, and the one-line fixes most sites still have not made.

6 min read1 diagramAll 31 chapters

Performance is the frontend topic where opinion is cheapest and data is most available, so it is where a candidate can differentiate fastest simply by knowing the actual field numbers.

The three metrics, and what happened to the fourth

MetricMeasures“Good” threshold
Largest Contentful Paintloading — when the main content appears≤ 2.5 s
Interaction to Next Paintinteractivity — worst-case interaction latency across the visit≤ 200 ms
Cumulative Layout Shiftvisual stability — how much the page moves under the user≤ 0.1

All three are assessed at the 75th percentile of page loads, segmented between mobile and desktop. That percentile choice is deliberate and worth saying out loud: it means a quarter of your users can have a worse experience than your reported number.

Interaction to Next Paint fully replaced First Input Delay — stable in March 2024, with the old metric removed from tooling that September. The change mattered because the old one measured only the delay before the first interaction was processed, so a page could score perfectly while every interaction after the first was slow. The new one measures the whole interaction through to the next paint, across the whole visit. There is still no fourth Core Web Vital as of August 2026.

One genuinely important thing in flight: the Soft Navigations API, which heuristically detects single-page-application route changes so the metrics can attribute them. Final origin trial in Chrome 147, unflagged from Chrome 151. This matters enormously, because today a single-page app gets one paint measured at the hard navigation and nothing thereafter — every subsequent route change is invisible to field data.

What the field data actually says

From the Chrome user-experience dataset, July 2026: just over 18 million origins, of which 55.7% pass all three Core Web Vitals — up from about 51% eighteen months earlier. So nearly half the web still fails, and the trend is improvement of roughly three points a year.

From the 2025 Web Almanac, which is the richest measured source available: mobile 48% passing, desktop 56%. Individually, interaction latency passes on 97% of desktop pages and 77% of mobile ones; loading passes on 74% and 62%.

The fixes, ranked by how much of the web is still missing them

THE CHEAPEST PERFORMANCE WINS, RANKED BY HOW MUCH OF THE WEB STILL HASN'T DONE THEM — 2025 Web Almanac, mobile 82.7% do NOT set fetchpriority="high" on the LCP image one attribute — and the browser’s guess is usually wrong 62% have at least one image with no width/height or aspect-ratio median 2 per page, 26 at the 90th percentile — this is most of your CLS 23% send Cache-Control: no-store, which disables back/forward cache instant back navigation is the cheapest win that exists, and this switches it off 16.5% lazy-load their OWN largest contentful element an unforced error — you delayed the one image the metric measures 11% still register an unload handler, also killing bfcache and 28% of the top thousand desktop sites do, which is worse, not better WHY THIS LIST BEATS ANY FRAMEWORK CHOICE Every row is a one-line change, needs no re-architecture, and is being skipped by most of the web. Do these before you argueabout rendering strategy. And the number that shows performance is not solved: median total blocking time is 92 ms on desktop and 1,916 ms on mobile — andmobile blocking time got 58% worse year over year even while the interaction metric improved. Faster phones are masking heavier code, not fixing it. That single pair of numbers is the best answer to “why do my scores look fine on my laptop while users complain?”
Every row is a one-line change that most of the web has not made. The pair of numbers at the bottom is the best single argument that performance is not a solved problem.

Some context behind those rows. The largest element is an image on about 85% of desktop pages and 76% of mobile ones — so the loading metric is, in practice, an image delivery metric. And image formats are barely modernised: JPEG is still 57% of largest-element images, PNG 26%, and WebP only 11%.

On layout stability: 87% of mobile pages load a web font but only 22% pre-connect to its origin and about 15% preload it, and 40% of mobile pages run animations that are not composited — meaning they animate properties that force layout rather than running on the compositor.

Techniques with actual published outcomes

Two categories have named case studies with business metrics attached, which is much stronger evidence than the usual advice:

  • Speculation Rules — prerendering the likely next navigation. One eyewear retailer published mobile loading dropping from 4.69 to 2.66 seconds with mobile conversion up 101% and desktop up 156%; a publisher reported loading down 17.9% with engagement peaks up 8.9%. Say the caveat out loud though, because it is commonly misunderstood: this improves the next page, not the current one. Adoption is only 3–5% among the largest sites but around 24% in the long tail, almost entirely because one content management system ships it by default.
  • Interaction latency work, with published outcomes: a property platform cut it 80% and reported 36% more conversions year over year; a travel site cut it 72% for a 7% sales lift; a news publisher cut blocking time thirtyfold and halved its bounce rate; a retailer cut it 50% for a click-through gain.

The mechanics behind that second group are the same everywhere: break long tasks so the browser can paint between them, using the scheduler yield API, and attribute the remaining ones with the Long Animation Frames API rather than guessing. Note that a widely repeated ‘40–60% improvement from yielding’ figure could not be traced to a primary source — use the named case studies instead.

Three pieces of folklore to push back on

“We moved to server rendering, so we're fast.” Server rendering helps the loading metric and does nothing for interaction latency — that is main-thread work, and server-component-heavy applications can ship more JavaScript than the single-page app they replaced once the client boundary spreads.

“Our Lighthouse score is 95, so users are fine.” Lab blocking time and field interaction latency diverge badly. The 92-millisecond-desktop against 1,916-millisecond-mobile split is that divergence. Lab tools run on your machine; your users are on a mid-range phone on a congested network.

“Code splitting always helps.” It converts one long task into a request waterfall unless you also prefetch. Splitting without prefetching frequently makes the interaction it was meant to speed up slower.

The general form of all three: each is a real technique being credited with fixing a metric it does not touch. The discipline is asking which of the three metrics does this change actually move, and through what mechanism?

Check yourself

Why did INP replace FID?FID measured only the delay before the first interaction was processed, so a page could score perfectly while every later interaction was slow. INP measures the whole interaction through to the next paint, across the visit.
What fraction of the web passes Core Web Vitals?About 56% of origins as of July 2026, up from roughly 51% eighteen months earlier. Not 'most'.
What is the single cheapest LCP fix most sites skip?fetchpriority="high" on the largest image — about 83% of mobile pages do not set it, and the largest element is an image on three quarters of them.
Does server rendering fix interaction latency?No. It helps the loading metric only. Interaction latency is main-thread work, and server-component apps can ship more JavaScript than the SPA they replaced.
← Build tooling after the Rust migrationCross-platform mobile, and how to actually choose →