Despliegue: Docker & endpoint CDP
Ejecuta Clearcote como un endpoint CDP permanente y apunta hacia él cualquier framework que ya uses —Playwright, Puppeteer, browser-use, Crawl4AI, Stagehand— sin cambiar el código. Lanza el binario directamente (sin --enable-automation), así que navigator.webdriver sigue en false: sigiloso por construcción.
Imagen oficial de Docker
Descarga la imagen y listo. Cualquier cliente CDP se conecta a través del puerto expuesto.
docker run -d --rm -p 127.0.0.1:9222:9222 -e CC_FINGERPRINT=user-7423 teamflatearth/clearcote # CDP on http://localhost:9222from 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())La imagen trae integrados el build abierto para Linux, verificado con SHA-256, y las fuentes con métricas clonadas de las de Windows (para que el texto latino mida como las fuentes de la persona; el paquete de fuentes del build abierto no incluye tipografías CJK, así que el texto en chino, japonés y coreano se renderiza sin fuente hasta que ejecutes el build con licencia, cuyo paquete sí las incluye), y usa por defecto una persona coherente de Linux nativo. El navegador se ejecuta en modo headed sobre una pantalla virtual (CC_HEADLESS=1 para headless puro). Se configura por completo con variables de entorno:
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| Variable | Significado |
|---|---|
CC_FINGERPRINT | Seed → identidad estable. Sin ella, todos los contenedores presentan la misma identidad (seed clearcote-docker), así que dale a cada contenedor la suya. |
CC_PLATFORM | linux (por defecto) | windows | macos | android. Una persona de Windows también activa Widevine y, en el build con licencia (151 r15+), el dialecto de shaders HLSL (CC_WIDEVINE / CC_SHADER_DIALECT para cambiarlo). |
CC_BRAND, CC_BRAND_VERSION | Chrome (por defecto) | Edge | Opera | Vivaldi, y la versión que declara. |
CC_ACCEPT_LANGUAGE, CC_TIMEZONE | Lista de idiomas y zona horaria IANA. |
CC_TLS_PROFILE | Déjala sin definir: el TLS sigue a la versión de Chrome que declara la persona. Fija un chrome-<major> solo junto con un CC_BRAND_VERSION que coincida. |
CC_HARDWARE_CONCURRENCY, CC_GPU_VENDOR, CC_GPU_RENDERER, CC_STORAGE_QUOTA | Valores individuales de la persona. |
CC_HEADLESS, CC_SCREEN | 1 para headless puro; el tamaño de la pantalla virtual (por defecto 1920x1080x24). |
CC_EXTRA_ARGS | Switches adicionales del navegador, separados por espacios. |
CLEARCOTE_LICENSE_KEY, CC_VERSION | Ejecutan el build con licencia; ver más abajo. |
Declara el sistema operativo en el que corre el contenedor. Parte de lo que una página puede leer viene del sistema operativo del host, por debajo del navegador, y ningún ajuste de la persona llega hasta ahí. En esta imagen de Linux, el tamaño del texto lo calcula el escalador FreeType de Linux y las fuentes vienen de fontconfig, diga lo que digaCC_PLATFORM. Medido en esta imagen conCC_PLATFORM=windows: variar el tamaño de fuente en pasos de 0.01 px cambia el ancho del texto en el 66% de los pasos (Chrome real en Windows: 99%), y Segoe UI y Georgia aparecen como instaladas al medirlas, pero no se pueden cargar por nombre. El test de huella digital señala ambas cosas. La persona de Linux por defecto pasa el test. Para una identidad de Windows, ejecuta el build para Windows o usa los navegadores alojados, que corren en máquinas Windows. Lo mismo aplica aserve()ylaunch()en un servidor Linux. Detalles: el stack de fuentes por debajo del user agent.
Build con licencia en Docker: pasa una clave y monta la caché
La imagen trae integrado el build abierto. Define CLEARCOTE_LICENSE_KEY y el contenedor resuelve en su lugar el build con licencia: el más reciente o, en el plan Pro, uno concreto con CC_VERSION. Las claves gratuitas siempre ejecutan el build más reciente y se rechaza cualquier fijación de versión.
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=r28Monta siempre el volumen de caché. Un contenedor con licencia descarga el motor en el primer arranque; sin un volumen persistente, cada contenedor lo vuelve a hacer. Con el volumen, los contenedores siguientes arrancan desde el build en caché.
El log de arranque te dice qué motor obtuviste, así que una clave mal configurada se nota de inmediato y no en la primera solicitud bloqueada:
[clearcote] engine: /opt/xdg-cache/clearcote/pro-153.0.8010.36-r28/browser/chrome (licensed)
[clearcote] licence lease acquiredRequiere una imagen construida con el SDK 0.26.1 o posterior, y 0.30.0 o posterior para una clave gratuita de GitHub: el navegador con licencia espera que un contenedor gratuito mantenga su licencia al día mientras se ejecuta, y rechaza una imagen más antigua. Las imágenes publicadas más antiguas ignoran la clave y sirven el build abierto sin avisar; ejecuta docker pull teamflatearth/clearcote para actualizarla. Una ejecución con licencia también obtiene un lease de concurrencia al arrancar, así que el contenedor necesita acceso saliente a la API de licencias; si el lease falla, el contenedor termina indicando el motivo en lugar de iniciar un motor que no puede ejecutarse. Una clave gratuita ejecuta un navegador a la vez entre todos tus contenedores; consulta cómo se cuentan los navegadores con licencia.Seguridad: un endpoint CDP da control total del navegador. Publícalo solo en redes de confianza; -p 127.0.0.1:9222:9222 lo mantiene local al host. El docker/ Dockerfile se puede auditar: recompílalo y verifícalo tú mismo.Endpoint CDP permanente desde el SDK: serve()
Lanza el binario tú mismo y obtén una cdp_url a la que se conecta cualquier cliente. Es el mismo lanzamiento directo y sigiloso que el de la imagen, controlado desde tu propio proceso.
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()import { serve } from "clearcote";
const srv = await serve({ fingerprint: "seed-123", platform: "windows" });
// srv.cdpUrl -> connectOverCDP / puppeteer.connect({ browserURL, defaultViewport: null })
await srv.close();En modo headless, el navegador servido recibe una pantalla de tamaño real —la de la persona, o una tomada de equipos de escritorio reales— y su ventana se ajusta al área de trabajo antes de que se conecte ningún cliente, así que cada página, pestaña y popup reporta una ventana que cabe en su pantalla (SDK 0.31+). Pasa windowSize: { width, height } (window_size en Python, WindowSize en .NET) si quieres una ventana más pequeña, o tu propio --window-size en args para tomar el control.
Un endpoint, muchas identidades: clearcote serve
Desde la shell (paquetes de Python y Node, 0.29+), clearcote serve ejecuta un endpoint permanente que inicia un navegador distinto para cada identidad que pide una conexión, con su seed, proxy, zona horaria e idioma tomados de la URL de conexión. Un mismo seed reutiliza el navegador que ya está en ejecución.
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 defecto escucha en localhost y rechaza las solicitudes que podría hacer una página web. Las identidades inactivas se cierran tras --idle-timeout segundos, --max-browsers limita cuántas se ejecutan a la vez (las identidades adicionales reciben HTTP 429), --data-dir conserva el perfil de cada identidad entre reinicios, y --allow-host / --allow-origin permiten ejecutarlo detrás de un reverse proxy. Abre http://127.0.0.1:9222/ para ver qué está en ejecución. Con una clave Gratis con GitHub, solo se ejecuta un navegador a la vez. El script anterior de identidad única, clearcote-serve --port 9222 --fingerprint seed-123, sigue incluido en el paquete de Python.
Directo: el build abierto, sin SDK
El build abierto de la página de Releases es un binario de Chromium normal que puedes lanzar tú mismo con executable_path y switches. El build con licencia necesita el SDK, que es el que tiene su token de licencia. Los argumentos adicionales de abajo son los principales valores por defecto que el SDK agrega para este seed en Windows (además, combina feature flags y, detrás de un proxy, desactiva QUIC):
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")Construye tu propia imagen (con el SDK)
Clearcote distribuye un binario para Linux x64, así que se ejecuta en modo headless dentro de un contenedor. La imagen necesita las bibliotecas de runtime del navegador, fontconfig y el SDK. El navegador usa el paquete de fuentes de su propia versión en lugar de las fuentes del sistema; igual que en la imagen oficial, el build abierto no incluye tipografías CJK (el paquete del build con licencia sí las incluye). En Linux, la persona usa por defecto una identidad coherente de Linux nativo. La protección contra fugas de WebRTC está activada por defecto; las APIs de Privacy Sandbox siguen activadas, como en Google Chrome.
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"]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();Ejecuta el contenedor con--shm-size=1gpara evitar fallos de/dev/shmen páginas pesadas. En Python es idéntico (from clearcote import launch_persistent_context, opciones ensnake_case).
Qué se conecta por CDP
| Cliente | Cómo |
|---|---|
| Playwright | chromium.connect_over_cdp(url) / connectOverCDP(url) |
| Puppeteer | puppeteer.connect({ browserURL: url, defaultViewport: null }) |
| browser-use · Crawl4AI · Stagehand | apunta su ajuste de CDP/endpoint a la URL |
| Cualquier cosa que hable CDP | el DevTools Protocol en bruto, en ese puerto |
¿Prefieres que lo maneje un agente de IA? Consulta el servidor MCP. ¿Te preguntas por qué un lanzamiento directo es más sigiloso? Consulta Cómo funciona la detección.