Skip to content
All fingerprint checksAutomation surface

user activation only ever appeared after a real input event

Check id activation-without-input

What an ordinary browser yields

Either no activation at all, or activation that arrived only after a trusted input event the page could see (severity: warn).

What a detector infers

The row above this one reads navigator.userActivation once and expects it to be true, because the audit is reached by pressing a button. Its own note concedes what a snapshot cannot do: a finger and a debugger both leave `true` behind. The distinguishing evidence is not the value but WHEN it changed relative to what the document received. Transient activation is granted only by a trusted input event, and a trusted input event delivered to this document is necessarily visible to a capture-phase window listener — so a page that watches from mount can assert something a snapshot cannot: activation went true while zero trusted input events had ever arrived. That is the page's own event log against the browser's own activation state, with no reference value in it and nothing that can rot. What it catches in practice is the Chrome DevTools Protocol: Runtime.evaluate carries a userGesture flag, and Playwright and Puppeteer set it, so page.evaluate() hands the document a real activation with no event behind it. Measured on the reference machine against a Chromium stealth build driven by Playwright: with no evaluate() call at all, 725 samples and zero activation observations; with evaluate(), 383 observations, every single one recorded at zero input events, the first arriving exactly when the first evaluate() fired. It is an oracle for CDP-driven automation in general rather than for any one product, which is what makes it worth having — the same reading identifies anything wrapping Playwright or Puppeteer, whatever the build underneath is called. One limitation is measured rather than assumed, and anyone relying on this row should know it: the detection is probabilistic, not deterministic. Across six otherwise identical runs against one unchanged browser, this row fired in three. The two other findings in those runs were stable at six out of six, so the variance belongs to this check alone. The reason is in the mechanism: what it catches is an evaluate that lands BEFORE the first real input, and whether a given script does that depends on whether the driver's internals happen to resolve a selector or read a property before the first click. Half the runs did. That makes this a row that can confirm automation but can never clear it — a quiet result means nothing was seen this time, not that nothing is there. It never goes the other way, though. The false-positive direction stays closed by the witness requirement, and a browser driven by a person produced no firing in any run.

How to resolve it

There is nothing to fix for a person browsing normally — their click is the event that grants the activation, so the two agree by construction. If you are driving this page, the finding is not about the browser build: page.evaluate() sets Runtime.evaluate's userGesture flag, and that is what granted the activation. Evaluate with userGesture:false, or drive the page through real input (CDP Input.dispatchMouseEvent) so the activation has an event behind it.

How is a headless browser detected?

Read in the wild by

Kasada

Collects both halves of navigator.userActivation as separate signals — reading isActive as well as hasBeenActive is what makes the timing argument available to a detector at all.

user_activation_is_active, user_activation_has_been_active

Kasada ips.js teardown — the full 427-probe list

Every attribution traces to a published artifact. See the sources and their limits.

Nearby checks in Automation surface

See all 27 checks in Automation surface
Who builds this test

Clearcote is a browser built for fingerprint coherence

It is a Chromium fork, maintained by the same people who wrote this reference. It ships as a compiled browser rather than as a stealth script injected into someone else's — which is a description of how it is built, and is not an argument about how it behaves on this check.

This audit takes no position on how Clearcote scores on Automation surface checks, on this one, or anywhere else. It has no baseline corpus of other people's fingerprints to rank you against and no vendor scoreboard — nearly every check is self-referential, asking one browser the same question through two independent APIs and reporting whether both answers can be true at once. It runs identically on any browser, including ours. Run it on yours and read the result yourself.

See the other checks in Automation surface — the family activation-without-input belongs to.