Docs · How it works
Human input
Every click, keystroke and hold your agent asks for is dispatched as movement with human timing. There is no way around that layer — and that is the point.
The second gate
Getting the fingerprint right is what opens the door. What happens after that is a different question with a different answer: does this thing move like a person? The browser has stopped being the subject of the measurement, and the session has become it — where the pointer went, how long the gaps were, in what order the fields were filled.
Most automation never reaches that gate, because it never gets past the first one. Tools that do usually stop there anyway: they hand the page a synthetic click at a coordinate, which arrives with no approach, no dwell, no pressure and nothing before it. None of that is wrong in the sense of being a forged value. It is simply not what a hand produces.
So an agent here does not get a click at a coordinate. It says “click this element”, and what reaches the page is a pointer travelling there over a path with a duration, a landing, a press with a hold time, and a release — the whole sequence a mouse would have produced, generated for this profile.
The counter-intuitive part: added noise is a tell
The obvious way to make generated input look human is to roughen it — a wobble on the path, jitter on the timing, a little tremor. It is the first thing everyone tries. We tried it, measured it, and took it out.
An earlier version of our pointer model carried a synthetic hand tremor. Measured against a cohort of 120 people whose mouse movement was recorded in a browser, it produced 4.5 direction reversals per 100 samples against a cohort median of 1.11, with the cohort’s 90th percentile at 2.25. Four times the human rate — outside the band, not merely at its edge. Note what was not the problem: the path’s curvature sat comfortably inside the human range. Curvature is human. High-frequency reversal is not.
There is a reason for that, and the reason is the useful part. Real physiological hand tremor sits at 8–12 Hz with an amplitude on the order of a single mouse count — and it never reaches the page at all. Three stages remove it on the way: the mouse’s own polling rate, the operating system’s pointer acceleration, and finally the browser, which aligns pointer delivery to the display frame at roughly 60 Hz. At that rate the tremor band cannot even be represented. Pointing research routinely filters mouse traces above 9 Hz for exactly this reason: everything up there is noise, not signal.
Injecting tremor therefore emits frequencies no genuine trace contains. Far from hiding the generator, it signs it. The same lesson had already arrived from the entirely separate direction of the fingerprint layer, where noise added to a rendered image reads as manipulation rather than as diversity. Two independent axes, one rule:
Match the real distribution instead of perturbing a fake one.Every number in this layer is drawn from a measured human distribution or derived from one. Where no distribution is published, the model says so rather than inventing a plausible-looking wobble.
The corollary is worth keeping, because it inverts the intuitive guess: real human input is smoother in its path and more irregular in its timingthan a naive model assumes. Ours had it exactly backwards.
What is measured off real people
Four published sources carry the numbers. They are named here plainly, with what each one can and cannot support.
| Source | Scale | What it fixes |
|---|---|---|
| SapiMouse | 120 subjects, recorded in a browser | Pointer kinematics: speed, acceleration, jerk, path directness, angle change, direction reversals, and the distribution of gaps between samples. |
| Aalto keystroke corpus | 136 million keystrokes from 168,960 people, collected on the web | Typing: the interval between keys and its spread, how long a key is held, how often two keys overlap, and how often people correct a typo. |
| Brysbaert’s reading meta-analysis | 190 studies | Silent reading speed — 238 words per minute for non-fiction, with a spread of 51 between readers. |
| Form-completion benchmarking | Millions of real registration sessions | The total a session should add up to: registration forms average 95 seconds. |
Two things about that table matter more than the numbers in it. The mouse corpus was recorded in a browser, so it already sits at the frequency a page sees — corpora recorded at the operating-system level measure a different quantity and cannot calibrate this. And a corpus describes a population, so it fixes how much profiles should differ from one another as well as how each one behaves. A fleet whose members all type at the same speed is a fleet, however human each individual session looks.
Each profile therefore draws its own style from its seed and keeps it: typing speed (roughly 18 to 126 words per minute across the fleet), how long it holds a key, how often its keys overlap, how often it makes and fixes a typo, how ragged its rhythm is, how far it overshoots a target, how hard it scrolls. The same profile behaves the same way in six months; two profiles never behave alike.
What reaches the page
Three gesture families, each generated rather than replayed.
Pointer. Movement time follows Fitts’ law, so far and small targets take longer than near and large ones. The stroke aims slightly past the target and corrects back — a real ballistic overshoot, which is where a human trace’s curvature comes from and which a smooth easing curve never produces. The velocity profile is a sum of two or three overlapping impulses rather than one ramp; their overlap is where human jerk comes from. Samples go out on a quantised polling tick with occasional stalls, because a real event stream repeats one dominant interval and is still irregular overall.
Keyboard. Every character becomes a real key press and release pair with its own hold time and its own gap from the previous key, both drawn from the corpus distributions and adjusted by simple rules — word boundaries slow down, repeated characters speed up, punctuation is followed by a pause. Capitals are wrapped in genuine Shift events. Fast pairs sometimes overlap, the next key going down before the previous one comes up, which a mechanical typist never does. Typos happen at the profile’s own rate and are corrected with Backspace.
Scroll. A wheel gesture is a burst of ticks with a momentum shape — quick spin-up, long decelerating tail — not a uniform stream of identical deltas, which is the synthetic-scroll signature. The ticks always sum to exactly the displacement that was asked for.
The yes-or-no signals
Separate from all of the above sits a small set of checks that are not distributions at all. They have one right answer, a single wrong value stands out no matter how good the trajectory is, and they cost a detector nothing to run. Each of these is closed:
- Pressure. The pointer specification requires
pressureto be 0.5 while a button is down and 0 on release. The automation protocol defaults it to zero and the browser passes that through, sobuttons > 0 && pressure === 0is a one-line bot check. Ours reports 0.5 and 0 in the right places. - Coalesced sub-events. A 125 Hz mouse reports every 8 ms while the display draws every 16.7, so a genuine pointer event carries several merged samples inside it. One dispatched event can only ever produce one. The dispatcher therefore sends the moves that fall inside a single display frame together and without a sleep between them, and the browser merges them itself — the same way it merges real hardware.
- The event chain. Pointer → mouse → click arrives complete, and so does key → beforeinput → input. A gap in either is a sequence no hardware produces.
- Text provenance. Text arrives as key presses, not as direct insertion. The protocol offers both paths, and mixing them produces sequences no keyboard generates; the key path is used throughout.
- Focus provenance. Every focus change is explained by a click or a Tab that preceded it. “Navigation between text boxes without tabbing or a mouse click” is a signal named explicitly in a detection vendor’s own patent.
Above the single gesture: the session
A perfect click is still a machine if it arrives 200 milliseconds after the last one, every time, in a straight run down the form. This layer models the gaps between actions and the order they arrive in.
Pauses are a mixture, not one distribution. Each kind of pause — landing on a page, moving to the next field, reading, deciding, the hesitation before submitting, and the general gap between steps — has its own distribution with two components: an ordinary body plus a rarer long one. That structure exists because of a measured defect. The generator produced plenty of medium pauses and no long ones: its longest pause in a whole task was 1.5 seconds where a person doing the same task reached 3.45. Its median was fine. Widening a single distribution enough to produce the occasional four-second pause would have dragged the median up with it, so the tail was added separately. The kinds also draw from independent streams, so a long hop between fields does not imply a long decision every single time — a correlation no person has and a detector can measure.
Filling a form is not a straight line. A plan occasionally swaps two neighbouring fields, occasionally jumps back to re-edit one, and mixes clicks with Tab. “Perfect field order without jumps or returns” and “no errors across an entire task” are both named tells. Six per-profile traits decide how much: overall pace, how easily attention wanders, reading speed, how often a field gets revisited, how much this person likes Tab, and how far the order deviates. Straight top-to-bottom passes stay possible, because plenty of people do that too.
Tab is a coherence rule, not a preference. Tab moves focus to the next control in document order and nowhere else. So a plan may only use it when the target really is the previous field plus one — never for the first field of a form, where nothing holds focus yet, and never for a control the keyboard cannot operate, such as a radio group, which is one tab stop for the whole group. A Tab that lands three fields away is not a stylistic choice; it is a transition the browser refuses to perform.
Reading time is derived, not guessed. Page dwell comes out of 238 words per minute, slowed by about an eighth for reading on screen, applied to roughly a quarter of the visible words — because people skim, and the share they read falls as the page grows. It scales sub-linearly for the same reason: reading a 200-word page at full speed would put every page longer than a paragraph at the same ceiling, which collapses into one constant pause. A constant pause is the exact thing this layer exists not to emit.
What keeps the invented parts honest is the total. No corpus publishes “how long a person pauses between two form fields”, so those centres are modelling choices — but the sum they have to add up to is published, and a test holds them to it: a six-field form lands inside the 20-to-120-second human band, with real variance between fields. Change one centre and that test says whether the session still adds up.
What an agent can steer
Very little of the timing, deliberately — that is the design rather than a missing feature. An agent that could pass its own durations would pass round numbers, and a 2000-millisecond wait that repeats to the millisecond across every replay and every profile is precisely the machine cadence this layer removes. The agent sayswhere and what; the profile says how.
| Tool | Arguments beyond the element |
|---|---|
click | button, click_count, and at_x / at_y to aim at a fraction of the element instead of its centre — needed when the element is a picture rather than a control. |
type_text | text, replace to overwrite what a field already holds, submit to press Enter afterwards. |
press_key | key — Enter, Tab, Space or a single character — plus an optional element to click first. |
scroll | delta_x / delta_y; positive scrolls down, and it defaults to 600. |
press_and_hold | max_hold_ms, which can only shorten the hold and exists for experiments. |
There is no bypass through this interface. The tool that takes raw coordinates does not accept a “skip humanization” flag — its schema rejects unknown fields — and no path through the agent layer reaches the browser’s input surface without going through the generators. Two places elsewhere do differ, and it is worth being exact about them: the REST trusted-input endpoint accepts an explicithumanize: false for testing, and if you drive the browser overdirect CDP you are dispatching your own events, which nothing humanizes for you.
The worked example: press-and-hold
One challenge type is recorded as solved end to end against the live site, using only the agent tools, with the next step actually reached. It is the “press and hold the button” challenge, measured on Microsoft’s account signup. Three runs on the same day: two solved it with a singlepress_and_hold call, and the third needed two — because a real mouse pointer was sitting inside the visible window and mixed real input into the generated gesture.
What makes it a good example is that the input layer is the entire reason it works. The challenge asks for two presses and says so on the page: press once, wait for the confirmation, then press again. A single long press lands correctly on the target and is ignored, because the challenge has not started measuring yet; its frame then rebuilds, and everything reported afterwards is delivered somewhere it is no longer listening. What it grades is an empty hold.
So the whole thing is one uninterrupted timeline: a short wake-up press (190–280 ms), a pause (360–540 ms), then a hold of about ten seconds that reports continuously at 17 Hz with a pressure that drifts and pulls back toward its mean. Those numbers are calibrated against a corpus of solved and failed attempts — passing holds reported between 15.8 and 16.9 Hz, the failing one at 14.2 — rather than chosen to look busy. Nothing may run in between, not even a page query: a version that checked the page every 300 ms was refused where the identical gesture without the check passed, with the round trip as the only difference.
That is why the agent calls press_and_hold once and takes its snapshot afterwards, and why the tool plans the entire gesture up front instead of watching the page during it.
What this does not prove
The honest boundary of the page, because a claim that cannot be shown is worse than no claim.
- There is no external verdict on behavioural realism. No system we can query returns a behaviour sub-score; the ones that do sit behind commercial agreements. The comparison against the 120-subject cohort is the best instrument available, and its limits — a 2020 corpus, kinematics only — are the real limits of what can be claimed.
- A reCAPTCHA v3 score is not that verdict. Our browser scores 0.9 on Google’s own demo, the same value ordinary Chrome returns on the same line. But in a controlled run of our own — arms interleaved, device, address and page held constant — a bypass that emitted no pointer movement at all scored the same 0.9, and so did an untouched Chrome that never moved. On a page with no traffic history, v3 is evidently scoring the environment rather than the behaviour. That is neither evidence that the model works nor evidence that it fails; it is evidence that this axis is not being measured there. Treat any “we score 0.9” claim accordingly, ours included.
- The fine timing is still open. Trajectory shape sits inside the human band on the measures the cohort supports. The family around the gap between individual samples does not yet, and closing it is ongoing work.
- This page is about form-shaped interaction. Movement between pages, drift over a long session, and idle behaviour while nothing is happening are modelled either partly or not at all.
- Behaviour is one axis among several, and often not the heaviest.Network and device signals frequently outweigh it. A perfect input layer does not rescue a datacentre exit — see Coherence & proxies.
Next
- MCP server — the tools above, and how an agent reads a page before acting on it.
- Coherence & proxies — the first gate, and the network requirement behind both.
- Direct CDP — driving the browser yourself, and what you give up by doing so.