npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

typingnorm

v0.2.0

Published

Tell whether keystrokes came from a human, and score typing speed with each locale's own standard. Zero dependencies.

Readme

typingnorm

Tell whether keystrokes came from a human. Three rules, each with a false-positive rate measured on 2,245 real typists. Zero dependencies, works in the browser.

npm install typingnorm
import { check } from "typingnorm";

// events: [milliseconds, "D" | "U", physical key code, optional event.key]
const report = check(events);

report.verdict              // "human-consistent" | "synthetic-signals" | "insufficient-data"
report.flags                // ["zero_rollover"]
report.measures             // { wpm, rollover_pct, dwell_cv, ... }
report.falsePositiveBudget  // 0.0031

Collect events straight from the DOM. Use event.code, not event.key: the rules depend on the physical key, and event.key changes with the input method.

const events = [];
input.addEventListener("keydown", (e) => {
  if (!e.repeat) events.push([e.timeStamp, "D", e.code, e.key]);
});
input.addEventListener("keyup", (e) => events.push([e.timeStamp, "U", e.code, e.key]));

The rules

| Rule | What it catches | False positives on 2,245 humans | |---|---|---| | same_key_overlap | A physical key pressed again before release | 0.00% | | constant_dwell | Every key held for the same time, or too short to be real | 0.00% | | zero_rollover | No key overlap at all (only applied above 35 WPM) | 0.31% |

Every rule is speed-invariant on purpose. Fast and slow typists differ enormously in rollover, interval, and hold time, so any "how far from the human average" rule systematically misjudges people at the extremes. Those are exactly the people you should not misjudge: password managers, dictation, switch access, and on-screen keyboards all look robotic in the time domain.

Hand alternation looked like a strong feature and was cut: the effect reverses for slow typists, so using it as a hard rule misjudges 15.46% of real humans.

What this does and does not do

It catches careless automation. It does not catch a program that deliberately imitates human timing, including this project's own simulator.

check() returns signals, not a verdict on a person, and deliberately offers no isHuman boolean, because that invites callers to use it as a gate. Treat it as one input to a risk score, never as identity verification.

Below 150 keystrokes it returns insufficient-data rather than guessing. A login form gives you twenty or thirty keystrokes, which is not enough for any conclusion.

Parity with the Python package

This is a port of typingnorm on PyPI. Both implementations run the same test vectors from vectors.json in CI, so they cannot drift apart.

Method, data sources, and the measured false-positive rates: METHOD.md.

MIT.