Friday, October 23, 2026

fpscanner for self-hosted browser fingerprinting and bot detection

fpscanner for self-hosted browser fingerprinting and bot detection

fpscanner is a self-hosted TypeScript library that combines short-lived browser fingerprinting with client-side bot detection, built for defenders running fraud prevention on their own infrastructure.

Toolantoinevastel/fpscanner — self-hosted browser fingerprinting and bot detection library with real-world anti-replay and payload-hardening constraints
CategoryClient-side bot detection and browser fingerprinting library (TypeScript/JavaScript, MIT-licensed)
Primary UseCollecting encrypted fingerprint payloads with automation-signal checks like navigator.webdriver, CDP markers, and Playwright artifacts, for clustering, session correlation, and bot filtering on your own servers
Safe UseIntended for defensive use: authorized fraud prevention, bot mitigation, and security research on websites and applications you own or are contracted to protect
Telemetry NoteAs a defender-side tool, fpscanner leaves no offensive footprint; server-side, it emits observable artifacts such as fsid reuse, stale time timestamps, and repeated nonce values, which defenders can log to surface replay attempts and fingerprint drift

antoinevastel/fpscanner is a relaunch of a project that sat dormant for more than seven years, and the new version arrives with a sharpened thesis: the bot ecosystem has fundamentally changed, and the defender's tooling has not kept up. The README's framing is unusually candid about why. LLM-driven companies now crawl at a scale once reserved for specialized actors, frequently ignoring robots.txt and rate limits, while fraudsters no longer need to lean on public frameworks like OpenBullet — with language models, writing a custom bot tailored to one specific site has become cheap and fast. Against that backdrop, defenders are offered two bad options: naive open source libraries keyed to outdated heuristics, or expensive black-box bot management products that require routing all traffic through a third-party CDN. fpscanner positions itself squarely in the gap between them.

What you actually get is a lightweight, self-hosted library written in TypeScript and distributed through npm, MIT-licensed, with roughly 777 stars and a CI badge indicating automated testing. The core call is collectFingerprint(), which gathers browser signals and returns either an encrypted base64 string by default or a raw object when invoked with { encrypt: false }. The decrypted payload contains a fastBotDetection boolean, a structured fastBotDetectionDetails object, raw signals, a JA4-inspired fingerprint identifier called fsid, and two anti-replay fields: a Unix millisecond time and a random nonce. The design intent is clear — this is a building block you wire into your own server-side logic, not a managed verdict engine.

The detection logic focuses on what the README calls strong, low-noise signals from major automation frameworks rather than brittle trivia. The documented checks include hasWebdriver for navigator.webdriver === true (Selenium, Puppeteer, Playwright), hasWebdriverWritable inspecting the webdriver property descriptor, hasSeleniumProperty looking for document.$cdc_ and $wdc_ artifacts left by Selenium WebDriver, hasCDP for Chrome DevTools Protocol runtime markers, hasPlaywright targeting __playwright and __pw_* globals, hasMissingChromeObject for headless Chrome, and headlessChromeScreenResolution flagging the telltale 800x600 default. This is the modern canonical set — each of these has genuine signal-to-noise in production, unlike older canvas-pixel parlor tricks.

One of the more interesting architectural decisions is cross-context validation. fpscanner collects the same probes in the main page context, in iframes, and in Web Workers, then compares them. Automation frameworks frequently patch or spoof signals in the top-level context while forgetting nested execution environments, so a webdriver flag visible in a worker or iframe but absent from the main page is exactly the kind of inconsistency that separates real browsers from partially emulated ones. There is a practical escape hatch too: the skipWorker option exists for deployments where a strict Content-Security-Policy blocks blob: URLs, which tells you the worker path is instantiated via blob workers.

The anti-forgery posture deserves attention because it grapples honestly with the open source dilemma. Publishing detection logic makes it easier for attackers to study the checks, and the README acknowledges this asymmetry directly rather than pretending obscurity is a control. The mitigation strategy is layered: anti-replay protections (the time plus nonce pair) prevent a captured fingerprint from being replayed at scale, build-time key injection means an attacker cannot trivially mint valid encrypted payloads without access to your specific build, and optional obfuscation raises the cost of reverse-engineering to the point where forging a payload convincingly requires actually executing the collection code in a real browser.

Installation is a single standard step, npm install fpscanner, and the README is explicit that the out-of-the-box configuration ships with a placeholder encryption key and no obfuscation — fine for development, wrong for production. Custom builds inject your own key via npx fpscanner build --key=your-key, and the server side is expected to decrypt incoming payloads and enforce its own policy. The documented server pattern shows the shape of the logic without doing the work for you: reject when fastBotDetection is true, reject fingerprints older than a configurable staleness window (60 seconds in the example), and use fsid for session correlation. It is worth noting the sample decryption routine in the README is a toy XOR loop illustrating the payload format, not a hardened cipher — treat the encryption as an integrity and tamper-evidence measure, and put real transport security and key management around it.

Philosophically, the library rejects the single-boolean model of bot detection. The README's strongest argument is that even if an attacker defeats individual checks, producing fully consistent fingerprints over time is much harder, because fingerprints encode relationships between signals, contexts, and environments. Maintaining consistency across sessions, IPs, and accounts requires real execution, careful state management, and stable tooling. That is where the server side gains leverage: fingerprints tracked over time expose reuse patterns, drift, and inconsistencies when attackers rotate tooling incorrectly or partially emulate environments. In production, fingerprinting is a way to observe structure and anomalies at scale, not a one-shot verdict.

The fsid itself is described as JA4-inspired, which is a telling reference. JA4 in the TLS world works because it hashes a stable, ordered set of parameters into a compact, clusterable identifier, and fpscanner is attempting the same for browser signals: a short-lived identifier meant for attack detection and clustering rather than long-term device tracking. That short-lived framing is also a deliberate scope decision with privacy implications — the library is aimed at fraud workflows like signup, login, and sensitive action abuse, not persistent cross-site surveillance of visitors.

Scope discipline continues in the README's explicit non-goals section. The library deliberately does not cover traffic observability, historical analysis, rule iteration, or correlation across device, network, and behavioral signals — capabilities that full fraud platforms provide. The project is sponsored by Castle, a commercial fraud-detection vendor, and the README is transparent that fpscanner is the primitive layer while production teams will typically need those broader operational capabilities. Design trade-offs are further documented in Castle's two-part "Roll your own bot detection" article series on fingerprinting and server-side detection, which the author cites as reflecting the same philosophy rather than serving as library documentation.

For authorized defenders, the practical fit is straightforward: fraud teams protecting their own signup and login flows, security engineers who cannot or will not route all traffic through a third-party CDN, and researchers studying automation frameworks. Because the signals are documented and the code is open, it also works well as a teaching artifact — the detection table is essentially a checklist of what current Selenium, Puppeteer, and Playwright deployments leak by default. Red teams studying it should note the README's core claim in reverse: beating one check is easy, and sustaining consistent multi-context fingerprints across sessions is the hard problem.

What to watch for: the new release is explicitly a first version, with the README promising additional fingerprinting signals and more detection logic over time, so expect the signal set to evolve and pin versions accordingly. The master-branch CI badge suggests active maintenance, and the seven-year dormancy followed by a rewrite means older blog posts and integrations referencing the legacy API are likely stale. Operationally, defenders should log fsid reuse, stale time values, and repeated nonce values — replay attempts against these fields are themselves a high-quality detection signal the library hands you for free.

Official project repository for antoinevastel/fpscanner.
Download Tool

Educational analysis for authorized security professionals. Use only in controlled, authorized environments.

Share articleFacebookXLinkedIn

Continue exploring

Browse all articles →

0 comentários:

Post a Comment

Note: Only a member of this blog may post a comment.