Back to all posts

Measurements · Aug 1, 2026 · 5 min read

Adding noise is the tell, not the disguise

We added noise to hide two browser signals, canvas pixels and pointer paths. Both times the noise itself gave us away. The numbers, and what replaced it.

DG
By Davide GrasböckAug 1, 2026 · Updated Sep 17, 2026
Pixel art of a misty mountain lake at blue hour, the ridge mirrored cleanly on the left while the reflection on the right breaks apart into scattered pixels

In short

Adding random noise to a browser signal does not hide the signal, it marks it. We offset every canvas readback by up to two values per channel, and a public checker flagged the canvas as manipulated. We added hand tremor to pointer paths, and they reversed direction 17 times as often as a person recorded on the same bench. Both times the fix was to stop perturbing and match the real distribution instead, and we now treat added noise as a tell on every axis.

We shipped noise twice, on two signals that share no code: the pixels a page reads back from a canvas, and the path the pointer takes to a button. Both times the noise did exactly what it promised, and both times it became the most legible thing about the browser. Scalebrowser now reports the honest canvas value, and its pointer paths are calibrated against 120 recorded people instead of shaken by a tremor model.

What did the canvas noise do?

It gave every profile its own canvas fingerprint by adding a small, deterministic offset to the pixels. Whenever a page read a canvas back, through getImageData, toDataURL, toBlob or WebGL's readPixels, every channel of every pixel moved by up to two values, seeded per profile. It is the same family of defence Brave ships as farbling, which Brave describes as "slightly randomizing the output of semi-identifying browser features, in a way that's difficult for websites to detect". On one machine, five test profiles produced five different canvas hashes.

How did the canvas noise give itself away?

The public checker at BrowserScan marked the canvas as manipulated and took points off the browser's score for it. A graphics card draws a flat region as one colour, and our offset put variation into every flat region on the page, so the value no longer looked like any device. The research agrees that this is a dead end: Nguyen and Vadrevu attacked the randomisation defences deployed in real browsers in Breaking the Shield (WWW 2025) and concluded that "no fully deployable defense against canvas fingerprinting attacks exists currently".

Canvas readbackDistinct canvas hashes across 5 profilesWhat a page reads
Offset of up to 2 per channel, seeded per profile5 of 5a value no device draws, flagged as manipulated by BrowserScan
Honest device value1, shared by all 5the value this graphics card and driver draw
Source: Scalebrowser engine, canvas readback on one machine, five profiles, July 2026

So we took it out on every readback surface: canvas, WebGL, WebGPU, measureText and audio all report what the device really produces. That has a cost, and we accept it on purpose: profiles on the same machine share one canvas fingerprint. A shared honest value is ordinary, because every machine with the same hardware and drivers reports it too. A manipulated value is unique in the way that gets a browser looked at.

What went wrong with the pointer?

The same thing, on an axis with nothing in common with graphics. Human hands shake, a synthetic straight line does not, so our input layer added a small tremor and a lateral wobble to every pointer path. On our behaviour bench the result reversed direction 4.5 times per 100 samples, where a person recorded on the same bench reversed 0.27 times: 17 times as often.

The reason is the same as for the canvas. Physiological tremor sits around 8 to 12 hertz at an amplitude far below one pixel, and Chromium delivers pointer events aligned to the display frame, at about 60 per second, so the tremor never reaches the page at all. Injecting it produces movement no real trace contains. Detection research found the same from the other side: in BeCAPTCHA-Mouse, synthetic trajectories from generators trained to fool a classifier were caught at high rates, and the authors conclude that "GAN generators introduce patterns that allow its detection".

What replaced the noise?

  1. The tremor and the lateral wobble came out of the pointer path entirely.
  2. Movement is modelled the way clean human pointing is described in the motor-control literature: a duration from Fitts' law, one large ballistic impulse that slightly overshoots, and a small correction back onto the target.
  3. The targets come from the SapiMouse dataset, "mouse dynamics data from 120 subjects" recorded in the browser, and every change is measured against the middle 80 percent of those people.
MeasureScalebrowser today120 people, 10th to 90th percentile
Direction reversals per 100 samples2.770.56 to 2.25
Path length against the straight line1.121.06 to 1.66
Speed, pixels per millisecond0.6960.343 to 0.846
Jerk0.2140.185 to 0.412
Source: Scalebrowser behaviour bench, frame-aligned pointer events against the SapiMouse cohort of 120 people, last verified 16 August 2026

Six of the eleven measures on the bench now sit inside the human band. Direction reversals are down from 4.5 but still above it, and they are one of the five measures we have not closed yet. The root of most of the rest is timing: our events arrive 27.5 milliseconds apart where people sit around 17. We publish that number because it is the next thing to fix, not because it is finished. The human input page of the documentation tracks the current state.

What should you take from this if you build your own stack?

Before you add randomness to hide a value, ask what the real distribution of that value looks like, and whether your randomness could ever produce it. A canvas nobody else has and a hand that trembles at a frequency no mouse delivers are both easier to spot than the value you started with. Measure against real people or real devices first, then change the generator until it lands inside their band.

Run it on your own machine

Seven days to try it with your own agents on your own sites. Starting the trial needs a card.

Start the 7-day trial
DG

Davide Grasböck

Founder, Scalebrowser

Builds Scalebrowser, the browser layer for AI agents 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.