Skip to content
Performance Lab · LAB-05LCP / INP

Save the terrible website

LCP 7.8s. INP 840ms. CLS 0.42. 4.8MB of JavaScript. You have a budget and a mission.

Level
SYSTEMS
Read time
15 min
Experiment
Available
Type
INTERACTIVE

The question

Given a genuinely bad page, which fixes actually move the metrics, and which ones feel productive but change nothing?

Hypothesis

A small number of structural fixes dominate. Most micro-optimisations are noise next to render-blocking resources and main-thread work.

Method

Laboratory available

The instrument for this investigation runs in the laboratory, where the controls, the live model and the observation log share one workstation.

Enter the laboratory

Apply interventions one at a time. The bench models how each one affects the three Core Web Vitals and the total transfer. Order matters, some fixes are only worth applying after another one lands.

What we observed

MetricGoodNeeds improvementPoor
LCP. Largest Contentful Paint≤ 2.5s2.5s to 4.0s> 4.0s
INP. Interaction to Next Paint≤ 200ms200ms to 500ms> 500ms
CLS. Cumulative Layout Shift≤ 0.10.1 to 0.25> 0.25
Core Web Vitals thresholds (75th percentile of real users)

Why it happens

What actually moves each metric

  1. 01LCP: remove render-blocking resources, serve the hero image in a modern format at the right size, preload it, and make sure it is not lazy-loaded.
  2. 02LCP: cut time to first byte, caching and edge delivery beat every client-side trick.
  3. 03INP: break up long tasks, move work off the main thread, and keep event handlers under a frame's budget.
  4. 04INP: yield with scheduler.yield() or an explicit task split so the browser can paint between chunks.
  5. 05CLS: reserve space, width/height on images, min-height on ad and embed slots, font-display with a matched fallback metric.
  6. 06CLS: never insert content above existing content after load, including banners and consent bars.
example.htmlhtml
<link rel="preconnect" href="https://cdn.example.com" crossorigin><link rel="preload" as="image" href="/hero.avif" fetchpriority="high"><img src="/hero.avif" width="1600" height="900" alt="" fetchpriority="high"><!-- width/height reserve the aspect ratio box, so nothing shifts -->
Four lines that routinely fix a bad LCP and CLS

Bundle size matters, but not linearly. 1MB of JavaScript costs transfer time once, and parse + compile + execute time on every single load, on a CPU that may be five times slower than yours. That is why removing 200KB of JavaScript often beats removing 2MB of images.

Further research

Lab data (Lighthouse) and field data (Chrome UX Report) answer different questions. Lighthouse is a reproducible synthetic run used to compare changes; CrUX is what your actual users experienced, on their actual devices, over 28 days. A perfect Lighthouse score with a poor CrUX report means your synthetic profile does not resemble your users.

References

  1. 01web.devCore Web Vitals
  2. 02web.devOptimize INP
  3. 03web.devOptimize LCP