Performance Testing on Throttled Mobile Profiles
Every lab performance test is a simulation of some reader. Lighthouse's default mobile profile simulates one specific reader — a mid-range phone on a slowish 4G connection — and most teams never check whether that reader resembles their own. For a developer documentation site whose readers are mostly on laptops with fibre, the default is pessimistic, and a team chasing a 90 Lighthouse score may be optimizing for someone who never visits. For a consumer site whose readers use budget Android phones on congested networks, the default is optimistic, and a green score hides a slow site.
This guide explains what throttling profiles actually do, calibrates lab settings against field data for two static sites with very different audiences, adds testing on a real mid-range phone, and sets up CI runs with both a standard and a calibrated profile. It is part of Performance Budgets and Lighthouse CI.
Prerequisites
- Field data: CrUX for pages with enough traffic, or your own RUM with the
web-vitalslibrary. - Lighthouse 12 (CLI or Lighthouse CI), and WebPageTest for real-network tests.
- Optionally, a physical mid-range Android phone and a USB cable for remote debugging.
What Throttling Does
Lighthouse's default mobile preset applies:
| Setting | Value |
|---|---|
| Round-trip time | 150 ms |
| Download throughput | 1.6 Mbps |
| Upload throughput | 750 kbps |
| CPU slowdown | 4× |
| Viewport | 412 × 823, DPR 1.75 |
| Method | simulated (Lantern) |
"Simulated" means Lighthouse loads the page without throttling and then estimates what the timings would have been under these conditions, using a model of the network and CPU. It is fast and stable, but the model can misjudge sites with unusual loading patterns — many small requests, heavy use of HTTP/3, or service workers. "Devtools" throttling (--throttling-method=devtools) actually slows the connection and CPU in real time; it is slower and noisier but closer to reality for such sites. WebPageTest throttles at the packet level on real devices or VMs, the most realistic of the three.
Two Sites, Two Audiences
The two sites in this guide have opposite audiences:
- Developer docs: 1,300 pages, Eleventy, readers 71% desktop, mostly in North America and Europe.
- Consumer recipe blog: 2,100 pages, Astro, readers 83% mobile, a large share in South and Southeast Asia on mid-range Android phones.
For each, the p75 LCP from CrUX on the home page and two popular templates was compared with lab LCP under several profiles, five Lighthouse runs each:
| Profile | Docs lab LCP | Docs field p75 | Recipe lab LCP | Recipe field p75 |
|---|---|---|---|---|
| Lighthouse default mobile | 2.1 s | 1.2 s (mobile) | 2.4 s | 3.1 s |
| Desktop preset | 0.7 s | 0.8 s (desktop) | 0.9 s | — |
| Custom "fast 4G" (RTT 40 ms, 9 Mbps, CPU 2×) | 1.1 s | 1.2 s (mobile) | 1.4 s | 3.1 s |
| Custom "budget Android" (RTT 200 ms, 1.2 Mbps, CPU 6×) | 2.9 s | — | 3.2 s | 3.1 s |
For the docs site, the default mobile profile overstated mobile LCP by 75%; "fast 4G" matched the field within 0.1 s. For the recipe blog, the default understated field LCP by 0.7 s, and "budget Android" matched.
Step 1: Define a Calibrated Profile
Lighthouse CI accepts custom throttling in settings. The recipe blog added a "budget Android" collection alongside the default:
{
"ci": {
"collect": {
"url": ["http://localhost:4321/", "http://localhost:4321/recipes/dal-tadka/", "http://localhost:4321/collections/weeknight/"],
"numberOfRuns": 5,
"settings": {
"preset": "perf",
"formFactor": "mobile",
"throttlingMethod": "simulate",
"throttling": { "rttMs": 200, "throughputKbps": 1200, "cpuSlowdownMultiplier": 6 },
"screenEmulation": { "mobile": true, "width": 360, "height": 780, "deviceScaleFactor": 2 }
}
}
}
}
A separate config file keeps the default mobile profile, so results can still be compared with published benchmarks and with Search Console's lab data. Both run in CI; budgets apply to the calibrated one, as described in Writing a Performance Budget That Fails Builds.
Step 2: Check the CPU Multiplier Against the Runner
A 4× or 6× CPU slowdown is relative to the machine running the test. A CI runner that is much faster or slower than a typical developer laptop changes what "6×" means. Lighthouse reports a benchmarkIndex for the host; on GitHub's standard runners it was around 1,250, on a developer M2 laptop around 2,900. For the calibrated profile, the recipe team computed the slowdown per environment so that the effective CPU speed matched the target device — 6× on CI runners, 13× on laptops — and recorded the benchmark index with each result. Without that, laptop runs looked 40% faster than CI runs of the same build.
Step 3: Test on a Real Phone
Simulation cannot capture everything. Once a month, the recipe team runs the three key pages on a real Samsung Galaxy A14 (a common budget phone among its readers) over a real 4G connection, using Chrome remote debugging and the Performance panel, and a WebPageTest run on a Moto G-class device from the Mumbai location. The real-device results caught two things the simulation missed: a CSS backdrop-filter on the sticky header that cost 30–40 ms per frame on the phone's GPU during scrolling, and thermal throttling after two minutes that made long recipe pages with many images noticeably slower to scroll.
Step 4: Recalibrate When Things Change
Calibration drifts. The docs site's audience shifted after a product launch in India, raising its mobile share from 29% to 41% and moving field LCP up; the "fast 4G" profile then understated it. A monthly comparison of lab and field — the approach in Comparing Lab and Field Data with CrUX — flagged the gap, and the docs site added a second calibrated profile for the new audience segment.
Explaining Profiles to the Rest of the Team
Throttling settings look like arbitrary numbers to anyone outside the performance work, and a Lighthouse score that changes because the profile changed invites suspicion. Both teams added a short note at the top of each CI report stating the profile in plain words — "budget Android on congested 4G, our median recipe reader" — and kept a one-page explanation in the repository of how the profile was derived from field data and when it was last calibrated. When a product manager asked why the recipe site's Lighthouse score had "dropped" from 94 to 81 overnight, the answer was in that document: nothing had changed on the site, the report now used the profile that matched real readers, and the lower number was the more honest one.
Measured Impact
| Measure | Default profile only | Default + calibrated profiles |
|---|---|---|
| Docs: lab-to-field LCP gap (mobile) | +0.9 s (lab pessimistic) | +0.1 s |
| Recipes: lab-to-field LCP gap | −0.7 s (lab optimistic) | +0.1 s |
| Recipes: regressions caught in CI that the default missed (6 months) | — | 5 |
| Docs: optimization work avoided on non-issues (estimated) | — | ~3 weeks |
| CI time per pull request (both profiles) | 2.1 min | 3.4 min |
The docs team's biggest gain was negative: they stopped a planned project to shave 400 ms off mobile LCP that their actual readers would never have noticed.
Pitfalls & Rollback
- One profile for every site. The default is a convention, not a description of your readers.
- Comparing runs across machines without checking CPU speed. Record
benchmarkIndex. - Treating simulated throttling as ground truth. Validate with packet-level and real-device tests.
- Calibrating once. Audiences change; recheck monthly.
- Rollback: calibrated profiles are separate config files; removing them returns CI to the default profile without affecting anything else.
Conclusion
A lab test is only as useful as its resemblance to your readers. Keep Lighthouse's default mobile profile for comparability, add a profile calibrated to your field data, adjust CPU slowdown for the machine running the tests, and check the simulation against real devices regularly. On these two sites that turned lab numbers from misleading — in opposite directions — into predictions within 0.1 s of the field.
FAQ
What does Lighthouse's default mobile throttling simulate?
A mid-tier phone on a slow 4G connection, with about 150 milliseconds round-trip time, 1.6 Mbps download and a 4x CPU slowdown relative to the test machine. By default it uses simulated throttling, which estimates timings from an unthrottled load rather than slowing the network in real time.
Should I change the default throttling?
Keep the default for comparability with other sites and tools, but add a second profile calibrated to your own field data. If your readers are mostly on fast desktop connections or mostly on low-end Android devices, the default will overstate or understate their experience.
How do I calibrate throttling against field data?
Pick a few pages with enough field traffic, compare their CrUX or RUM p75 LCP with lab LCP under different throttling settings, and choose the setting whose lab results land closest to the field. Repeat when the audience or the site changes significantly.
Is CPU throttling on a fast machine realistic?
Roughly. A 4x slowdown on a modern laptop approximates a mid-range phone, but CPU throttling does not simulate thermal limits, memory pressure or slower GPUs. Testing on a real mid-range Android phone now and then keeps the lab honest.
Related
- Parent: Performance Budgets and Lighthouse CI — budgets and CI setup.
- Reducing Lighthouse Score Variance in CI — making repeated runs agree.
- Running WebPageTest Scripts Against Preview Deploys — packet-level tests on previews.
- Per-Template Performance Budgets — budgets for each template.
- Building a Core Web Vitals Dashboard from RUM Data — the field side of calibration.
Filed underHow-tosLighthouse