Blog

Agente de IA na web: um Chrome real com GPU para o Claude

Pôr um agente Claude (Playwright MCP, computer use) a navegar num Chrome com GPU num servidor: Xvfb vs Xorg dummy, Selenium, deteção de bots Cloudflare, medições.

Agente de IA na web: um Chrome real com GPU para o Claude

Um agente de IA que age na web (preencher um formulário, comparar ofertas, acompanhar um painel) precisa de um navegador real a correr em contínuo, noutro sítio que não o seu portátil. Dois erros fazem com que seja identificado como robô logo na primeira página:

  1. lançá-lo em modo headless: o Chrome anuncia-se então a si próprio como HeadlessChrome no seu User-Agent;
  2. lançá-lo sem GPU: a placa gráfica passa a ser SwiftShader (uma GPU emulada), ou o WebGL desaparece por completo.

Um PC de secretária nunca tem estas características. A regra é, portanto, simples: um Chrome real, em janela, num ecrã virtual, com uma GPU real.

Este artigo mostra como pôr o Chrome a correr com a GPU para um agente Claude, compara Xvfb e Xorg «dummy», cobre o Selenium e explica o que a GPU muda (ou não) face à deteção de bots da Cloudflare. Todas as medições são reproduzíveis: o script é público.

A arquitetura

Diagrama de implantação UML: o agente Claude controla o Chromium via Playwright MCP; o Chromium é apresentado no Xvfb e renderiza na GPU Intel UHD 770; o x11vnc permite ver o ecrã através de um túnel SSH

  • O agente (Claude Code ou o Claude Agent SDK) decide as ações;
  • o Playwright MCP expõe o navegador ao agente sob a forma de ferramentas (browser_navigate, browser_click, browser_type, browser_snapshot…) e controla o Chromium por CDP (Chrome DevTools Protocol);
  • o Chromium corre em modo de janela num ecrã virtual Xvfb e faz a renderização na GPU via ANGLE/Vulkan;
  • o x11vnc permite-lhe ver o ecrã e retomar o controlo (para uma autenticação de dois fatores, por exemplo).

O desenrolar de uma ação:

Diagrama de sequência UML: browser_navigate, Page.navigate por CDP, pedido ao site, eventuais verificações da Cloudflare, renderização na GPU, snapshot devolvido ao agente

As medições

Condições

  • Servidor de teste Linux GPU, VM configurada como a oferta Perf 2 (4 vCPU), GPU Intel UHD 770 partilhada entre várias VM (a VM vê o seu próprio dispositivo GPU, /dev/dri, com o driver Linux padrão), Debian 13;
  • Chromium 156, Playwright MCP 0.0.83, Selenium 4.31 + chromedriver 156, Xvfb (Xorg 21) e xserver-xorg-video-dummy 0.4.0;
  • a GPU não estava a ser usada por outras VM durante as medições;
  • medições de 29/10/2026.

Como é calculado

O banco de ensaio é uma página WebGL 2 (webgl-bench.html):

  1. um canvas de 1920×1080;
  2. um fragment shader que calcula 64 senos/cossenos por píxel, ou seja, cerca de 265 milhões de senos/cossenos por imagem;
  3. ?draws=N desenha N imagens em ecrã inteiro por frame (requestAnimationFrame);
  4. após cada frame, readPixels lê um píxel: isso obriga o navegador a terminar a renderização; caso contrário, poderia pôr os comandos em fila de espera e mostrar uma pontuação lisonjeira mas falsa;
  5. ao fim de 5 s: imagens/s = número de imagens ÷ duração. Verifica-se também que o programa está bem ligado e que o píxel lido tem a cor certa.

O Chrome é lançado com --disable-gpu-vsync --disable-frame-rate-limit para não ficar limitado a 60 imagens/s. A carga de CPU é a diferença dos contadores de /proc/stat apenas durante o teste, expressa em vCPU ocupados.

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

Resultado 1: a GPU faz a diferença (×20)

--headless=new, 10 imagens por frame:

RenderizaçãoImagens 1080p/sCPU ocupada
SwiftShader (por omissão, CPU)133,9 vCPU de 4
UHD 770, --use-angle=vulkan~2600,6 vCPU
UHD 770, --use-angle=gl-egl~230—

Com a GPU, a renderização é 20 vezes mais rápida e o processador fica livre. Para um agente, é o ponto-chave: sem GPU, uma página pesada (mapa, painel, vídeo) satura os 4 vCPU, e o agente, o Playwright e o ecrã virtual disputam o que sobra.

Resultado 2: Xvfb ou Xorg dummy, tanto faz

Ouve-se muitas vezes que é preciso substituir o Xvfb pelo Xorg com o driver dummy para «parecer mais real». Medido, em modo de janela, 1 imagem por frame:

Ecrã virtualSem opçõesSwiftShader forçadoGPU (--use-angle=vulkan)
XvfbWebGL desativado9,2 imagens/s67,6 imagens/s
Xorg + driver dummyWebGL desativado8,7 imagens/s58,8 imagens/s, depois contexto WebGL perdido
  • Nenhum dos dois usa a GPU por si só: o glxinfo mostra llvmpipe (renderização por software) em ambos;
  • sem opções, o Chrome desativa o WebGL em ambos;
  • com o driver dummy, o nosso teste com GPU perdeu o contexto WebGL ao fim de algumas imagens (eglCreateWindowSurface failed with error EGL_BAD_MATCH). O Xvfb, por seu lado, manteve-se estável.

A escolha do ecrã virtual é, portanto, secundária: é a GPU que conta para o desempenho, na maior parte das vezes. Fique pelo Xvfb, mais simples, e acrescente as duas opções de GPU ao Chrome.

Resultado 3: que motor de renderização o site vê

É o que um script de deteção lê (WEBGL_debug_renderer_info):

ConfiguraçãoMotor de renderização WebGL anunciado
--headless=new sem opçõesSwiftShader (CPU emulada)
Xvfb ou dummy, sem opçõessem WebGL
Selenium + Xvfb, sem opçõessem WebGL
Selenium + Xvfb, opções de GPUIntel(R) UHD Graphics 770
Playwright MCP, em janela no Xvfb, opções de GPUIntel(R) UHD Graphics 770
headless, opções de GPUIntel(R) UHD Graphics 770

Resultado 4: headless = identificado de imediato

O que um script JavaScript lê numa linha na página, nas quatro configurações (Chromium 156):

Headless sem GPUHeadless + GPUJanela Xvfb sem GPUJanela Xvfb + GPU
navigator.userAgent❌ HeadlessChrome/156…❌ HeadlessChrome/156…✅ Chrome/156…✅ Chrome/156…
Placa gráfica (WebGL)❌ SwiftShader✅ Intel UHD Graphics 770❌ nenhuma (WebGL desligado)✅ Intel UHD Graphics 770
screen❌ 800×600❌ 800×600✅ 1920×1080✅ 1920×1080
Tamanho da janela780×580780×580945×10601919×1079
  • O modo headless denuncia-se a si próprio: a palavra HeadlessChrome está escrita no User-Agent, enviado em cada pedido. É o sinal mais simples de bloquear, e todos os sistemas anti-bots o fazem. O ecrã de 800×600 confirma o diagnóstico;
  • sem GPU, mesmo em janela, o WebGL desaparece: nenhum navegador de secretária moderno está nesta situação;
  • só a última coluna se parece com um posto de trabalho real: um Chrome em janela num ecrã 1080p, com uma placa gráfica Intel real.

Corrigir o User-Agent à mão não chega: o modo headless tem outras diferenças (tamanho do ecrã, comportamento da renderização, API em falta), e um User-Agent que não bate certo com o resto é, ele próprio, suspeito. O mais fiável é não usar o modo headless de todo: num servidor, é exatamente para isso que serve o Xvfb.

Resultado 5: em janela, a GPU alivia enormemente a CPU

O modo de janela tem um custo: o Chrome tem de desenhar a página inteira no ecrã. Sem GPU, é o processador que faz tudo. A mesma animação WebGL 1080p, Chrome em janela no Xvfb, frequência normal (60 imagens/s no máximo), carga de CPU medida em toda a VM durante o teste:

Chrome em janela no XvfbImagens/sCPU ocupada (VM de 4 vCPU)
Sem GPU (SwiftShader)9,83,4 vCPU: a VM está saturada
Sem GPU, cena 3× mais pesada4,03,7 vCPU
Com a GPU UHD 77060 (fluido)0,3 vCPU
Com a GPU, cena 3× mais pesada600,3 vCPU

Com a GPU, o Chrome mostra 6 vezes mais imagens usando mais de 10 vezes menos CPU, ou seja, cerca de 70 vezes menos CPU por imagem. Sem GPU, a VM fica saturada e nem sequer chega às 10 imagens/s: o agente, o Playwright e o resto do sistema lutam pelas migalhas, cada ação demora mais e as páginas pesadas tornam-se inutilizáveis. Com a GPU, sobram 3,7 vCPU livres para o trabalho útil.

É a combinação vencedora: o modo de janela evita ser identificado, e a GPU torna-o gratuito para o processador.

O que a GPU muda face à Cloudflare

A Cloudflare (Bot Management, Turnstile) combina muitos sinais: impressão digital TLS e HTTP/2, reputação do endereço IP, testes JavaScript na página, comportamento (ritmo, movimentos), modelos estatísticos. Um navegador sem GPU denuncia-se depressa nos testes JavaScript: SwiftShader como placa gráfica, ou nenhum WebGL, é uma assinatura típica de navegador automatizado num datacenter.

Com a GPU, o Chrome anuncia uma placa Intel real e renderiza a página como um PC de secretária. Na prática, isso reduz os falsos positivos: CAPTCHA ou bloqueios em sites onde o seu agente tem todo o direito de ir.

Mas convém ser claro: CDP + driver + bom IP não torna o navegador indetetável.

  • o controlo por CDP deixa, ele próprio, vestígios detetáveis;
  • os endereços de datacenter são conhecidos como tal;
  • o comportamento de um agente (velocidade, encadeamento das ações) deteta-se;
  • as regras mudam constantemente: o que passa hoje será bloqueado amanhã.

A abordagem certa: fazer-se reconhecer

Para um agente legítimo, o caminho duradouro é ser identificado em vez de escondido:

  • Web Bot Auth («signed agents» na Cloudflare): o agente assina os seus pedidos HTTP com uma chave Ed25519 (HTTP Message Signatures, RFC 9421) e publica a sua chave pública num diretório; os sites podem então autorizá-lo explicitamente;
  • um User-Agent honesto, o respeito pelo robots.txt e pelos termos de utilização, um débito razoável;
  • nos seus próprios sites atrás da Cloudflare (testes E2E, monitorização), uma regra WAF que deixa passar o IP do seu servidor.

Implementação

1. Pacotes

apt install chromium xvfb x11vnc nodejs npm

2. Ecrã virtual e 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 em :99 (apenas localhost)
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
# a partir do seu computador:
ssh -L 5900:localhost:5900 root@seu-servidor   # depois um cliente VNC em localhost:5900

O VNC só escuta em localhost: só se lhe acede pelo túnel SSH.

3. Playwright MCP com a GPU

Ficheiro /root/mcp.json:

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

Com o Claude Code instalado no servidor:

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

Ou como servidor HTTP, se o agente corre noutro sítio (túnel SSH para a porta):

DISPLAY=:99 npx @playwright/mcp@latest --config /root/mcp.json --port 8931
# ponto de acesso MCP: http://localhost:8931/mcp

Para verificar, peça ao agente que abra uma página que mostre o motor de renderização WebGL: deve anunciar 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 meu_script.py

Com o Selenium 4.31 do Debian, indique explicitamente o chromedriver via Service(...): caso contrário, não o encontra (NoSuchDriverException).

Perguntas frequentes

Headless ou em janela no Xvfb? Em janela, sem hesitar. O headless anuncia-se como HeadlessChrome e é bloqueado na maioria dos sites protegidos. Além disso, o modo de janela permite seguir o agente por VNC e retomar o controlo. Reserve o headless para os seus próprios testes, nos seus próprios sites.

E o computer use do Claude (capturas de ecrã + cliques)? Precisa de um ecrã real: Xvfb + um navegador em janela, exatamente o esquema acima. A GPU renderiza cada captura mais depressa e deixa a CPU para o resto.

Uma oferta Perf 1 é suficiente? Para um agente que navega em sites comuns, sim. As medições acima foram feitas com 4 vCPU (Perf 2), útil se o agente abrir vários separadores ou páginas pesadas.

Experimentar

Servidor Linux GPU com Intel UHD 770 na VM, Mesa e Vulkan já instalados. A partir de 14,99 € s/ IVA/mês, acesso root, IPv6 dedicado. Veja também: Chrome com GPU num servidor Linux e Xvfb: guia prático.