Scalebrowser

navigator.connection: rtt 0 and a 50 ms grid

What navigator.connection reveals: rtt 0 from a headless build, Chromium's 50 ms grid against the spec's 25, and why rtt 75 matched 0.00 percent of visitors.

Davide Valli · Founder, Scalebrowser

Published Nov 14, 2026 · 7 min read

Short answer

navigator.connection gives a headless build away with rtt 0, and a pinned value can be impossible: Chromium rounds rtt to multiples of 50 milliseconds, although the specification says 25. Against AmIUnique on 30 July 2026, rtt 75 with downlink 10 matched 0.00 percent of visitors, where rtt 50 with downlink 10 matched 7.68 percent. We learned it from our own profile data, which drew off-grid values in 47 percent of draws until that day. The same numbers also leave the browser as request headers, and those have to agree with JavaScript.
50 ms, Chromium's rtt grid, beside three steps of a staircase

navigator.connection is one of the smaller surfaces of a fingerprint, and one of the easiest to get wrong. It holds three numbers and a flag that describe the network, all of them estimates, all of them rounded before a page sees them. We got the rounding wrong ourselves for months, because we followed the specification instead of the browser. This is what the values mean, what a headless build reports, and what our own data taught us about a grid nobody checks.

What does navigator.connection report?

navigator.connection reports the browser's estimate of the current connection: rtt for the round-trip time in milliseconds, downlink for the bandwidth in megabits per second, effectiveType for a class such as 4g, and saveData for the data saver setting. The WICG Network Information draft defines rtt as the effective round-trip time "rounded to nearest multiple of 25 milliseconds", and MDN's rtt page repeats the 25. Chromium does something else, and the Chromium source, read on 27 September 2026, is the only reference a checker needs.

ValueWhat the specification saysWhat Chromium does
rttnearest multiple of 25 millisecondsmultiple of 50 milliseconds
downlinknearest multiple of 25 kilobits per secondrounded to a multiple of 50 kilobits per second, capped at 10 megabits per second
bothno per-site variationmultiplied by a factor between 0.9 and 1.1 per hostname before rounding

The spread per hostname exists "to reduce fingerprinting", as the source comments put it. MDN marks the whole API as not Baseline, because "it does not work in some of the most widely-used browsers", so every reading below is a Chromium reading.

Why does a headless browser report rtt 0?

A headless browser reports rtt 0 when its build hands out no round-trip estimate at all, and that depends on the build more than on the headless mode. The project detect-headless, with 308 GitHub stars, lists it as its "Connection Rtt" test: "navigator.connection.rtt, if present, has value 0 on headless browser." On 25 August 2026 we read the value with the same script in three setups, loaded from our own check page as the origin.

SetuprttUser agent says
Playwright, headless, its bundled Chromium 1410HeadlessChrome/141
Playwright, headless, installed Chrome 141100HeadlessChrome/141
real Chrome 151 on Windows100Chrome/151

Both Playwright setups ran headless on the same machine in the same minute, and only the bundled build answered 0. A real desktop Chrome that has loaded pages reports a value on the grid, and 100 is the most ordinary one we saw.

Why is rtt 75 impossible in Chrome?

rtt 75 is impossible in Chrome because Chromium rounds rtt to a multiple of 50 milliseconds after it applies the per-hostname factor, so 75, 125, 175 and 225 never reach a page. The specification's 25 millisecond grid makes them look plausible, and that is exactly how they got into our own profile data. Our sampler, our validator and our data all repeated the 25 millisecond rule without anyone reading the browser, and until 30 July 2026, 47 percent of draws produced an rtt of 75, 125, 175 or 225. On that day we compared single values against AmIUnique, one axis per run, with real Chrome 150 as the reference.

rttdownlinkShare of AmIUnique visitors with this value
50107.68 percent, the same share as real Chrome 150
75100.00 percent
5090.01 percent
Source: Scalebrowser persona measurement against AmIUnique, one axis changed per run, reference real Chrome 150.0.7871.187, 30 July 2026
Chromium rounds rtt to multiples of 50 milliseconds, so rtt 75 matched 0.00 percent of AmIUnique visitors, where rtt 50 with downlink 10 matched 7.68 percent, the share of real Chrome 150.

An rtt of 75 is not a rare value that narrows the crowd; it is a value no Chrome produces, and one comparison finds it. The third row shows that downlink matters as well: 9 is on the grid, yet the pair was several hundred times rarer than the one with 10, because a broadband connection runs into the 10 megabit cap. We corrected the data on 30 July 2026, and stored profiles take the corrected value at their next start. These are the values Chromium rounds, and a value that ignores the rounding contradicts the engine that is supposed to have produced it.

Do the connection headers agree with JavaScript?

The connection headers agree with JavaScript inside one renderer, but not between the navigation and the renderer, even in real Chrome. RTT, Downlink, ECT and Save-Data are client hints as well as properties, so a server that asks for them with Accept-CH receives them on the navigation request and on every subresource. On 14 September 2026 we read all three surfaces on one Windows machine with a bench that serves a page over HTTPS and records its request headers.

Browserrtt: navigation / subresource / JavaScriptdownlink: navigation / subresource / JavaScript
Chrome for Testing 154.0.8037.950 / 100 / 1001.5 / 1.35 / 1.35
branded Chrome 153.0.8010.3750 / 100 / 1001.75 / 1.5 / 1.5
our 154 engine, no persona50 / 100 / 1001.7 / 1.4 / 1.4
our 154 engine, persona rtt 50, downlink 1050 / 50 / 5010 / 9.8 / 9.8
Source: Scalebrowser header bench, one Windows host, 2 captures per browser, first capture shown, 14 September 2026

The three control browsers separated the navigation from the renderer in all six of their captures, so a difference between those two is normal. A difference between a subresource header and the script in the same renderer appeared in none of the eight captures. Our own 151 engine did produce one: on 12 September 2026, with a persona, it sent an rtt of 100 in the header and 50 to JavaScript, and a downlink of 1.45 against 9.9. We fixed it on 13 September, and the last row is the reading on the 154 engine.

Downlink differs from one site to the next because Chromium multiplies the estimate by a factor between 0.9 and 1.1 that depends on the hostname. A broadband connection at the 10 megabit cap therefore reads anywhere from 9.0 to 10.0, depending on the site. An rtt already on the grid stays where it is, because 50 times 0.9 to 1.1 does not leave the 50 millisecond step. Until 30 July 2026 our engine answered a constant 10 to every hostname; since then, measured on 8 hostnames that day, it varies per host the way Chrome does.

What should you check in your own browser?

You should check four things, and each of them is a single comparison a site can make too:

  1. Read navigator.connection.rtt in the browser your agent uses, and expect a non-zero multiple of 50.
  2. Read downlink, and expect a step of 0.05 no higher than 10; a broadband desktop usually sits at or just under 10.
  3. Log the RTT and Downlink headers on a server you control after asking for them with Accept-CH, and compare the subresource headers with what JavaScript reported in the same load.
  4. Open two different hostnames and compare downlink; a value identical to the last decimal on every site is more stable than Chrome.

The page on testing your setup lists further ways to read what a site sees, including a check page that runs without an account. How Pixelscan judges a mismatch, including the one real Chrome also gets, is covered in Pixelscan and 'Masking detected'.

Real browser profiles for your AI agent, on your PC.

Each profile keeps its own identity, logins and proxy. Your agent drives it over MCP and signs in without seeing a password.

Download free for Windows

Free plan with 3 profiles · No credit card · Runs on your PC

Written by

Davide Valli

Founder, Scalebrowser

Builds Scalebrowser, browser automation for the agentic era that runs on your own machine. Measures every change a web page could observe against a real browser before it ships, and writes up the ones that turned out wrong.

All articles by Davide Valli

More in Detection

All 19 articles in Detection