Article

How probeo simulates page speed

A page speed number is only useful if it can be compared: across the pages of a site, and on the same page over time. Probeo checks every page it manages, each time it rechecks them, so it needs a number that comes out the same way every time. It gets one by measuring what a single visit can measure and modeling the rest.

This is how that model works, and where it stops.

Why not run Lighthouse on every page

A lab test such as Lighthouse loads a page in a real browser under one simulated device and connection. It is thorough, and slow: running it for every page, on four connections, at every recheck, would take far longer than the check itself.

Field data, such as the Chrome User Experience Report, is real users on real devices. It only exists for pages and sites with enough Chrome traffic to report, so most pages on most sites have none. Probeo’s model fills that gap: every page gets a number, and every number is produced the same way.

What probeo measures

The crawler visits each page once in a headless browser and records three things from that visit:

  • Time to first byte: from the browser’s navigation timing, the wait between the request and the first byte of the response.
  • HTTP version: HTTP/1.1, HTTP/2 or HTTP/3, from the same navigation.
  • The HTML’s size: the encoded size of the page’s response.

Probeo also records the size of every asset the page loads: scripts, stylesheets, images and fonts, each with its host. These are the model’s only inputs. Everything below is computed from them.

The four connections

Every page is modeled on four connections, so a page that is fine on broadband and slow on a weak mobile signal shows both.

Connection Bandwidth Round trip
Broadband 40 Mbps 30 ms
5G 75 Mbps 40 ms
4G Fast 20 Mbps 60 ms
4G/3G Slow 5 Mbps 150 ms

The site-level view uses 4G/3G Slow by default, the connection where page weight and round trips cost the most.

Load time

The estimate starts from the measured time to first byte. To that it adds the time to move every byte the page loads at the connection’s bandwidth, and the round trips the requests need.

Round trips come from two places. Each host the page loads from serves its requests in batches: six at a time over HTTP/1.1, thirty over HTTP/2 and fifty over HTTP/3, and each batch beyond the first costs a round trip. Each host other than the page’s own also costs a connection: three round trips, or one over HTTP/3. Probeo knows the page’s own HTTP version and assumes HTTP/2 for every other host.

So a page that loads from twelve hosts pays for eleven extra connections, however small each file is. On 4G/3G Slow, at three round trips of 150 ms each, that is about five seconds.

First contentful paint

First contentful paint is the moment the browser shows anything. The model counts only what has to arrive before that can happen: the page’s stylesheets, and its scripts.

Scripts count fully when a script in the <head> blocks rendering, and at about a third of their size otherwise, since deferred and async scripts don’t hold up the first paint. The same batching and connection costs apply to the hosts these files come from, discounted on fast connections. A Google Fonts stylesheet without display=swap adds up to 400 ms, because the text waits for the font.

The result is kept between 100 ms and six seconds after the first byte.

Largest contentful paint

The model takes the page’s largest image, by bytes, as its largest element. Its paint time is the first byte, plus a round trip to request it, plus one more if it comes from another host, plus the time to transfer it.

Largest contentful paint is then the latest of four times: that image, the first paint, the first paint plus a penalty for render-blocking CSS of up to 400 ms, and the first paint plus a penalty for fonts of up to 600 ms. It is capped at eight seconds after the first paint.

Each page also gets a grade from its LCP on each connection:

Grade LCP
Exceptional under 0.6 s
Excellent under 1.5 s
Good under 2.5 s
Fair under 4 s
Poor under 7 s
Bad 7 s or more

Layout shift and interaction

Cumulative layout shift and interaction to next paint can’t be estimated from bytes. They depend on what the page does once it is running. Probeo reports a risk for each instead, from what the HTML shows.

  • Layout shift risk: images without width and height, scripts in the body loaded without async or defer, a hero section with a background image and no height, and Google Fonts without display=swap. Each counts toward a score, rated low, moderate, high or critical.
  • Interaction risk: the share of the page’s bytes, and of its files, that are JavaScript. A page that is mostly script has more work to do before it can respond to a tap or a click.

Both are risks, not measurements. A page rated high may behave well, and the rating says where to look.

What the model can’t tell you

The numbers are estimates, and they leave things out. The model doesn’t see how long JavaScript takes to run, how busy the browser’s main thread is, or what the page does after it loads. Its largest image may not be the element a browser reports as the largest paint. Real networks vary in ways four fixed profiles don’t.

So read the numbers as a comparison. Two pages, or one page this month and last, were modeled the same way, so the difference between them comes from the pages. For what real visitors experience, the Core Web Vitals report in Google Search Console shows field data where Chrome has collected enough of it.

Where this shows up

Each page’s estimates, grade and risks are on its performance results in probeo. The performance docs cover what to do about each one: Core Web Vitals, loading metrics and page weight.