Canvas bridge
Renderize canvas e WebGL numa GPU remota real, para que os pixels que uma página lê sejam coerentes com a GPU que o host de renderização de fato tem — ajuste as strings de GPU do seu perfil para corresponderem a ela. Experimental e opt-in — sem --canvas-bridge-url, o Clearcote renderiza tudo localmente, exatamente como antes.
Por que ele existe
O Clearcote renderiza canvas/WebGL na GPU que a máquina host tiver de fato. Se um perfil declara uma GPU diferente da do host, verificações rigorosas de antidetect / de adulteração do navegador que comparam os pixels renderizados com o hardware declarado podem notar a divergência — não dá para fazer uma GPU emitir, via software, os pixels exatos de outra. O canvas bridge elimina essa divergência: em vez de renderizar localmente e falsificar só a string da GPU, ele encaminha as operações de canvas/WebGL para um host remoto que tem a GPU que você quer apresentar, e devolve os pixels reais desse host. Como o que se encaminha são as operações (e não uma biblioteca fixa de imagens pré-gravadas), ele dá conta da maioria dos canvases gerados, não só de probes conhecidos.
Como funciona
As APIs de leitura — getImageData, toDataURL, readPixels e measureText — retornam os pixels autênticos do host da ponte; o ruído local de farbling não é aplicado no caminho da ponte (os pixels da ponte são a referência real). O transporte é um WebSocket que carrega um fluxo compacto de mensagens binárias. Os pixels vêm da GPU que o navegador de renderização tiver.
clearcote (your automation host) bridge host (real GPU)
+-----------------------------+ +-------------------------+
| page: getImageData / | ops --> | render browser |
| toDataURL / readPixels | | renders on the real GPU,|
| CanvasBridgeClient <-- pixels ---------| reads back the pixels |
+-----------------------------+ +-------------------------+Do que você precisa
- Um host de renderização — qualquer máquina cuja GPU você queira apresentar (uma GPU Windows para uma persona Windows). A GPU dele passa a ser a identidade de canvas que os seus perfis apresentam, então escolha um hardware que corresponda à persona que você quer mostrar (uma máquina NVIDIA para apresentar NVIDIA, e assim por diante). Aponte o
--backend cdpdo servidor para um Chrome comum que você roda nessa máquina (recomendado), ou use--backend localcom um binário do Clearcote. - Um caminho de rede privado entre o seu host de automação e o host da ponte. A ponte fala WebSocket em texto puro (
ws://) — rode-a sempre numa rede privada ou num túnel criptografado (Tailscale, WireGuard ou encaminhamento de porta via SSH). Nunca exponha a porta da ponte na internet pública.
Configuração
1. Inicie o servidor de renderização no host com GPU real. É um pequeno coordenador em Python que controla um navegador headless e reproduz as operações encaminhadas no canvas real dele, então os pixels que ele devolve são exatamente o que aquela GPU produz. A GPU real do host de renderização passa a ser a identidade de canvas/WebGL. Com --backend cdp, ele imprime a string de renderer da GPU de renderização ao iniciar (render GPU='ANGLE (…)') — anote-a para o passo 3. Com --backend local, leia as strings de um Chrome comum na mesma máquina.
pip install playwright # one-time (no browser download needed for CDP)
# a regular Chrome on the GPU host, started with --remote-debugging-port=9222
# --user-data-dir=<a separate folder> (Chrome ignores the port on its default profile);
# its CDP URL is webSocketDebuggerUrl from http://127.0.0.1:9222/json/version
python tools/canvas-bridge-server/server.py \
--backend cdp \
--cdp-url ws://127.0.0.1:9222/devtools/browser/... \
--port 8443
# Or let the server launch a Clearcote binary itself:
# python tools/canvas-bridge-server/server.py \
# --backend local \
# --chrome /path/to/clearcote/chrome.exe \
# --port 84432. Crie um túnel. ws:// não é criptografado — coloque os dois hosts na mesma rede Tailscale/WireGuard, ou encaminhe a porta via SSH. Por padrão, o servidor escuta só em localhost; então, no Tailscale/WireGuard, inicie-o com --host <that interface's IP>. A rota por SSH abaixo funciona do jeito que está:
ssh -N -L 8443:localhost:8443 user@bridge-host
# the bridge is now reachable at ws://127.0.0.1:84433. Inicie o cliente (o Clearcote da sua automação) apontando para a ponte, com as strings da GPU de renderização — o renderer exatamente como o servidor o imprimiu, e o vendor como Google Inc. (<first name in the renderer>), por exemplo Google Inc. (Intel). A ponte faz os pixels corresponderem à GPU de renderização, e esses valores fazem as strings reportadas corresponderem também. Sem eles, o nome da GPU da persona e os pixels vindos da ponte não batem:
--canvas-bridge-url=ws://127.0.0.1:8443 \
--no-sandbox \
--fingerprint=<seed> \
--fingerprint-gpu-vendor='Google Inc. (Intel)' \
--fingerprint-gpu-renderer='ANGLE (Intel, Intel(R) UHD Graphics ... D3D11)'| Flag | Significado |
|---|---|
| --canvas-bridge-url | Endpoint da ponte, ws://host:port. Obrigatório para ativar a ponte. |
| --canvas-bridge-auth | Credenciais HTTP Basic user:secret opcionais, para uma implantação que coloca autenticação na frente do servidor. O servidor de referência não as verifica, então conte com a rede privada ou o túnel para o controle de acesso. |
| --no-sandbox | Obrigatório — o cliente abre o socket da ponte a partir do processo renderer, e o sandbox bloqueia isso. |
| --fingerprint | A seed da sua persona. |
| --fingerprint-gpu-vendor / --fingerprint-gpu-renderer | As strings da GPU de renderização: o renderer exatamente como o servidor o imprimiu, o vendor como Google Inc. (<first name in the renderer>). |
| --canvas-bridge-mode | Política por origem: off, all (padrão), allow ou deny. |
| --canvas-bridge-allow / --canvas-bridge-deny | Listas de eTLD+1 separadas por vírgula, usadas por mode=allow ou mode=deny. |
| --canvas-bridge-fallback | Comportamento em cache miss a frio: block (o padrão) espera pela ponte; local serve pixels locais em vez de travar. |
Pelo SDK
O SDK (Node, Python e .NET; versão atual 0.31.1) expõe uma opção dedicada, canvasBridge / canvas_bridge / CanvasBridge. Definir uma URL de ponte emite os switches e adiciona --no-sandbox automaticamente. Para a mesma política de allow-list num script de inicialização completo, veja Exemplos.
const browser = await clearcote.launch({
fingerprint: "user-1",
gpuVendor: "Google Inc. (Intel)", // "Google Inc. (<first name in the renderer>)"
gpuRenderer: "ANGLE (Intel, Intel(R) UHD Graphics ... D3D11)", // exactly as the server printed it
canvasBridge: {
url: "ws://127.0.0.1:8443",
auth: "user:secret",
mode: "allow",
allow: ["example.com"],
fallback: "local",
},
});Confirme que está funcionando
- O log do cliente imprime
canvas-bridge: connected to <host>:<port>quando a conexão dá certo (rode com--enable-logging=stderr --v=1para ver). - Carregue uma página que calcula o hash de uma superfície de canvas/WebGL — com a ponte conectada, os hashes correspondem à GPU do host da ponte, não à do seu host de automação. Verificação rápida: rode o mesmo
canvas.toDataURL()com e sem a ponte; os resultados são diferentes. - Se a ponte estiver inacessível, o Clearcote registra um aviso e volta para a renderização local — uma ponte mal configurada degrada de forma controlada e nunca quebra a página.
Ressalvas & limites
- Identidade de canvas = o host da ponte, não a seed. Todos os perfis que compartilham um host de ponte compartilham o hash de canvas/WebGL desse host, então dá para vinculá-los pelo hash de canvas. Para muitas identidades não vinculáveis, rode um host de ponte (GPU) por grupo de identidades.
- Latência. Uma leitura de pixels que não acha nada no cache da ponte vira uma ida e volta bloqueante pela rede (timeout de 5s, depois fallback local), a menos que
fallbacksejalocal; o motor faz prefetch depois de cada desenho, então leituras repetidas de pixels de um canvas que não mudou não esperam. Cada chamada demeasureTextcontinua sendo uma ida e volta. Mantenha o host da ponte na mesma LAN/datacenter; evite a ponte em páginas sensíveis à latência e pesadas em canvas. - Texturas WebGL procedurais passam pela ponte. Fontes de textura de imagem, canvas 2D, vídeo,
ImageBitmape 3D fazem aquele canvas voltar para a renderização local; assim, continuam corretas, mas fora da ponte. --no-sandboxé obrigatório no cliente, e o transporte é em texto puro — use sempre um túnel; nunca exponha a porta da ponte publicamente.
Experimental. No build aberto desde v0.1.0-pre.12, e no build licenciado. Para a referência canônica (com a tabela completa de solução de problemas), veja o guia do canvas bridge no GitHub. A maioria das configurações não precisa da ponte — veja Flags de fingerprint para os controles padrão no nível do motor.