The first run came back at 62. The client’s brand team had already approved the hero video. Our job was to explain, in numbers, what that cost.
We run a fixed seven-day Lighthouse pass on production-like builds before we sign off on perf. Not because the score is destiny—because it forces the same conversation every time: what moved LCP, what did not, and what we refuse to pretend is “later.”
Day one: baseline and lies
We snapshot three URLs: home, highest-traffic template, slowest route from RUM. We disable extensions, throttle to 4G, and run three cold starts each. The score is not the deliverable. The filmstrip and dependency tree are.
In 2026 most of our wins still sit in LCP: hero media, font loading, server response. CLS is often a content problem dressed as engineering—images without dimensions, injected banners, cookie bars that reflow the grid.
Days two–four: the three levers that still work
Media. We convert the LCP candidate to a format the browser actually prioritises. Sometimes that means a still frame until interaction. Sometimes it means breaking a marketing rule. The marketing lead almost always prefers a fast still to a slow reel.
Fonts. font-display: swap is not a personality. We subset, we preload one critical face, we delete weights nobody uses.
Server. We trace TTFB to data fetching, not to “Next.js feels slow.” The fix is usually one over-fetch or a geographic miss on the primary database.
Sample guardrail we add to CI—not as law, as a forcing function:
# lighthouse-ci.yml (excerpt)
assert:
assertions:
'categories.performance': ['error', { minScore: 0.88 }]
'first-contentful-paint': ['warn', { maxNumericValue: 2000 }]
We relax thresholds for preview branches. Production gets the tighter band.
Days five–six: INP and the third‑party veto
Interactive delays show up late. We list every third‑party script, who owns it, and whether it earns its milliseconds. Anything that touches the checkout path gets a sunset date or loads after consent.
Day seven: the written report nobody skips
One page: before/after traces, URLs touched, scripts deferred or removed, and explicit non-goals—what we did not optimise and why.
Where this breaks down
When stakeholders treat Core Web Vitals as a sprint ticket instead of a budget. When design keeps adding autoplay because “conversion tests said so” without measuring LCP regressions. When RUM is not wired—we will not argue with synthetic data alone.
Our read
We still use Lighthouse because it is cheap, repeatable, and humbling. The score is a side effect. The habit is the product: name the LCP element, measure it daily for a week, and stop shipping surprises to mobile users on Monday morning.