Pular para o conteúdo

Deploy — Docker & endpoint CDP

Rode o Clearcote como um endpoint CDP permanente e aponte para ele qualquer framework que você já usa — Playwright, Puppeteer, browser-use, Crawl4AI, Stagehand — sem mudar o código. Ele inicia o binário diretamente (sem --enable-automation), então navigator.webdriver continua false: discreto por construção.

Imagem Docker oficial

Baixe a imagem e pronto. Qualquer cliente CDP se conecta pela porta exposta.

bash
docker run -d --rm -p 127.0.0.1:9222:9222 -e CC_FINGERPRINT=user-7423 teamflatearth/clearcote   # CDP on http://localhost:9222
python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp("http://localhost:9222")   # your code, unchanged
    page = browser.contexts[0].new_page()                            # the container's own profile
    page.goto("https://example.com")
    print(page.title())

A imagem já vem com o build aberto para Linux, com SHA-256 verificado, e com as fontes metric-clone do Windows (para que texto em alfabeto latino tenha as mesmas medidas das fontes da persona; o bundle do build aberto não tem faces CJK, então texto em chinês, japonês e coreano é renderizado sem fonte até você rodar o build licenciado, cujo bundle as inclui), e usa por padrão uma persona Linux nativa coerente. O navegador roda em modo headed num display virtual (CC_HEADLESS=1 para headless puro). Configure tudo com variáveis de ambiente:

bash
docker run -d -p 127.0.0.1:9222:9222 -e CC_PLATFORM=linux -e CC_FINGERPRINT=user-7423 -e CC_ACCEPT_LANGUAGE=en-US -e CC_TIMEZONE=America/New_York teamflatearth/clearcote
VariávelSignificado
CC_FINGERPRINTSeed → identidade estável. Sem essa variável, todos os contêineres apresentam a mesma identidade (seed clearcote-docker), então dê a cada contêiner o seu próprio seed.
CC_PLATFORMlinux (padrão) | windows | macos | android. Uma persona Windows também ativa o Widevine e, no build licenciado (151 r15+), o dialeto de shader HLSL (use CC_WIDEVINE / CC_SHADER_DIALECT para substituir).
CC_BRAND, CC_BRAND_VERSIONChrome (padrão) | Edge | Opera | Vivaldi, e a versão que a marca declara.
CC_ACCEPT_LANGUAGE, CC_TIMEZONELista de idiomas e fuso horário IANA.
CC_TLS_PROFILEDeixe sem definir: o TLS segue a versão do Chrome que a persona declara. Fixe um chrome-<major> só junto com um CC_BRAND_VERSION correspondente.
CC_HARDWARE_CONCURRENCY, CC_GPU_VENDOR, CC_GPU_RENDERER, CC_STORAGE_QUOTAValores individuais da persona.
CC_HEADLESS, CC_SCREEN1 para headless puro; o tamanho da tela virtual (padrão 1920x1080x24).
CC_EXTRA_ARGSSwitches extras do navegador, separados por espaço.
CLEARCOTE_LICENSE_KEY, CC_VERSIONRodar o build licenciado — veja abaixo.
Declare o mesmo sistema operacional em que o contêiner roda. Parte do que uma página consegue ler vem do sistema operacional do host, abaixo do navegador, e nenhuma configuração de persona chega até lá. Nesta imagem Linux, o texto é dimensionado pelo scaler FreeType do Linux e as fontes vêm do fontconfig, não importa o que diga o CC_PLATFORM. Medido nesta imagem com CC_PLATFORM=windows: variar o tamanho da fonte em passos de 0,01 px muda a largura do texto em 66% dos passos (Chrome real no Windows: 99%), e Segoe UI e Georgia aparecem como instaladas nas medições, mas não podem ser carregadas pelo nome. O teste de fingerprint sinaliza as duas coisas. A persona Linux padrão passa. Para uma identidade Windows, rode o build para Windows ou use os navegadores hospedados, que rodam em máquinas Windows. O mesmo vale para serve() e launch() num servidor Linux. Detalhes: a pilha de fontes por baixo do user agent.

Build licenciado no Docker — passe uma chave, monte o cache

A imagem já vem com o build aberto embutido. Defina CLEARCOTE_LICENSE_KEY e o contêiner passa a resolver o build licenciado — o mais recente ou, no plano Pro, um específico com CC_VERSION. Chaves gratuitas sempre rodam o build mais recente, e a fixação de versão é recusada.

bash
docker run -d -p 127.0.0.1:9222:9222 -v clearcote-cache:/opt/xdg-cache -e CLEARCOTE_LICENSE_KEY=cc_lic_... teamflatearth/clearcote

# Pro only: pin a major, an exact build, or a revision
#   -e CC_VERSION=153        -e CC_VERSION=153.0.8010.36        -e CC_VERSION=r28

Sempre monte o volume de cache. Um contêiner licenciado baixa o motor na primeira inicialização; sem um volume persistente, cada contêiner faz isso de novo. Com o volume, os contêineres seguintes iniciam a partir do build em cache.

O log de inicialização mostra qual motor você recebeu, então uma chave mal configurada aparece na hora, e não na primeira requisição bloqueada:

text
[clearcote] engine: /opt/xdg-cache/clearcote/pro-153.0.8010.36-r28/browser/chrome (licensed)
[clearcote] licence lease acquired
Exige uma imagem gerada a partir do SDK 0.26.1 ou mais recente, e 0.30.0 ou mais recente para uma chave gratuita via GitHub — o navegador licenciado espera que um contêiner gratuito mantenha a licença em dia enquanto roda, e recusa uma imagem mais antiga. Imagens publicadas mais antigas ignoram a chave e servem o build aberto sem avisar — rode docker pull teamflatearth/clearcote para atualizar. Uma execução licenciada também reserva um lease de concorrência na inicialização, então o contêiner precisa de acesso de saída à API de licenças; se o lease falhar, o contêiner encerra informando o motivo, em vez de iniciar um motor que não consegue rodar. Uma chave gratuita roda um navegador por vez, somando todos os seus contêineres — veja como os navegadores licenciados são contados.
Segurança: um endpoint CDP dá controle total do navegador. Publique-o apenas em redes confiáveis — -p 127.0.0.1:9222:9222 o mantém restrito ao host. O docker/ Dockerfile é auditável — faça o build e verifique você mesmo.

Endpoint CDP permanente pelo SDK — serve()

Inicie o binário você mesmo e receba uma cdp_url à qual qualquer cliente se conecta. A mesma inicialização direta e discreta da imagem, controlada pelo seu próprio processo.

python
from clearcote import serve

srv = serve(fingerprint="seed-123", platform="windows")   # -> srv.cdp_url
# attach ANY CDP client:
#   playwright:  p.chromium.connect_over_cdp(srv.cdp_url)
#   puppeteer:   puppeteer.connect({ browserURL: srv.cdp_url, defaultViewport: null })
#   browser-use / Crawl4AI / Stagehand: point them at srv.cdp_url
srv.close()
javascript
import { serve } from "clearcote";
const srv = await serve({ fingerprint: "seed-123", platform: "windows" });
// srv.cdpUrl -> connectOverCDP / puppeteer.connect({ browserURL, defaultViewport: null })
await srv.close();

No modo headless, o navegador servido recebe um display de tamanho real — o da persona, ou um sorteado entre desktops reais — e a janela é ajustada à área útil da tela antes que qualquer cliente se conecte, então toda página, aba e popup reporta uma janela que cabe na tela (SDK 0.31+). Passe windowSize: { width, height } (window_size no Python, WindowSize no .NET) para uma janela menor, ou o seu próprio --window-size em args para assumir o controle.

Um endpoint, muitas identidades — clearcote serve

No shell (pacotes de Python e Node, 0.29+), o clearcote serve roda um endpoint permanente que inicia um navegador separado para cada identidade que uma conexão pede — com seed, proxy, fuso horário e idioma tirados da URL de conexão. O mesmo seed reaproveita o navegador que já está rodando.

bash
clearcote serve --port 9222 --idle-timeout 300 --max-browsers 16

# then, from any Playwright client:
#   chromium.connect_over_cdp("http://127.0.0.1:9222?fingerprint=acct-1&platform=windows")
#   chromium.connect_over_cdp("http://127.0.0.1:9222?fingerprint=acct-2&proxy=socks5://user:pass@host:1080&geoip=true")
#   (a password-protected proxy needs the licensed build)

Por padrão, ele escuta só em localhost e recusa requisições que uma página web poderia fazer. Identidades ociosas são fechadas depois de --idle-timeout segundos, --max-browsers limita quantas rodam ao mesmo tempo (as identidades além do limite recebem HTTP 429), --data-dir mantém o perfil de cada identidade entre reinicializações, e --allow-host / --allow-origin permitem rodá-lo atrás de um proxy reverso. Abra http://127.0.0.1:9222/ para ver o que está rodando. Com uma chave Grátis com GitHub, só um navegador roda por vez. O script antigo de identidade única, clearcote-serve --port 9222 --fingerprint seed-123, continua no pacote Python.

Direto — o build aberto, sem SDK

O build aberto da página de Releases é um binário comum do Chromium, que você pode iniciar por conta própria com executable_path e switches. O build licenciado precisa do SDK, que guarda o token de licença. Os argumentos extras abaixo são os principais padrões que o SDK adiciona para este seed no Windows (ele também mescla feature flags e, atrás de um proxy, desliga o QUIC):

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(
        executable_path=r"C:\clearcote\chrome.exe",
        ignore_default_args=["--enable-automation", "--enable-unsafe-swiftshader"],
        args=[
            "--fingerprint=seed-123",
            "--fingerprint-platform=windows",
            "--fingerprint-brand=chrome",
            "--accept-lang=en-US,en",
            "--lang=en-US",
            "--timezone=America/New_York",
            "--webrtc-ip-handling-policy=disable_non_proxied_udp",
            "--ignore-gpu-blocklist",
        ],
    )
    browser.new_page().goto("https://example.com")

Crie a sua própria imagem (com o SDK)

O Clearcote distribui um binário Linux x64, então ele roda em modo headless num contêiner. A imagem precisa das bibliotecas de runtime do navegador, do fontconfig e do SDK. O navegador usa o bundle de fontes da própria versão, e não as fontes do sistema; assim como na imagem oficial, o build aberto não tem faces CJK (o bundle do build licenciado as inclui). No Linux, a persona usa por padrão uma identidade Linux nativa coerente. A proteção contra vazamentos do WebRTC vem ativada por padrão; as APIs do Privacy Sandbox continuam ativas, como no Google Chrome.

dockerfile
FROM node:22-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
      xz-utils libnss3 libnspr4 libgbm1 libasound2 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
      libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 libxfixes3 libxext6 libxrender1 \
      libpango-1.0-0 libcairo2 libx11-6 libxcb1 libexpat1 libdbus-1-3 ca-certificates \
      fontconfig fonts-liberation fonts-noto-color-emoji fonts-unifont fonts-ipafont-gothic fonts-wqy-zenhei \
 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
RUN npm i clearcote
RUN node --input-type=module -e "import { download } from 'clearcote'; await download();"   # bake the binary in
COPY run.mjs .
CMD ["node", "run.mjs"]
run.mjs
import { launchPersistentContext } from "clearcote";
const ctx = await launchPersistentContext("/tmp/prof", {
  headless: true,
  fingerprint: "user-1",
  proxy: { server: "http://gateway:8080", username: "u", password: "p" },
  geoip: true,      // timezone + languages + WebRTC IP matched to the proxy exit
  humanize: true,   // trusted bezier input; navigator.webdriver stays false
  args: ["--no-sandbox"],
});
const page = ctx.pages()[0] ?? (await ctx.newPage());
await page.goto("https://example.com");
await ctx.close();
Rode o contêiner com --shm-size=1g para evitar crashes de /dev/shm em páginas pesadas. Em Python é idêntico (from clearcote import launch_persistent_context, opções em snake_case).

O que se conecta via CDP

ClienteComo
Playwrightchromium.connect_over_cdp(url) / connectOverCDP(url)
Puppeteerpuppeteer.connect({ browserURL: url, defaultViewport: null })
browser-use · Crawl4AI · Stagehandaponte a configuração de CDP/endpoint deles para a URL
Qualquer coisa que fale CDPo DevTools Protocol puro, na porta

Prefere que um agente de IA controle o navegador? Veja o servidor MCP. Quer saber por que uma inicialização direta é mais discreta? Veja Como a detecção funciona.