La détection des bots de TRACIO identifie les navigateurs automatisés, les outils headless et les attaques scriptées grâce à une architecture à deux couches : la collecte côté client dans l'agent du navigateur et l'analyse côté serveur. Elle couvre les frameworks d'automatisation courants, les navigateurs headless, les agents de navigation IA et les navigateurs anti-détection avec des faux positifs quasi nuls, tout en plaçant automatiquement en allowlist les crawlers légitimes des moteurs de recherche.
L'agent du navigateur exécute un large ensemble de contrôles et en rapporte les
résultats. Côté serveur, ces résultats sont pondérés en un score de bot, et le
score est mappé sur un verdict. Un petit nombre d'indicateurs sans ambiguïté sont
décisifs à eux seuls et imposent un verdict bot, quel que soit le reste.
Quels contrôles s'exécutent, comment ils sont pondérés et où se situent les seuils ne sont pas publiés — sur aucune offre. Les documenter indiquerait aux opérateurs de bots exactement quoi changer pour passer outre la protection. Ce que vous recevez à la place, c'est le verdict, une étiquette de type de bot et — à partir de Business — des codes de motif qui nomment la classe d'observation à l'origine de la décision.
Chaque identification porte un verdict de bot. Il vous parvient sous la forme
bot.result dans le payload du webhook et sous la forme
result.bot dans le SDK client.
| Résultat | Description |
|---|---|
human | Aucun indicateur d'automatisation trouvé. Les crawlers vérifiés se résolvent eux aussi en human. |
bot | Automatisation ou accès scripté détecté. Une étiquette bot.type l'accompagne. |
uncertain | Signaux mixtes ou faibles — ni clairement humain, ni clairement automatisé. |
Cela est mappé sur le champ métier decision.action (real, fake ou
suspicious) utilisé dans tout le tableau de bord et dans le payload du webhook.
bot.score accompagne le verdict. Dans la version 2 du payload de webhook, il
s'agit d'un décimal 0..100 — le nombre même que le tableau de bord affiche pour
cette visite. (Dans le schéma gelé de la version 1, c'est une fraction 0..1 ;
voir Webhooks.)
bot.type est présent lorsque le résultat est bot. Il s'agit soit du nom d'un
bot ou d'un runtime reconnu, soit d'une famille, lorsque nommer le contrôle
précis révélerait le fonctionnement interne du détecteur :
bot.type | Signification |
|---|---|
playwright, jsdom, electron | Le runtime d'automatisation nommé a été identifié |
browser_use, claude_computer_use, skyvern, genspark, fellou | L'agent de navigation IA nommé a été identifié |
automation | Outillage d'automatisation, sans nommer le contrôle précis |
headless | Un navigateur s'exécutant sans interface utilisateur |
antidetect | Un build anti-détection / d'usurpation d'empreinte |
extension | Une extension de navigateur pilotant l'automatisation, un proxy ou un VPN |
privacy_browser | Un build de navigateur durci pour la confidentialité (par exemple Mullvad Browser) |
other | Détecté, mais hors du vocabulaire publié |
La liste est fermée par conception : un contrôle ajouté demain au détecteur
apparaîtra comme other plutôt que de laisser fuiter son nom interne. Traitez
bot.type comme une étiquette sur laquelle brancher, et non comme un enum
exhaustif à valider : de nouveaux runtimes nommés sont ajoutés au fil du temps.
Sur les offres Business et Enterprise, le payload du webhook porte un tableau
reasons — huit entrées au maximum, triées par importance. Un code nomme la
classe d'observation, jamais le contrôle qui la sous-tend :
| Code | Ce que cela signifie |
|---|---|
automation_signature | Traces d'outillage d'automatisation |
headless_browser | Un navigateur sans interface utilisateur |
anonymous_browser | Un build durci pour la confidentialité ou anti-détection déguisé en banal |
privacy_hardening | Paramètres de confidentialité agressifs |
behavior_anomaly | Schémas d'interaction non humains |
fingerprint_tampering | Des valeurs qui devraient concorder entre elles ne concordent pas |
environment_anomaly | L'environnement d'exécution est incohérent en interne |
identity_mismatch | L'identité déclarée contredit ce qui est observé |
virtual_environment | Un émulateur plutôt que du matériel physique |
strong_automation_evidence | Indicateurs de bot sans ambiguïté — décisifs à eux seuls |
detection_signal | Autres contrôles déclenchés |
severity vaut high, medium ou low, et représente la part du verdict que
cette classe explique pour cette visite — et non une propriété fixe du code. Le
même code peut arriver en high sur une visite et en low sur une autre : ne le
mettez donc pas en cache comme une constante.
privacy_hardening mérite une attention particulière : il se déclenche aussi bien
pour des visiteurs ordinaires soucieux de leur vie privée que pour de l'évasion.
Pondérez-le avec le reste plutôt que d'agir sur lui seul.
virtual_environment provient de la détection d'émulateur. Il n'existe pas sur le
web de verdict distinct « s'exécute sous un hyperviseur » : les indices qu'un
navigateur peut voir — un moteur de rendu logiciel générique, un nombre de cœurs
anormalement bas — apparaissent tout aussi souvent sur des machines ordinaires sans
pilote GPU et dans des sessions de bureau à distance ; nous n'en faisons donc pas un
verdict que vous devriez remettre en question.
| Capacité | Disponibilité |
|---|---|
| Détection d'automatisation, headless et d'agents IA | Toutes les offres |
| Allowlist des crawlers vérifiés | Toutes les offres |
| Détection d'émulateur | Toutes les offres |
Indicateurs anti-détection (bot.antidetectScore, 0..100) | Pro et au-delà |
| Codes de motif, bloc comportemental | Business et au-delà |
| Détection des DevTools | Business et au-delà |
Le scoring anti-détection est encore en cours de calibrage.
bot.antidetectScoreest communiqué pour que vous puissiez l'observer et ajuster votre propre politique — traitez-le comme une entrée de votre décision de risque plutôt que comme un motif de blocage à lui seul.
Les contrôles propres au mobile ne sont pas efficaces sur le web. La détection de root, de jailbreak, d'applications clonées/dupliquées et de Frida dépend de signaux natifs qu'un navigateur ne peut pas collecter. TRACIO ne livre que des SDK navigateur : appuyez-vous donc sur les verdicts d'automatisation, headless, agent IA, anti-détection, émulateur et comportementaux, qui sont pleinement actifs sur le web.
Les bons bots connus sont reconnus à leur user-agent, puis vérifiés par rapport à l'IP de connexion : une résolution DNS inverse sur l'IP, un contrôle que le hostname obtenu appartient au domaine de l'opérateur, et une résolution directe confirmant qu'il pointe de nouveau vers la même IP. C'est la procédure de vérification que publient les opérateurs de crawlers eux-mêmes.
| Crawler | Domaines vérifiés |
|---|---|
.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 |
Un crawler vérifié se résout en human. Une requête qui prétend être Googlebot
alors que son IP appartient manifestement à quelqu'un d'autre est classée comme bot
— une résolution simplement absente ou expirée n'est pas considérée comme une
preuve d'usurpation.
La dynamique d'interaction — mouvement du pointeur, cadence du clavier, défilement —
alimente le verdict comme preuve de la présence d'un humain, et non de quel
humain il s'agit. À partir de Business, l'agrégat est livré dans le bloc behavior
du webhook :
{ "behavior": { "score": 87, "verdict": "human", "confidence": 0.92 }}score va de 0..100 (plus c'est élevé, plus c'est humain), verdict vaut
human, uncertain ou bot, et confidence (0..1) indique sur combien de
preuves repose le verdict — une visite courte avec deux mouvements de pointeur
obtient ici un score faible, même lorsque le verdict paraît décisif.
Le bloc n'est présent que lorsque le scoring comportemental s'est réellement exécuté pour cette visite. Un bloc absent signifie « pas de données », jamais « rien de suspect » — ne lisez pas son absence comme un signal propre.
Le SDK client expose un booléen de commodité, result.bot.detected, ainsi qu'un
confidence sur une échelle 0..100 :
const result = await tracio.getResult()
if (result.bot.detected) { console.warn(`Bot detected (confidence ${result.bot.confidence})`) showCaptcha() return}
await login(credentials)Sur votre serveur, agissez sur la livraison du webhook. Le verdict
de bot réside dans l'objet bot — bot.result et 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")})Les valeurs nulles et vides sont omises du payload : lisez donc bot.type de
manière défensive plutôt que de l'exiger dans votre schéma.
La détection des bots de TRACIO est conçue pour des faux positifs quasi nuls, mais des cas limites existent :
| Scénario | Risque | Atténuation |
|---|---|---|
Extensions de navigateur modifiant navigator | Faible | La validation croisée entre de nombreux contrôles empêche un déclenchement isolé |
| Logiciels de sécurité d'entreprise | Très faible | La classification headless exige des preuves corroborantes |
| Outils d'accessibilité | Nul | Les API d'accessibilité n'alimentent pas la détection des bots |
| Utilisateurs de VPN/proxy | Nul | Les indicateurs réseau sont suivis séparément du verdict de bot |
Si vous constatez des faux positifs, examinez bot.type (et reasons à partir de
Business) pour comprendre quelle classe d'observation s'est déclenchée, puis
ajustez votre politique. Voir Dépannage pour les causes
courantes.