Aller au contenu

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é.

bash
docker run -d --rm -p 127.0.0.1:9222:9222 -e CC_FINGERPRINT=user-7423 teamflatearth/clearcote   # CDP on http://localhost:9222

Cela exécute Chrome sans sa sandbox, comme le faisaient toutes les images antérieures à sdk-0.41.0. Ajoutez le profil seccomp de l’image et Chrome tourne avec sa sandbox ; voir la sandbox de Chrome plus bas.

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())

L’image embarque le build ouvert pour Linux, vérifié par SHA-256, 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) et, depuis sdk-0.41.0, des polices pour les autres systèmes d’écriture qu’une machine Windows sait afficher d’origine (voir Polices), 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). Faute de GPU dans le conteneur, WebGL fait son rendu en logiciel, via le backend dont les limites correspondent au GPU qu’annonce la persona : Mesa pour une persona Linux, en mode headed comme en headless, et SwiftShader pour une persona Windows. Tout se configure par variables d’environnement :

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
VariableRôle
CC_FINGERPRINTSeed → identité stable. Sans cette variable, chaque conteneur reçoit sa propre seed aléatoire, affichée au démarrage et conservée dans le profil du conteneur d’un redémarrage à l’autre (les images antérieures à sdk-0.39.0 donnaient la même seed à tous les conteneurs). Définissez-la pour choisir ou réutiliser une identité.
CC_PLATFORMlinux (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_VERSIONChrome (par défaut) | Edge | Opera | Vivaldi, et la version annoncée.
CC_ACCEPT_LANGUAGE, CC_TIMEZONEListe 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_QUOTAValeurs individuelles de la persona.
CC_HEADLESS, CC_SCREEN1 pour du pur headless ; la taille de l’écran virtuel (par défaut 1920x1080x24).
CC_EXTRA_ARGSOptions supplémentaires du navigateur, séparées par des espaces. Placé ici, --disable-runtime-suppression correspond au stock_runtime du SDK (conservé uniquement sur un moteur qui le possède) ; --no-sandbox désactive la sandbox de Chrome.
CLEARCOTE_LICENSE_KEY, CC_VERSIONExécuter le build sous licence — voir ci-dessous.
CC_IDLE_EXIT_SECONDSS’arrêter dès qu’aucun client CDP n’est connecté depuis ce nombre de secondes, décompté à partir de la première réponse du navigateur (par défaut : jamais). Associez-la à --rm pour qu’un conteneur abandonné disparaisse lui aussi. Images à partir de sdk-0.40.0.
CC_SECRETS_FILEUn fichier JSON à l’intérieur du conteneur, contenant CLEARCOTE_LICENSE_KEY et/ou CC_PROXY, lu une seule fois au démarrage puis supprimé — voir garder les secrets hors de docker inspect. Images à partir de sdk-0.40.0.
CLEARCOTE_FONT_DIRSVos propres polices, montées dans le conteneur (par exemple une copie du dossier Fonts d’une machine Windows) — voir Polices. Images à partir de sdk-0.41.0.
CLEARCOTE_FALLBACK_FONT_DIRSDes polices utilisées uniquement pour les caractères que rien d’autre ne couvre. L’image la définit avec ses propres polices d’écritures (/usr/local/share/clearcote/fonts) ; n’y touchez pas, sauf si vous les remplacez.
CLEARCOTE_PERSONA_ENV0 laisse la persona sur la ligne de commande du navigateur. Par défaut, sur un moteur qui le permet (build sous licence à partir de la r32), la persona parvient au navigateur du conteneur par son environnement, si bien qu’elle n’apparaît pas dans la liste des processus de l’hôte ; la ligne serve-state indique persona_env. Images à partir de sdk-0.41.0.
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 dise CC_PLATFORM. Mesuré sur cette image avec CC_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. De vraies polices Windows montées avec CLEARCOTE_FONT_DIRS corrigent les noms sur le build sous licence à partir de la r32 (Polices), mais pas le scaler, qu’aucun réglage n’atteint. 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 pour serve() et launch() 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é.

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=154        -e CC_VERSION=154.0.8037.57        -e CC_VERSION=r36

Montez 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 :

text
[clearcote] engine: /opt/xdg-cache/clearcote/pro-154.0.8037.57-r36/browser/chrome (licensed)
[clearcote] licence lease acquired
Né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.

À partir de l’image sdk-0.40.0, plusieurs conteneurs sous licence qui démarrent en même temps sur le même volume de cache ne téléchargent le moteur qu’une seule fois : le premier le récupère et les autres l’attendent.

Garder les secrets hors de docker inspect

Chaque variable -e fait partie de la configuration du conteneur : quiconque peut lancer docker inspect dessus (ou lire docker compose config, ou la plupart des tableaux de bord de conteneurs) voit en clair CLEARCOTE_LICENSE_KEY et le mot de passe contenu dans une URL CC_PROXY. À partir de l’image sdk-0.40.0, vous pouvez plutôt les passer dans un fichier : un fichier JSON à l’intérieur du conteneur, désigné par CC_SECRETS_FILE, que le conteneur lit une seule fois au démarrage puis supprime. Le fichier doit appartenir à l’utilisateur de l’image (uid 10001).

bash
printf '{"CLEARCOTE_LICENSE_KEY": "%s"}' "$CLEARCOTE_LICENSE_KEY" > clearcote-secrets.json
tar --owner=10001 --group=10001 --mode=600 -cf clearcote-secrets.tar clearcote-secrets.json
id=$(docker create -p 127.0.0.1:9222:9222 -e CC_SECRETS_FILE=/tmp/clearcote-secrets.json   -v clearcote-cache:/opt/xdg-cache teamflatearth/clearcote)
docker cp - "$id:/tmp" < clearcote-secrets.tar    # copy the file in before the container starts
docker start "$id"
rm clearcote-secrets.json clearcote-secrets.tar

C’est ce que fait le lancement sous macOS des SDK. Quiconque a accès au daemon Docker peut toujours lire les fichiers et la mémoire d’un conteneur en cours d’exécution : considérez donc l’accès au daemon comme un accès à la clé.

Depuis sdk-0.40.0, l’image exécute tini comme processus init : les processus auxiliaires du navigateur qui se terminent dans le conteneur (par exemple ceux de scripts lancés avec docker exec qui démarrent leurs propres navigateurs) sont nettoyés au lieu de s’accumuler. docker stop atteint toujours le navigateur et libère la place de licence.

Polices

Le navigateur ne voit que les polices que le SDK lui indique : les sosies Windows du bundle de sa version, puis les répertoires ci-dessous. Rien d’autre sous /usr/share/fonts ne lui parvient, si bien qu’une police installée dans l’image ne peut jamais modifier les largeurs que rapporte une persona Windows. À partir de l’image sdk-0.41.0 :

  • Les polices d’écritures sont intégrées. Emoji en couleur, chinois, japonais et coréen (WenQuanYi Zen Hei, IPA Gothic), et des polices Noto pour l’arabe, l’arménien, le bengali, le cherokee, le dévanagari, l’éthiopien, le géorgien, le gujarati, le gurmukhi, le kannada, le khmer, le lao, le malayalam, le birman, le cingalais, le tamoul, le télougou, le thaï, le tibétain et d’autres encore, dans /usr/local/share/clearcote/fonts, que CLEARCOTE_FALLBACK_FONT_DIRS liste après le bundle. Elles ne servent qu’aux caractères que le bundle ne sait pas dessiner, si bien que ces caractères s’affichent au lieu d’apparaître comme des cases vides, sur le build ouvert comme sur le build sous licence. Aucune famille latine n’est ajoutée.
  • Vos propres polices. Montez un répertoire de polices, typiquement une copie du dossier C:\Windows\Fonts d’une machine Windows, et indiquez-le dans CLEARCOTE_FONT_DIRS. Il est placé avant le bundle. Sur le build sous licence à partir de la r32, chaque famille qu’il fournit s’affiche telle quelle, sous son propre nom, et Helvetica, Times, Courier et les familles génériques CSS suivent ; les moteurs plus anciens conservent leurs sosies et n’utilisent le répertoire que pour les caractères que rien d’autre ne couvre. N’utilisez que des polices dont vous détenez la licence. Hors de Docker, le même réglage correspond au fontDirs du SDK.
bash
docker run -d -p 127.0.0.1:9222:9222 -v /srv/windows-fonts:/fonts:ro -e CLEARCOTE_FONT_DIRS=/fonts \
  -e CC_PLATFORM=windows -v clearcote-cache:/opt/xdg-cache -e CLEARCOTE_LICENSE_KEY=cc_lic_... teamflatearth/clearcote
docker exec <container> clearcote info --quick   # which writing systems render, which families are genuine
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.

La sandbox de Chrome

Sous Linux, la sandbox de Chrome exécute chaque renderer (le processus qui analyse et exécute une page) dans ses propres namespaces, sous un filtre seccomp, si bien qu’une page qui compromet son renderer y reste confinée. Avec --no-sandbox, ce renderer dispose de tout ce dont dispose l’utilisateur du conteneur : ses fichiers, son réseau et ses autres processus. Le profil seccomp par défaut de Docker refuse les appels qui créent ces namespaces ; les images antérieures à sdk-0.41.0 exécutaient donc toujours Chrome avec --no-sandbox.

À partir de l’image sdk-0.41.0, le conteneur vérifie d’abord : il effectue les mêmes appels que la sandbox de Chrome, et exécute Chrome avec sa sandbox s’ils aboutissent. Démarrez-le avec le profil seccomp fourni avec l’image, qui est le profil par défaut de Docker auquel s’ajoutent les deux appels de namespace dont Chrome a besoin :

bash
# copy the profile out of the image (--tmpfs keeps docker from first copying the engine into a volume)
docker run --rm --tmpfs /opt/xdg-cache --entrypoint cat teamflatearth/clearcote /etc/clearcote/seccomp.json > clearcote-seccomp.json
docker run -d -p 127.0.0.1:9222:9222 --security-opt seccomp=clearcote-seccomp.json teamflatearth/clearcote
yaml
# docker compose
services:
  clearcote:
    image: teamflatearth/clearcote
    ports: ["127.0.0.1:9222:9222"]
    security_opt: ["seccomp=./clearcote-seccomp.json"]
  • Le log indique ce qui a été retenu : [clearcote] sandbox: on (…), ou [clearcote] sandbox: OFF, Chrome runs with --no-sandbox: …, avec la raison et la manière de l’activer. La ligne serve-state contient "sandbox": true ou false. Sans le profil, le conteneur fonctionne exactement comme avant.
  • Il faut aussi l’utilisateur propre à l’image (pas --user 0), CAP_SYS_CHROOT (accordée par défaut ; rajoutez --cap-add SYS_CHROOT après --cap-drop ALL), un hôte qui autorise les user namespaces non privilégiés, et une machine amd64. S’il manque l’un de ces éléments, le conteneur se rabat sur --no-sandbox et en indique la raison.
  • Le compromis : avec le profil, n’importe quel processus du conteneur, pas seulement Chrome, peut créer un user namespace doté de son propre namespace réseau, ce qui donne accès à du code réseau du noyau que le profil par défaut de Docker tient hors de portée. Les renderers de Chrome, où s’exécutent les pages non fiables, restent sous le filtre propre à Chrome. Sans la sandbox, un renderer compromis dispose de tout ce dont dispose l’utilisateur du conteneur ; le profil reste donc le meilleur choix. N’utilisez pas --privileged, --cap-add SYS_ADMIN ou seccomp=unconfined à la place : ils désactivent une bien plus grande partie de la protection du conteneur.
  • CC_EXTRA_ARGS=--no-sandbox la désactive volontairement. --no-zygote, --disable-namespace-sandbox, --renderer-cmd-prefix= et le canvas bridge (--canvas-bridge-url=) la désactivent aussi, car Chrome ne peut pas faire tourner sa sandbox avec eux dans ce contexte.
  • Le lancement sous macOS des SDK passe lui-même le profil, sur un Docker qui tourne sur un processeur x86_64. Sur Apple silicon, l’image tourne en émulation, et la sandbox y reste désactivée pour l’instant.

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.

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();

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é.

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)

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) :

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")

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, si bien que les polices que vous installez avec apt lui restent invisibles tant que vous ne les listez pas : créez des liens vers les polices d’écritures dans un même répertoire et indiquez-le dans CLEARCOTE_FALLBACK_FONT_DIRS (SDK 0.41.0+), comme le fait l’image officielle, ou vos propres polices dans CLEARCOTE_FONT_DIRS (voir Polices). Ne listez jamais l’ensemble de /usr/share/fonts : ses familles latines modifieraient les largeurs d’une persona Windows. 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. Avec libegl1 et libgl1-mesa-dri installés, le SDK fait le rendu WebGL d’une persona Linux via Mesa sur EGL, avec les limites et la forme de renderer que rapportent de vraies machines Linux : en headless depuis le SDK 0.39.0, et aussi en headed depuis la version 0.42.0, si bien que les deux modes présentent une seule et même surface WebGL. Sans ces paquets, le rendu se rabat sur SwiftShader. Un lancement headed sous Xvfb, sans gestionnaire de fenêtres, voit sa fenêtre ajustée à l’écran avant la première page (SDK 0.42.0).

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 libegl1 libgl1-mesa-dri \
      fontconfig fonts-noto-color-emoji fonts-ipafont-gothic fonts-wqy-zenhei \
 && F=/usr/local/share/clearcote/fonts && mkdir -p $F && cd /usr/share/fonts \
 && cp -l truetype/noto/NotoColorEmoji.ttf truetype/wqy/wqy-zenhei.ttc opentype/ipafont-gothic/ipag.ttf $F/ \
 && rm -rf /var/lib/apt/lists/*
# emoji + CJK, used only where the bundle has no glyph
ENV CLEARCOTE_FALLBACK_FONT_DIRS=/usr/local/share/clearcote/fonts
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();
Lancez le conteneur avec --shm-size=1g pour éviter les plantages liés à /dev/shm sur les pages lourdes. En Python, c’est identique (from clearcote import launch_persistent_context, options en snake_case).

Ce qui se connecte via CDP

ClientComment
Playwrightchromium.connect_over_cdp(url) / connectOverCDP(url)
Puppeteerpuppeteer.connect({ browserURL: url, defaultViewport: null })
browser-use · Crawl4AI · Stagehandpointez leur réglage CDP/endpoint vers l’URL
Tout ce qui parle CDPle 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.