Method note
How to report a Lighthouse score without overstating it
Run Lighthouse twice on the same page and the number moves. That is the tool working correctly. This is a run protocol that produces a number you can defend, and the sentence to put beside it when a client asks what it proves.

Seven Lighthouse runs, one page, one afternoon, one laptop.
| Run | Device profile | Network setting | Page state | Performance score | LCP | CLS | TBT | What changed |
|---|---|---|---|---|---|---|---|---|
| 1 | Mobile, 412 by 823 | Simulated, 150 ms RTT, 1,638 Kbps, 4x CPU | Cold, storage cleared | 99 | 1,005 ms | 0.046 | 0 ms | Baseline |
| 2 | Mobile, 412 by 823 | Simulated, 150 ms RTT, 1,638 Kbps, 4x CPU | Cold, storage cleared | 99 | 1,052 ms | 0.046 | 0 ms | Nothing |
| 3 | Mobile, 412 by 823 | Simulated, 150 ms RTT, 1,638 Kbps, 4x CPU | Cold, storage cleared | 99 | 995 ms | 0.046 | 0 ms | Nothing |
| 4 | Mobile, 412 by 823 | Simulated, 150 ms RTT, 1,638 Kbps, 4x CPU | Cold, storage cleared | 100 | 995 ms | 0.046 | 0 ms | Nothing |
| 5 | Mobile, 412 by 823 | Simulated, 150 ms RTT, 1,638 Kbps, 4x CPU | Warm, storage kept from run 4 | 100 | 862 ms | 0.046 | 10 ms | Page state |
| 6 | Desktop, 1,350 by 940 | Simulated, 40 ms RTT, 10,240 Kbps, 1x CPU | Cold, storage cleared | 99 | 342 ms | 0.000 | 0 ms | Device preset |
| 7 | Desktop, 1,350 by 940 | Simulated, 40 ms RTT, 10,240 Kbps, 1x CPU | Cold, storage cleared | 100 | 324 ms | 0.000 | 0 ms | Nothing |
This evidence is first-party. I ran these against https://www.intelliblitz.com/, a site we own, on 2026-07-28 between 13:32 and 13:34 UTC. They describe that page at that moment. They are not a benchmark, and no third-party site was touched to produce them.
Read the first four rows again. Nothing was changed between them, and the score still moved. That is the instrument behaving normally, and Lighthouse documents why it happens: page nondeterminism, local network variability, web server load, client hardware, resource contention from whatever else the machine is doing, and the browser's own scheduling. Its own advice is blunt about the remedy. The median score of five runs, the documentation says, is twice as stable as one run.
So the useful question is not which number is correct. It is what a number is allowed to support, and that depends on how it was produced.
Step 1. Write the configuration down before you write the number down
A performance score is not a measurement. It is a weighted average of five metric scores, and the weights carried in the runs above are First Contentful Paint 10, Speed Index 10, Largest Contentful Paint 25, Total Blocking Time 30, Cumulative Layout Shift 25. Two of those, LCP and TBT, carry more than half the result between them. A score that moves may be reporting a real change in one metric, a rounding boundary in another, or nothing at all.
Every one of those five metrics is produced under conditions the tool or you chose. Record them before you record the number, because a score without its configuration cannot be repeated, and a result nobody can repeat is an anecdote.
Step 2. Run it four times and change nothing
Four identical runs is enough to see a spread rather than a coincidence, and one short of what the documentation asks for. Mine produced 99, 99, 99 and 100. A fifth would have made the median defensible; I ran four, which is a limit on this evidence, not a recommendation.
What moved and what did not
The score moved by one point. Underneath it, LCP ranged from 995 ms to 1,052 ms, a spread of 57 ms. Speed Index, which the table does not carry, ranged from 2,480 ms to 2,840 ms, a spread of 360 ms on a base of 2,480. CLS was 0.046 in all four. TBT was 0 ms in all four.
That last pair matters more than the first. The two metrics that stayed still are the ones with the heaviest weights, and they stayed still because this page has almost no JavaScript work to block the main thread. On a page with a heavy bundle, TBT is where the noise lives, and TBT is 30 percent of the score. The spread you see is a property of the page under test, not a constant to carry to the next site.
Performance 100
LCP 995 ms | CLS 0.046 | TBT 0 ms
Lighthouse 13.4.0, Chrome 150.0.7871.187, headless
Mobile emulation, simulated throttling, storage cleared
2026-07-28T13:33:16ZEstablishesOne lab result for one URL, under one recorded configuration, at one moment, on one machine.
Does not establishWhat any visitor experienced. Whether the page is faster than it was last month. Whether 100 is repeatable, which only the other runs can address, and they answer 99.
Step 3. Change the device profile, then read what else moved
Runs 6 and 7 use the desktop preset. The score barely moved. Everything under it did: LCP fell from about 1,000 ms to about 330 ms, and CLS fell from 0.046 to 0.000.
The preset is a configuration, not a variable
Changing one flag did not change one thing. The desktop preset swaps the emulated viewport from 412 by 823 to 1,350 by 940, drops the CPU slowdown from 4x to 1x, and changes the simulated network from 150 ms and 1,638 Kbps to 40 ms and 10,240 Kbps. Three variables move together. If you want to isolate the viewport, you have to override the throttling settings by hand and say that you did.
Layout shift is a property of the viewport as much as the page
CLS of 0.046 on mobile and 0.000 on desktop is the same markup measured against two different layouts. The desktop runs also requested 95 resources where the mobile runs requested 80, because responsive images resolve differently at a different width. Neither number is the truth about the page. They answer different questions, and only one of them matches how most of that site's visitors arrive.
Step 4. Change the page state and watch the network leave
Run 5 is the baseline configuration with one flag added, --disable-storage-reset, executed immediately after run 4 in the same browser profile.
A warm run is a different question, not a better answer
The page transferred 8,172 bytes. Runs 1 through 4 each transferred about 5.5 MB. LCP dropped to 862 ms, below anything the cold runs produced, and TBT rose from 0 ms to 10 ms.
That is a legitimate measurement of a returning visitor and a dishonest measurement of a first visit. If a report quotes a warm number without saying so, the client is being shown the best case and told it is the case. Say which one you ran, in the same sentence as the number.
Step 5. Decide what leaves the building
Now the number has to survive a client asking what it means.
| Question the client asks | One lab run | Repeated lab runs | Field data |
|---|---|---|---|
| Is the page slow right now? | Weak, one sample under one configuration | Yes, for that configuration and moment | Yes, for real visits in the collection window |
| Did our fix help? | No, the change may be smaller than the spread | Yes, if the spread is smaller than the change | Yes, once enough visits accumulate |
| What do our actual visitors experience? | No | No | Yes, within the dataset's eligibility rules |
| Which element is holding LCP back? | Yes, the diagnostic names it | Yes, and confirms it is consistent | No, field data reports timings, not causes |
| Is this page faster than a competitor's? | No, and do not ask this of a lab run | No | Only where both are in the dataset |
The right column deserves a name. The Chrome UX Report is a dataset that reflects, in its own words, how real-world Chrome users experience popular destinations on the web: real visits, real devices, real networks, subject to eligibility rules that exclude pages without enough traffic to be statistically meaningful. It is not a better lab run. web.dev is explicit that connection setup, redirects and other delays before the first byte land inside field LCP and can push the two apart.
Column two is the one most reports skip. Repeating the run takes minutes and converts a number you have to hedge into a number you can defend.
Step 6. Write the sentence that travels with the number
The command that produced run 1, verbatim, so the whole thing is repeatable:
lighthouse https://www.intelliblitz.com/ \
--only-categories=performance \
--output=json --output-path=run-1.json \
--chrome-flags="--headless=new --user-data-dir=/tmp/lh-profile \
--no-first-run --no-default-browser-check" \
--quiet
Run 5 adds --disable-storage-reset. Runs 6 and 7 add --preset=desktop. Nothing else differs.
None of this is an AgencyProof capability. What the product does in this family is narrower: it checks first-pass performance signals on sampled pages. Static performance signals and Lighthouse lab measurements, when present, are point-in-time diagnostics. They are not field data or a guarantee of user experience. If you want a lab score, you run the tool yourself, exactly as above.
What the protocol cannot give you is a claim about visitors. Seven runs on one laptop on one connection describe one machine's view of one page. They do not tell you what the site felt like to somebody on a train, and no number of repetitions will convert lab evidence into field evidence.
So here is the sentence to put beside the number, with your own values substituted:
Lighthouse 13.4.0 scored this page 99 on four consecutive mobile runs and 100 on one, under simulated throttling with a cleared cache, on 2026-07-28. That is a lab result for this page under those conditions, not a measurement of what visitors experienced.
Provenance
- Written by
- Balaji PonnambalamFounder, AgencyProof
- Technical review
- Written and self-reviewed against the codebaseAgencyProof is a one-person engineering team; there is no second reviewer to claim.
- Published
- Evidence basis
- Examples come from AgencyProof's own sites, scanned by us.
Every product claim in an article is checked against the AgencyProof source tree before publication, and traced to the code path that implements it. Where the article describes a method rather than a shipped behaviour, it says which it is.
Related reading
Audit LabHow to tell a broken link from a protected endpoint
A response code is evidence, not a verdict. How to read 404, 403, 429, timeouts and bot challenges before calling a link broken.
Agency Field NotesDecide what blocks a launch before the findings arrive
An automated severity label is an input to a launch decision. Agree the blocker test with the client before the findings arrive.
Agency Field NotesWhat to check on a live site when nothing is supposed to have changed
Recurring QA earns its place by catching drift, not by repeating the launch ceremony on a site nobody changed.