What gets measured
Mouse movement. A human hand moves in smooth, slightly wobbly arcs (Bezier curves with random velocity). It slows down as it nears the target — this is Fitts's Law, the rule that the closer you get to something small, the more carefully you aim — usually overshoots a little, then corrects. A scraper that jumps straight to a point with page.mouse.move(x, y) draws a perfectly straight line, which is statistically impossible for a real hand.
Timing patterns. How long between the page loading and your first action? How does your scrolling speed up and slow down? How evenly spaced are your keystrokes? How long do you stay on a page? Machine-learning models (software trained on examples to spot patterns) trained on millions of sessions detect this at sub-millisecond precision — now even finer thanks to WASM shared-buffer timers.
Session shape. Do you load the images and fonts a browser normally would? Do you visit the homepage first, or jump straight to a deep URL? Real users hesitate and load CSS and tracking pixels; bots and plain HTTP scrapers usually do not.
Biometric micro-signals. The faint tremor in a human's mouse path. Click pressure on touch devices. The rhythm of switching between mouse and keyboard. These are increasingly part of premium behavioural models.
Why it catches "perfect" scrapers
A scraper can have a Chrome 148 JA4 fingerprint, a home-broadband (residential) IP, a genuine canvas hash, a perfectly matched timezone — and still fail behavioural scoring. The four identity layers all say "this is a real Chrome user." The behaviour layer replies: "this real Chrome user moves the mouse like nobody who has ever touched a computer."
That gap is what makes behaviour so hard to fake. Identity signals can be configured ahead of time (Camoufox C++ patches) or at request time (curl_cffi TLS). Behaviour is different: it cannot be configured statically because it has to be generated as the session runs, and accurately modelling how humans move and type is much harder than it looks. Tooling that approximated human input has historically been re-characterised within months by ML models retrained on the newer patterns.
Inputs that behavioural models weigh
When working with sites you own or are authorized to automate, the inputs behavioural models weigh most heavily are well documented:
- Input generation. Tools such as Botasaurus with Humancursor (Bezier curves with random jitter and Fitts's Law deceleration), or Camoufox's
humanize=True, generate pointer and scroll input that falls inside the statistical range of ordinary human input rather than the perfectly straight lines a naive script produces. - Navigation path. Models score the shape of a whole session — landing on a homepage, dwelling, scrolling, and following internal links produces a different signal than jumping straight to a deep URL. This is one reason behavioural scoring looks across multiple requests.
- Timing distribution. A constant pause such as
time.sleep(2)is itself a machine-like signal; varied timing likerandom.uniform(1.8, 4.3)sits closer to natural session timings.
The key takeaway: behavioural detection is probabilistic (a likelihood score, not a yes/no) and evaluates the session as a whole. At very high request rates from one IP, the session-level pattern stops resembling a single human regardless of input quality. Distributing authorized, device-like traffic across many home or mobile IPs — what a residential proxy pool provides — keeps each IP's rate within what a single real person could plausibly produce.
Provenance vs behaviour: two different questions
Behavioural analysis and input provenance detection are frequently discussed as one topic, but they ask questions of very different strength, and confusing them leads to the wrong conclusions about which matters.
Behaviour asks whether an interaction looks human. It is statistical: a model scores pointer velocity curves, dwell distributions, and scroll rhythms against a population, and returns a likelihood. Because it is statistical it has a tunable threshold, real false positives (users on trackpads, tablets, or assistive devices sit in the tails), and it can in principle be approximated by generating input with realistic dynamics.
Provenance asks where the event entered the system. It is structural: Event.isTrusted is set by the engine and cannot be written from page script, so an event dispatched by JavaScript is marked as such with no ambiguity and no threshold. There is nothing to approximate, because the flag is not derived from the event's properties.
The practical implication is that the two fail against different things. Page-level scripting - constructing events and calling dispatchEvent, or assigning to input.value - fails provenance immediately regardless of how realistic the synthesised dynamics are. Protocol-driven automation such as a browser driven over its debugging interface produces genuinely trusted events, passes provenance cleanly, and is then evaluated on behaviour alone. Knowing which of the two a given setup is subject to determines entirely which signals are worth attention.
The structural signals behind the statistical ones
Underneath the scoring model sit a handful of checks that are closer to arithmetic than to machine learning, and they carry disproportionate weight because they are cheap and near-deterministic.
- Press dwell - the interval between
pointerdownandpointerup, orkeydownandkeyup. Real presses occupy tens of milliseconds. Pairs landing in the same millisecond, or at an identical interval every time, did not come from a finger. - Approach - real pointers travel to a control, emitting
pointermoveevents along a curved path with acceleration and deceleration. Aclickwith no preceding movement toward the target has no approach at all. - Landing dispersion - repeated interactions with the same control land on slightly different pixels. Pixel-identical coordinates across several clicks indicate a computed centre point.
- Event cadence - pointer events arrive at the input device's hardware sampling rate, which is not a round number and drifts. Events spaced on a clean software timer match no real device.
- Cascade completeness - a real keystroke produces
keydown, thenbeforeinput/keypress, theninput, thenkeyup. A field whose value changed without the page observing any of them was written programmatically.
Each is individually weak and jointly strong, and none requires a trained model to evaluate - which is why they run on far more sites than full behavioural scoring does.
The strategic conclusion for data collection is to treat interaction as a cost rather than a challenge. Flows that require simulating a person are the expensive path and carry this entire class of signal; where the same public data is reachable without it, that route is cheaper, faster, and structurally quieter. Keeping scrapers on that path is a large part of what a managed web data API handles on their behalf.
