Page speed advice usually starts with a score out of a hundred. That number is a simulation, and treating it as the goal produces work that improves the score and not the site.
Two kinds of measurement
Lab data is a single load performed by a tool: a chosen location, a simulated device, a simulated connection, an empty cache.
Its value is that it is repeatable. Change something, test again, and the difference is attributable. It is a comparison instrument.
Field data is collected from real visitors on real devices. It is what search engines use, and it is the honest answer to whether the site is fast.
It also moves slowly: typically a rolling month, so a fix made this morning will not show for weeks. This is why people conclude a change did nothing.
Why they disagree
Lab tests usually simulate a mid-range phone on a throttled connection, because that is closer to the average visitor than a desktop on fibre.
If your visitors are mostly on desktops in one country, your field data will be better than your lab score. If they are mostly on phones on mobile networks, it may be worse.
Neither is lying. They measure different populations.
What to actually measure
Three things, and they correspond to what a visitor perceives.
How quickly the main content appears. Usually the largest image or heading. This is the one most affected by hosting and by image handling.
How quickly the page responds to the first interaction. A page that has drawn but ignores taps for two seconds feels broken, and this is almost always JavaScript occupying the main thread.
How much the layout moves while loading. Content jumping as images and adverts arrive causes mis-taps and is the most irritating of the three to experience. It is usually fixed by giving images explicit dimensions, which is cheap.
Where the server's part ends
The server is responsible for how long it takes to begin responding. Everything after that is the page.
curl -o /dev/null -s -w 'connect %{time_connect} ttfb %{time_starttransfer} total %{time_total}\n' https://example.com/
A time to first byte of a few hundred milliseconds is fine. Two seconds is a server or application problem, and no amount of image optimisation will address it.
Run it several times: the first request may be uncached and unrepresentative, and a single measurement of anything is a guess. Understanding caching layers goes into why the second run differs.
Test the right pages
Almost everyone tests the homepage, and for many sites it is the least representative page there is.
Visitors arrive on articles, product pages and landing pages. Those often carry more images, more third-party scripts and heavier queries.
Test the three or four pages that actually receive entrances, and test them on mobile, because that is what the tool's default reflects and usually what your traffic is.
Third-party scripts
When a lab result is poor and the server is fast, the cause is very often code loaded from elsewhere: analytics, chat widgets, embedded video, advertising, consent banners.
Each is a connection to another host, and your page waits on servers you do not control. A chat widget nobody uses can cost more than every image on the page.
The measurement that settles it is loading the page with third-party scripts blocked and comparing. If the difference is large, the work is deciding what to remove rather than optimising what remains. Serving fonts and third-party assets locally deals with reducing it.
Do one thing at a time
Change one thing, measure, keep or revert. Changing five things and testing once tells you the total and nothing about which of them mattered, and one of them may have made things worse while the others compensated.
Measure at the same time of day when comparing, since server load varies.
Know when to stop
Going from four seconds to two is transformative. Going from 92 to 96 is not perceptible to anyone.
A perfect score is achievable by removing things visitors want. The goal is a site that feels immediate, which is usually reached well before the score stops improving. There is more on spending the effort where it pays in speeding up a website in the right order.
Measure the server's share directly
Testing tools report a combined number. Separating out what the server contributed takes one command and is the only part you can act on directly.
curl -s -o /dev/null -w 'dns %{time_namelookup} tcp %{time_connect} tls %{time_appconnect} ttfb %{time_starttransfer} total %{time_total}\n' https://example.com/
Read the gaps instead of the values. The distance between tls and ttfb is the time the server spent producing the page; everything before it is network and negotiation.
A large first figure points at DNS, and a large gap to ttfb points at the application or the database. Those are different problems with different owners, and a single overall score cannot tell them apart. Monitoring your hosting resources walks through what to look at when it is the server.
The first run is not the number
Measuring immediately after a deployment, a cache clear or a configuration change produces the worst result the site will ever give, and it is the run people quote.
for i in 1 2 3 4 5; do
curl -s -o /dev/null -w '%{time_starttransfer}\n' "https://example.com/?r=$i"
done
Discard the first and read the rest. A cold cache, an empty opcode cache and an unwarmed connection pool are all real costs, and none of them describes what a visitor arriving at a running site experiences.
Both numbers are worth knowing, but separately. The cold figure tells you what happens after every deployment; the warm one tells you what most visitors get. Reporting one as the other is how a change gets credited or blamed for something it did not do.
Read the spread, not a single figure
One measurement of a busy server is a sample of a distribution, and the distribution is what visitors experience.
for i in $(seq 1 30); do
curl -s -o /dev/null -w '%{time_starttransfer}\n' "https://example.com/?r=$i"
done | sort -n | awk '{a[NR]=$1} END {printf "median %.3f p90 %.3f worst %.3f\n", a[int(NR/2)], a[int(NR*0.9)], a[NR]}'
A median of 200 milliseconds with a worst case of four seconds is a different site from one that is consistently at 600, even though the average may be similar. The second is slow; the first is intermittently broken, and only the spread shows it.
Where the worst cases cluster at particular times, the cause is usually something scheduled instead of the page itself.
Check whether you measured the cache
A cached page is fast regardless of what the application does, so measuring one tells you nothing about the pages that cannot be cached.
curl -sI https://example.com/ | grep -iE 'x-cache|cf-cache-status|age|x-litespeed-cache' curl -sI -H 'Cookie: wordpress_logged_in=1' https://example.com/ | grep -iE 'x-cache|cf-cache-status'
A hit on the first and a miss on the second is normal and is exactly the point: the second figure is what a logged-in customer, a checkout or a search result actually costs.
Optimising against cached measurements produces a site that tests well and feels slow to the people doing something, which is the specific failure that makes a good score and a complaining customer coexist. Compression and cache headers in cPanel walks through what the headers are saying.