Signals
Every signal the SDK collects, what it measures, and the weight it carries in similarity matching. A signal's weight is how much it distinguishes one device from another, which is its entropy, not merely how stable it is.
Weights come in four tiers. Distinguishing signals are device-specific and decide identity; bucketing signals are near-ubiquitous and only group candidates. The persistence engine page explains how these weights feed the 0.82 / 0.62 similarity thresholds and the entropy gate.
Signal catalog
| Signal | What it is | Weight | Rationale |
|---|---|---|---|
canvas | Hash of a 2D canvas render: text, shapes, blends. | Distinguishing · 4 | High entropy from the exact GPU, driver, and OS text stack. A browser update can rewrite it, so it is never the only signal, but it is a primary distinguisher. |
webgl | Hash of a WebGL scene render. | Distinguishing · 4 | High entropy from the GPU pipeline. Same drift risk as canvas, same importance. |
webglVendor | Full unmasked GPU vendor and renderer string. | Distinguishing · 4 | Distinctive and fairly stable. On Apple Silicon this is the ANGLE-over-Metal string that the chip name is parsed from. |
webgpu | WebGPU adapter info, 30+ hardware limits, and feature flags. | Distinguishing · 4 | The richest hardware signal, 25 to 35 bits of entropy versus 15 to 20 for WebGL. Exposes GPU details WebGL now masks. Available on Chromium and Safari 18+; null on browsers without WebGPU. |
gpuChip | Normalized chip parsed from the renderer: apple-m5, apple-m4-pro, intel, amd, nvidia. | Hard rule · 0 | A physical, immutable property. Used as a negative-only discriminator: a matching chip adds no weight (a whole office may share an M1 Pro), but two SPECIFIC chips that differ hard-split the devices even when every render hash is identical. Generic values (apple-silicon on Safari) never force a split. |
fonts | Set of installed fonts detected by render measurement. | Distinguishing · 4 | User-installed fonts add real entropy on top of the stock OS set, and the set changes slowly. Jaccard overlap tolerates a few additions. |
audio | Hash of an OfflineAudioContext oscillator render. | Distinctive · 3 | Reflects the audio DSP stack. Distinctive, but shifts occasionally, so it sits a tier below the render hashes. |
screen | Resolution including scaling, plus color depth. | Distinctive · 3 | Varies across models and external displays. Docking to a monitor or changing scaling moves it. |
fontPreferences | Measured pixel widths of a probe string across generic and system font stacks. | Distinctive · 3 | Captures subpixel hinting and the OS text stack, higher entropy than font presence. Distinguishing when the rendering pipeline differs. |
speechVoices | Hash of the installed text-to-speech voice set (name, language, local vs cloud). | Distinctive · 3 | Pins the operating system and its version precisely: Windows 11 ships neural voices Windows 10 lacks, macOS has "Samantha" and "Alex", Linux has the eSpeak set. A whole OS-version population shares it. |
hardwareConcurrency | Logical CPU core count reported by the browser. | Population · 2 | Stable, but a whole product line shares one value, so it narrows the field rather than identifying a machine. |
languages | Ordered browser language list, e.g. ["de-DE", "en"]. | Population · 2 | Narrows locale, but millions share "en-US". |
timezone | IANA timezone from the Intl API, e.g. Europe/Berlin. | Population · 2 | Stable and follows the person, but everyone in a city shares it. |
architecture | CPU architecture from Client Hints: arm or x86. | Population · 2 | Cleanly separates Apple Silicon (arm) from Intel Macs (x86) on Chromium, where navigator.platform still reports MacIntel for both. Every Apple Silicon device shares "arm", so it narrows rather than identifies. |
colorGamut, mediaFeatures, mediaDevices, mediaCodecs, webgpuArchitecture | Display gamut, stable CSS media + pointer/hover features, audio/video device counts, the codec support matrix (H.264/HEVC/AV1/VP9/Opus/FLAC), and the WebGPU GPU family. | Population · 2 | Display, input, and codec capabilities add entropy across a population. They shift with an external monitor, an accessibility change, a plugged-in peripheral, or hardware decode support, so they carry moderate weight. |
tlsFingerprint | Server-side JA4/JA3 + HTTP/2 fingerprint of the TLS ClientHello, read from an edge proxy. | Population · 2 | Network-level and impossible to spoof from JavaScript, so a strong bot and browser-family signal. Browser-family level (many share one), and only present when a fingerprinting proxy sits in front. See self-hosting for how to enable it. |
platform, vendor, deviceMemory, colorDepth, touch, platformVersion, mathFingerprint, screenFrame, audioBaseLatency, userAgent | OS platform, browser vendor, RAM bucket, color depth, touch class, OS version, transcendental-math hash, screen insets, audio latency, UA string. | Bucketing · 1 | Near-ubiquitous or fast-changing. Every Mac shares the platform and math stack; screen insets and audio latency add a little entropy. Useful for grouping candidates cheaply, weak for identity. |
ip / asn | Request IP and its autonomous system, resolved server-side. | Network hint | Corroboration only. Mobile devices rotate IPs daily and whole households share one address, so it can nudge a score but never decide a match. |
How to read the tiers
Two devices only merge when their distinguishing signals agree, not when their common signals line up. A browser update that rewrites the canvas and WebGL hashes leaves the GPU renderer, fonts, screen, and audio in agreement, so the same device still re-links. Two different laptops with the same OS, CPU, and browser build differ on the render hashes and GPU renderer, so they stay separate.