Typical tier 1 collection time
| Browser | Typical time |
|---|---|
| Chrome / Edge | ~1200 ms |
| Firefox | ~1400 ms |
| Safari | ~1600 ms |
Overlap collection with page load
The fastest way to ship fingerprinting without adding perceived latency is to start collection the moment your script executes. Use createCollector, call start() at the top of your page-load handler, and await getResult() only when you actually need the value, for example on form submit or before an API call.
In a typical single-page app, by the time the user has interacted with the first screen, the 1.2 to 1.6 s collection window has already passed and getResult() returns immediately.
Overlapping slow collectors
Some slow collectors run their asynchronous work in two stages. An early, non-blocking stage kicks off the slow browser call (for example an RTCPeerConnection offer or a media-device enumeration) without waiting for it; a later stage awaits the result. Because every slow collector's early stage fires before any of the awaits, the slow calls run concurrently instead of one after another, and wall-clock collection time drops by roughly the latency of the slowest call rather than their sum.
The two-stage path is hash-identical to the simple one-stage path by construction, so a collector produces byte-identical output whichever form it uses. This is verified by unit test.
Not every slow collector benefits equally. Some do only a quick synchronous check up front and keep their real work in the later stage, because splitting it would change timing semantics or run into browser concurrency limits. Others do useful synchronous work up front to take advantage of the overlap window.
import { getFingerprint, createCollector } from 'doorman-benny'; // Background pattern: start early, await late.
const collector = createCollector();
collector.start();
//... page load, user interaction...
const result = await collector.getResult(); // Warmup opt-in: yield before sampling.
const stableResult = await getFingerprint({ warmup: true }); // Pipeline timing: profiling only.
const timed = await getFingerprint({ performance: true });
console.log(timed._pipeline?.collect); // collection step ms
console.log(timed._pipeline?.checks); // consistency+incognito+automation ms
console.log(timed._pipeline?.total); // end-to-end msThe warmup option and performance option are independent; they can be combined.
Browser compatibility
| Browser | Support level |
|---|---|
| Chrome 90+ | Excellent |
| Edge 90+ | Excellent |
| Firefox 88+ | Good |
| Safari 14+ | Good |
| Mobile Chrome | Good |
| Mobile Safari | Good |
Last reviewed 2026-06-04

