Where did this text come from?
Most paste detectors answer a yes/no question. That question is close to useless: pasting a URL and pasting an entire cover letter are the same event under that model. This one keeps a running breakdown of what the text is made of, and updates it as the text changes.
Write something
Try it three ways: type normally, paste a block in, then delete the pasted part again. The breakdown follows the text as it stands, not the history of what happened to it.
What it’s made of
The verdict appears once there is something to judge.
Verify it on the server
The score above came from the browser, so a determined user could edit it before posting. This sends the raw event log to /api/verify, where the same engine recomputes the verdict from scratch.
How it decides
Two sources of truth, used together, because each covers the other’s blind spot. InputEvent.inputType says what the user meant to do — the spec requires a paste event to precede any insertFromPaste. A diff of the value against the last known one says what actually happened, which is the only way to catch anything that changes a field without announcing itself: extensions, password managers, framework re-renders, automation drivers.
Underneath is a piece table with provenance attached — a list of runs that always sums to the field’s length. Paste a hundred characters and rewrite half, and you get fifty typed and fifty pasted. Delete the paste entirely and the pasted ratio returns to zero, because that is the honest answer.
What it deliberately does not do
- It withholds timing signals rather than downweighting them. An IME user composing Japanese produces multi-character inserts with meaningless inter-key intervals; a swipe keyboard delivers whole words; dictation arrives in large chunks. Scoring those on typing dynamics would not detect misconduct, it would detect not typing English on a laptop. The same applies to
accessibilityMode, for users on switch access, word prediction or text expansion. - It keeps no text and makes no network calls. Keystroke timing is behavioural biometric data; under GDPR it becomes special-category data the moment it is used to identify someone. The default retains lengths and timings only, with clocks coarsened to 10 ms. This demo page overrides that so it can show your text back to you — a real deployment should not.
- A score is never a bare number. Every point is attributable to a named signal with a sentence explaining it, and withheld signals stay visible with their reason. A reviewer can see what was considered and what was discounted.
- A fully pasted field scores “review”, not “suspicious”. Someone may legitimately have drafted in another editor. It takes corroborating evidence — a trip away from the page, impossible typing speed — to reach the top band.
The limits, plainly
It cannot detect a ghostwriter. Someone transcribing text from a phone beside their keyboard produces an entirely ordinary typing profile. This measures how text entered a field, never who composed it.
It is client-side. JavaScript can be disabled, the payload edited, the events synthesised. Server-side replay raises the cost of a forgery; it does not eliminate it.