Lighthouse CI vs WebPageTest for Regression Gates

A performance budget is only as good as the check that enforces it. The two tools most static sites consider for that check are Lighthouse CI, which runs Lighthouse inside the CI job against a preview build, and WebPageTest, which loads the preview on real browsers and devices from test locations and reports back through its API. Both can fail a pull request. They differ in how noisy they are, what they catch, how long they take and what they cost — and a gate that is too noisy gets ignored, while one that is too slow gets skipped.

This comparison ran both as gates on every pull request of a 1,900-page Astro documentation and marketing site for eight weeks, alongside a set of deliberately introduced regressions, and recorded variance, catches, false alarms, time and cost. It belongs to Performance Budgets and Lighthouse CI; the Lighthouse CI setup is in Setting Up Lighthouse CI for a Static Site.

Method

  • Pages: six URLs covering every template — home, docs article, docs index, blog post, pricing, changelog.
  • Lighthouse CI 0.14 on the GitHub Actions standard runner, against the static build served locally, mobile preset, 5 runs per URL, median assertions.
  • WebPageTest (hosted, API) against the pull request's preview deploy, Moto G Power on 4G from one location, 3 runs per URL, first view, median.
  • Assertions, both tools: LCP, Total Blocking Time (TBT), CLS, total JavaScript bytes and total transfer bytes per template, with tolerances set from two weeks of baseline variance.
  • Regressions: 12 deliberate changes introduced in throwaway pull requests over the eight weeks, each with a known effect, plus whatever real regressions occurred.

Variance

Two weeks of runs on unchanged main gave each tool's noise:

Metric (median of runs, CoV across builds)Lighthouse CIWebPageTest
LCP7.8%4.1%
TBT31%18%
CLS0% (deterministic here)0%
JS bytes0%0%
Performance score4.6 points SD—

TBT under Lighthouse CI was the noisiest metric: shared runners vary in CPU speed, and simulated throttling multiplies that variation. Byte counts were perfectly stable in both, which is why they make the best hard gates.

Coefficient of variation of LCP and TBT for each tool on unchanged builds Paired bars. LCP varied by 7.8 percent in Lighthouse CI and 4.1 percent in WebPageTest. Total Blocking Time varied by 31 percent in Lighthouse CI and 18 percent in WebPageTest. Run-to-run noise by metric Lighthouse CI WebPageTest LCP variation 7.8% 4.1% TBT variation 31% 18%
Two weeks of daily runs on main with no performance-relevant changes; medians of 5 Lighthouse runs and 3 WebPageTest runs per URL.

Regressions Caught

Deliberate regressionEffectLighthouse CIWebPageTest
+180 KB JS on docs (date library)JS bytes, TBTCaught (bytes)Caught (bytes)
Hero image 400 KB largerLCP, bytesCaughtCaught
Removed fetchpriority on heroLCP +300 msCaughtCaught
Font preload removedLCP +250 msMissed (within noise)Caught
Third-party chat widget addedTBT, bytesCaughtCaught
CSS 30 KB largerBytesCaughtCaught
Image without dimensionsCLSCaughtCaught
Late-injected bannerCLSCaughtCaught
Synchronous script in headLCP +400 msCaughtCaught
Slow CDN header (no cache on HTML)TTFB, LCPMissed (served locally)Caught
Unminified JSBytesCaughtCaught
Long task in click handlerINP (not measured)MissedMissed

Lighthouse CI caught 9 of 12; WebPageTest caught 11. The two Lighthouse misses are structural: a 250 ms LCP change was inside its noise band, and a caching problem cannot show when Lighthouse CI loads a locally served build. Neither caught the interaction regression — a page-load test does not interact; that needs an interaction test such as the one in Measuring Web Vitals in Playwright Tests.

Number of deliberate regressions caught by each tool Vertical bars. Lighthouse CI caught 9 of 12 regressions. WebPageTest caught 11 of 12. Running both caught 11. The one missed by both was an interaction regression that page-load tests cannot see. Regressions caught out of twelve 9 Lighthouse CI 11 WebPageTest 11 Both together
Twelve deliberate regressions over eight weeks; both tools used the same assertions and tolerances.

False Alarms

Over eight weeks of real pull requests (214 PRs):

MeasureLighthouse CIWebPageTest
Failed checks on PRs with no performance change93
Of those, TBT assertions72
Re-run to green93

Nine false alarms in 214 PRs was tolerable but noticeable; after the team dropped the TBT assertion's tolerance from 20% to 35% and kept TBT as a warning rather than an error, Lighthouse CI false alarms fell to 2 in the following month without missing any of the deliberate regressions that had triggered on bytes.

Time and Cost

MeasureLighthouse CIWebPageTest
Time added to PR checks2 min 40 s6–14 min (queue + runs)
Runs per PR30 (6 URLs × 5)18 (6 URLs × 3)
Monthly cost at ~110 PRsCI minutes only (~300)Paid API plan
Needs a deployed previewNoYes

WebPageTest's time depended on queueing at the test location, which made it the slowest check on most pull requests — long enough that developers merged before it finished on several occasions.

Making Results Readable for Developers

A gate is only useful if developers can act on a failure without a performance specialist. Both tools produce rich reports, but the default output differed in how quickly someone could see why. Lighthouse CI's temporary public storage gives a link to the full report per URL, and its assertion output names the metric and the threshold; the team added a short PR comment that lists only failing assertions, with a link to the report and a diff of resource sizes against main generated from the Lighthouse JSON. WebPageTest's strength is the filmstrip and waterfall comparison between two tests, which made the font-preload and caching regressions obvious at a glance — a developer looking at the comparison could see the font request start half a second later, or the HTML coming from the origin instead of the edge.

The combination the team settled on posts one comment per pull request: Lighthouse CI's failing assertions and size diff immediately, and, for the nightly WebPageTest run on main, a message in the team channel only when a metric moved beyond its tolerance, with the comparison link. In the month after that change, the median time from a failing gate to a fix pushed was 40 minutes, down from most of a day when failures required someone to dig through raw reports.

Verdict

Decision tree for placing Lighthouse CI and WebPageTest in the pipeline The root asks when the check runs. On every pull request, use Lighthouse CI with byte budgets as errors and metric budgets as warnings. Nightly or before a release, run WebPageTest on real devices against the production or release candidate. For interaction regressions, add a Playwright test that measures event timing. For field truth, rely on RUM and CrUX dashboards. Where each tool fits When does the check run? Every pull request Lighthouse CI bytes as errors Nightly / pre-release WebPageTest real device + CDN Interactions Playwright event timing INP proxy Real readers RUM + CrUX the final word
The combination caught every regression that a page-load test can see.
  • Gate pull requests with Lighthouse CI, asserting byte budgets as errors and LCP, TBT and CLS as warnings with tolerances from your own variance. It is fast, free beyond CI minutes, and caught every byte-driven regression.
  • Run WebPageTest nightly and before releases against production or the release candidate, on a real device and through the CDN. It caught the two regressions Lighthouse CI structurally could not.
  • Add an interaction test for INP; neither page-load tool covers it.

Pitfalls

  • Asserting on the Lighthouse score. Assert on bytes and individual metrics.
  • Setting tolerances from guesswork. Measure two weeks of variance first.
  • Testing a local build only. CDN and header problems need a test through the real host.
  • Gates slower than code review. Developers merge around them.

Conclusion

As pull request gates on the same site, Lighthouse CI was quicker, cheaper and noisier, catching 9 of 12 deliberate regressions; WebPageTest was slower and steadier, catching 11, including a CDN caching problem that a local build cannot show. The arrangement that worked was both: Lighthouse CI on every pull request with byte budgets as hard failures, and WebPageTest on a schedule through the real CDN.

FAQ

Which is better as a pull request gate, Lighthouse CI or WebPageTest?

Lighthouse CI for most static sites. It runs inside the CI job, takes a couple of minutes, and with several runs per URL and assertions on stable metrics it caught most real regressions in this comparison. WebPageTest measured more realistically and caught two regressions Lighthouse missed, but it is slower and costs more, so it fits better as a nightly or pre-release check.

Why do Lighthouse scores vary so much between CI runs?

Lighthouse simulates a slow device and network from a trace recorded on whatever machine runs it. Shared CI runners vary in CPU speed and load, so the simulated timings vary too. Running three to five times per URL and taking the median, asserting on byte budgets that do not vary, and using a dedicated runner reduce the noise.

What does WebPageTest measure that Lighthouse CI does not?

WebPageTest loads pages on real devices or real browsers with traffic-shaped network connections in chosen locations, records a filmstrip and full waterfall, and can test repeat views, scripted multi-step journeys and different connection profiles. Lighthouse CI simulates throttling on the CI machine with a single first-view load.

Should a performance gate fail on the Lighthouse score?

Better not. The score is a weighted blend that moves with small changes in any metric and has the highest run-to-run variance. Assert on resource sizes and counts, which are deterministic, and on individual metrics such as LCP and Total Blocking Time with tolerances measured from your own variance.

Filed underComparisonsLighthouse