Playwright & Puppeteer
O Clearcote é só Chromium, então funciona como navegador drop-in para as ferramentas de automação que você já usa.
Pelo SDK (recomendado)
O pacote clearcote (npm, PyPI e NuGet) transforma as opções de identidade em argumentos nomeados e devolve objetos comuns do Playwright. No primeiro uso, ele baixa o navegador e verifica o SHA-256 — o build aberto sem chave de licença, o build licenciado mais recente com uma (veja Instalação) — e aplica os padrões descritos mais abaixo.
# pip install clearcote
from clearcote import launch
browser = launch(fingerprint="seed-123", platform="windows", brand="Chrome")
page = browser.new_page()
page.goto("https://example.com")
browser.close()SDK atual: 0.45.0. Desde a 0.23, o launch() em Python e Node roda sobre um diretório de perfil real e descartável (apagado ao fechar), em vez do modo anônimo, para que a superfície que depende do perfil corresponda à de um Chrome real e widevine: true consiga carregar o módulo de DRM. Ele devolve um handle que se comporta como um navegador: newPage() funciona normalmente, mas newContext() devolve esse mesmo contexto de perfil, e não um contexto isolado. Para ter cookie jars separados, inicie navegadores separados; passe ephemeralProfile: false / ephemeral_profile=False para o antigo Browser em modo anônimo, ou userDataDir / user_data_dir para manter o perfil.
A API assíncrona (clearcote.async_api) aceita as mesmas opções de persona e proxy dentro de um loop asyncio e devolve objetos assíncronos do Playwright; o launch() dela usa o modo anônimo, então use launch_persistent_context() para ter um perfil (e para widevine=True). O SDK .NET cobre LaunchEphemeralProfileAsync (recomendado — o LaunchAsync do .NET usa o modo anônimo e não consegue ajustar uma janela headless), LaunchPersistentContextAsync, ServeAsync, download verificado, licenciamento, Geoip e entrada humana (chamadas explícitas a HumanClickAsync / HumanTypeAsync / HumanSelectOptionAsync, e não uma flag de inicialização). Perfis salvos, profile: "auto", verificações de coerência de renderização, Widevine e os helpers de agente são, por enquanto, exclusivos de Python & Node. Para fluxos completos prontos para copiar e colar, veja Exemplos.
Puppeteer e outros clientes CDP (serve)
O SDK não tem um launcher para o Puppeteer. Em vez disso, o serve() inicia o Clearcote com as configurações de inicialização do SDK (persona, proxy, padrões) e um endpoint CDP no loopback, e qualquer cliente CDP se conecta a ele — Puppeteer, o connectOverCDP do Playwright, browser-use, Crawl4AI, Stagehand. Funciona com o build licenciado, e nada adiciona --enable-automation. O humanize roda do lado do Playwright, então não se aplica a um cliente conectado dessa forma.
import { serve } from "clearcote";
import puppeteer from "puppeteer-core";
const srv = await serve({ fingerprint: "seed-123", platform: "windows" });
const browser = await puppeteer.connect({ browserURL: srv.cdpUrl, defaultViewport: null });
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.disconnect();
await srv.close();No modo headless, o serve() dá ao navegador um display de tamanho real e ajusta a janela à área útil da tela antes que qualquer cliente se conecte (0.31+); passe windowSize / window_size para uma janela menor. No shell, o clearcote serve faz o mesmo como um serviço permanente — e pode dar a cada conexão o próprio navegador, com identidade, proxy, fuso horário e idioma tirados da URL de conexão. Veja Deploy.
Controlando o binário diretamente (build aberto)
Você também pode apontar o seu próprio launcher para o build aberto com executablePath (Node) ou executable_path (Python) e passar as opções de identidade como args. O build licenciado não inicia dessa forma — ele precisa do token de licença que o SDK obtém, então use launch() ou serve(), descritos acima. Remova --enable-automation, como o SDK faz (o Puppeteer e versões mais antigas do Playwright adicionam essa flag, que coloca o Chromium no modo de automação). Nenhum dos padrões do SDK (idioma, política de WebRTC, geometria da janela) se aplica nesse caminho.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
executable_path=r"C:\clearcote\chrome.exe",
headless=False,
ignore_default_args=["--enable-automation"],
args=[
"--fingerprint=seed-123",
"--fingerprint-platform=windows",
"--timezone=America/New_York",
],
)
page = browser.new_page()
page.goto("https://abrahamjuliot.github.io/creepjs/")
browser.close()Resolva ou pré-baixe o binário verificado
O SDK resolve o navegador nesta ordem: um executablePath / executable_path explícito, depois CLEARCOTE_BINARY, depois uma version que você pediu (ou CLEARCOTE_BROWSER_VERSION), depois o build licenciado, se encontrar uma chave de licença (a opção licenseKey, CLEARCOTE_LICENSE_KEY ou ~/.clearcote/license.key) e, por fim, o build aberto fixado nesta versão do SDK. Um caminho que você informar é verificado antes da inicialização, em busca de arquivos ausentes ou truncados. Chame download / executable_path quando quiser aquecer o cache sem iniciar o navegador, usar um diretório de cache personalizado ou optar, em tempo de execução, pelo build aberto mais recente no GitHub.
from clearcote import download, launch
chrome = download(cache_dir=r"C:\clearcote-cache", auto_update=True)
browser = launch(executable_path=chrome, fingerprint="seed-123")O modo fixado confere os valores SHA-256 embutidos no SDK. autoUpdate / auto_update é opcional (opt-in) e confere o manifesto de checksums da versão; quando o gpg está disponível, também confere o manifesto assinado contra o fingerprint fixado da chave de assinatura do Clearcote. Isso vale só para o build aberto: com uma chave de licença, o download() baixa o build licenciado atual (escolha um com version ou releaseChannel — veja como escolher um build). No .NET, o DownloadAsync baixa apenas o build aberto; para pré-baixar o licenciado, use ExecutablePathAsync(new LaunchOptions { LicenseKey = … }).
Coerente por padrão (sem flags extras)
Seja qual for a forma como você inicia o navegador, o motor mantém as superfícies secundárias de acordo com a persona escolhida — numa persona Windows, com o que um desktop real com Chrome no Windows reporta. A plataforma da persona é, por padrão, o sistema operacional do host; então, num host Linux, essas superfícies seguem uma persona Linux, a menos que você passe platform. Os limites de getParameter do WebGL (WebGL1 + WebGL2) reportam os valores da persona, limitados ao que a GPU desta máquina consegue de fato entregar, e UNMASKED_RENDERER / UNMASKED_VENDOR são constantes durante a sessão (a mesma GPU em todos os sites, acompanhando a persona). Numa persona Windows, navigator.getBattery() reporta um desktop ligado na tomada, navigator.connection, uma conexão residencial, e AudioContext, a taxa de amostragem e a latência correspondentes do WASAPI do Windows. getScreenDetails() reporta um único monitor, e @media (pointer: fine) / (hover: hover) correspondem a um desktop com mouse.
Verificado no 153 r26, em modo headed no Windows (setembro de 2026): o BrowserScan não reporta bot e o CreepJS mostra 0% de stealth. Atrás de um proxy, adicione geoip para que o fuso horário e o WebRTC correspondam à saída.
Padrões coerentes (substituíveis)
O SDK aplica alguns padrões corretos do ponto de vista de stealth, para que os indícios óbvios não vazem:
- Inicializações em modo headed não emulam viewport por padrão (
viewport: null/no_viewport=True), para quewindow.innerWidthacompanhe a janela real do sistema operacional — um viewport emulado de 1280×720 dentro de uma janela real é indício de uma janela impossível. Passe umviewportexplícito para substituir esse padrão. Num servidor Linux sem gerenciador de janelas (Xvfb, o seu próprio contêiner), onde--start-maximizednão faz nada, a janela em modo headed é ajustada à área útil da tela antes da primeira página, como uma janela maximizada de desktop (SDK 0.42.0). - Inicializações em modo headless recebem um display realista e uma janela ajustada a ele antes da primeira página: a tela da persona ou, sem persona, um tamanho real de desktop. A partir do SDK 0.42.0, isso vale em todas as plataformas, mesmo quando uma persona não tem efeito, então a página nunca vê a superfície headless crua de 800×600 do motor. Uma opção
viewportouscreensua desliga isso, e um--screen-infoseu define o display por conta própria. Um--window-size,--window-positionou--start-maximizedseu mantém o display e pula só o ajuste; noserve(), um--window-positionsozinho também mantém o display, e só uma flag de tamanho ou o--screen-infodeixa a geometria inteiramente por sua conta. - Uma única superfície WebGL no Linux: num host Linux, o WebGL de uma persona Linux renderiza via Mesa sobre EGL tanto em modo headless quanto headed (SDK 0.42.0; o host precisa de
libegl1), então a página vê uma só string de renderer, lista de extensões e conjunto de limites nos dois modos, na forma OpenGL ES que a maioria das máquinas Linux reais reporta. Sem EGL, uma inicialização em modo headed usa o GL de desktop do Mesa, e uma persona Windows renderiza via SwiftShader. Um--use-angleou--use-glseu emargstem prioridade, e uma inicialização em modo headless continua recebendo--ignore-gpu-blocklistjunto, para que o WebGL siga funcionando. - Claro ou escuro vem da persona no build licenciado a partir do 154 r32: os contextos que o SDK cria deixam desligada a emulação de esquema de cores do Playwright (SDK 0.41.0+), que, do contrário, forçaria o modo claro. Passe
colorScheme/color_schemepara emular um mesmo assim. - A persona fica fora da linha de comando no build licenciado a partir do 154 r32: o seed, os overrides da persona e as credenciais do proxy chegam ao navegador pelo ambiente dele, e não pela entrada dele na lista de processos (SDK 0.41.0+;
personaEnv: falsepara manter a linha de comando). Veja Opções de inicialização. - O WebRTC usa
disable_non_proxied_udppor padrão, então nenhum UDP sai por fora do proxy e o endereço da sua própria máquina continua privado. Só o seu próprio--webrtc-ip-handling-policyemargssubstitui esse padrão — e, no build aberto,webrtcIp/geoip, que voltam a deixar o UDP do WebRTC sair pela sua própria conexão (o build licenciado bloqueia o UDP do WebRTC de qualquer forma). Com essa política e semwebrtcIp, a página não recebe nenhum candidato ICE — atrás de um proxy, passegeoip(ouwebrtcIp) para que o WebRTC reporte o endereço do proxy, ousocks5Udppara levar UDP real por um proxy SOCKS5. - Atrás de um proxy, QUIC / HTTP-3 fica desligado, como acontece com um Chrome real atrás de um proxy — então nenhum UDP é tentado por fora dele.
- A plataforma da persona é, por padrão, o sistema operacional do host, e a marca, Google Chrome. Sem
timezonee semgeoip, o fuso horário segue o idioma (en-US→ Nova York). - As credenciais do proxy vão para o navegador, e não para o Playwright, onde o motor oferece suporte: SOCKS5 sempre (o Playwright simplesmente não consegue se autenticar em SOCKS5), HTTP(S) no 151 r19+, para que o cache de páginas continue ativo (Python & Node). Veja abaixo.
- O
humanizefaz uma checagem prévia de actionability antes de cada clique confiável (visível / habilitado / estável + uma checagem de sobreposição comelementFromPoint) e, se preciso, recorre ao clique nativo, para que um clique confiável nunca dispare sob um overlay ou no meio de uma animação.
Dica: derive o seed do id da sua própria conta/tenant, para que cada identidade seja reproduzível — mesmo seed, mesmo fingerprint do navegador, sempre. Veja a lista completa de switches em Flags de fingerprint.