Cookie-based trial gates fail the moment a user clears their browser history. A hardware-bound device fingerprint persists through cookie clears, browser switches, and incognito mode, making it the practical foundation for per-device trial enforcement.
The abuse pattern in three moves
Free-trial abuse is rarely sophisticated. The typical sequence is: sign up, use the trial, hit the limit, clear cookies (or use a browser's built-in 'clear history' button), create a new account. Some users go further: after cookie-clearing stops working, they try a different browser. After that, they try incognito. Many sites give up at step one.
The cost is real. Marketing attribution for trials becomes meaningless. Conversion signals get polluted. In SaaS with seat limits or usage caps, abusers consume server-side resources that are never monetised.
The reason this pattern succeeds is that most trial gates are storage-based: a cookie, a localStorage flag, or a server-side record tied to a session identifier. All of these evaporate when the user controls the storage layer.
Why cookies and a single browser fingerprint both fail
Cookies are trivially cleared. Any browser ships a 'clear browsing data' button that removes them in one click, and browsers in private mode never write them at all. Tying the trial gate to a cookie is equivalent to tying it to user goodwill.
IP blocking is blunt: shared offices, NAT, mobile carriers, and VPNs mean that blocking an IP hits collateral users at a high rate.
A single browser fingerprint is better than a cookie but still breaks across browsers. Most fingerprinting libraries produce a hash that is specific to the browser engine: Chrome and Firefox on the same machine produce different hashes because their audio DSP, canvas rasteriser, and WebGL pipeline produce different outputs. An abuser who exhausts a trial in Chrome and reopens in Firefox looks like a different device.
Why common trial gates fail and what holds
| Defense | Defeated by | Holds against |
|---|---|---|
| Cookie / localStorage flag | Clear browsing data (one click) | Nothing: user fully controls storage |
| IP address block | VPN, mobile carrier NAT, shared office | Some volumetric attacks |
| Disposable email block | Any real or forwarded email address | Automated bulk signups from known domains |
| Single browser fingerprint | Opening a different browser (Chrome to Firefox) | Same-browser re-signups |
| Hardware fingerprint (hardwareFingerprint) | Getting a physically different device | Cookie clears, browser switches, incognito, VPNs |
What a cross-browser hardware identity is
The solution is to separate hardware-bound signals (properties of the physical device that are the same in every browser) from engine-bound signals (properties of how a specific browser processes content). A hash derived only from hardware-bound signals will be identical in Chrome, Safari, Firefox, and Brave on the same machine, regardless of whether cookies exist, regardless of which browser is open, and regardless of incognito mode.
This is the `hardwareFingerprint` field returned by `getFingerprint` in the `doorman-benny` library. It is derived from the hardware-bound subset of the full signal set, collected in the same pipeline pass that also produces the per-browser `fingerprint`. You do not need a separate call.
For a deeper explanation of why the hardware-vs-engine split matters structurally, see the companion post on hardware vs engine fingerprint identity.
Wiring it up
The implementation pattern is straightforward: at signup, collect a fingerprint, extract the `hardwareFingerprint`, and check it against your existing trial records. If a match is found, the device already has a trial on record.
Install the package first.
npm install doorman-bennyimport { getFingerprint } from 'doorman-benny';
async function evaluateTrialEligibility(): Promise<boolean> {
const result = await getFingerprint();
// The hardware fingerprint is stable across Chrome, Safari, Firefox, and Brave
// on the same physical device. It survives cookie clears and incognito mode.
const hardwareId = result.hardwareFingerprint;
// Send to your backend for trial-record lookup.
const response = await fetch('/api/trial/check', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hardwareFingerprint: hardwareId }),
});
const { eligible, reason } = await response.json();
if (!eligible) {
// Surface a message appropriate to your product.
// Avoid 'fingerprint' in user-facing strings.
console.log('Trial not available:', reason);
}
return eligible;
}Call this before showing the trial sign-up form or at account creation. The hardware fingerprint check is the device-level gate; your existing email/account layer stays in place above it.
Handling false positives
No device identification is perfect. Hardware-bound signals can shift on legitimate events: an OS reinstall, a hardware upgrade, connecting an external monitor or USB hub that changes reported geometry, or a major OS version update that alters platform reporting.
A few practices keep false positives manageable. First, treat the hardware fingerprint as a risk signal rather than a hard gate. If a hardware ID matches a prior trial record, raise the friction (require email verification or a manual review) rather than silently blocking. Second, log which hardware signals contributed to the match using the `crossBrowser.stableSignals` field so support staff can reason about edge cases.
Third, pair the hardware check with `compareFingerprints` in cross-browser mode when you have a stored prior fingerprint. The comparison API gives you a `matchScore` (0 to 100) and a `hardwareMatch` boolean that you can tune independently. This is more nuanced than a raw hash equality check.
Finally, legitimate incognito use is not fraud. The `incognito.incognitoLikelihood` field on the result is informational context, not a fraud signal, and should not feed into the trial gate on its own.
import { getFingerprint, compareFingerprints } from 'doorman-benny';
async function detectDuplicateTrial(
storedFingerprint: object,
): Promise<{ isDuplicate: boolean; confidence: number }> {
const currentResult = await getFingerprint();
// Cross-browser mode compares only hardware-bound signals.
// This is the right mode for 'is this the same device regardless of browser'.
const comparison = compareFingerprints(
storedFingerprint as any,
currentResult,
{ mode: 'cross-browser' }
);
return {
isDuplicate: comparison.hardwareMatch || comparison.match,
confidence: comparison.matchScore,
};
}compareFingerprints returns matchScore (0-100), match, and hardwareMatch. Use hardwareMatch for a deterministic equality check; use matchScore for a graded similarity signal that tolerates minor hardware drift.
Frequently asked questions
Does clearing cookies break the hardware fingerprint?
No. The hardware fingerprint is derived from signals that the browser cannot clear, such as the GPU model, CPU architecture, and installed fonts. Cookie clearing removes storage-based identifiers but does not affect how hardware-bound signals are reported. The hardwareFingerprint will be identical before and after a cookie clear on the same device.
Does switching to incognito mode defeat the hardware fingerprint?
No. Incognito mode blocks cookies and storage writes, but hardware-bound signals are still available and still produce the same values. The hardwareFingerprint will match between a user's normal and incognito sessions on the same device. See the related post on fingerprints in incognito mode for a full explanation.
What about VPNs? Does IP masking affect the fingerprint?
No. The fingerprint is collected entirely on the client side from browser APIs. It does not include the IP address and is not affected by VPN use. This is both a privacy property (the fingerprint does not reveal network location) and a fraud-detection property (VPN masking does not defeat it).
Can an abuser defeat the hardware fingerprint by using a virtual machine?
A virtual machine produces different hardware-bound signals than the host machine, so a VM signup and a host machine signup will generally produce different hardwareFingerprint values. However, if the same VM image is reused to generate multiple signups, those signups will share a hardwareFingerprint, which is exactly the pattern you want to catch. The consistency.spoofLikelihood check may also flag virtualized environments depending on the signals available.
Is this compliant with GDPR or ePrivacy?
Fingerprinting for fraud prevention generally qualifies for a security and fraud-prevention exemption under GDPR and most ePrivacy frameworks, provided the processing is proportionate and disclosed in a privacy notice. The laws/fingerprinting-anti-fraud-exemption page covers the legal landscape in detail. This is engineering documentation and not legal advice.
Get started
Stop trial abuse before it compounds
npm install doorman-benny. Hardware-bound device identity, cross-browser matching, and free anti-spoof scoring in one package. No cookies, no server round-trip for the fingerprint.
Last reviewed June 9, 2026

