TRACIO est un système d'identification client-serveur. Le client collecte des signaux du navigateur et les envoie au serveur, qui calcule un identifiant de visiteur stable, exécute des algorithmes de détection et renvoie des résultats enrichis. Cette section explique chaque étape du 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)Lorsque tracio.getResult() est appelé, le client collecte 300+ signaux de navigateur distincts, organisés en tiers. La collecte utilise un pipeline multi-phases avec des Web Workers et des iframes partagées pour la performance.
L'agent embarque 303 signaux répartis en 15 catégories :
| Catégorie | Signaux | Catégorie | Signaux |
|---|---|---|---|
| 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 couvre WebGL et WebGPU au même titre que le rendu 2D ; Tamper est la deuxième catégorie par la taille, car reconnaître un environnement modifié demande plus de sondes que de lire un environnement intact.
Le pipeline de collecte s'exécute en quatre étapes afin de minimiser le blocage du thread principal :
Étape 1 (Immédiate) : signaux haute priorité rapides à collecter (propriétés navigator, écran, fuseau horaire). La sonde TURN démarre également ici car elle s'exécute en parallèle.
Étape 2 (Idle Callback) : signaux synchrones qui bénéficient d'une période d'inactivité (media queries CSS, sondes de stockage, tests de cookies).
Étape 3 (Async) : signaux nécessitant des API asynchrones ou du rendu (canvas, WebGL, empreinte audio, détection de polices, rendu des emoji).
Web Worker : collecte de signaux isolée dans un thread dédié (détection des fonctionnalités WASM, doNotTrack).
Une iframe cachée partagée est créée une seule fois et réutilisée par plusieurs collecteurs (emoji, MathML, couleurs système, polices, cadre d'écran) afin d'éviter le surcoût lié à la création d'iframes séparées par signal.
Chaque signal suit une structure cohérente :
interface Signal<T> { s: number // Status code v: T // Value (when successful)}Codes de statut :
| Code | Signification |
|---|---|
0 | Succès |
-1 | Non disponible (propriété undefined) |
-2 | Vérification secondaire échouée |
-3 | Comportement inattendu |
-4 | Timeout |
-5 | Désactivé |
-6 | Bloqué par CSP |
-7 | Erreur de sécurité |
Les signaux collectés sont sérialisés en JSON, puis chiffrés et compressés avant transmission :
Sérialisation JSON : toutes les valeurs de signaux sont regroupées dans un objet JSON indexé par signal, plus des champs de métadonnées (c pour la clé API, t pour le tag, lid pour le linked ID).
Compression : si le payload dépasse 1024 octets, il est compressé avec CompressionStream("deflate-raw").
Chiffrement XOR : le payload est enveloppé dans une enveloppe de chiffrement :
Encodage Base64 : le payload chiffré est encodé en Base64url et envoyé comme corps du POST.
La requête est envoyée à l'endpoint d'ingress avec des paramètres de requête pour la version du client et la clé API. Les credentials CORS sont inclus pour envoyer les cookies first-party.
Le serveur reçoit le payload chiffré et le traite à travers plusieurs sous-systèmes :
Le serveur décode l'enveloppe XOR, décompresse si nécessaire et parse les données de signaux JSON. Le code de statut et la valeur de chaque signal sont extraits et validés.
Le visitor ID est calculé selon une approche de hachage hiérarchisé (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 identityChaque tier extrait ses signaux désignés, construit une chaîne canonique et la hache avec MurmurHash3-x64-128. Les trois hashes de tiers sont concaténés et encodés en base62 pour produire le visitor ID final.
Le score de confiance (0.0 à 1.0) indique à quel point le système est certain que ce visiteur a été correctement identifié :
_vid_t correspond à un visiteur connu, la confiance est maximale.Le moteur de détection des bots exécute plusieurs détecteurs et combine leurs sorties pondérées en un score de bot ; un signal à échec forcé (hard-fail) impose à lui seul un verdict de bot. La valeur publique bot.score est une échelle 0..100 et le verdict vous parvient sous la forme bot.result. Les seuils exacts ne sont pas publiés : un seuil que l'on peut lire est un seuil auquel on peut s'ajuster. Les détecteurs contributeurs incluent :
Les détecteurs d'instrumentation (Frida), de root/jailbreak et d'app clonée existent dans la plateforme, mais leurs emplacements d'entrée sont exclusivement natifs : l'agent navigateur ne les collecte pas, ils ne contribuent donc pas à un verdict web. Voir Détection des bots pour ce qui est pleinement actif sur le web.
Les signaux d'enrichissement côté serveur sont calculés à partir des données de signaux brutes et de l'IP intelligence. Ils incluent la détection VPN/proxy/Tor, la géolocalisation IP, l'analyse d'altération du navigateur et le suspect scoring.
Le sous-système d'IP intelligence fournit :
Le serveur renvoie une réponse JSON contenant :
{ "visitorId": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "bot": { "detected": false, "confidence": 2, "reasons": [] }}C'est le résultat auquel tracio.getResult() se résout dans le navigateur. L'événement
complet et enrichi — incluant le bot_result canonique
(human / bot / uncertain), la géolocalisation et les smart signals — est
livré côté serveur via les webhooks, lisible via la
Server API et affiché dans le tableau de bord.
Le client stocke un token de visiteur à la fois dans un cookie first-party (expiration 365 jours, SameSite=Lax) et dans localStorage pour la persistance entre les sessions.
| Étape | Emplacement | Description |
|---|---|---|
| 1 | Navigateur | Initialiser l'agent, créer l'iframe partagée |
| 2 | Navigateur | Collecter 300+ signaux (parallèle, multi-phases) |
| 3 | Navigateur | Chiffrer et compresser le payload |
| 4 | Réseau | POST vers le serveur |
| 5 | Serveur | Déchiffrer, extraire les signaux, calculer le visitor ID |
| 6 | Serveur | Exécuter la bot detection et les smart signals |
| 7 | Serveur | Construire la réponse |
| 8 | Réseau | Renvoyer la réponse JSON |
| 9 | Navigateur | Stocker le cookie de visiteur |
Aller-retour total : des millisecondes. La collecte des signaux en occupe l'essentiel — les allers-retours réseau et le travail côté serveur pèsent moins — et la durée varie selon l'appareil et la connexion du visiteur. Rien de tout cela ne bloque le rendu de la page : l'agent se charge de façon asynchrone et chaque vérification susceptible d'être lente est bornée par son propre timeout.