How Input Latency Compensation Actually Works
Your keyboard and mouse are slow, and there is a measurable amount of it. A wireless peripheral can add tens of milliseconds between the physical press and the browser hearing about it. Latency compensation measures that specific delay and subtracts it from your result.
This article documents exactly what it measures, how, and — the part that matters most — what it cannot reach.
The delay chain
When you press a key or click, several things happen in sequence before a number appears. Which segment a measurement tool can subtract depends entirely on where in the page it is running.
| Segment | Typical size | Compensable? |
|---|---|---|
| Physical press to signal leaving the device | Unknown | No — never happened yet |
| Device transport (Bluetooth, dongle) | 10–100 ms | Yes — this is what the probe measures |
| Event delivery and browser dispatch | 1–5 ms | Partly — included in the measurement |
| Browser processing and script execution | Variable | No — variable, so not correctable |
| Compositing and panel refresh before you see the signal | 0–17 ms at 60 Hz | No — page code cannot observe it |
| Your perception and motor execution | This is the reaction time | No — it is the measurement target |
Exactly one of those segments is both large and reachable. That is the whole opportunity here, and it is worth being precise about how narrow it is.
How the probe measures it
The probe is driven by real interactions rather than a timer, which is what makes it meaningful. For each of five rounds:
- It records a timestamp with
performance.now()the instant your input event arrives. - It subtracts the event’s own
timeStamp, which the browser sets at the hardware level. The difference is your transport delay. - Any sample outside 0–150 ms is discarded as implausible for a hand-driven input.
- If fewer than three samples survive, no compensation is applied and the panel says so, rather than extrapolating from thin data.
- Otherwise the median of the accepted samples is used as the offset.
The median is doing real work here. With an odd number of samples it is the middle value outright; with an even number it is the mean of the two middle samples, rounded. Either way a single Bluetooth hiccup — one 90 ms outlier in a set of five — moves the result slightly instead of wrecking it. An average would have been dragged upward by that outlier every time.
What it cannot do
- It cannot measure display latency. By the time your code runs, it has no visibility into how long until pixels change. On a 60 Hz panel the signal you see may arrive up to 16.7 ms after the code committed it, averaging about 8.3 ms, and none of that is knowable from inside the page.
- It cannot track drift. A median is a summary of five samples at one moment. If your connection degrades mid-session, the offset you measured no longer applies.
- It cannot remove browser scheduling. Frame scheduling and garbage collection pauses are variable, so subtracting a fixed number would sometimes over-correct and sometimes under-correct.
- It is off by default. No result is ever silently adjusted. Every mode works immediately, and the readout shows the applied latency only when compensation is on.
Getting a clean reading
- Close every other application that might steal USB attention.
- Touch-type or move the mouse continuously during the probe so the radio stays active — a fully idle Bluetooth link can negotiate a lower-power mode and skew the first sample.
- Discard any round where you pressed slightly before you were ready; a premature press produces a nonsense sample that will be rejected, wasting a round.
- Look for a value that does not move much between the first and second run. A stable median is the goal.
If the probe will not complete, the usual cause is a sample count below three — which usually means the rejected outliers were consistent, i.e. the device is slower than 150 ms end to end. That is worth knowing: it means switching to a wired peripheral will help more than any compensation.
Does it change your score?
Only by the measured offset, and only downward. When it is on and completes, the displayed result is the raw elapsed time minus the accepted latency, floored at 1 ms. For anyone comparing their own scores over weeks this changes very little, because a stable offset cancels out of the comparison. For anyone asking "is 240 ms good in absolute terms" it changes the answer, which is why the probe exists.
It also cannot help with the largest source of drift on most setups — which is not the input device at all but whether a Bluetooth peripheral was used on one day and a wired one the next. No correction fixes an inconsistent setup; only changing the setup does.
Run the probe yourself
Open the calibration panel on the test page and run the latency probe. It reports the accepted median, the number of samples it used, and whether it applied compensation at all.
Constants quoted here are this site’s own, fromsrc/engine/. The 0–150 ms acceptance window, the three-sample minimum and the median aggregation are implemented in latency.tsand calibrationUi.ts. Segment sizes for non-latency rows are typical published ranges, not measurements from your device; see the sources page.