// the find
antoinevastel/fpscanner
Self-hosted browser fingerprinting and bot detection with real-world constraints in mind.
A self-hosted TypeScript library that collects a browser fingerprint and flags common automation markers (navigator.webdriver, CDP, Playwright globals) client-side, meant as a free alternative to routing traffic through a commercial bot-detection vendor. Aimed at teams who want basic bot signals on signup/login flows without paying for or trusting a third-party CDN.
Cross-context validation (comparing platform/webGL/webdriver state between main thread, iframe, and worker) is a real technique — spoofing a single global is easy, keeping three execution contexts consistent is harder for a bot author to get right. The fsid format encodes signals into fixed-width sections so you can do partial matching (same GPU hash, different screen) instead of just a single opaque hash, which is genuinely useful for clustering bot traffic over time. Detection logic is broken into small, individually testable modules under src/detections, and CI runs on every push.
The 'encryption' is a repeating-key XOR cipher over JSON — since the plaintext structure (starts with `{"time":`) is predictable, this is a known-plaintext attack away from full key recovery, so the anti-forgery story is weaker than the README implies. All the detection signals (navigator.webdriver, CDP markers, Playwright globals) are exactly what playwright-extra-stealth and puppeteer-stealth have patched around for years, so it catches unsophisticated bots but not the custom LLM-written scrapers the README says motivated the project. The build step patches files directly inside node_modules/fpscanner/dist via a postinstall hook, which is fragile the moment someone changes lockfile behavior or a CI cache restores node_modules without re-running install. There's no server-side nonce store, rate limiter, or scoring logic included — despite the 'production-ready' framing, you still have to build the actual decision layer yourself.