Your Speed Test Is Measuring the Wrong Road
My connection tests at 99 Mbps, and its latency gets 25x worse the moment anything downloads. No speed test will show you that, they measure a stretch of road you mostly don't use, and the number itself is a construction, not a constant. Then my own speed test lied to me too.

Quick question. Don't skip it, the rest depends on you answering first.
Two people. One has a 100 Mbps connection, the other 25 Mbps. Both are about to join a video call. Whose call is more likely to stutter?
Pick one. Actually pick.
You picked the 25. Almost everyone does, it's four times slower, and video needs bandwidth.
You can't actually tell. And in my experience the 100 Mbps connection is often the worse one.
That sounds like a trick, so let me show you the measurement that speed tests never put in front of you. It's from my own connection, and it's the reason I stopped trusting the number on the box.
The number I had to rerun three times
I timed a round trip on my connection while it sat idle. Then I timed the same thing while a download was running.
Twenty-five times slower. Same connection, seconds apart.
Sixty-two milliseconds is fine. Fifteen hundred is a call where everyone talks over each other, because nobody can tell when anyone has stopped speaking.
And my connection tests at 99 Mbps. Every speed test you can name calls it fast.
So what happened in those two seconds?
Reasonable guess: congestion. The pipe is full, everything slows down, physics.
Close. The real answer is stranger, and once you see it you'll recognise it in your own house.
When a router receives more data than it can forward, it has two options: throw some away, or hold onto it.
Throwing data away sounds like failure. So for years, manufacturers built routers with generous memory that hold onto everything rather than dropping any of it.
Picture a supermarket that refuses, on principle, to ever turn a customer away. Generous. Now it's busy, the queue reaches the back of the shop, and you're behind two hundred full trolleys holding one apple.

That's your router when someone starts a download. Your keystroke, a tiny packet that needs to arrive now, gets in line behind a movie. It isn't being slowed down. It's waiting its turn, politely, for a second and a half.
Drag the queue and watch what happens to the small packet:
The blue packet is yours. It isn't slow, it's last in line.
It's called bufferbloat, and dropping those packets would genuinely have been kinder. Dropped packets are how a sender learns to slow down. Queueing them just hides the problem until your call falls apart.
That's the 1530. Not a slow connection, a polite one.
It takes about two seconds to measure. So here's the real question: why has no speed test ever shown it to you?
Because the test never goes where the trouble is
Second question, same rules. Answer before you read on.
When a speed test measures your connection, what is it connecting to?
You probably pictured a server on the internet, somewhere nearby.
Frequently, it's a server inside your own ISP's network, and not by accident. Ookla's server network is largely built by the operators themselves: ISPs, carriers, universities and hosting companies install Ookla's server software on their own hardware and register it to be listed as a testing endpoint. So when the test picks the "nearest" server, that server is often one your ISP runs.
Follow the traffic:
The test turns around inside your ISP's network. It never crosses a peering link, the handoff between your ISP and everybody else, which is exactly where congestion lives, and exactly where your ISP has the least commercial incentive to spend money.
You're measuring the on-ramp and drawing conclusions about the motorway.
So the 300 Mbps on your screen is real. It's just measuring the wrong road.
And the number itself is a construction
That's where the test goes. Now: what is it actually doing when it gets there?
You'd think it downloads something and times it. So did I. Here's that idea as code:
const t0 = performance.now()
const res = await fetch('/big-file')
await res.arrayBuffer()
const mbps = (bytes * 8) / ((performance.now() - t0) * 1000)
I wrote roughly that, ran it, and got about a fifth of what every other speed test reported. My first thought was that the others were inflating.
They weren't. Mine was broken three ways at once.
It timed the handshake. DNS lookup, TCP handshake, TLS negotiation, none of that is bandwidth, all of it inside my stopwatch.
It timed the warm-up. TCP deliberately starts slow and accelerates as it gains confidence the path can take it. Timing a car over its first twenty metres from a standstill tells you very little about the car. I now discard the first 1.2 seconds of every measurement.
And one connection often can't fill your line. This is the one that surprised me.
TCP won't send endlessly. It sends a batch, waits for confirmation that it arrived, then sends more. So the amount you can move is set by how much is allowed in flight at once, divided by how long the confirmation takes to come back:
throughput ≈ data in flight ÷ round-trip time

Think of a courier who refuses to leave with the next parcel until the last one has been signed for. Widen the road as much as you like, it changes nothing, because they spend most of the journey waiting for a signature. The only ways to move more are to carry more per trip, shorten the trip, or send more couriers.
Which is why your bandwidth does not appear in that formula. Road width was never the constraint.
On a short path the ceiling sits comfortably above your line rate and one connection saturates it fine. On a long one, a server in another country, which is most of the internet, it can fall below what you're paying for, and you end up measuring the distance rather than the pipe. So my test sends six couriers at once, which isn't a trick to flatter the number: it's what your browser already does every time it loads a page.
Put that together and a speed test isn't a download, timed. It's several connections, with the beginning thrown away, averaged over a window somebody chose.
Every one of those is a judgement call. Not a physical constant. Which is why two honest speed tests can disagree substantially and neither is lying, and why the number on your screen was, in a real sense, authored.
Then my own tool lied to me
Here's where I have to admit something.
I fixed all of it. Six parallel connections. Warm-up discarded. Incompressible payloads. Latency read from the browser's own timing instead of a stopwatch. Loaded latency measured and graded. I knew every trap in this article, because I'd fallen into each one.
I shipped it. And it showed me this:
Download 99.2 Mbps
Chart peak 1.00 Mbps
A completely flat graph, next to a 99 Mbps result.
Both numbers come from the same counter. One of them is lying.
Before I tell you which: the live graph checks the running byte total every 100 milliseconds and calculates speed over the previous half-second. Look back 500 ms, see how many bytes arrived, divide.
That's the whole algorithm. It has no error handling to get wrong, no edge case to forget.
So where's the bug?
The counter below rises at exactly 100 Mbps the entire time. Drag the slider until something breaks.
Found it?
The timer that fires every 100 ms is a request, not a guarantee. When six connections are streaming flat out, the browser's main thread is busy, and those ticks drift late.
Once they drift more than 500 ms apart, looking back half a second finds no earlier sample at all.
The window collapses onto a single point. Zero bytes, across zero milliseconds. Zero Mbps.
Now look at the shape of that failure:
The faster your connection, the busier the thread, the later the ticks, the more likely the graph reads zero.
It worked flawlessly on a slow connection. It broke on a fast one.
Which is the exact opposite of how anyone would think to test it, and precisely why I shipped it without noticing. I had written this article in my head before I found it. I was going to tell you how careful I'd been.
So, whose call stutters?
Back to the two people.
The 25 Mbps connection, if its router keeps a short queue and its ISP has a healthy handoff to the rest of the internet, will hold a flawless call. Twenty-five megabits is many times what a video call needs.
The 100 Mbps connection, if it's bloated at the buffer and congested at the peering link, will be a stuttering mess, while still proudly reporting 100 Mbps, because the test measured the one stretch of road where nothing was wrong.
The number on the box cannot tell you which is which. That's the lie. Not that it's false, that it's answering a question you never asked, and staying quiet about the one you did.
Three things worth taking away:
The big number is the least interesting thing on the page. It's real. It just describes a narrower path than you think, often one your own ISP owns.
Go and find your latency under load. Not idle ping, latency while something is downloading. If it's many times your idle figure, that single number explains more of your daily frustration than bandwidth ever will.
A bigger plan probably won't fix it. Bufferbloat isn't a shortage of capacity, it's a queue allowed to grow too long, and an oversized buffer still fills whenever the link saturates, whatever its speed. The fix is on the router: SQM or fq_codel, which keep the queue short and drop packets instead of hoarding them.
You can run mine at /devtools/speed-test. It measures latency under load and grades it, whether or not the result is flattering.

Mine gets an F. I built it anyway.
Leave a comment
No account needed. Leave the name blank and you'll get a random one.