Guides

Comment détecter les navigateurs headless et l'automatisation sur votre page d'inscription

Les signaux du navigateur qui trahissent les inscriptions faites avec Puppeteer, Playwright et Selenium, pourquoi chacun peut être falsifié seul et comment les combiner sans bloquer de vraies personnes.

9 min de lecture · Mis à jour le 2026-10-31 · Attrelix

Pourquoi les bots utilisent désormais de vrais navigateurs

Il y a quelques années, la plupart des bots d'inscription étaient de simples scripts HTTP qui envoyaient votre formulaire directement. Ils sont faciles à arrêter : ils n'exécutent pas de JavaScript, donc rien de ce que votre page calcule dans le navigateur ne parvient au serveur. Aujourd'hui, la plupart des bots sérieux pilotent un vrai navigateur via Puppeteer, Playwright ou Selenium, souvent en headless, parfois à travers un navigateur anti-détection qui maquille son empreinte. Ils exécutent votre JavaScript, affichent votre page et remplissent votre formulaire comme le ferait une personne.

Les détecter, c'est chercher les endroits où un navigateur automatisé diffère de celui qu'utilise un humain. Aucun des signaux ci-dessous n'est une preuve à lui seul — un opérateur déterminé peut corriger chacun d'eux — mais ils coûtent peu à collecter et s'additionnent.

Signal 1 : l'indicateur WebDriver

Les navigateurs sous automatisation de type WebDriver mettent navigator.webdriver à true. Cela fait délibérément partie du standard WebDriver, et les configurations par défaut de Selenium, Puppeteer et Playwright l'exposent.

const automated = navigator.webdriver === true;

Les plugins « stealth » le suppriment ou le remplacent, donc son absence ne prouve rien. Sa présence, en revanche, est quasi concluante : les vrais utilisateurs ne l'ont pratiquement jamais.

Signal 2 : le user agent headless

Chrome headless s'identifie comme HeadlessChrome dans son user agent, sauf si l'opérateur le remplace. Vérifiez-le aussi côté serveur, à partir de l'en-tête de la requête, car la chaîne que le navigateur annonce en JavaScript peut différer de celle qu'il envoie.

Signal 3 : un client du protocole DevTools attaché

Puppeteer et Playwright pilotent Chrome via le protocole DevTools. Quand un client du protocole écoute les événements de la console, journaliser un objet pousse le navigateur à le sérialiser, en lisant même des propriétés qu'une page normale ne toucherait jamais. Un getter qui note s'il a été lu est un moyen connu de le remarquer :

function devtoolsProtocolAttached() {
  let read = false;
  const e = new Error();
  Object.defineProperty(e, "stack", { get() { read = true; return ""; } });
  console.debug(e);
  return read;
}

Il se déclenche aussi quand un développeur a les DevTools ouverts : donnez-lui un poids modéré plutôt que d'en faire un verdict.

Signal 4 : rendu logiciel et fenêtres étranges

Les navigateurs headless sur des serveurs n'ont pas de GPU, donc WebGL se rabat sur un moteur de rendu logiciel comme SwiftShader ou llvmpipe. Vous pouvez lire le nom du moteur via l'extension WEBGL_debug_renderer_info quand le navigateur l'expose. Certaines configurations headless annoncent aussi une fenêtre de largeur ou de hauteur nulle. Les machines virtuelles et les bureaux à distance partagent ces traits : ce sont des signaux faibles à eux seuls.

Signal 5 : une empreinte qui se contredit

Les navigateurs anti-détection existent pour ressembler à de nombreux vrais navigateurs différents. Ils y parviennent en remplaçant des propriétés, et ces remplacements sont rarement parfaitement cohérents. À comparer :

  • Le système d'exploitation du user agent face à navigator.platform et aux User-Agent Client Hints.
  • La famille de navigateur du user agent face aux fonctionnalités propres à ce moteur.
  • Les polices installées face à celles fournies avec ce système.
  • Un canvas dessiné deux fois de suite qui donne deux images différentes — signe de bruit injecté.
  • Notification.permission qui dit « denied » alors que la Permissions API dit « prompt ».

Chaque contradiction est faible seule, car les extensions de confidentialité et les configurations inhabituelles en produisent certaines. Deux ou trois ensemble forment un schéma fort.

Signal 6 : le jeton qui n'est jamais revenu

Une technique simple et robuste : faites demander par le script de la page d'inscription un jeton à courte durée de vie et à usage unique, placez-le dans un champ caché du formulaire et vérifiez-le côté serveur. Un bot qui saute votre JavaScript arrive sans jeton valide ; un bot qui rejoue un ancien jeton arrive avec un jeton déjà utilisé. Inutile de savoir comment fonctionne le bot pour voir qu'il n'a jamais vraiment exécuté votre page. Gardez le jeton à usage unique, lié à votre site, et faites-le expirer en quelques minutes.

Signal 7 : le comportement, pas l'empreinte

Une empreinte se falsifie ; le comportement, beaucoup moins. Une personne lit le formulaire, bouge le pointeur et tape. Un script remplit les champs et envoie quelques centaines de millisecondes après le chargement de la page, sans aucun événement d'entrée de confiance.

La mesure fiable ne demande aucun logiciel supplémentaire : votre agent émet le jeton visiteur au chargement de la page et votre serveur compare cet horodatage au moment de la vérification. Moins d'une seconde entre le chargement et l'inscription, c'est un script. Quand l'agent peut aussi signaler des événements d'entrée de confiance, un envoi instantané sans aucun événement de pointeur, de touche ou tactile est une seconde confirmation indépendante.

Une réserve sur le signal 3 : dans Chrome aujourd'hui, l'astuce DevTools ne se déclenche que si le client d'automatisation s'abonne aux événements de console ; traitez-la comme un bonus, pas comme le détecteur principal.

Combinez, ne bloquez jamais sur un seul signal

Traitez chaque signal comme des points dans un score et décidez sur le total. Une pondération raisonnable pour commencer, du plus fort au plus faible :

SignalPoidsPourquoi
navigator.webdriver à trueélevéPresque jamais vrai pour de vrais utilisateurs
User agent HeadlessChromeélevéSeules les versions headless l'envoient
Jeton absent ou rejouéélevéLe script de la page n'a pas tourné, ou une seule fois pour plusieurs inscriptions
Protocole DevTools attachémoyenLes développeurs avec DevTools ouverts le déclenchent aussi
Contradictions OS ou navigateurmoyenRemplacements anti-détection, mais aussi certaines extensions
Rendu logiciel, fenêtre nullefaibleLes VM et bureaux à distance les partagent

Associez les signaux du navigateur à ceux du serveur — inscriptions depuis des plages IP cloud, rafales depuis un sous-réseau, comptes liés au même appareil — et très peu de bots paraîtront propres sur tous à la fois.

Ce qu'il ne faut pas faire

  • Ne bloquez pas sur la seule absence de plugins ou de langues. Les navigateurs renforcés pour la confidentialité les suppriment.
  • Ne publiez pas votre logique de détection sous forme de vérifications aux noms évidents qu'un opérateur pourrait rechercher et contourner d'un coup ; collectez des faits bruts dans le navigateur et décidez côté serveur.
  • Ne faites jamais aveuglément confiance à ce que dit le navigateur. Le client est sous le contrôle du bot. La vérification se fait sur votre serveur, avec votre secret.

Comment Attrelix s'y prend

L'agent Attrelix collecte ces faits du navigateur et un jeton visiteur à usage unique sur votre page d'inscription ; le serveur les combine avec les signaux de réseau, de boîte e-mail et de comptes liés en un seul score. Tous les poids sont publics dans la documentation, et aucun signal faible ne peut à lui seul envoyer une inscription en examen.

En résumé

  • Les bots modernes utilisent de vrais navigateurs ; cherchez où l'automatisation diffère d'un humain.
  • WebDriver, user agent headless et jetons absents sont forts ; le reste est faible mais s'additionne.
  • Décidez côté serveur, à partir d'un score, jamais sur un seul indicateur du navigateur.

Plus de guides