The report that gets ignored
A forty-page PDF of Lighthouse audits, each with the tool's boilerplate explanation, a score out of 100 in a coloured circle, and a list of "opportunities" with estimated savings that do not add up. It lands with the engineering team, who already know Lighthouse exists, and it is filed. Nothing changes because nothing in it told anyone what to do first, why, or how they would know it worked.
We have written that report. We stopped. Here is the format that replaced it, which is shorter, harder to write and gets acted on.
Section 1: field data, one page
Start with what real visitors experience, because that is what Google ranks on and what the client's customers feel. From CrUX (via Search Console, PageSpeed Insights' field section, or the CrUX API) for the origin and for each key page group:
| Page group | LCP p75 | INP p75 | CLS p75 | Status | |---|---|---|---|---| | Home | 3.4s | 180ms | 0.02 | Poor (LCP) | | Service pages | 2.9s | 310ms | 0.15 | Poor (INP, CLS) | | Blog posts | 2.1s | 140ms | 0.01 | Good |
Mobile and desktop separately, because they differ and mobile is what matters. Then one paragraph: which metrics fail, on which pages, and what share of traffic those pages carry. This section tells the client whether they have a problem and how big.
If field data is thin (a low-traffic site), say so, install real-user monitoring as the first recommendation, and use lab data with an explicit caveat.
Section 2: attribution per failing metric
For each metric that fails on a page group, what is causing it, established from traces and field attribution, not from Lighthouse's guesses.
LCP, service pages. The LCP element is the hero image (img.hero__img). Breakdown from traces on a throttled mobile profile: TTFB 600ms, resource load delay 1100ms, load duration 500ms, render delay 100ms. The 1100ms delay is because the image is inserted by the slider script, which loads after the tag manager. The element is also lazy-loaded.
INP, service pages. Field attribution over 7 days: 68 percent of poor INP interactions target button.menu-toggle, event type pointer, with input delay averaging 280ms during dom-interactive load state. The blocking script in the long animation frame is the chat widget loader.
CLS, service pages. Shift records show two sources: the testimonial carousel resizing when its script initialises (score 0.09), and the web font swap on headings (0.05).
Each attribution names the element, the cause and the evidence. An engineer reading it knows exactly where to look and does not have to trust us.
Section 3: fixes, prioritised
A table, ordered by expected impact divided by effort. Each row:
| # | Fix | Metric | Pages | Expected impact | Effort | Owner |
|---|---|---|---|---|---|---|
| 1 | Render hero as server-side <img> with fetchpriority="high", remove lazy | LCP | Service, Home | LCP −1.0s | 2h | Front end |
| 2 | Load chat widget on first interaction, not on load | INP | All | INP −150ms | 1h | Front end |
| 3 | Reserve carousel height; init without resize | CLS | Service | CLS −0.09 | 2h | Front end |
| 4 | Font metric overrides for heading fallback | CLS | All | CLS −0.05 | 1h | Front end |
| 5 | Move tag manager to load after LCP | LCP, INP | All | LCP −0.3s, INP −50ms | 1h | Marketing + FE |
| 6 | Object cache and TTFB work on host | LCP | All | TTFB −300ms | 4h | Back end |
Expected impact is an estimate from the traces, stated as a number so it can be wrong in a specific way. Effort is honest. Owner matters: fix 5 needs marketing's agreement, and saying so in the report avoids the fix stalling in a meeting nobody scheduled.
Six to ten rows. Not forty. The long tail goes in an appendix, marked as such.
Section 4: what we did not recommend, and why
The Lighthouse opportunities that are real but not worth it right now. "Reduce unused CSS: 40KB. Would save ~50ms; not worth the refactor risk this quarter." "Minify JavaScript: already minified; the audit is flagging source maps." This section is what stops the client's team spending a week on the wrong thing because a tool said so, and it is what earns the report credibility.
Section 5: verification plan
How everyone will know it worked.
- Lab: before/after traces on the same throttled profile for each fix, recorded in a shared doc as fixes ship.
- Field: the RUM dashboard (set up as fix 0 if it does not exist) showing p75 by page group daily; Search Console's report expected to reflect changes over 28 days from the last fix.
- Targets: LCP under 2.5s, INP under 200ms, CLS under 0.1 at p75 on mobile for each page group. Stated so the engagement has an end.
- Regression guard: a Lighthouse CI or similar check in the deploy pipeline with budgets set just above the post-fix numbers, so the next marketing script that regresses INP fails a build rather than a quarter.
Section 6: appendix
Raw traces, the attribution data export, the full Lighthouse output for reference, the long-tail list. Here so nobody says it was hidden; here so it does not dilute the report.
Why this format works
It is ordered the way an engineer thinks: is there a problem, where exactly, what do I do first, how will I know. It gives numbers that can be checked. It assigns owners. It says what not to do. And it is short enough to read in the meeting where the work gets approved.
This is the deliverable from every Core Web Vitals audit we run. The traces take a day; the field attribution takes a week of data; the report takes an afternoon to write because the format does the organising. The Lighthouse PDF took an hour to generate, and it was worth about that.