Guides

Persistence engine

A visitor in Veriprint is not a single hash. It is a cluster of signal vectors that follows a device as its browser, hardware, and network change. This page explains how matching, weighting, and drift tracking work, and where the limits are.

A visitor is a cluster, not a hash

Naive fingerprinting hashes all signals into one string; a single changed value (a browser update shifting the canvas render, a new monitor changing the screen resolution) produces a different hash and a false new visitor. Veriprint instead stores each visitor as a weighted signal vector. On every identify call, the incoming vector is compared against known visitors using entropy-weighted similarity:

SimilarityDecision
≥ 0.82Link to the existing visitor at high confidence.
≥ 0.62Link to the existing visitor with a lowered confidence score: enough signals moved that the match is plausible but not certain.
< 0.62Mint a new visitorId. The response reports matchedVia: ["new"].

Weighting by distinctiveness

A signal's weight is how much it distinguishes one device from another, which is its entropy, not merely how stable it is. This distinction matters. Every MacBook reports platform MacIntel, the same core count, the same timezone within a city, and the same stock system fonts. Those signals are perfectly stable and almost useless for telling two machines apart. Weighting them highly makes two similar laptops look identical and merges them into one visitor, which is the worst error the engine can make.

So the highest weights go to signals that are both reasonably durable and high entropy: the GPU renderer string, the installed-font set, and the canvas, WebGL, and audio render hashes. Ubiquitous signals get low weight and are used to bucket candidates, not to decide identity.

TierWeightSignalsWhy
Distinguishing4canvas, WebGL, GPU renderer, fontsDevice-specific. The GPU renderer separates an M4 from an M5; the render hashes and font set separate two otherwise identical laptops. These decide identity.
Distinctive, noisier3audio, screen resolutionReal entropy, but a little noisier or coarser than the top tier.
Population-narrowing2CPU cores, languages, timezoneStable, but a whole product line or a whole city shares one value. Helpful context, weak on their own.
Bucketing only1platform, vendor, memory, colorDepth, touch, userAgentNear-ubiquitous or fast-changing. Useful for grouping candidates cheaply, almost no identity power. IP and ASN are a weak network hint on top.

A Chrome update that rewrites the canvas and WebGL hashes still leaves the GPU renderer, fonts, screen, and audio in agreement, so the same device re-links. Two different laptops that share every common signal but differ on the render hashes and GPU renderer stay separate.

The entropy gate

Reweighting is not enough on its own, because a device with many matching common signals can still score high. A fingerprint-only match (one with no surviving anchor) is therefore accepted only if the distinguishing signals also agree past a floor. If two devices line up on timezone, platform, core count, and language but their canvas, WebGL, audio, and GPU renderer disagree, the match is rejected and a new visitorId is minted.

Similar devices without anchors
Two identical-model laptops in a privacy browser that blocks canvas, WebGL, and audio may offer nothing that distinguishes them. Veriprint declines to guess: it gives them separate IDs and relies on anchors to tell them apart. A false split is safer than a false merge.

Anchors short-circuit matching

The SDK writes the returned visitorId into three independent stores (a cookie, localStorage, and the Cache API) and sends whatever survives back as anchors on the next call. Any one valid anchor resolves the visitor directly, and the SDK rewrites all three stores, so clearing cookies alone does not break the chain:

anchor-cycle
visit 1  → all 3 anchors written (cookie, localStorage, Cache API)
user clears cookies
visit 2  → localStorage + cache anchors still match → same visitorId
         → cookie is re-written        (matchedVia: ["localStorage", "cache"])
user clears ALL site data
visit 3  → no anchors → fingerprint similarity match at 0.87 → same visitorId
         → all 3 anchors re-written    (matchedVia: ["fingerprint"])

Drift tracking with EMA decay

Devices drift: fonts get installed, browsers update, displays change. On each linked identify, the stored vector moves toward the new observation with an exponential moving average at alpha = 0.25, so the stored value becomes 75% history and 25% new observation. Identity follows the device through gradual change instead of snapping to a stale snapshot, while a one-off anomaly (a spoofed signal, a temporary VM) cannot drag the cluster far.

When a returning device is re-linked (via anchor or similarity), its original firstSeenAt is preserved and visitCount keeps accumulating, so account-age and velocity checks stay meaningful across storage wipes.

Persistence curve and limitations

Honest expectations
Fingerprint-based identification is probabilistic. Veriprint reports a confidence score on every match precisely because no fingerprint is a permanent, guaranteed identifier. Do not build flows that assume it is.
  • Weeks: strong. Anchors usually survive, and signal drift is minimal; most returns match at high confidence.
  • A few months: good. EMA tracking absorbs browser updates and normal drift; matches remain reliable, with occasional lowered-confidence links.
  • Beyond that: graceful degradation. Accumulated drift lowers similarity; some visitors resolve as new.
  • Multi-year: realistic only for devices that keep at least one anchor and do not change hardware. Pure fingerprint recognition across years of drift is not something you should plan around.

Hard resets (a new device, a fresh OS install, or aggressive anti-fingerprinting browsers that randomize signals) produce a new visitor. That is by design: guessing would create false merges, which are worse for fraud decisions than false splits. Use confidence and confidenceLevel to decide how much weight each match should carry in your own logic.