Playwright & Puppeteer
Clearcote es simplemente Chromium, así que funciona como reemplazo directo del navegador en las herramientas de automatización que ya usas.
Con el SDK (recomendado)
El paquete clearcote (npm, PyPI y NuGet) convierte las opciones de identidad en argumentos con nombre y devuelve objetos normales de Playwright. En el primer uso descarga el navegador y verifica su SHA-256 —el build abierto sin clave de licencia, el build con licencia más reciente con una (consulta Instalación)— y aplica los valores por defecto que se describen más abajo.
# 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 actual: 0.45.0. Desde la 0.23, launch() en Python y Node se ejecuta sobre un directorio de perfil real y desechable (se borra al cerrar) en lugar de en modo incógnito, de modo que la superficie que depende del perfil coincide con la de un Chrome real y widevine: true puede cargar el módulo DRM. Devuelve un handle que se comporta como un navegador: newPage() funciona como siempre, pero newContext() devuelve ese mismo contexto de perfil en lugar de uno aislado. Si necesitas cookies separadas, lanza navegadores separados; pasa ephemeralProfile: false / ephemeral_profile=False para obtener el Browser en modo incógnito de antes, o userDataDir / user_data_dir para conservar el perfil.
La API asíncrona (clearcote.async_api) acepta las mismas opciones de persona y proxy dentro de un loop de asyncio y devuelve objetos asíncronos de Playwright; su launch() es en modo incógnito, así que usa launch_persistent_context() para tener un perfil (y para widevine=True). El SDK de .NET cubre LaunchEphemeralProfileAsync (recomendado: LaunchAsync en .NET es en modo incógnito y no puede ajustar una ventana headless), LaunchPersistentContextAsync, ServeAsync, la descarga verificada, las licencias, Geoip y la entrada humanizada (llamadas explícitas a HumanClickAsync / HumanTypeAsync / HumanSelectOptionAsync en lugar de un flag de lanzamiento). Los perfiles guardados, profile: "auto", las comprobaciones de coherencia de renderizado, Widevine y los helpers para agentes son, por ahora, solo para Python & Node. Para flujos completos listos para copiar y pegar, consulta Ejemplos.
Puppeteer y otros clientes CDP (serve)
El SDK no tiene un launcher para Puppeteer. En su lugar, serve() inicia Clearcote con la configuración de lanzamiento del SDK (persona, proxy, valores por defecto) y un endpoint CDP en loopback, y cualquier cliente CDP se conecta a él: Puppeteer, connectOverCDP de Playwright, browser-use, Crawl4AI, Stagehand. Funciona con el build con licencia, y nada agrega --enable-automation. humanize funciona del lado de Playwright, así que no se aplica a un cliente conectado de esta 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();En modo headless, serve() le da al navegador una pantalla de tamaño real y ajusta su ventana al área de trabajo antes de que se conecte ningún cliente (0.31+); pasa windowSize / window_size si quieres una ventana más pequeña. Desde una shell, clearcote serve hace lo mismo como servicio permanente, y puede darle a cada conexión su propio navegador, con la identidad, el proxy, la zona horaria y el idioma tomados de la URL de conexión. Consulta Despliegue.
Usar el binario directamente (build abierto)
También puedes apuntar tu propio launcher al build abierto con executablePath (Node) o executable_path (Python) y pasar las opciones de identidad como args. El build con licencia no arranca de esta forma: necesita el token de licencia que obtiene el SDK, así que usa launch() o serve(), descritos arriba. Quita --enable-automation como hace el SDK (Puppeteer y las versiones anteriores de Playwright lo agregan; pone a Chromium en su modo de automatización). Por esta vía no se aplica ninguno de los valores por defecto del SDK (idioma, política de WebRTC, geometría de la ventana).
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()Resolver o descargar de antemano el binario verificado
El SDK resuelve el navegador en este orden: un executablePath / executable_path explícito, luego CLEARCOTE_BINARY, luego una version que hayas pedido (o CLEARCOTE_BROWSER_VERSION), luego el build con licencia si encuentra una clave de licencia (la opción licenseKey, CLEARCOTE_LICENSE_KEY o ~/.clearcote/license.key) y, por último, el build abierto fijado en esta versión del SDK. Si indicas una ruta, se comprueba antes del lanzamiento que no falten archivos ni haya archivos truncados. Llama a download / executable_path cuando quieras precargar la caché sin lanzar el navegador, usar un directorio de caché personalizado u optar por el build abierto más reciente de GitHub en tiempo de ejecución.
from clearcote import download, launch
chrome = download(cache_dir=r"C:\clearcote-cache", auto_update=True)
browser = launch(executable_path=chrome, fingerprint="seed-123")El modo fijado verifica los valores SHA-256 integrados en el SDK. autoUpdate / auto_update es opcional (opt-in) y verifica el manifiesto de checksums de la versión; si gpg está disponible, también comprueba el manifiesto firmado contra la huella fijada de la clave de firma de Clearcote. Solo se aplica al build abierto: con una clave de licencia, download() descarga en su lugar el build con licencia actual (elige uno con version o releaseChannel; consulta cómo elegir un build). En .NET, DownloadAsync solo descarga el build abierto; para descargar de antemano el build con licencia, usa ExecutablePathAsync(new LaunchOptions { LicenseKey = … }).
Coherente por defecto (sin flags adicionales)
Lances con lo que lances, el motor mantiene las superficies secundarias en concordancia con la persona que elegiste; con una persona de Windows, con lo que reporta un Chrome real de escritorio en Windows. La plataforma de la persona es, por defecto, el sistema operativo de tu host, así que en un host Linux estas superficies siguen a una persona de Linux, a menos que pases platform. Los límites de getParameter de WebGL (WebGL1 + WebGL2) reportan los valores de la persona, con un tope en lo que la GPU de esta máquina realmente puede ofrecer, y UNMASKED_RENDERER / UNMASKED_VENDOR son constantes durante la sesión (la misma GPU en todos los sitios, acorde con la persona). Con una persona de Windows, navigator.getBattery() reporta un equipo de escritorio conectado a la corriente, navigator.connection una conexión residencial y AudioContext la frecuencia de muestreo y la latencia de Windows WASAPI correspondientes. getScreenDetails() reporta un único monitor, y @media (pointer: fine) / (hover: hover) corresponden a un equipo de escritorio con mouse.
Comprobado en 153 r26, en modo headed en Windows (septiembre de 2026): BrowserScan no reporta ningún bot y CreepJS muestra 0% stealth. Detrás de un proxy, agrega geoip para que la zona horaria y WebRTC coincidan con la salida.
Valores por defecto coherentes (se pueden cambiar)
El SDK aplica algunos valores por defecto correctos desde el punto de vista del stealth para que no se cuelen las señales más obvias:
- Los lanzamientos en modo headed no emulan el viewport por defecto (
viewport: null/no_viewport=True), así quewindow.innerWidthsigue a la ventana real del sistema operativo: un 1280×720 emulado dentro de una ventana real es una señal de ventana imposible. Pasa unviewportexplícito para cambiarlo. En un servidor Linux sin gestor de ventanas (Xvfb, tu propio contenedor), donde--start-maximizedno hace nada, la ventana headed se ajusta al área de trabajo de la pantalla antes de la primera página, como una ventana de escritorio maximizada (SDK 0.42.0). - Los lanzamientos headless reciben una pantalla realista y una ventana ajustada a ella antes de la primera página: la pantalla de la persona o, sin persona, un tamaño de escritorio real. Desde el SDK 0.42.0 esto se cumple en todas las plataformas aunque la persona no llegue a aplicarse, así que una página nunca ve la superficie headless desnuda de 800×600 del motor. Un
viewportoscreenpropio desactiva este comportamiento, y con tu propio--screen-infodefines tú mismo la pantalla. Tu propio--window-size,--window-positiono--start-maximizedconserva la pantalla y solo omite el ajuste; enserve(), un--window-positionpor sí solo también conserva la pantalla, y solo un switch de tamaño o--screen-infodeja la geometría por completo en tus manos. - Una sola superficie WebGL en Linux: en un host Linux, el WebGL de una persona de Linux se renderiza mediante Mesa sobre EGL tanto en headless como en headed (SDK 0.42.0; el host necesita
libegl1), así que la página ve la misma cadena del renderer, la misma lista de extensiones y los mismos límites en ambos casos, en la forma OpenGL ES que reporta la mayoría de las máquinas Linux reales. Sin EGL, un lanzamiento headed usa el GL de escritorio de Mesa, y una persona de Windows se renderiza mediante SwiftShader. Tu propio--use-angleo--use-glenargstiene prioridad, y un lanzamiento headless sigue recibiendo--ignore-gpu-blocklistjunto con él, así que WebGL sigue funcionando. - El modo claro u oscuro viene de la persona en el build con licencia desde 154 r32: los contextos que crea el SDK dejan desactivada la emulación de esquema de colores de Playwright (SDK 0.41.0+), que de otro modo forzaría el modo claro. Pasa
colorScheme/color_schemepara emular uno de todos modos. - La persona no aparece en la línea de comandos en el build con licencia desde 154 r32: el seed, los overrides de la persona y las credenciales del proxy llegan al navegador a través de su entorno, no de su entrada en la lista de procesos (SDK 0.41.0+;
personaEnv: falsepara conservar la línea de comandos). Consulta Opciones de lanzamiento. - WebRTC usa por defecto
disable_non_proxied_udp, así que ningún tráfico UDP sale por fuera del proxy y la dirección propia de tu máquina se mantiene privada. Solo lo cambia tu propio--webrtc-ip-handling-policyenargsy, en el build abierto,webrtcIp/geoip, que vuelven a dejar salir el UDP de WebRTC por tu propia conexión (el build con licencia bloquea el UDP de WebRTC en cualquier caso). Con esa política y sinwebrtcIp, una página no obtiene ningún candidato ICE; detrás de un proxy, pasageoip(owebrtcIp) para que WebRTC reporte la dirección del proxy, osocks5Udppara llevar UDP real a través de un proxy SOCKS5. - Detrás de un proxy, QUIC / HTTP-3 está desactivado, igual que en un Chrome real detrás de un proxy, así que no se intenta enviar UDP por fuera de él.
- La plataforma de la persona es, por defecto, el sistema operativo de tu host, y la marca, Google Chrome. Sin
timezonenigeoip, la zona horaria sigue al idioma (en-US→ Nueva York). - Las credenciales del proxy van al navegador, no a Playwright, donde el motor lo soporta: SOCKS5 siempre (Playwright no puede autenticarse en SOCKS5 en absoluto) y HTTP(S) en 151 r19+, para que la caché de páginas siga activa (Python & Node). Ver más abajo.
humanizeejecuta una comprobación previa de accionabilidad antes de cada clic confiable (visible / habilitado / estable + una comprobación deelementFromPointpara ver si está tapado) y, si no la supera, recurre al clic nativo, así que un clic confiable nunca se dispara bajo un overlay ni en mitad de una animación.
Consejo: deriva el seed del id de tu propia cuenta/tenant para que cada identidad sea reproducible: mismo seed, misma huella digital del navegador, siempre. Consulta la lista completa de switches en Flags de huella digital.