Orange textured background

Comparison

Benny vs ClientJS

ClientJS is the classic lightweight fingerprint. Benny is a modern two-hash library. Here's the honest comparison, including where ClientJS still fits.

TL;DR

ClientJS is one of the original open-source fingerprinting libraries: a tiny, readable, Apache-2.0, pure-JavaScript file that folds a basic set of browser properties into a single 32-bit integer. It is genuinely simple, and for low-stakes recognition it still works.

It is also effectively unmaintained, with its last release in 2021, and it predates modern signal techniques. There is no WebGL pixel readback, no WebGPU, no audio fingerprint, no cross-browser identity, and no anti-spoof.

Benny tags every signal as hardware or engine and returns two hashes, a per-browser fingerprint and a deterministic cross-browser hardwareFingerprint, plus a compareFingerprints API with six modes and free anti-spoof scoring. If you need a tiny source-available drop-in for coarse recognition, ClientJS is fine. If you need cross-browser matching or anti-fraud, that is Benny.

At a glance

BennyClientJS
Cost (free tier)FreeFree (Apache 2.0)
LicenseClosed-sourceApache 2.0 (open source)
MaintenanceActiveLast release 2021
Fingerprint outputTwo hashes (per-browser + hardware)Single 32-bit integer
Deterministic cross-browser IDYes (hardwareFingerprint)No
Comparison APIBuilt in, 6 modesYou build it
Anti-spoof in free tierYesNo
WebGL pixel readbackYesNo
WebGPU signalYesNo
Audio fingerprintYesNo
Runtime dependenciesZeroZero (pure JS)
Native mobile SDKNo (web only)No (web only)

Architecture: one integer vs two hashes

ClientJS collects a basic set of browser properties (user agent, screen, timezone, language, fonts, plugins, storage flags, and a canvas print) and folds them into a single 32-bit integer. It is fast and tiny, and it does not distinguish signals that depend on the browser from signals that depend on the underlying hardware.

Benny tags every signal as hardware-bound or engine-bound and produces two hashes: fingerprint for per-browser identity, and hardwareFingerprint for deterministic cross-browser identity. Same device, three browsers, three different fingerprint values, but one identical hardwareFingerprint.

A single integer is enough to recognize a returning visitor inside one browser. It cannot tell you that a Chrome visitor and a Safari visitor are the same device. That gap is the difference between simple recognition and cross-browser device matching.

Signal coverage: classic vs modern

ClientJS predates most of the signal techniques that carry entropy today. Its canvas check is a basic print, and it has no WebGL pixel readback, no WebGPU, and no audio fingerprint. The signal set it ships is the signal set you get; it has not changed materially since 2021.

Benny measures what the hardware does: GPU identity and a WebGPU trace, WebGL pixel readback rather than only reported constants, an audio path, and a set of hardware-bound device characteristics that stay stable across browsers. More entropy, and entropy that survives a browser switch.

For coarse, low-stakes recognition, ClientJS's lighter signal set is not a dealbreaker. For distinguishing similar devices or resisting evasion, modern signal coverage matters.

Comparison API: ship it or build it

ClientJS hands you an integer. If you want to ask whether this device is the same as last week's with one changed property, or similar enough to count as the same user across browsers, you write that matching logic yourself.

Benny ships compareFingerprints with six modes: exact, cross-browser, hardware-only, engine-only, strict, and lenient. Each returns a weighted similarity score, constraint violations, fuzzy matches on screen and audio attributes, and a numeric diff vector ready for downstream scoring.

If you are building anti-fraud, where the question is rarely an exact yes or no and usually how similar two devices are, that comparison logic is the actual product. Benny gives it to you. ClientJS leaves it to you.

Anti-spoof: free vs none

ClientJS has no spoof or tamper detection. It records what the browser reports and hashes it, so a spoofed user agent or an anti-detect browser passes straight through.

Benny runs a rule-based consistency check on every fingerprint result and returns a score, a list of flags, and a spoofLikelihood rating of low, medium, or high. It catches automation attributes, spoofed user agents, anti-detect browser signatures, and claimed-versus-actual hardware mismatches, all in the free tier.

If anti-spoof is part of your use case, ClientJS gives you nothing to build on, and Benny ships it in the box.

Where ClientJS is ahead

Honesty time. ClientJS has real advantages, and pretending otherwise would be obvious.

It is open source and tiny. ClientJS is Apache-2.0 and a single readable, pure-JavaScript file with no runtime dependencies. If you require source-available code you can audit and fork, or you want the smallest possible footprint, ClientJS meets that bar and Benny, being closed-source, does not.

It is proven for simple recognition. It has been deployed for years for coarse visitor recognition and basic analytics. If that is all you need, and you do not need anything added after 2021, it does the job.

Frequently asked questions

Is Benny the Doorman a drop-in alternative to ClientJS?

Both are free, client-side libraries that return a browser fingerprint, so the core integration is similar. Benny additionally returns a deterministic cross-browser hardwareFingerprint, a compareFingerprints API, and free anti-spoof scoring, so it covers ClientJS's per-browser recognition plus cross-browser matching. Migrating is an npm install and a call swap.

Is ClientJS still maintained?

ClientJS's last release was v0.2.1 in 2021, and the project has had no significant activity since. It still runs and works for basic recognition, but it has not added any newer signal techniques and receives no fixes, so for anything security-sensitive a maintained library is the safer choice.

What is the main difference between Benny and ClientJS?

ClientJS folds a basic signal set into a single 32-bit integer for per-browser recognition. Benny tags each signal as hardware-bound or engine-bound and returns two hashes, including a hardwareFingerprint that stays the same across Chrome, Safari, Firefox, and Brave on one device. That cross-browser identity, plus modern signals and anti-spoof, is the core difference.

Which is better for anti-fraud, Benny or ClientJS?

Benny. ClientJS has no comparison API and no spoof detection, so a spoofed or anti-detect browser passes straight through. Benny ships a compareFingerprints API with six match modes and a free anti-spoof consistency score on every result, which is what anti-fraud actually needs.

When should I still pick ClientJS?

ClientJS is Apache-2.0 and a single dependency-free file, so it wins when you require source-available code you can audit and fork, or you want the smallest possible footprint for coarse, low-stakes recognition. If you do not need cross-browser matching, anti-spoof, or signals added after 2021, it is a reasonable lightweight choice.

Benny is best for you if…

  • You need to recognize the same device across Chrome, Safari, and Firefox without standing up a server.
  • You are building anti-fraud and want a built-in compareFingerprints API plus free anti-spoof checks in the box.
  • You want modern signal coverage (WebGPU, WebGL pixel readback, audio) rather than a signal set frozen in 2021.
  • You want a library that is actively maintained.
  • A closed-source library is acceptable for your team or use case.

ClientJS is better for you if…

  • You require a source-available, open-source library you can audit and fork (Apache 2.0).
  • You want the smallest possible footprint: one readable, dependency-free file.
  • You only need coarse, low-stakes per-browser recognition and do not need cross-browser matching or anti-spoof.
  • You are maintaining a legacy integration already built on ClientJS.

Or migrate gradually

If you already run ClientJS, you do not have to rip it out on day one. Benny is additive, and the two can run side by side during a migration.

  • Keep ClientJS, add the cross-browser hash

    Leave your existing ClientJS integer in place for per-browser recognition and call Benny's hardwareFingerprint alongside it for the cross-browser device match ClientJS cannot produce.

  • Add anti-spoof to a ClientJS pipeline

    Layer Benny's consistency check on top of a ClientJS fingerprint so spoofed user agents and anti-detect browsers get flagged instead of passing through unscored.

  • Migrate the matching logic

    Replace hand-written ClientJS comparison code with Benny's compareFingerprints modes, then retire the ClientJS integer once the new identity is bedded in.