Déploiement — Docker & endpoint CDP
Exécutez Clearcote comme endpoint CDP permanent et pointez-y n’importe quel framework existant — Playwright, Puppeteer, browser-use, Crawl4AI, Stagehand — sans modifier votre code. Il lance directement le binaire (sans --enable-automation), donc navigator.webdriver reste à false : furtif par construction.
Image Docker officielle
Récupérez l’image et c’est parti. N’importe quel client CDP se connecte via le port exposé.
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())L’image embarque le build ouvert pour Linux, vérifié par SHA-256, ainsi que des polices aux métriques identiques à celles de Windows (pour que le texte latin ait les mêmes dimensions qu’avec les polices de la persona ; le bundle du build ouvert ne contient aucune police CJK, si bien que le texte chinois, japonais et coréen s’affiche sans police tant que vous n’exécutez pas le build sous licence, dont le bundle les inclut), et utilise par défaut une persona Linux native cohérente. Le navigateur tourne en mode headed sur un écran virtuel (CC_HEADLESS=1 pour du pur headless). Tout se configure par variables d’environnement :
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 | Rôle |
|---|---|
CC_FINGERPRINT | Seed → identité stable. Sans cette variable, tous les conteneurs présentent la même identité (seed clearcote-docker) : donnez donc à chaque conteneur la sienne. |
CC_PLATFORM | linux (par défaut) | windows | macos | android. Une persona Windows active aussi Widevine et, sur le build sous licence (151 r15+), le dialecte de shader HLSL (CC_WIDEVINE / CC_SHADER_DIALECT pour changer ce comportement). |
CC_BRAND, CC_BRAND_VERSION | Chrome (par défaut) | Edge | Opera | Vivaldi, et la version annoncée. |
CC_ACCEPT_LANGUAGE, CC_TIMEZONE | Liste des langues et fuseau horaire IANA. |
CC_TLS_PROFILE | À laisser vide : le TLS suit la version de Chrome annoncée par la persona. N’épinglez un chrome-<major> qu’avec un CC_BRAND_VERSION correspondant. |
CC_HARDWARE_CONCURRENCY, CC_GPU_VENDOR, CC_GPU_RENDERER, CC_STORAGE_QUOTA | Valeurs individuelles de la persona. |
CC_HEADLESS, CC_SCREEN | 1 pour du pur headless ; la taille de l’écran virtuel (par défaut 1920x1080x24). |
CC_EXTRA_ARGS | Options supplémentaires du navigateur, séparées par des espaces. |
CLEARCOTE_LICENSE_KEY, CC_VERSION | Exécuter le build sous licence — voir ci-dessous. |
Annoncez l’OS sur lequel tourne le conteneur. Une partie de ce qu’une page peut lire provient du système d’exploitation hôte, sous le navigateur, et aucun réglage de la persona ne l’atteint. Dans cette image Linux, le texte est dimensionné par le scaler FreeType de Linux et les polices viennent de fontconfig, quoi que diseCC_PLATFORM. Mesuré sur cette image avecCC_PLATFORM=windows: faire varier une taille de police par pas de 0,01 px modifie la largeur du texte pour 66 % des pas (vrai Chrome sous Windows : 99 %), et Segoe UI et Georgia apparaissent comme installées à la mesure, mais ne peuvent pas être chargées par leur nom. Le test d’empreinte signale les deux. La persona Linux par défaut passe le test. Pour une identité Windows, utilisez le build Windows ou les navigateurs hébergés, qui tournent sur des machines Windows. Il en va de même pourserve()etlaunch()sur un serveur Linux. Pour en savoir plus : la pile de polices sous le user agent.
Build sous licence dans Docker — passez une clé, montez le cache
L’image embarque le build ouvert. Définissez CLEARCOTE_LICENSE_KEY et le conteneur résout à la place le build sous licence — le plus récent, ou, avec l’offre Pro, un build précis via CC_VERSION. Les clés gratuites exécutent toujours le dernier build, et tout épinglage est refusé.
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=r28Montez toujours le volume de cache. Un conteneur sous licence télécharge le moteur à son premier démarrage ; sans volume persistant, chaque conteneur recommence. Avec le volume, les conteneurs suivants démarrent à partir du build en cache.
Le log de démarrage indique quel moteur vous avez obtenu, si bien qu’une clé mal configurée se voit tout de suite plutôt qu’à la première requête bloquée :
[clearcote] engine: /opt/xdg-cache/clearcote/pro-153.0.8010.36-r28/browser/chrome (licensed)
[clearcote] licence lease acquiredNécessite une image construite à partir du SDK 0.26.1 ou plus récent, et 0.30.0 ou plus récent pour une clé gratuite obtenue via GitHub — le navigateur sous licence attend d’un conteneur gratuit qu’il maintienne sa licence à jour pendant qu’il tourne, et refuse une image plus ancienne. Les anciennes images publiées ignorent la clé et servent discrètement le build ouvert — lancez docker pull teamflatearth/clearcote pour mettre à jour. Une exécution sous licence prend aussi un bail de concurrence au démarrage : le conteneur a donc besoin d’un accès sortant à l’API de licence ; si le bail échoue, le conteneur s’arrête en indiquant la raison au lieu de démarrer un moteur incapable de tourner. Une clé gratuite exécute un seul navigateur à la fois sur l’ensemble de vos conteneurs — voir comment les navigateurs sous licence sont comptés.Sécurité : un endpoint CDP donne le contrôle total du navigateur. Ne l’exposez qu’à des réseaux de confiance — -p 127.0.0.1:9222:9222 le limite à la machine hôte. Le Dockerfile de docker/ est auditable — reconstruisez l’image et vérifiez-la vous-même.Endpoint CDP permanent depuis le SDK — serve()
Lancez vous-même le binaire et obtenez une cdp_url à laquelle n’importe quel client se connecte. Le même lancement direct et furtif que l’image, piloté depuis votre propre processus.
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 headless, le navigateur servi reçoit un écran de taille réelle — celui de la persona, ou un écran tiré de vrais PC de bureau — et sa fenêtre est ajustée à la zone de travail avant que le moindre client ne se connecte : chaque page, onglet et popup renvoie ainsi une fenêtre qui tient dans son écran (SDK 0.31+). Passez windowSize: { width, height } (window_size en Python, WindowSize en .NET) pour une fenêtre plus petite, ou votre propre --window-size dans args pour prendre la main.
Un endpoint, plusieurs identités — clearcote serve
Depuis le shell (packages Python et Node, 0.29+), clearcote serve fait tourner un endpoint permanent qui démarre un navigateur distinct pour chaque identité demandée par une connexion — sa seed, son proxy, son fuseau horaire et sa langue étant tirés de l’URL de connexion. Une même seed réutilise son navigateur déjà lancé.
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)Par défaut, il écoute sur localhost et refuse les requêtes qu’une page web pourrait émettre. Les identités inactives se ferment au bout de --idle-timeout secondes, --max-browsers plafonne le nombre de navigateurs simultanés (les identités supplémentaires reçoivent un HTTP 429), --data-dir conserve le profil de chaque identité d’un redémarrage à l’autre, et --allow-host / --allow-origin permettent de le faire tourner derrière un reverse proxy. Ouvrez http://127.0.0.1:9222/ pour voir ce qui tourne. Avec une clé Gratuit avec GitHub, un seul navigateur tourne à la fois. L’ancien script mono-identité clearcote-serve --port 9222 --fingerprint seed-123 est toujours présent dans le package Python.
Lancement direct — le build ouvert, sans SDK
Le build ouvert publié sur la page Releases est un simple binaire Chromium que vous pouvez lancer vous-même avec executable_path et des options en ligne de commande. Le build sous licence nécessite le SDK, qui détient son jeton de licence. Les arguments supplémentaires ci-dessous sont les principales valeurs par défaut que le SDK ajoute pour cette seed sous Windows (il fusionne aussi des feature flags et, derrière un proxy, désactive 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")Construire votre propre image (pilotée par le SDK)
Clearcote fournit un binaire Linux x64 : il tourne donc en headless dans un conteneur. L’image a besoin des bibliothèques d’exécution du navigateur, de fontconfig et du SDK. Le navigateur utilise le bundle de polices propre à sa version plutôt que les polices du système ; comme avec l’image officielle, le build ouvert ne contient aucune police CJK (le bundle du build sous licence les inclut). Sous Linux, la persona correspond par défaut à une identité Linux native cohérente. La protection contre les fuites WebRTC est active par défaut ; les API Privacy Sandbox restent actives, comme dans 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();Lancez le conteneur avec--shm-size=1gpour éviter les plantages liés à/dev/shmsur les pages lourdes. En Python, c’est identique (from clearcote import launch_persistent_context, options ensnake_case).
Ce qui se connecte via CDP
| Client | Comment |
|---|---|
| Playwright | chromium.connect_over_cdp(url) / connectOverCDP(url) |
| Puppeteer | puppeteer.connect({ browserURL: url, defaultViewport: null }) |
| browser-use · Crawl4AI · Stagehand | pointez leur réglage CDP/endpoint vers l’URL |
| Tout ce qui parle CDP | le DevTools Protocol brut, sur le port |
Vous préférez le faire piloter par un agent IA ? Voir le serveur MCP. Curieux de savoir pourquoi un lancement direct est plus furtif ? Voir Comment fonctionne la détection.