fpscanner: self-hosted browser fingerprinting and bot detection in TypeScript
Self-hosted browser fingerprinting and bot detection with real-world constraints in mind.
At a glance
- What is it?
- fpscanner is a lightweight TypeScript library that collects browser fingerprint signals in the browser and helps defenders spot automation, with payload encryption, anti-replay protection and optional obfuscation built in. It is deliberately a building block rather than a complete fraud platform, and the project says so in its own non-goals section.
- Who is it for?
- fpscanner is a reasonable fit for a team that wants to collect browser fingerprint signals under its own control and detect automation on its own infrastructure, without routing traffic through a vendor CDN. It is not a fraud platform, a rule engine or a historical analysis tool, and the project itself points to Castle for those capabilities.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A fingerprinting library for defenders who want to keep the traffic on their own servers
fpscanner describes itself as a lightweight browser fingerprinting library for bot detection, and the phrase self-hosted appears in the project description and again in the README body. That is the design decision that shapes everything else. The library produces signals on the page and hands them to the defender's own backend, rather than requiring the traffic to pass through a third-party CDN or a vendor's decision endpoint.
The threat model in the README is specific rather than generic. It argues that scraping has become mainstream because AI and LLM driven companies crawl at a scale that used to be limited to specialists, often without respecting robots.txt or rate limits. At the same time, fraudsters no longer need public automation frameworks, because writing a custom bot for one site is cheaper with language model assistance. The consequence on the defender side is a choice between naive open source signal collections and expensive black-box products that require routing traffic elsewhere.
The stated goal is modest on purpose. The README says the goal is not to promise perfect detection but to give building blocks that reflect how bots behave today. That framing matters when you evaluate the library, because it sets an expectation of primitives you compose rather than a classifier you turn on.
There is a commercial dimension to the project as well. The README states that the project is sponsored by Castle, and it presents Castle as a production-grade platform for bot and fraud detection covering traffic observability, historical analysis, rule iteration and correlation across device, network and behavioral signals. The library is the open part of that stack, and the non-goals section is where the boundary is drawn explicitly.
Client-side signals are the fast path, and the README calls them strong but few
The feature table describes two capabilities. The first is fast bot detection through client-side detection of strong automation signals, naming navigator.webdriver, CDP usage and Playwright markers among them. The second is browser fingerprinting, and the wording of that row carries the important constraint: the fingerprint is short-lived and designed for attack detection, clustering and session correlation, explicitly not for long-term device tracking.
That distinction is the design's ethical and legal center, and it is also a technical constraint on how you use the output. A fingerprint that is meant to expire between sessions cannot be used as a permanent cross-session identifier, so a system built on fpscanner has to accumulate its own history server-side if it wants to notice reuse over time. The README makes exactly that point, listing tracking fingerprints over time, spotting reuse patterns and drift, and surfacing inconsistencies as things the server side can do with the signal.
The library is written in TypeScript and ships as an npm package named fpscanner at version 1.0.8, with example directories for Node.js and Python under examples/. The repository layout shows a Vite based build, a Playwright configuration for browser tests, a bin/ directory with a command line entry point, and both unit and browser test suites.
The stated philosophy underneath the signals is worth repeating because it shapes what you get. The project says no single signal is perfect and that attackers will read the code, so the goal is not obscurity but making abuse operationally expensive. The check list of automation artifacts will age as frameworks change, and the project's own answer is that new signals and more detection logic are expected over time.
Build-time key injection is what stops a captured payload from being replayed
Three hardening mechanisms carry most of the technical weight, and they are described as removing easy shortcuts rather than being unbreakable.
Anti-replay protection uses a timestamp plus a nonce, so a valid fingerprint cannot simply be captured once and reused at scale. Payload encryption prevents trivial forgery of a well-formed request. Build-time key injection means an attacker cannot generate valid encrypted payloads without access to your specific build, and the optional obfuscation step raises the cost of reverse-engineering the client code.
The build scripts make that injection concrete. The package exposes several build variants, and the development build is the clearest illustration of how the key enters the bundle.
node bin/cli.js build --key=dev-key --no-obfuscatevite build && tsc --emitDeclarationOnlyThe two commands are the plain and obfuscated branches of the same build, one without obfuscation and one with it, and the production target runs the build without a development key. The watch script shows the same mechanism during development, with the encryption key passed as an environment variable named FP_ENCRYPTION_KEY.
npm run build:obfuscate && npx playwright testThe practical consequence for an adopter is that FP_ENCRYPTION_KEY becomes a secret that belongs in your build pipeline and not in a public repository. The project publishes its own reasoning for why: the goal is to force real execution and limit replay, so an attacker cannot read the repository, reimplement a serializer and start sending convincing fingerprints from a headless script.
Consistency over time is the signal the server side actually uses
The README is careful about a point that many fingerprinting libraries skip. Detection does not stop at a single boolean flag, and even an attacker who focuses on defeating individual checks has a much harder problem producing fully consistent fingerprints over time.
The argument is that fingerprints encode relationships between signals, contexts and environments, so keeping them consistent across sessions, IP addresses and accounts requires real execution, careful state management and stable tooling. Partial emulation of an environment, or rotating tooling incorrectly, leaves traces. That is what makes reuse patterns and drift visible to the server.
This reframes the library's role. Rather than returning a verdict, it returns material that a server can accumulate and compare over time. A defender who only logs the fingerprint and never correlates it is using a small part of what is available.
The limits are acknowledged too. The project publishes its non-goals in a dedicated README section, and the sponsor paragraph names the categories of capability that the library intentionally does not cover, namely traffic observability, historical analysis, rule iteration, and correlation across device, network and behavioral signals. That is an unusually clear statement of scope, and it is the place to look when someone asks whether fpscanner can replace a commercial bot management product. It cannot, by its own account.
Running the browser tests locally with Playwright
Because the library detects automation artifacts, its own test suite runs inside a browser, and the package scripts reflect that. The default test command delegates to the Playwright suite rather than the unit runner.
npm run build:obfuscate && npx playwright testRunning the suite headed is a separate script, which matters when you are debugging signal collection by watching the values appear.
npx playwright test --headedThe repository carries a playwright.config.ts at the top level, alongside vite.config.ts, tsconfig.json and a .babelrc. The build output is declared in package.json: a CommonJS entry at dist/fpScanner.cjs.js, an ES module at dist/fpScanner.es.js, and TypeScript declarations emitted separately by tsc. The published files list is dist, src, bin and scripts, so the sources travel with the package rather than only the compiled bundle.
There is also a publish-time verification script, since prepublishOnly runs node scripts/verify-publish.js before anything goes out, and separate beta and stable publish targets driven by a safe-publish script. Those details suggest a release process with checks in it, which is useful context for a library that ends up in the authentication path of a website.
A live demo runs at fpscanner.com, and the project news entry notes that the current version is the first release of the rewritten FPScanner after more than seven years without updates, combining fingerprinting and bot detection in one library.
A rewritten project under active push, with an MIT licence and a vendor sponsor
The repository is not archived, and the last push was on 2026-10-20. The project news entry describes the current release as the first one after more than seven years without any updates, so this is a rewrite rather than an incremental continuation of the old code. The package version is 1.0.8, and there are no GitHub releases, so npm is the distribution channel rather than tagged release artifacts.
Licensing is MIT, with a LICENSE file at the top of the repository. That matters more than usual for a fingerprinting library, because the code that decides which signals you collect is code you may need to audit, and the MIT terms make it practical to read, vendor and modify without copyleft obligations on your application.
The sponsorship arrangement is worth naming plainly for anyone evaluating the project. Castle sponsors the work and sells a platform that covers the areas the library does not. That does not make the library a marketing shell, since the code, the signals and the hardening are all in the open repository. It does mean the boundary between the free primitives and the paid operational layer is drawn by the sponsor, which is exactly why the README includes a non-goals section instead of leaving it to inference.
The topic list on the repository is itself a description of the intended use: browser, browser-fingerprint, detection, fraud-detection, authentication, visitor-identifier, javascript and fingerprintjs among them. Read as a whole, the project positions itself as an open building block for authentication and fraud workflows where the traffic cannot or should not be sent to a third party.
Editorial conclusion
fpscanner is a reasonable fit for a team that wants to collect browser fingerprint signals under its own control and detect automation on its own infrastructure, without routing traffic through a vendor CDN. It is not a fraud platform, a rule engine or a historical analysis tool, and the project itself points to Castle for those capabilities. Before you build on it, verify three things yourself: that the signals your traffic actually produces are enough to separate your users from automation, that the key you inject at build time is protected as a secret in your build pipeline, and that the client-side checks you rely on are backed by server-side validation, because the library's own framing is that no single signal is a verdict.
Frequently asked questions
What is fpscanner and what is it used for?
fpscanner is a lightweight browser fingerprinting library for bot detection, published as the npm package fpscanner and written in TypeScript. It focuses on self-hosted fingerprinting and bot detection primitives, with a live demo at fpscanner.com.
How does fpscanner prevent a captured fingerprint from being replayed?
The README describes anti-replay protections built on a timestamp plus a nonce, payload encryption to prevent trivial forgery, and build-time key injection so valid payloads cannot be generated without access to your build. Optional obfuscation raises the cost of reverse-engineering the client code.
Can fpscanner be used for long-term device tracking?
No. The feature table describes the fingerprint as short-lived and designed for attack detection, clustering and session correlation rather than long-term device tracking. Detecting reuse over time is instead done server-side by correlating fingerprints across sessions.
What does fpscanner not cover?
The README points to a Limits and non-goals section and names traffic observability, historical analysis, rule iteration, and correlation across device, network and behavioral signals as capabilities outside the library, which it says are covered by the sponsoring platform Castle.
How do you build fpscanner with an encryption key and obfuscation?
The package exposes a command line build, and the development variant runs node bin/cli.js build --key=dev-key --no-obfuscate. During development the key is passed as FP_ENCRYPTION_KEY in the watch script, and the Playwright test suite is run with npm run build:obfuscate && npx playwright test.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/antoinevastel-fpscanner)Was this useful?