Blog

Agent IA sur le web : un vrai Chrome avec GPU pour Claude

Faire naviguer un agent Claude (Playwright MCP, computer use) dans un Chrome avec GPU sur serveur : Xvfb vs Xorg dummy, Selenium, détection de bots Cloudflare, mesures et implémentation.

Agent IA sur le web : un vrai Chrome avec GPU pour Claude

Un agent IA qui agit sur le web (remplir un formulaire, comparer des offres, suivre un tableau de bord) a besoin d’un vrai navigateur qui tourne en continu, ailleurs que sur votre portable. Deux erreurs le font repérer comme robot dès la première page :

  1. le lancer en mode headless : Chrome s’annonce alors lui-même comme HeadlessChrome dans son User-Agent ;
  2. le lancer sans GPU : la carte graphique devient SwiftShader (un GPU émulé), ou WebGL disparaît complètement.

Un PC de bureau n’a jamais ces caractéristiques. La règle est donc simple : un vrai Chrome, en fenêtre, sur un écran virtuel, avec un vrai GPU.

Cet article montre comment faire tourner Chrome avec le GPU pour un agent Claude, compare Xvfb et Xorg « dummy », couvre Selenium, et explique ce que le GPU change (ou pas) face à la détection de bots de Cloudflare. Toutes les mesures sont reproductibles : le script est public.

L’architecture

Diagramme de déploiement UML : l'agent Claude pilote Chromium via Playwright MCP ; Chromium s'affiche sur Xvfb et rend sur le GPU Intel UHD 770 ; x11vnc permet de regarder l'écran via un tunnel SSH

  • L’agent (Claude Code ou le Claude Agent SDK) décide des actions ;
  • Playwright MCP expose le navigateur à l’agent sous forme d’outils (browser_navigate, browser_click, browser_type, browser_snapshot…) et pilote Chromium par CDP (Chrome DevTools Protocol) ;
  • Chromium tourne en mode fenêtré sur un écran virtuel Xvfb, et fait son rendu sur le GPU via ANGLE/Vulkan ;
  • x11vnc vous permet de regarder l’écran, et de reprendre la main (pour une double authentification, par exemple).

Le déroulé d’une action :

Diagramme de séquence UML : browser_navigate, Page.navigate par CDP, requête vers le site, vérifications Cloudflare éventuelles, rendu GPU, snapshot renvoyé à l'agent

Les mesures

Conditions

  • Serveur de test Linux GPU, VM configurée comme l’offre Perf 2 (4 vCPU), GPU Intel UHD 770 partagé entre plusieurs VM (la VM voit son propre périphérique GPU, /dev/dri, avec le pilote Linux standard), Debian 13 ;
  • Chromium 156, Playwright MCP 0.0.83, Selenium 4.31 + chromedriver 156, Xvfb (Xorg 21) et xserver-xorg-video-dummy 0.4.0 ;
  • le GPU n’était pas sollicité par d’autres VM pendant les mesures ;
  • mesures du 29/10/2026.

Comment c’est calculé

Le banc d’essai est une page WebGL 2 (webgl-bench.html) :

  1. un canvas de 1920×1080 ;
  2. un fragment shader qui calcule 64 sinus/cosinus par pixel, soit environ 265 millions de sinus/cosinus par image ;
  3. ?draws=N dessine N images plein écran par frame (requestAnimationFrame) ;
  4. après chaque frame, readPixels lit un pixel : cela oblige le navigateur à terminer le rendu, sinon il pourrait mettre les commandes en file d’attente et afficher un score flatteur mais faux ;
  5. au bout de 5 s : images/s = nombre d’images ÷ durée. On vérifie aussi que le programme est bien lié et que le pixel lu a la bonne couleur.

Chrome est lancé avec --disable-gpu-vsync --disable-frame-rate-limit pour ne pas être limité à 60 images/s. La charge CPU est la différence des compteurs de /proc/stat pendant la seule durée du test, rapportée en vCPU occupés.

chromium --headless=new --use-angle=vulkan --ignore-gpu-blocklist \
  --disable-gpu-vsync --disable-frame-rate-limit \
  --enable-logging=stderr --v=0 "file:///root/webgl-bench.html?draws=10" \
  2>&1 | grep -m1 RESULT

Résultat 1 : le GPU fait la différence (×20)

--headless=new, 10 images par frame :

RenduImages 1080p/sCPU occupé
SwiftShader (défaut, CPU)133,9 vCPU sur 4
UHD 770, --use-angle=vulkan~2600,6 vCPU
UHD 770, --use-angle=gl-egl~230—

Avec le GPU, le rendu est 20 fois plus rapide et le processeur reste libre. Pour un agent, c’est le point clé : sans GPU, une page lourde (carte, tableau de bord, vidéo) sature les 4 vCPU, et l’agent, Playwright et l’écran virtuel se disputent ce qui reste.

Résultat 2 : Xvfb ou Xorg dummy, peu importe

On entend souvent qu’il faut remplacer Xvfb par Xorg avec le pilote dummy pour « faire plus vrai ». Mesuré, en mode fenêtré, 1 image par frame :

Écran virtuelSans optionSwiftShader forcéGPU (--use-angle=vulkan)
XvfbWebGL désactivé9,2 images/s67,6 images/s
Xorg + pilote dummyWebGL désactivé8,7 images/s58,8 images/s, puis contexte WebGL perdu
  • Aucun des deux n’utilise le GPU par lui-même : glxinfo affiche llvmpipe (rendu logiciel) sur les deux ;
  • sans option, Chrome désactive WebGL sur les deux ;
  • avec le pilote dummy, notre essai GPU a perdu le contexte WebGL au bout de quelques images (eglCreateWindowSurface failed with error EGL_BAD_MATCH). Xvfb, lui, a été stable.

Le choix de l’écran virtuel est donc secondaire : c’est le GPU qui compte pour les performances, la plupart du temps. Restez sur Xvfb, plus simple, et ajoutez les deux options GPU à Chrome.

Résultat 3 : quel moteur de rendu voit le site

C’est ce que lit un script de détection (WEBGL_debug_renderer_info) :

ConfigurationMoteur de rendu WebGL annoncé
--headless=new sans optionSwiftShader (CPU émulé)
Xvfb ou dummy, sans optionpas de WebGL
Selenium + Xvfb, sans optionpas de WebGL
Selenium + Xvfb, options GPUIntel(R) UHD Graphics 770
Playwright MCP, fenêtré sur Xvfb, options GPUIntel(R) UHD Graphics 770
headless, options GPUIntel(R) UHD Graphics 770

Résultat 4 : headless = repéré tout de suite

Ce qu’un script JavaScript lit en une ligne sur la page, dans les quatre configurations (Chromium 156) :

Headless sans GPUHeadless + GPUFenêtre Xvfb sans GPUFenêtre Xvfb + GPU
navigator.userAgent❌ HeadlessChrome/156…❌ HeadlessChrome/156…✅ Chrome/156…✅ Chrome/156…
Carte graphique (WebGL)❌ SwiftShader✅ Intel UHD Graphics 770❌ aucune (WebGL coupé)✅ Intel UHD Graphics 770
screen❌ 800×600❌ 800×600✅ 1920×1080✅ 1920×1080
Taille de fenêtre780×580780×580945×10601919×1079
  • Le mode headless se dénonce lui-même : le mot HeadlessChrome est écrit dans le User-Agent, envoyé à chaque requête. C’est le signal le plus simple à bloquer, et tous les systèmes anti-bots le font. L’écran de 800×600 confirme le diagnostic ;
  • sans GPU, même en fenêtre, WebGL disparaît : aucun navigateur de bureau moderne n’est dans ce cas ;
  • seule la dernière colonne ressemble à un vrai poste de travail : un Chrome en fenêtre sur un écran 1080p, avec une vraie carte graphique Intel.

Corriger le User-Agent à la main ne suffit pas : le mode headless a d’autres différences (taille d’écran, comportement du rendu, API absentes), et un User-Agent qui ne colle pas avec le reste est lui-même suspect. Le plus fiable est de ne pas utiliser le mode headless du tout : sur un serveur, c’est exactement à ça que sert Xvfb.

Résultat 5 : en fenêtre, le GPU décharge énormément le CPU

Le mode fenêtré a un coût : Chrome doit dessiner toute la page à l’écran. Sans GPU, c’est le processeur qui fait tout. Même animation WebGL 1080p, Chrome en fenêtre sur Xvfb, fréquence normale (60 images/s maximum), charge CPU mesurée sur toute la VM pendant le test :

Chrome en fenêtre sur XvfbImages/sCPU occupé (VM de 4 vCPU)
Sans GPU (SwiftShader)9,83,4 vCPU : la VM est saturée
Sans GPU, scène 3× plus lourde4,03,7 vCPU
Avec le GPU UHD 77060 (fluide)0,3 vCPU
Avec le GPU, scène 3× plus lourde600,3 vCPU

Avec le GPU, Chrome affiche 6 fois plus d’images en utilisant plus de 10 fois moins de CPU, soit environ 70 fois moins de CPU par image. Sans GPU, la VM est saturée et n’atteint même pas 10 images/s : l’agent, Playwright et le reste du système se battent pour les miettes, chaque action prend plus de temps, et les pages lourdes deviennent inutilisables. Avec le GPU, il reste 3,7 vCPU libres pour le travail utile.

C’est la combinaison gagnante : le mode fenêtré évite d’être repéré, et le GPU le rend gratuit pour le processeur.

Ce que le GPU change face à Cloudflare

Cloudflare (Bot Management, Turnstile) combine de nombreux signaux : empreinte TLS et HTTP/2, réputation de l’adresse IP, tests JavaScript dans la page, comportement (rythme, mouvements), modèles statistiques. Un navigateur sans GPU se trahit vite dans les tests JavaScript : SwiftShader comme carte graphique, ou pas de WebGL du tout, c’est une signature typique de navigateur automatisé dans un datacenter.

Avec le GPU, Chrome annonce une vraie carte Intel et rend la page comme un PC de bureau. Concrètement, cela réduit les faux positifs : des CAPTCHA ou des blocages sur des sites où votre agent a parfaitement le droit d’aller.

Mais il faut être clair : CDP + pilote + bonne IP ne rend pas indétectable.

  • le pilotage par CDP laisse lui-même des traces détectables ;
  • les adresses de datacenter sont connues comme telles ;
  • le comportement d’un agent (vitesse, enchaînement des actions) se repère ;
  • les règles changent en permanence : ce qui passe aujourd’hui sera bloqué demain.

La bonne approche : se faire reconnaître

Pour un agent légitime, la voie durable est d’être identifié plutôt que caché :

  • Web Bot Auth (« signed agents » chez Cloudflare) : l’agent signe ses requêtes HTTP avec une clé Ed25519 (HTTP Message Signatures, RFC 9421) et publie sa clé publique dans un annuaire ; les sites peuvent alors l’autoriser explicitement ;
  • un User-Agent honnête, le respect de robots.txt et des conditions d’utilisation, un débit raisonnable ;
  • sur vos propres sites derrière Cloudflare (tests E2E, supervision), une règle WAF qui laisse passer l’IP de votre serveur.

Mise en place

1. Paquets

apt install chromium xvfb x11vnc nodejs npm

2. Écran virtuel et VNC (systemd)

# /etc/systemd/system/xvfb.service
[Unit]
Description=Xvfb :99
[Service]
ExecStart=/usr/bin/Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp
Restart=always
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/x11vnc.service
[Unit]
Description=x11vnc sur :99 (localhost uniquement)
After=xvfb.service
Requires=xvfb.service
[Service]
ExecStart=/usr/bin/x11vnc -display :99 -localhost -forever -shared -nopw
Restart=always
[Install]
WantedBy=multi-user.target
systemctl enable --now xvfb x11vnc
# depuis votre ordinateur :
ssh -L 5900:localhost:5900 root@votre-serveur   # puis un client VNC sur localhost:5900

VNC n’écoute que sur localhost : on y accède seulement par le tunnel SSH.

3. Playwright MCP avec le GPU

Fichier /root/mcp.json :

{
  "browser": {
    "browserName": "chromium",
    "launchOptions": {
      "executablePath": "/usr/bin/chromium",
      "headless": false,
      "args": ["--use-angle=vulkan", "--ignore-gpu-blocklist", "--no-sandbox"]
    }
  }
}

Avec Claude Code installé sur le serveur :

claude mcp add playwright --env DISPLAY=:99 -- \
  npx @playwright/mcp@latest --config /root/mcp.json

Ou en serveur HTTP, si l’agent tourne ailleurs (tunnel SSH vers le port) :

DISPLAY=:99 npx @playwright/mcp@latest --config /root/mcp.json --port 8931
# point d'accès MCP : http://localhost:8931/mcp

Pour vérifier, demandez à l’agent d’ouvrir une page qui affiche le moteur de rendu WebGL : il doit annoncer Intel(R) UHD Graphics 770.

4. Selenium + Xvfb

apt install python3-selenium chromium-driver
from selenium import webdriver
from selenium.webdriver.chrome.service import Service

o = webdriver.ChromeOptions()
o.binary_location = "/usr/bin/chromium"
for a in ["--use-angle=vulkan", "--ignore-gpu-blocklist",
          "--no-sandbox", "--window-size=1920,1080"]:
    o.add_argument(a)
driver = webdriver.Chrome(options=o, service=Service("/usr/bin/chromedriver"))
xvfb-run -a -s "-screen 0 1920x1080x24" python3 mon_script.py

Avec le Selenium 4.31 de Debian, indiquez explicitement chromedriver via Service(...) : sinon il ne le trouve pas (NoSuchDriverException).

Questions fréquentes

Headless ou fenêtré sur Xvfb ? Fenêtré, sans hésiter. Le headless s’annonce HeadlessChrome et se fait bloquer sur la plupart des sites protégés. Le mode fenêtré permet en plus de suivre l’agent par VNC et de reprendre la main. Réservez le headless à vos propres tests, sur vos propres sites.

Et le computer use de Claude (captures d’écran + clics) ? Il a besoin d’un vrai écran : Xvfb + un navigateur fenêtré, exactement le schéma ci-dessus. Le GPU rend chaque capture plus vite et laisse le CPU au reste.

Une offre Perf 1 suffit-elle ? Pour un agent qui navigue sur des sites classiques, oui. Les mesures ci-dessus ont été faites avec 4 vCPU (Perf 2), utile si l’agent ouvre plusieurs onglets ou des pages lourdes.

Essayer

Serveur Linux GPU avec Intel UHD 770 dans la VM, Mesa et Vulkan déjà installés. À partir de 14,99 € HT/mois, accès root, IPv6 dédiée. Voir aussi : Chrome avec le GPU sur un serveur Linux et Xvfb : guide pratique.