The background-collection pattern
getFingerprint blocks the caller for up to 1 to 1.6 seconds. For interactive pages that pattern adds measurable latency. The solution is to decouple the start of collection from the moment you need the result.
createCollector returns a CollectorHandle immediately. No collection begins yet. Call start() as early as possible in the page lifecycle (top of a script, inside a DOMContentLoaded handler, or in a framework's app initialiser). Collection then runs in the background. By the time the user has filled a form or clicked a button, getResult() typically resolves instantly because collection finished during idle time.
CollectorHandle methods
start() is idempotent. Calling it multiple times is safe; only the first call begins collection. It never throws.
getResult() returns the stored FingerprintResult promise. If start() was never called, getResult() auto-starts collection and waits for it. getResult() also never throws; on any error it resolves to an empty FingerprintResult.
import { createCollector } from 'doorman-benny'; // Place at the very top of your page-load handler.
// Collection begins immediately and runs in the background.
const collector = createCollector();
collector.start(); //... modules load, network requests fire, user sees the first screen... // By now collection is likely done. getResult() resolves with little or no wait.
async function onFormSubmit() { const result = await collector.getResult(); if (result.automation.automationLikelihood === 'high') { throw new Error('Automated submission blocked'); } await submitToServer({ deviceId: result.hardwareFingerprint, fingerprint: result.fingerprint, });
}The collector passes the same FingerprintOptions to getFingerprint internally. All options (tiers, timeout, exclude, debug) apply.
Two-stage collection
Some signal collectors split their work into two stages: an early, non-blocking stage that kicks off slow asynchronous work, and a later stage that awaits it and returns the SignalResult.
This is an internal implementation detail; createCollector callers never interact with the two stages directly. The two-stage pattern improves wall-clock collection time by overlapping slow async calls across collectors. The FingerprintResult shape returned by getResult() is identical regardless of which collectors use the two-stage form.
Comparison with getFingerprint
createCollector is a scheduling wrapper around getFingerprint. The FingerprintResult it produces is identical in shape. The only difference is when collection starts: immediately with getFingerprint, or at the explicit start() call with createCollector. Use createCollector whenever the page lifecycle gives you any time before you need the result.
Last reviewed 2026-06-04

