TRACIO is een client-server-identificatiesysteem. De client verzamelt browsersignalen en stuurt ze naar de server, die een stabiele bezoekersidentificator berekent, detectiealgoritmen uitvoert en verrijkte resultaten teruggeeft. In dit hoofdstuk wordt elke fase van de pipeline uitgelegd.
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)Wanneer tracio.getResult() wordt aangeroepen, verzamelt de client 300+ verschillende browsersignalen die in tiers zijn georganiseerd. De verzameling gebruikt een meerfasige pipeline met Web Workers en gedeelde iframes voor de performance.
De agent levert 300+ signalen verdeeld over 15 categorieën:
| Categorie | Signalen | Categorie | Signalen |
|---|---|---|---|
| Tamper | 82 | Fonts | 15 |
| Navigator | 72 | Network | 15 |
| Bot | 32 | Persistence | 14 |
| Canvas | 26 | Intl | 13 |
| CSS | 19 | Audio | 12 |
| Privacy | 17 | Storage | 12 |
| Crypto | 16 | Behavioral | 5 |
| Display | 15 |
Canvas dekt naast 2D-rendering ook WebGL en WebGPU; Tamper is de grootste categorie, omdat het herkennen van een aangepaste omgeving meer probes vergt dan het uitlezen van een onaangepaste.
De verzamelingspipeline draait in vier fasen om het blokkeren van de main thread te minimaliseren:
Fase 1 (Direct): Signalen met hoge prioriteit die snel te verzamelen zijn (navigator-eigenschappen, screen, tijdzone). De TURN-probe start hier ook, aangezien deze gelijktijdig wordt uitgevoerd.
Fase 2 (Idle Callback): Synchrone signalen die profiteren van een inactieve periode (CSS-media-queries, storage-probes, cookie-tests).
Fase 3 (Async): Signalen die asynchrone API's of rendering vereisen (canvas, WebGL, audio-fingerprint, fontdetectie, emoji-rendering).
Web Worker: Geïsoleerde signaalverzameling in een dedicated thread (WASM-featuredetectie, doNotTrack).
Er wordt eenmalig een gedeeld verborgen iframe aangemaakt dat door meerdere collectors wordt hergebruikt (emoji, MathML, systeemkleuren, fonts, screen-frame), om de overhead van het aanmaken van aparte iframes per signaal te vermijden.
Elk signaal volgt een consistente structuur:
interface Signal<T> { s: number // Status code v: T // Value (when successful)}Statuscodes:
| Code | Betekenis |
|---|---|
0 | Succes |
-1 | Niet beschikbaar (eigenschap undefined) |
-2 | Secundaire controle mislukt |
-3 | Onverwacht gedrag |
-4 | Timeout |
-5 | Uitgeschakeld |
-6 | Geblokkeerd door CSP |
-7 | Beveiligingsfout |
Verzamelde signalen worden geserialiseerd naar JSON en vervolgens vóór verzending versleuteld en gecomprimeerd:
JSON-serialisatie: Alle signaalwaarden worden verpakt in een JSON-object, gesleuteld per signaal, plus metadatavelden (c voor API-sleutel, t voor tag, lid voor linked ID).
Compressie: Als de payload groter is dan 1024 bytes, wordt deze gecomprimeerd met CompressionStream("deflate-raw").
XOR-versleuteling: De payload wordt in een versleutelingsenvelop verpakt:
Base64-codering: De versleutelde payload wordt Base64url-gecodeerd en als POST-body verzonden.
Het verzoek wordt naar het ingress-endpoint gestuurd met query-parameters voor de client-versie en API-sleutel. CORS-credentials worden meegestuurd om first-party-cookies te verzenden.
De server ontvangt de versleutelde payload en verwerkt deze via verschillende subsystemen:
De server decodeert de XOR-envelop, decomprimeert indien nodig en parseert de JSON-signaaldata. De statuscode en waarde van elk signaal worden geëxtraheerd en gevalideerd.
De bezoekers-ID wordt berekend met een tiered hashing-aanpak (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 identityElke tier extraheert zijn aangewezen signalen, bouwt een canonieke string op en hasht deze met MurmurHash3-x64-128. De drie tier-hashes worden aaneengeschakeld en in base62 gecodeerd om de uiteindelijke bezoekers-ID te produceren.
De confidence-score (0.0 tot 1.0) geeft aan hoe zeker het systeem is dat deze bezoeker correct is geïdentificeerd:
_vid_t-cookie overeenkomt met een bekende bezoeker, is de confidence maximaal.De bot-detectie-engine voert meerdere detectoren uit en combineert hun gewogen uitkomsten tot een bot-score; een hard-fail-signaal forceert op zichzelf al een bot-verdict. De publieke bot.score is een waarde op een schaal van 0..100 en het verdict bereikt je als bot.result. Exacte drempelwaarden worden niet gepubliceerd: een drempel die je kunt lezen, is een drempel waar je je op kunt afstemmen. Bijdragende detectoren zijn onder meer:
Detectoren voor instrumentatie (Frida), root/jailbreak en gekloonde apps bestaan wel in het platform, maar hun invoerslots zijn uitsluitend native — de browser-agent verzamelt ze niet, dus dragen ze niet bij aan een web-verdict. Zie Botdetectie voor wat op het web volledig actief is.
Server-side verrijkingssignalen worden berekend uit de ruwe signaaldata en IP-intelligence. Deze omvatten VPN-/proxy-/Tor-detectie, IP-geolocatie, browser-tampering-analyse en suspect-scoring.
Het IP-intelligence-subsysteem levert:
De server retourneert een JSON-antwoord met daarin:
{ "visitorId": "X7fh2Hg9LkMn3pQr5tBvQw3xZa9mK2pL4nR8dT6y", "bot": { "detected": false, "confidence": 2, "reasons": [] }}Dit is het resultaat waartoe tracio.getResult() in de browser wordt geresolved. Het
volledige, verrijkte event — inclusief de canonieke bot_result
(human / bot / uncertain), geolocatie en smart signals — wordt
server-side geleverd via webhooks, is leesbaar via de
Data API en wordt getoond in het dashboard.
De client slaat een bezoekers-token op in zowel een first-party-cookie (365 dagen geldig, SameSite=Lax) als localStorage voor persistentie over sessies heen.
| Stap | Locatie | Beschrijving |
|---|---|---|
| 1 | Browser | Agent initialiseren, gedeeld iframe aanmaken |
| 2 | Browser | 300+ signalen verzamelen (parallel, meerfasig) |
| 3 | Browser | Payload versleutelen en comprimeren |
| 4 | Netwerk | POST naar de server |
| 5 | Server | Ontsleutelen, signalen extraheren, bezoekers-ID berekenen |
| 6 | Server | Bot detection en smart signals uitvoeren |
| 7 | Server | Antwoord opbouwen |
| 8 | Netwerk | JSON-antwoord retourneren |
| 9 | Browser | Bezoekers-cookie opslaan |
Totale round-trip: milliseconden. De signaalverzameling is daarin veruit het grootste deel — de netwerkhops en het serverwerk zijn kleiner — en de duur hangt af van het apparaat en de verbinding van de bezoeker. Niets hiervan blokkeert het renderen van de pagina: de agent laadt asynchroon en elke controle die traag kan zijn, wordt begrensd door zijn eigen timeout.