Het bot-detectiesysteem van TRACIO identificeert geautomatiseerde browsers, headless tools en scriptmatige aanvallen met behulp van een tweelaags architectuur: signaalverzameling aan de clientzijde en analyse aan de serverzijde. Het detecteert gangbare automatiseringsframeworks, headless browsers, AI-browsingagents en antidetect-browsers met vrijwel nul false positives, en plaatst legitieme zoekmachine-crawlers automatisch op de allowlist.
De browser-agent verzamelt een reeks bot-specifieke en cross-validatiesignalen die de beslissingen aan de serverzijde voeden. De onderstaande signaal-ID's zijn illustratief — de interne ID's vormen geen stabiel openbaar contract:
| Signal | Description |
|---|---|
s300 (webdriver) | navigator.webdriver-vlag — door automatiseringsframeworks op true gezet |
s301 (eval length) | eval.toString().length — Chrome/Edge: 33, Firefox: 37. Andere waarden wijzen op instrumentatie. |
s305 (bot composite) | Doorzoekt window/document op 14 automatiseringsframework-artefacten |
s97 (headless markers) | CDP-artefacten, notificatierechten, plugin-aantal, buitenafmetingen |
s157 (automation scan) | Uitgebreide scan naar Selenium, Puppeteer, PhantomJS, Playwright en 10 meer |
s158 (iframe webdriver) | Maakt een verborgen iframe aan en leest daarin navigator.webdriver. Vangt tools die het hoofdframe patchen maar iframes vergeten. |
s159 (native function) | Verwijdert Function en Object en test of getters werkelijk native zijn. Detecteert Proxy-gebaseerde instrumentatie. |
s155 (window CRC32) | CRC32-hashscan van elke window-eigenschap om geïnjecteerde automatiserings-globals te detecteren |
s163 (devtools trap) | Console-getter-val — detecteert wanneer DevTools actief geopend zijn |
De server voert een set detectoren uit waarvan de gewogen outputs worden
gecombineerd tot een bot-score. De score wordt via drempelwaarden aan een
verdict toegewezen — bot wanneer deze ≥ 0,70 is,
suspicious bij ≥ 0,30, anders human — en een hard-fail-signaal (zoals
navigator.webdriver) forceert direct een bot-verdict. Bot-verdicts dragen
een vrij bot_type-label.
Representatieve detectoren en hun effect:
| Detector | Effect |
|---|---|
| Webdriver-vlag | Hard-fail → bot (type webdriver) |
| Composite automatisering / framework-scan | Hoog gewicht → bot (type {framework}) |
| Headless markers | Gewogen → bot (type headless) |
| Eval-length-anomalie | Gewogen → bot (type unknown) |
| Bad-bot-UA-patroon | Gewogen → bot (type {label}) |
| Geverifieerde goede bot (reverse DNS) | Allowlist → human |
| Gedragsmatig (rate / entropie / interactie) | Gewogen → bot (type rateBot) |
| VM (Enterprise) · Emulator · DevTools (Business+) | Gewogen device-/tamper-signalen |
Tier & beschikbaarheid. DevTools-detectie draait op Business en Enterprise; VM-detectie is Enterprise; emulatordetectie draait op alle abonnementen. Dit alles werkt in de web-agent. Detectie van root, jailbreak, gekloonde/dual-apps, Frida en fabrieksreset is afhankelijk van native-mobielsignalen en is niet effectief in de uitsluitend web-gebaseerde uitrol (in ontwikkeling). Vertrouw op de verdicts voor automatisering, headless, AI-agents, antidetect, VM/emulator en gedrag, die op web volledig actief zijn.
Bot-detectie schrijft bij elk event een bot_result-veld (en bot.result in de
webhook-payload).
bot_result is een van drie canonieke waarden:
| Result | Description |
|---|---|
human | Geen automatiseringsindicatoren gevonden. Geverifieerde zoekmachine-crawlers resulteren ook in human. |
bot | Geautomatiseerde of scriptmatige toegang gedetecteerd. Een vrij bot_type-label vergezelt dit. |
uncertain | Gemengde of zwakke signalen — noch duidelijk menselijk, noch duidelijk geautomatiseerd. |
Dit wordt toegewezen aan het zakelijke decision-veld (real, fake of suspicious)
dat overal in het dashboard wordt gebruikt, en aan bot.result in de
webhook-payload.
"bot" is)bot_type is een vrije string. De onderstaande waarden zijn illustratieve voorbeelden van
wat de detectoren uitgeven, geen uitputtende enum:
| Type | Detection Method |
|---|---|
webdriver | navigator.webdriver is true |
selenium | Selenium-specifieke window/document-eigenschappen gedetecteerd |
puppeteer | Puppeteer-/Chromium-headless-indicatoren gematcht |
playwright | Playwright-specifieke markers of UA-string gedetecteerd |
headless | 2+ van 11 headless markers geactiveerd |
phantomjs | PhantomJS-globals gedetecteerd (callPhantom, _phantom) |
nightmare | NightmareJS-globals gedetecteerd |
unknown | Eval-length-anomalie of andere niet-specifieke automatiseringsindicatoren |
rateBot | Gedragsmatige rate-analyse overschreed drempelwaarden |
De meest directe detectie. Alle belangrijke automatiseringsframeworks zetten navigator.webdriver = true conform de WebDriver-specificatie. Dit wordt gecontroleerd in zowel het hoofdframe (s300) als een verborgen iframe (s158) om tools te vangen die alleen het hoofdframe patchen.
Uitgebreid scannen van window- en document-eigenschappen op framework-specifieke artefacten:
| Framework | Properties Detected |
|---|---|
| Selenium | _Selenium_IDE_Recorder, _selenium, calledSelenium, __selenium_evaluate, $cdc_* (ChromeDriver) |
| Puppeteer | domAutomation, domAutomationController, HeadlessChrome UA |
| Playwright | __playwright, automation-controlled flag |
| PhantomJS | callPhantom, _phantom |
| NightmareJS | __nightmare, nightmare |
| CefSharp | CefSharp |
| Awesomium | awesomium |
| WebDriverIO | wdioElectron |
| Cypress | __cypress window-eigenschap |
De scan gebruikt ook een regex-patroon /^([a-z]){3}_.*_(Array|Promise|Symbol)$/ om de door Selenium geïnjecteerde helper-globals te detecteren.
Er worden 11 markers geëvalueerd, met een drempel van 2 of meer voor classificatie:
| Marker | Signal | Condition |
|---|---|---|
| webdriver | s300 | = "true" |
| missing vendor flavors | s28 | Geen chrome-/safari-objecten op window |
| CDP headless chrome | s305 | headlessChrome = true |
| notification denied | s88 | Notification.permission = "denied" bij eerste bezoek |
| chrome no runtime | s89 | window.chrome bestaat maar chrome.runtime ontbreekt |
| single language | s90 | navigator.languages.length <= 1 |
| default screen 800x600 | s5 | Standaardresolutie van headless Chrome |
| HeadlessChrome UA | UA | User-Agent bevat "HeadlessChrome" |
| zero outer dimensions | s97 | outerWidth = 0 en outerHeight = 0 |
| WebGL SwiftShader | s70 | Renderer bevat "swiftshader" (software-GPU) |
| WebGL llvmpipe | s70 | Renderer bevat "llvmpipe" (software-GPU) |
Bekende goede bots worden herkend aan het User-Agent-patroon. Elk wordt geverifieerd via reverse DNS om spoofing te voorkomen:
.googlebot.com)| Bot | Allowed Domains |
|---|---|
.googlebot.com, .google.com | |
| Bing | .search.msn.com |
| Apple | .applebot.apple.com |
| Yahoo | .crawl.yahoo.net |
| Yandex | .yandex.com, .yandex.net, .yandex.ru |
| DuckDuckGo | .duckduckgo.com |
Als een verzoek beweert Googlebot te zijn, maar de reverse DNS van het IP naar een vreemd domein resolvt (een bevestigde PTR-mismatch, niet louter een ontbrekende/verlopen lookup), wordt het geclassificeerd als bot (type spoofed:google).
Rate-gebaseerde detectie met entropie-scoring:
| Rate (req/min) | Entropy Threshold | Action |
|---|---|---|
| 120+ | < 0.1 | bot (type: rateBot) |
| 60-120 | < 0.3 | bot (type: rateBot) |
| 45-60 | < 0.1 | bot (type: rateBot) |
| < 45 | Any | Normal |
Aanvullende regel: geen muis-/toetsenbordgebeurtenissen na 30+ seconden sessieduur classificeert het bezoek als bot met type noInteraction.
eval.toString().length produceert consistente waarden per engine:
Elke andere waarde wijst erop dat de eval-functie door een automatiseringsframework is gehookt, wat het bezoek classificeert als bot met type unknown.
De client-SDK stelt een handige boolean beschikbaar, result.bot.detected:
const result = await tracio.getResult()
if (result.bot.detected) { // Log and block console.warn(`Bot detected (confidence ${result.bot.confidence})`) showCaptcha() return}
// Proceed with loginawait login(credentials)Reageer op uw server op de webhook-levering. Bot-detectie
bevindt zich in het bot-object — bot.result en bot.type:
// `event` is the webhook delivery body (/docs/webhooks)app.post("/webhook/tracio", async (req, res) => { const event = req.body
if (event.bot.result === "bot") { await db.blockedRequests.insert({ visitorId: event.visitorId, botType: event.bot.type, ip: event.ip, timestamp: new Date(), }) }
res.status(200).send("OK")})De bot-detectie van TRACIO is ontworpen voor vrijwel nul false positives. Toch kunnen randgevallen voorkomen:
| Scenario | Risk | Mitigation |
|---|---|---|
Browserextensies die navigator wijzigen | Laag | Meervoudige signaal-cross-validatie voorkomt triggering door één enkel signaal |
| Bedrijfsbeveiligingssoftware | Zeer laag | Headless-detectie vereist 2+ markers |
| Toegankelijkheidstools | Geen | Toegankelijkheids-API's triggeren geen enkel detectiesignaal |
| VPN-/proxygebruikers | Geen | VPN-gebruik wordt los van bot-detectie bijgehouden |
Als u false positives tegenkomt, bekijk dan het bot.type-veld om te begrijpen welke detector werd getriggerd en pas uw beleid dienovereenkomstig aan.