TRACIO is a client-server identification system. The client collects browser signals and sends them to the server, which computes a stable visitor identifier, runs detection algorithms, and returns enriched results. This section explains each stage of the pipeline.
Browser TRACIO Cloud | | |-- Tracio.init({ publicKey }) ---------> | (init, no network) | | |-- tracio.getResult() ----------------> | | 1. Collect 300+ browser signals | | 2. Encrypt (XOR + deflate + B64) | | 3. POST to ingress endpoint | | | | |-- Decrypt & extract signals | |-- Compute visitor ID (MurmurHash3-128) | |-- Run bot detection (weighted scoring) | |-- Run smart signals (server-side enrichment) | |-- Run IP intelligence (VPN/proxy/Tor) | |-- Store visit event | | |<-- JSON response ------------------- | | visitorId, confidence, | | bot detection, smart signals | | | |-- Store visitor cookie (_vid_t) -----> | (365-day persistence)When tracio.getResult() is called, the client collects 300+ distinct browser signals organized into tiers. Collection uses a multi-phase pipeline with Web Workers and shared iframes for performance.
The agent ships 303 signals across 15 categories:
| Category | Signals | Category | Signals |
|---|---|---|---|
| Navigator | 67 | Audio | 12 |
| Tamper | 56 | Privacy | 12 |
| Bot | 26 | Display | 11 |
| Canvas | 22 | Fonts | 11 |
| CSS | 18 | Network | 11 |
| Crypto | 15 | Storage | 11 |
| Persistence | 14 | Behavioral | 4 |
| Intl | 13 |
Canvas covers WebGL and WebGPU as well as 2D rendering; Tamper is the second-largest category because detecting a modified environment takes more probes than reading an unmodified one.
The collection pipeline runs in four stages to minimize main thread blocking:
Stage 1 (Immediate): High-priority signals that are fast to collect (navigator properties, screen, timezone). The TURN probe also starts here as it runs concurrently.
Stage 2 (Idle Callback): Synchronous signals that benefit from an idle period (CSS media queries, storage probes, cookie tests).
Stage 3 (Async): Signals requiring asynchronous APIs or rendering (canvas, WebGL, audio fingerprint, font detection, emoji rendering).
Web Worker: Isolated signal collection in a dedicated thread (WASM feature detection, doNotTrack).
A shared hidden iframe is created once and reused by multiple collectors (emoji, MathML, system colors, fonts, screen frame) to avoid the overhead of creating separate iframes per signal.
Every signal follows a consistent structure:
interface Signal<T> { s: number // Status code v: T // Value (when successful)}Status codes:
| Code | Meaning |
|---|---|
0 | Success |
-1 | Not available (property undefined) |
-2 | Secondary check failed |
-3 | Unexpected behavior |
-4 | Timeout |
-5 | Disabled |
-6 | CSP blocked |
-7 | Security error |
Collected signals are serialized to JSON, then encrypted and compressed before transmission:
JSON serialization: All signal values are packed into a JSON object keyed by signal, plus metadata fields (c for API key, t for tag, lid for linked ID).
Compression: If the payload exceeds 1024 bytes, it is compressed using CompressionStream("deflate-raw").
XOR Encryption: The payload is wrapped in an encryption envelope:
Base64 encoding: The encrypted payload is Base64url-encoded and sent as the POST body.
The request is sent to the ingress endpoint with query parameters for client version and API key. CORS credentials are included to send first-party cookies.
The server receives the encrypted payload and processes it through several subsystems:
The server decodes the XOR envelope, decompresses if needed, and parses the JSON signal data. Each signal's status code and value are extracted and validated.
The visitor ID is computed using a tiered hashing approach (V3):
Tier 1 (Frozen): 20 base62 characters - Stable hardware signals that rarely change - Canvas, WebGL renderer, audio fingerprint, fonts - Provides long-term visitor identity
Tier 2 (Semi-stable): 10 base62 characters - Signals that change with browser updates - User-Agent data, Client Hints, plugins - Extensible without breaking Tier 1
Tier 3 (Volatile): 10 base62 characters - Signals that change frequently - Screen resolution, timezone, language - Used for confidence scoring, not identityEach tier extracts its designated signals, builds a canonical string, and hashes it with MurmurHash3-x64-128. The three tier hashes are concatenated and encoded in base62 to produce the final visitor ID.
The confidence score (0.0 to 1.0) indicates how certain the system is that this visitor has been correctly identified:
_vid_t cookie matches a known visitor, confidence is maximum.The bot detection engine runs multiple detectors and combines their weighted outputs into a bot score; a hard-fail signal forces a bot verdict on its own. The public bot.score is a 0..100 value and the verdict reaches you as bot.result. Exact thresholds are not published — a threshold you can read is a threshold you can tune against. Contributing detectors include:
Instrumentation (Frida), root/jailbreak and cloned-app detectors exist in the platform, but their input slots are native-only — the browser agent does not collect them, so they do not contribute to a web verdict. See Bot Detection for what is fully active on web.
Server-side enrichment signals are computed from the raw signal data and IP intelligence. These include VPN/proxy/Tor detection, IP geolocation, browser tampering analysis, and suspect scoring.
The IP intelligence subsystem provides:
The server returns a JSON response containing:
{ "visitorId": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "bot": { "detected": false, "confidence": 2, "reasons": [] }}This is the result tracio.getResult() resolves to in the browser. The
full, enriched event — including the canonical bot_result
(human / bot / uncertain), geolocation, and smart signals — is
delivered server-side through webhooks, readable through the
Server API, and surfaced in the dashboard.
The client stores a visitor token in both a first-party cookie (365-day expiry, SameSite=Lax) and localStorage for persistence across sessions.
| Step | Location | Description |
|---|---|---|
| 1 | Browser | Initialize agent, create shared iframe |
| 2 | Browser | Collect 300+ signals (parallel, multi-phase) |
| 3 | Browser | Encrypt and compress payload |
| 4 | Network | POST to server |
| 5 | Server | Decrypt, extract signals, compute visitor ID |
| 6 | Server | Run bot detection and smart signals |
| 7 | Server | Build response |
| 8 | Network | Return JSON response |
| 9 | Browser | Store visitor cookie |
Total round-trip: milliseconds. Signal collection dominates it — the network hops and the server-side work are the smaller part — and it varies with the visitor's device and connection. Nothing here blocks page rendering: the agent loads asynchronously and every check that can be slow is bounded by its own timeout.