Throttling and simulation
How Lighthouse makes a fast laptop stand in for a mid-range phone: simulated, applied and no throttling, the CPU benchmark and slowdown, and why the same page scores differently on different machines. Recorded with Lighthouse 13.6.0.
- 01Tell the three methods apartSay what simulated, applied and provided throttling do to the page load, and where each one's slow numbers come from.
- 02Read a simulated reportExplain why the trace and the report disagree, and how Lantern works out a slow phone's numbers from a fast load.
- 03Compare results fairlyRead the benchmark, pick a CPU multiplier for your machine, and explain why PageSpeed Insights and your laptop disagree.
Three ways to slow a page down
In How Lighthouse works, Lighthouse tested the Leaf and Kettle store on a fast laptop. Yet its numbers were for a slow phone. The course ran it on the store again, checking Performance only. The report said the store's LCP, Largest Contentful Paint, was 2,694.7 ms. LCP is the moment the biggest image or block of text appeared.
Then the course opened the trace from that same run. A trace is the full recording of a page load, the kind you read in Reading a performance trace. In the trace, LCP happened at 785 ms.
// One Lighthouse run on the store, Performance only.// Both numbers are the store's LCP from that run, in milliseconds (ms).const lcp = { inTheTrace: 785, inTheReport: 2694.7 }; console.log(`The trace shows LCP at ${lcp.inTheTrace} ms.`);console.log(`The report says LCP was ${lcp.inTheReport} ms.`);- Lines 1 and 2 are comments. Both numbers come from one Lighthouse run, in milliseconds (ms).
- Line 3 holds them: LCP as the trace saw it, and LCP as the report gave it.
- Lines 5 and 6 print
The trace shows LCP at 785 ms.andThe report says LCP was 2694.7 ms.
Same run, same page, and the report's LCP is more than three times later. Which one is right? Both are. They answer two different questions:
- The trace says what really happened, on this fast laptop.
- The report says how long the same load would take on a mid-range phone, on a slow network.
Lighthouse never loaded the store slowly. It loaded it at full speed, then worked out the phone's numbers. Making a fast computer behave like a slower device is called throttling: slowing something down on purpose. You did it yourself in The Performance panel, with DevTools' CPU and network menus.
Lighthouse has three ways to deal with the slow phone. It calls them throttling methods:
simulateis the default. Lighthouse loads the page at full speed, then calculates the phone's numbers. That's where 785 and 2,694.7 came from.devtoolsreally slows the network and the CPU down while the page loads. This lesson calls it applied throttling.providedslows nothing down. The report calls it "Provided by environment": any slowness comes from your own setup, like a real phone.
The course ran every method on the store. Here is the store's LCP four ways: the real load and the estimate from one simulated run, then the other two methods.
Look at the second and third bars. One was worked out, and one was timed on a load that was really slowed down. Yet they landed close together, at 2,694.7 and 2,759.3 ms. The default method works like a satnav:
On Sunday morning, you drive to the tea shop on empty roads, and your satnav saves every turn. Then you ask it how long the same drive takes in Monday's rush hour. It doesn't send you out again. It works out each stretch at rush-hour speed, keeps them in order, and adds them up.
- In real life: The Sunday drive on empty roads
- In Lighthouse: The real load, at the laptop's full speed
- In real life: Every turn and stretch the satnav saved
- In Lighthouse: The trace, and the log of every request
- In real life: Rush-hour speeds
- In Lighthouse: A slow phone on a slow network
- In real life: The rush-hour time the satnav works out
- In Lighthouse: The metrics in the report, like LCP
Throttling makes a fast computer stand in for a slow phone. Lighthouse's default doesn't slow the page down: it loads it fast, then calculates. So the trace shows the fast load, and the report shows the estimate. The other two methods really slow the load down, or leave the slowing to you.
The course ran each method five times, taking turns. Pick a method to see every run:
Chrome loaded the store at full speed, and LCP came at 761 ms. Lantern then worked out a slow phone's LCP from that load: 2,688.9 ms. The median score was 90. Each run took 6.2 s, and the load with its waits took 3.1 s of it.
Before you trust a number from Lighthouse, check which method made it. The next two sections look at the methods one at a time.
Simulated throttling and the Lantern model
Start with the default, since it made the two LCPs. The docs say simulated throttling "uses a simulation of a page load, based on the data observed in the initial unthrottled load." Here is what that means, in four steps:
- Load the page at full speed. Lighthouse even turns off any network throttling first. Its source does that for every method except
devtools. - Keep the notes. It saves the trace, and a log of every request: when it started, what started it, and how big it was.
- Draw a map of the load. A model called Lantern turns the notes into a map of the load's steps. The map shows which step waited for which.
- Time it again, slowly. Lantern replays the map on an imaginary slow phone, and reads the metrics off the new timeline.
Lighthouse's docs name the model in one line: "Lantern is how Lighthouse simulates network and cpu throttling." Another of its docs says simulated throttling works "by replaying network activity on its own."
A map of steps and waits
Lantern's map is a dependency graph. Each step of the load is a node, and there are two kinds:
- A network node is one request, like downloading
app.js. - A CPU node is one task on the main thread, like running
app.js.
An arrow between two nodes means the second had to wait for the first. Here are the steps the store's first paint waited for, drawn that way:
The page has to arrive before the browser can ask for its stylesheets and its script. app.js has to arrive before it can run. The first paint needs both stylesheets and the finished script. Lantern finds this order in the real load. Then it times every step again:
Last night you cooked dal on a big gas stove, and noted how long each step took. A friend with a camping stove, four times weaker, asks how long it'll take them. You don't cook it again. You keep the order of the steps, make each cooking step four times longer, and add them up.
- In real life: Each step in your notes, with its time
- In Lighthouse: A node: one request, or one task on the main thread
- In real life: No frying the onions before they're chopped
- In Lighthouse: An arrow:
app.jshas to arrive before it can run - In real life: A stove four times weaker
- In Lighthouse: The CPU slowdown: each task takes 4 times as long
- In real life: Your total, worked out at the table
- In Lighthouse: Lantern's estimate, with no second load
Lantern's source times the two kinds of node in different ways:
- A CPU node takes as long as it did in the real load, times the CPU slowdown: 4 by default. Tasks that lay out the page get half that slowdown.
- A network node is timed on the slow network. Every round trip, a message to the server and back, takes 150 ms, including the ones that open a connection. The download runs at 1.6 megabits a second.
- To each request, it also adds how long the server took to answer, which it estimates from the real load.
So the estimate keeps what really made the store slow. Its server held the page back for 700 ms in every load, fast or slow. A slow server stays slow in the estimate, and a big file gets slower.
Each metric stretches differently
The same run gave three metrics, both ways. FCP, First Contentful Paint, is when the first text or image appeared. SI, Speed Index, is how quickly the page's content showed up on the screen.
// The same run: three metrics, observed in the real load and reported, in ms.const observed = { FCP: 785, LCP: 785, SI: 1125 };const reported = { FCP: 1944.7, LCP: 2694.7, SI: 2353.4 }; for (const metric of Object.keys(observed)) { const times = (reported[metric] / observed[metric]).toFixed(1); console.log(`${metric}: observed ${observed[metric]} ms, reported ${reported[metric]} ms, ${times} times later`);}- Line 2 holds what Lighthouse observed: its word for what Chrome saw in the real load.
- Line 3 holds what the report gave: Lantern's estimates.
- Line 6 divides one by the other, to see how many times later the estimate is. Line 7 prints one line per metric.
- It prints
FCP: observed 785 ms, reported 1944.7 ms, 2.5 times later, thenLCP: observed 785 ms, reported 2694.7 ms, 3.4 times later. The last line isSI: observed 1125 ms, reported 2353.4 ms, 2.1 times later.
So Lantern doesn't multiply the whole page by one number. Look at FCP and LCP. In the real load, they happened together, at 785 ms. In the estimate, LCP comes 750 ms after FCP.
That's because each metric replays its own part of the graph. For FCP, Lantern keeps only what the first paint needed, like the picture above. For LCP, it keeps every request that finished before LCP, except low-priority images. That's a bigger part of the graph, so LCP can stretch further.
One metric isn't estimated at all: CLS, Cumulative Layout Shift, which measures how much things moved around on the screen. Lantern has no model for it, so Lighthouse reads it from the real load. The simulated runs gave a CLS of 0.1364, the same as the provided runs, which slowed nothing down.
Now the two LCPs from the start make sense. The trace is the Sunday drive. The report is the rush-hour sum. The docs warn about exactly this: the trace values "will not match up with Lighthouse's metric results, as the original trace is prior to the simulation." In DevTools, the report's menu even names it: View Unthrottled Trace.
Why it's the default
Simulation is quick and steady. The docs call it "both very fast and deterministic": the same notes always give the same estimate. On accuracy, they say it's "roughly as accurate or better than DevTools throttling for most sites", but it "suffers from edge cases".
Why it matters: when a simulated report looks odd, open the trace to see what happened, and in what order. Then read the report for how slow that order would be on a phone.
Applied throttling
Sometimes you want the slow load itself, not a sum. Maybe you want to watch the long tasks happen in the trace. That's what devtools throttling gives you. The Lighthouse panel calls it DevTools throttling. This lesson calls it applied throttling, because the slowdown is really applied while the page loads.
A learner drives to the tea shop with an instructor beside her. The instructor's side of the car has a second brake pedal, and the instructor keeps pressing it. The car really goes slower, the trip really takes longer, and the dashcam films the slow trip.
- In real life: The instructor's brake pedal
- In Lighthouse: The throttling Lighthouse turns on in Chrome
- In real life: The car really going slower
- In Lighthouse: The page really loading slowly
- In real life: The dashcam film of the slow trip
- In Lighthouse: The trace, which now matches the report
Lighthouse presses two brakes, the same two kinds of throttling you used in The Performance panel:
- The network. Chrome adds a delay to every request, and caps the download speed.
- The CPU. Chrome slows the page's work down 4 times. The docs say this "actually interrupts execution of CPU work at periodic intervals to emulate a slower processor."
The network delay needs a bigger number than the phone's 150 ms round trip. As The Performance panel explained, DevTools delays each whole request. A real phone network delays each small packet of data. The docs put it plainly: "this throttling isn't highly accurate."
To make up for it, Lighthouse multiplies the round trip by 3.75, so every request waits 562.5 ms. It also multiplies the download speed by 0.9. Choosing test conditions compares the two kinds of network slowing.
Because Chrome measures the slow load itself, the report says what Chrome saw. Compare one run of each kind:
// LCP in ms from two runs: what Chrome saw in the load, and what the report said.const simulated = { saw: 785, reported: 2694.7 };const applied = { saw: 2760, reported: 2760.4 }; console.log(`Simulated: Chrome saw ${simulated.saw} ms, and the report said ${simulated.reported} ms.`);console.log(`Applied: Chrome saw ${applied.saw} ms, and the report said ${applied.reported} ms.`);- Line 1 is a comment. Both runs loaded the store, and both numbers are LCP in ms.
- Line 2 is the first simulated run, the one from the start. Line 3 is the first run with applied throttling.
- Lines 5 and 6 print
Simulated: Chrome saw 785 ms, and the report said 2694.7 ms.andApplied: Chrome saw 2760 ms, and the report said 2760.4 ms.
With applied throttling, the two numbers agree. The extra 0.4 is only rounding: Lighthouse rounds what it observed to whole milliseconds. The docs promise the same for the trace: with DevTools throttling, its numbers "will match" the report's. Why it matters: when you need a trace that lines up with the report, use applied throttling.
Slower runs
Applied throttling costs time. Here is how long each whole run took, with each method:
// How long each whole run took, in ms. Five runs of each method, taking turns.const runs = { simulate: [6667.3, 6237.8, 6175.5, 6224.1, 6177.1], devtools: [17666.7, 17630.9, 17668.5, 17695.2, 17729.6], provided: [14807.7, 14751.4, 14764, 15395.1, 14739.8],};const median = (list) => [...list].sort((a, b) => a - b)[Math.floor(list.length / 2)]; for (const [method, times] of Object.entries(runs)) { console.log(`${method}: ${(median(times) / 1000).toFixed(1)} seconds a run`);}- Lines 3 to 5 are recorded: five runs of each method, taking turns.
- Line 7 sorts a list and takes the middle value, the median.
- Line 10 prints
simulate: 6.2 seconds a run,devtools: 17.7 seconds a runandprovided: 14.8 seconds a run.
The DevTools runs took almost three times as long as the simulated ones. Some of that is the slow load. But look at provided. It slowed nothing down, and still took 14.8 seconds. Most of the extra time is waiting.
Remember the photographer in How Lighthouse works, who waits until everyone keeps still? With simulate, Lighthouse waits for 1,000 ms of quiet. With the other two methods, every wait grows to 5,250 ms. That's after the first paint, after the load event, for a quiet network, and for a quiet CPU.
Its source does this when the method "requires observation": when the numbers come from watching the load itself. So it watches for longer before it stops.
One more number changed. CLS was 0.1623 with applied throttling, and 0.1364 with the other two. CLS always comes from the real load. In a slower real load, things can arrive at different moments, so the page can shift differently.
Provided: no slowing at all
The third method, provided, adds no throttling. On this laptop, the store loaded at full speed. Those are the laptop's numbers, not a phone's.
So what is it for? For when the slowness comes from somewhere else. It's like driving the route as it is today, with no sums and no second brake. The main case is a real phone. Lighthouse can test a phone plugged in over USB. Its docs suggest these flags "to disable any additional emulation":
--screenEmulation.disabled --throttling.cpuSlowdownMultiplier=1 --throttling-method=provided
The phone is already slow, so Lighthouse shouldn't slow it down again. For the most realistic network, the docs point to packet-level tools, which slow every packet your computer sends. Exercise 6 asks you to find the one they name.
Here are all three methods side by side, the median of five runs each:
// The same five runs of each method: the score, and LCP in ms.const runs = { simulate: { score: [90, 90, 89, 90, 90], lcp: [2694.7, 2688.9, 2836.9, 2688.4, 2685.8] }, devtools: { score: [83, 81, 81, 81, 81], lcp: [2760.4, 2745.8, 2759.3, 2758.9, 2787.2] }, provided: { score: [95, 95, 95, 95, 95], lcp: [753.7, 745.4, 746.7, 798.9, 748.8] },};const median = (list) => [...list].sort((a, b) => a - b)[Math.floor(list.length / 2)]; for (const [method, { score, lcp }] of Object.entries(runs)) { console.log(`${method}: score ${median(score)}, LCP ${median(lcp)} ms`);}- Lines 3 to 5 are recorded: each run's score, and its LCP.
- Line 10 prints the medians:
simulate: score 90, LCP 2688.9 ms,devtools: score 81, LCP 2759.3 msandprovided: score 95, LCP 748.8 ms.
Same page, three scores. The two ways of imitating the phone gave LCPs about 70 ms apart. Yet applied throttling scored 81, not 90. The score weighs five metrics, as The Lighthouse score showed, and the other four moved more than LCP did. Exercise 3 asks you to find one of them in the playground.
Read this table across. Each row is one method: what it does to the load, where its slow numbers come from, and whether its trace matches its report.
| Method | What happens to the load? | Where do the slow numbers come from? | Does the trace match the report? |
|---|---|---|---|
Simulated (simulate) | Chrome loads the page at full speed. | Lantern works them out from the fast load. | No. The trace is the fast load. |
Applied (devtools) | Chrome really slows the network and the CPU. | Chrome measures them in the slowed load. | Yes. The trace is the slowed load. |
Provided (provided) | Lighthouse slows nothing down. | From your own setup, like a real phone, or nowhere. | Yes. The trace is the load as it happened. |
CPU benchmarking and slowdown
Both methods that imitate the phone use the same number for the CPU: 4. The phone's CPU is 4 times slower. But 4 times slower than what? The docs answer: CPU throttling "is expressed relative to the performance of the host device." The host is the computer running Lighthouse.
You met this problem in The Performance panel, walking at Ravi's pace. "Five times slower" means something different for every walker. DevTools solves it by calibrating: it tries slowdowns until a benchmark scores like a phone. Lighthouse doesn't calibrate. By default, its docs say, it uses "a constant 4x CPU multiplier".
It does measure the host, though. In every run, before the page loads, Lighthouse runs a benchmark: a small test program that counts how much work the CPU gets done. Lighthouse saves the result as benchmarkIndex. The report shows it near the bottom, as "Unthrottled CPU/Memory Power". This laptop's median was 3,009.5.
The docs give rough ranges for a few kinds of device. Two of them matter here:
- A high-end desktop, like a 16-inch MacBook Pro, scores 1,500 to 2,000.
- A mid-tier phone, like a Moto G4, scores 125 to 800.
The docs call each range a bracket. The default 4x is meant for the first one. In the docs' words, it "moves a typical run in the high-end desktop bracket somewhere into the mid-tier mobile bracket."
What the multiplier changes
The course ran the simulation on this laptop with four multipliers, three runs each:
// The simulation with each CPU slowdown multiplier, three runs each: TBT in ms, and the score.const runs = { 1: { tbt: [0, 0, 0], score: [91, 91, 90] }, 2: { tbt: [16, 8.5, 8], score: [90, 90, 90] }, 4: { tbt: [83, 83, 41.5], score: [89, 89, 90] }, 8: { tbt: [225, 216, 215], score: [84, 84, 84] },};const median = (list) => [...list].sort((a, b) => a - b)[Math.floor(list.length / 2)]; for (const [multiplier, { tbt, score }] of Object.entries(runs)) { console.log(`${multiplier}x: TBT ${median(tbt)} ms, score ${median(score)}`);}- Lines 3 to 6 are recorded: the TBT and the score of each run, for each multiplier.
- Line 8 takes the median of three.
- Line 11 prints
1x: TBT 0 ms, score 91,2x: TBT 8.5 ms, score 90,4x: TBT 83 ms, score 89and8x: TBT 216 ms, score 84.
TBT, Total Blocking Time, adds up how far each long task ran past 50 ms, after the first paint. At 1x, no task was long enough to block, so TBT was 0. Each step up stretched the tasks in the graph further past 50 ms. At 8x, TBT reached 216 ms, and the score fell to 84.
Why it matters: the multiplier decides how bad a busy main thread looks. Pick it to match the device you care about. Try each multiplier here, and the slower machine from the next section:
The simulation on this laptop, benchmark 3,029.5, with the CPU 4 times slower. Median TBT 83 ms, LCP 2,836.2 ms, and score 89.
To set the multiplier yourself, use the flag --throttling.cpuSlowdownMultiplier. Lighthouse's help says it "Controls simulated + emulated CPU throttling". So it works for both simulate and devtools.
Comparing results across machines
Here's a puzzle teams run into. Two people test the same page with Lighthouse, on two laptops, and get two different scores. Nobody did anything wrong.
The reason is in the last section: the 4x goes on top of whatever the laptop can do. On a slower laptop, every task in the real load already takes longer. Lantern then stretches it 4 times more.
A running coach tells the whole team: run at a quarter of your top speed, to feel what a beginner feels. For the fastest runner, that works. A runner who's already slow ends up barely moving, far slower than any beginner.
- In real life: "Run at a quarter of your top speed"
- In Lighthouse: The default 4x CPU slowdown
- In real life: The fastest runner
- In Lighthouse: A fast laptop, like this one
- In real life: A slow runner, barely moving
- In Lighthouse: A slower laptop, slowed down 4 more times
- In real life: "You, just run at your usual pace"
- In Lighthouse: Calibrating: a multiplier of 1
The course didn't have a slow laptop, so it made one. Before Lighthouse started, it slowed the tab down 4 times with DevTools' CPU throttling. So Lighthouse saw what looked like a slower computer: even its benchmark ran slower. Then the course ran Lighthouse with the default 4x, and again with 1x:
// This machine, and a slower one: the tab slowed down 4 times. Benchmark indexes, and each run's score.const machines = { "this machine, 4x": { benchmark: [2992.5, 3013, 3009.5, 3027, 3006.5], score: [90, 90, 89, 90, 90] }, "slower machine, 4x": { benchmark: [680.5, 683, 682], score: [74, 72, 72] }, "slower machine, 1x": { benchmark: [683.5, 682.5, 687.5], score: [89, 89, 89] },};const median = (list) => [...list].sort((a, b) => a - b)[Math.floor(list.length / 2)]; for (const [machine, { benchmark, score }] of Object.entries(machines)) { console.log(`${machine}: benchmark ${median(benchmark)}, score ${median(score)}`);}- Line 3 is this laptop: its five default runs.
- Line 4 is the slower machine with the default 4x. Line 5 is the same machine with the multiplier set to 1.
- Line 10 prints
this machine, 4x: benchmark 3009.5, score 90, thenslower machine, 4x: benchmark 682, score 72. The last line isslower machine, 1x: benchmark 683.5, score 89.
Same page. With the default 4x, the slower machine scored 72 instead of 90. Set to 1x, it scored 89, one point from this laptop. The benchmark barely moved between lines 4 and 5: the multiplier doesn't change the machine.
Where did 1x come from? The docs have a second table, for picking a multiplier. Find the kind of machine you test on, then the kind of device you want to imitate. A machine in the mid-tier phone range, testing for a mid-tier phone, gets 1x. It's already as slow as the target. The stand-in's 682 is in that range.
The docs add a rule for the ends of each range: "If your device's BenchmarkIndex falls on the higher end of its bracket, use a higher multiplier." Near the lower end, use a lower one.
Lighthouse can warn you, too. Run it from the command line with the default multiplier, on a benchmark of 1,000 or less. The report then gets a warning: "The tested device appears to have a slower CPU than Lighthouse expects. This can negatively affect your performance score." The course ran Lighthouse from Node, which doesn't add the warning. So its reports had none, even on the stand-in.
Why it matters: before you compare two scores, compare the two benchmarks. If they're far apart, the gap in scores may come from the machines, not the page.
A lab test imitates one device, but your real visitors bring their own. Two browser APIs give a page a rough idea of the device it's on:
navigator.hardwareConcurrencyis the number of logical processors: roughly, how many things the CPU can work on at once.navigator.connection.effectiveTypeis a rough label for the connection, like"4g". Not every browser has it.
Why PageSpeed Insights disagrees with your laptop
PageSpeed Insights runs Lighthouse with the same method. The docs say simulated throttling "matches the setup of PageSpeed Insights and the Lighthouse CLI default." Same Lantern, same slow phone. So why can its score differ from your laptop's?
Go back to the satnav. Two satnavs can do the same rush-hour sum and still disagree, if each one saved a different Sunday drive. PageSpeed Insights starts from a different real load, in three ways:
- A different computer. It runs on Google's machines, so its benchmark and its real load aren't yours.
- A different road to your server. Its docs say "PageSpeed also runs in a Google datacenter that can vary based on network conditions." It reports running in North America, Europe or Asia. Lantern keeps some numbers from the real load, like how long each server took to answer. From a different place, those come out different.
- A different page. It loads the public address. It can't see a build on your laptop, or a change you haven't put online yet.
So before you compare two reports, compare where they ran. A Lighthouse report lists it near the bottom, under these labels. The PageSpeed Insights docs point to the same place to see where its test ran.
- Unthrottled CPU/Memory Power: the benchmark.
- CPU throttling: the multiplier and the method, like "4x slowdown (Simulated)".
- Network throttling: the round trip and the download speed it imitated.
Why it matters: if the benchmarks or the places are far apart, a different score says more about the machines than about your page. And remember the forecast from How Lighthouse works: PageSpeed Insights' field data is another thing again, measured on real visits.
Which method?
Each job below needs one of the three methods. For each one, ask: do you want a quick estimate, a load that's really slow, or no slowing from Lighthouse at all?
- Quick, repeatable checks on every pull request
- Matching PageSpeed Insights' setup
- A trace whose numbers match the report
- Watching a really slowed-down load's long tasks
- A real phone over USB
- This laptop's own full speed, with nothing slowed
Sort each job by the throttling method that suits it.
Common mix-ups
- "Lighthouse loads my page on a slow network." No. By default, it loads it at full speed. Then Lantern calculates the slow phone's numbers.
- "The trace shows what the report measured." No. With the default method, the trace is the fast load. The report's metrics are Lantern's estimate.
- "4x slower means the same thing on every machine." No. It's 4 times slower than the machine running Lighthouse. A slower machine scored 72 instead of 90.
- "DevTools throttling is the accurate one." No. It delays whole requests, not packets, and the docs call it not highly accurate. They say simulation is roughly as accurate or better for most sites.
- "Provided imitates a phone in some other way." No. It slows nothing down. On a laptop, you get the laptop's own numbers: the store scored 95.
- "PageSpeed Insights should match my laptop." No. It runs the same simulation, but from a real load on Google's machine, in a Google datacenter.
Practice exercises
Try each one before you open the hints.
This is the three-metrics example, with the numbers from the third simulated run. What does the second line print?
// The same run: three metrics, observed in the real load and reported, in ms.
const observed = { FCP: 769, LCP: 769, SI: 1096 };
const reported = { FCP: 1936.9, LCP: 2836.9, SI: 2309.1 };
for (const metric of Object.keys(observed)) {
const times = (reported[metric] / observed[metric]).toFixed(1);
console.log(`${metric}: observed ${observed[metric]} ms, reported ${reported[metric]} ms, ${times} times later`);
}LCP: observed 769 ms, reported 2836.9 ms, 3.7 times later. The real load was about as fast as the first run's, but Lantern's estimate came out later. Each run's notes are a little different, so each estimate is too.
This is the machines example with one more row: this laptop, with the multiplier set to 1. What does the last line print?
// This machine, and a slower one: the tab slowed down 4 times. Benchmark indexes, and each run's score.
const machines = {
"this machine, 4x": { benchmark: [2992.5, 3013, 3009.5, 3027, 3006.5], score: [90, 90, 89, 90, 90] },
"slower machine, 4x": { benchmark: [680.5, 683, 682], score: [74, 72, 72] },
"slower machine, 1x": { benchmark: [683.5, 682.5, 687.5], score: [89, 89, 89] },
"this machine, 1x": { benchmark: [3010, 3039.5, 3031.5], score: [91, 91, 90] },
};
const median = (list) => [...list].sort((a, b) => a - b)[Math.floor(list.length / 2)];
for (const [machine, { benchmark, score }] of Object.entries(machines)) {
console.log(`${machine}: benchmark ${median(benchmark)}, score ${median(score)}`);
}this machine, 1x: benchmark 3031.5, score 91. The benchmark measures the machine before any slowdown, so the multiplier doesn't change it. With no CPU slowdown in the estimate, the score went up by one.
In the first playground, what was the median TBT of the runs with applied throttling?
171.4 ms. The simulated runs' median was 42.5 ms. Really slowing the CPU gave far more blocking than Lantern's estimate did, and that's part of why the score fell to 81.
In the second playground, what was the median TBT on the slower machine with the default 4x?
507 ms. This laptop at 4x had 83 ms. On the slower machine, every task was already longer before Lantern stretched it 4 times. At 1x, its TBT came back down to 88 ms.
Your machine's benchmark is in the middle of the high-end desktop range. You want to imitate a low-end phone. Which multiplier does the docs' table suggest?
10x, with a range of 5 to 20. A low-end phone is much slower than a mid-tier one, so the slowdown has to be bigger than the default 4x.
The docs name a command line tool for packet-level throttling on Mac and Linux. What is its npm package called?
@sitespeed.io/throttle. It slows your whole machine's network, packet by packet, and it needs sudo. The docs also show how to run Lighthouse while it's on.
Check your understanding
For each question, ask three things: what really loaded, what was worked out, and on which machine.
Question 1 of 7What does the first line of the three-metrics example print?
Read the code, then predict// The same run: three metrics, observed in the real load and reported, in ms. const observed = { FCP: 785, LCP: 785, SI: 1125 }; const reported = { FCP: 1944.7, LCP: 2694.7, SI: 2353.4 }; for (const metric of Object.keys(observed)) { const times = (reported[metric] / observed[metric]).toFixed(1); console.log(`${metric}: observed ${observed[metric]} ms, reported ${reported[metric]} ms, ${times} times later`); }Choose an answer to see the explanation.
Question 2 of 7What does the last line of the machines example print?
Read the code, then predict// This machine, and a slower one: the tab slowed down 4 times. Benchmark indexes, and each run's score. const machines = { "this machine, 4x": { benchmark: [2992.5, 3013, 3009.5, 3027, 3006.5], score: [90, 90, 89, 90, 90] }, "slower machine, 4x": { benchmark: [680.5, 683, 682], score: [74, 72, 72] }, "slower machine, 1x": { benchmark: [683.5, 682.5, 687.5], score: [89, 89, 89] }, }; const median = (list) => [...list].sort((a, b) => a - b)[Math.floor(list.length / 2)]; for (const [machine, { benchmark, score }] of Object.entries(machines)) { console.log(`${machine}: benchmark ${median(benchmark)}, score ${median(score)}`); }Choose an answer to see the explanation.
Question 3 of 7You open the trace of a simulated Lighthouse run. Its LCP is three times earlier than the report's. Why?
Choose an answer to see the explanation.
Question 4 of 7In a simulated run, which of these metrics does Lantern not estimate?
Choose an answer to see the explanation.
Question 5 of 7Why did each DevTools-throttled run take almost three times as long as a simulated one?
Choose an answer to see the explanation.
Question 6 of 7A teammate's laptop benchmarks 680 and scores 72. Yours benchmarks 3,000 and scores 90 on the same page. What's going on?
Choose an answer to see the explanation.
Question 7 of 7Why can PageSpeed Insights give a different score from Lighthouse on your laptop?
Choose an answer to see the explanation.
Key takeaways
- Throttling makes a fast computer stand in for a slow phone. Lighthouse has three methods: simulate, devtools and provided.
- Simulate, the default, loads the page at full speed. Lantern then replays its graph of requests and tasks on a slow phone. It's quick and steady, but the trace shows the fast load.
- Applied throttling really slows the network and the CPU. The trace matches the report, and each run takes longer.
- Provided slows nothing down. Use it when the device is already slow, like a real phone.
- The CPU slowdown is relative to the machine. Check the benchmark, and change the multiplier on a much slower or faster machine.
- PageSpeed Insights runs the same simulation from a different real load. Compare environments before you compare scores.
Remember the one-liner.
Throttling starts from your machine: know which method ran, and on what.
Sources
The facts on this page come from these docs and source files:
- Network Throttling and CPU Throttling, Lighthouse docs.
- report-utils.js, the report's labels, Lighthouse 13.6.0 source.
- emulation.js, Lighthouse 13.6.0 source.
- Score Variability, Lighthouse docs.
- Architecture, Lighthouse docs.
- Lantern, Lighthouse docs.
- BaseNode.ts, Lantern's dependency graph, Chrome DevTools frontend source.
- Simulator.ts, Lantern's simulator, Chrome DevTools frontend source.
- Constants.ts, Lantern's throttling presets, Chrome DevTools frontend source.
- FirstContentfulPaint.ts, Lantern's FCP, Chrome DevTools frontend source.
- LargestContentfulPaint.ts, Lantern's LCP, Chrome DevTools frontend source.
- Lantern's metrics, Chrome DevTools frontend source.
- metrics.js, the observed metrics, Lighthouse 13.6.0 source.
- constants.js, the default settings, Lighthouse 13.6.0 source.
- config.js, Lighthouse 13.6.0 source.
- Lighthouse docs: Testing on a mobile device, Lighthouse docs.
- cli-flags.js, the command line's help, Lighthouse 13.6.0 source.
- environment.js, Lighthouse 13.6.0 source.
- About PageSpeed Insights, Google for Developers.
Coming next: Reading audits and insights, also in Measuring in the lab. Turn the report into a short, ordered list of fixes, and learn which savings are estimates.