Get your free SEO audit today Call 91 060 30 90
</>Technical Guide · 18 min read

Technical speed auditing with Lighthouse and PageSpeed Insights

This site's Core Web Vitals guide explains what each metric (LCP, INP, CLS) measures and what technically makes it fail. This guide is about something else: the process and tooling used to audit a site's speed, and the interpretation mistakes that lead teams to "fix" a number without first understanding what that number actually measures. Lighthouse and PageSpeed Insights get confused constantly because they share an engine, but they answer different questions, and treating them as interchangeable is the most common cause of misdirected optimization work.

How Lighthouse scores: a simulation, not a real-world measurement

Lighthouse runs a single simulated page load in a headless instance of Chrome, under network and CPU conditions fixed in advance, and calculates a 0-to-100 score by combining several metrics with different weights. In current Lighthouse versions the performance category weighs roughly: Total Blocking Time 30%, Largest Contentful Paint 25%, Cumulative Layout Shift 25%, First Contentful Paint 10% and Speed Index 10%. The combination isn't a linear average: it uses a log-normal distribution curve calibrated against real HTTP Archive data, which means improving from 40 to 50 points is far easier than improving from 90 to 95, even if the real time saved in milliseconds is similar in both ranges.

That curve is why chasing "100 on Lighthouse" as a goal in itself is usually a poor use of time: the last few points demand disproportionate effort relative to the real benefit to the user, and that effort is almost always better spent on other pages in the template that are still in the range where every improvement counts a lot.

PageSpeed Insights: lab and field on the same screen

PageSpeed Insights (PSI) isn't a separate tool from Lighthouse: it runs Lighthouse underneath to generate the "lab experience" section, but it also queries the Chrome User Experience Report (CrUX) to show, on the same screen, the "real user experience" aggregated over the last 28 days. That's the only real difference between the two tools, and it's a decisive one: the field report (CrUX) is what Google uses as a ranking signal, not the lab one.

A technical nuance that's often overlooked: CrUX reports the 75th percentile (p75), not the average. When PSI says field LCP is "2.1 s", it means 75% of real visits had an LCP equal to or better than that value, not that it's the typical time. And if a specific URL doesn't get enough traffic to have its own CrUX data (a minimum sample threshold Google doesn't publish exactly), PSI automatically falls back to aggregated origin-level data (the whole domain), which may not represent that particular page well, especially if the rest of the site has a very different performance profile.

How to read the "Opportunities" and "Diagnostics" sections

A Lighthouse report splits recommendations into two blocks with different logic. Opportunities are optimizations with an estimated savings in milliseconds or kilobytes calculated specifically for that load ("Eliminate render-blocking resources: estimated savings 480 ms"). Diagnostics are informational signals with no direct savings estimate, but that indicate risk (DOM size, main-thread work breakdown, JavaScript execution time).

The most common reading mistake is adding up the estimated savings of several opportunities as if they stacked linearly. They don't: each estimate is calculated in isolation, assuming only that specific issue gets fixed, so if two opportunities compete for the same bottleneck (for example, two different resources blocking the same main thread), fixing both doesn't add up their two savings separately, because the second fix already finds part of the path cleared by the first one.

Opportunity                              Estimated savings
Eliminate render-blocking resources      480 ms
Reduce unused JavaScript                 310 ms
Serve images in next-gen formats         220 ms

Naive sum: 1,010 ms
Real expected savings after applying all 3: considerably less,
because all three compete for the same main thread
and the same network connection.

The trap of a fast lab score with slow field data (and the reverse)

It's common for a recently optimized site to score 95 on Lighthouse and still show a mediocre field LCP in PageSpeed Insights, and the reason is almost never a measurement error but a real difference in conditions. Lighthouse simulates a fixed profile (roughly a mid-range mobile phone with a limited 4G connection) in a single run with an empty cache. Field data, on the other hand, aggregates weeks of visits from real users with the full variety of devices, rural or congested networks, and outdated browsers the lab never reproduces. For businesses with a geographically dispersed customer base, this mismatch between an optimistic lab and a harsher real field is extremely common and doesn't mean the optimization failed, only that it represents the slowest slice of the real audience worse.

The opposite case happens too: a site with a mediocre lab score can show better-than-expected field data, usually because a large share of real traffic is repeat visits with the browser cache already warm (assets already downloaded on prior visits), while Lighthouse always starts from a completely empty cache and penalizes that cold first load which, in practice, many users never experience.

Throttling profiles: why the comparison only holds if the profile is the same

By default Lighthouse applies simulated throttling: instead of actually slowing down the network and CPU during the load, it runs the page with no restrictions and then applies a mathematical model over the captured trace to estimate how it would have behaved with a more limited connection and CPU. It's faster to run and reasonably accurate, but it's an estimate, not a direct measurement. The alternative is applied throttling (via the DevTools Protocol), which does actually slow down the network and CPU during execution: slower to run and with more variance between runs, but truer to a real, constrained device.

The default CPU profile in Lighthouse's mobile mode applies a 4x slowdown to the CPU of the machine running the test, to approximate the performance of a mid-range phone. This has an important practical consequence: comparing a Lighthouse score obtained on a powerful laptop without that throttling against another obtained with the standard mobile profile is not a valid comparison, even though both use the "same tool". For two audits to be comparable to each other (before/after a change, or between two pages on the same site), you need to fix the same device profile, the same throttling type, and, if possible, repeat each run several times and keep the median, because a single Lighthouse run has notable variance even on the same machine at the same moment, attributable to operating system and network noise.

Automating Lighthouse in CI: catching regressions before they ship

Running Lighthouse manually now and then catches problems that are already live, but doesn't stop them from going live. The way to turn it into a real safeguard is to run it in the continuous integration pipeline against every change, with a performance budget that fails the build if a metric regresses past a threshold. The Lighthouse CLI lets you run it headlessly and export the result as JSON:

npm install -g lighthouse
lighthouse https://www.yourdomain.com/ \
  --output json --output-path ./report.json \
  --preset=desktop --throttling-method=devtools

For continuous regression testing, Lighthouse CI (LHCI) adds automatic comparison against a reference build plus an assertions file defining the acceptable thresholds:

// lighthouserc.js
module.exports = {
  ci: {
    collect: { numberOfRuns: 3, url: ['https://staging.yourdomain.com/'] },
    assert: {
      assertions: {
        'categories:performance': ['error', { minScore: 0.85 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'total-blocking-time': ['warn', { maxNumericValue: 300 }],
      },
    },
    upload: { target: 'temporary-public-storage' },
  },
};

With numberOfRuns: 3 the audit runs three times and uses the median, reducing the noise of a single isolated run. Wired in as a required step in a pipeline (GitHub Actions, GitLab CI or similar), this turns a performance regression into a visible build failure before deployment, instead of a finding discovered later in production that has to be rolled back.

Frequently asked questions

Should I optimize for the Lighthouse score or for PageSpeed Insights' field data?

For ranking, only field data (CrUX) matters, but Lighthouse remains the useful prior diagnostic tool: it lets you detect and fix concrete causes before waiting weeks for them to show up in field data. Use it to diagnose, not as the final goal.

Why does my Lighthouse score change between runs without me changing anything?

That's expected: a single run has variance from system noise, network noise, and the machine running Chrome itself. For a reliable comparison, run it several times (at least three) and compare the median, not a single isolated run.

What's the difference between "mobile" and "desktop" mode in PageSpeed Insights?

They apply different throttling profiles and viewports: mobile mode simulates a constrained CPU and a slower connection, meant to represent the most demanding end of the audience. Google weighs mobile field data more heavily since it usually accounts for most of the real traffic.

Is it worth running Lighthouse locally (localhost) during development?

It's useful for catching structural problems (excess JavaScript, images without dimensions, blocking resources) before publishing, but the exact score isn't representative: localhost has neither the network latency nor the real load of production hosting, so the specific figure needs to be re-checked against the public URL.

Want to talk about technical SEO for your site?

Tell us about your project and we'll tell you how we can help, no strings attached.

Call 91 060 30 90