Skip to content
All fingerprint checks
Automation surface

every keypress had a keydown behind it

Pim· Clearcote Research 2 min readCheck id interaction-keypress-without-keydown

Every keypress preceded by a keydown. N/A when no keypress arrived, or when composition or paste was used (severity: warn).

What a detector infers

The UI Events spec generates keypress as the DEFAULT ACTION of a keydown - it is not an independent event, it is what a keydown does when it produces a character. So a keypress arriving with no keydown before it is structurally impossible from a key being pressed, on any engine and any platform.

This is not a check against CDP, which is invisible here when used properly; it is a check against the shortcut of sending only Input.dispatchKeyEvent's "char" type, which injects the character straight into the renderer and skips the keydown the keypress is supposed to be the consequence of. MEASURED, AND NOW FIXED UPSTREAM.

On SeleniumBase 4.51.3 this fired on every character: keypress, beforeinput and input per character, with zero keydown and zero keyup across the whole sequence, against a control arm of proper rawKeyDown/char/keyUp that produced the full five-event sequence. Re-measured on 4.51.5, send_keys now sends the complete triad with key, code and windows_virtual_key_code populated, plus a symbol table so punctuation stops colliding with control keys - it passes this row cleanly.

The invariant is unchanged and still catches anything sending bare char events, which includes 4.51.3 and earlier and several other wrappers; what has changed is that naming this one as an example would now be out of date.

The confounders are all handled by declining rather than judging: IME composition produces keydown with keyCode 229 and no keypress at all, mobile virtual keyboards behave the same way, and paste, autofill and dictation produce input events with no key events - none of those can orphan a keypress because none of them emits one, and the row declines outright whenever a composition or a paste was seen rather than reasoning about an input method it cannot model.

How to resolve it

Send the full triad per character - rawKeyDown with key and code populated, then char, then keyUp - instead of char alone. That is three Input.dispatchKeyEvent calls, and it is what a real keyboard generates and what Playwright's keyboard.type already does.

Nearby checks in Automation surface

See all 50 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 interaction-keypress-without-keydown belongs to.