Clearcote is an open-source stealth Chromium that stops your scrapers and browser agents from getting blocked. Bot detectors flag automation by reading the browser fingerprint; Clearcote corrects that fingerprint inside Chromium's C++ — so the browser presents as one ordinary, coherent Chrome install, all the way down to the TLS handshake. Point your existing Playwright or Puppeteer at it over the same API, and nothing else in your code changes.
Blink · V8 · BoringSSL patched in-tree · ANGLE / D3D11-backed WebGL · JA3/JA4-coherent TLS · Windows + Linux · signed, checksummed, reproducible releases
| single-surface C++ patches |
headless / stealth (audited) |
across every realm |
open engine, free forever |
Meet Clyde — chameleons blend in to stay unseen. So does your browser. · 💬 Join us on Discord
|
Every spoofed getter is a C++ getter: |
One real Chromium keeps the JS identity, the UA / UA-CH headers, and the TLS JA3/JA4 + HTTP/2 stack in agreement. No spoofed-JS-over-real-TLS seam for a cross-check to catch. |
|
|
A single |
32 small single-purpose diffs in |
Every release is GPG-signed, checksummed, and reproducible from source. Rebuild it yourself and diff the hash. Trust the math, not the vendor. |
🆕 What's new — v0.1.0-pre.21 + SDK
clearcote0.15.0. Network request-header hygiene: under a fingerprint persona the engine no longer emits redundantCache-Control/Pragmarequest headers on navigations and reloads, matching a real Chrome cold navigation (the effective cache mode is unchanged; with no persona, stock behavior is preserved). Humanized cursor — seeded motion model: the SDK's humanizer now drives a shared, persona-seeded trajectory/timing core (minimum-jerk submovements, Fitts-law duration, colored noise, endpoint dwells) that is bit-identical across the Python and Node SDKs — one fingerprint ⇒ one stable motor identity — with an offline motion-score validator. Prior surfaces remain: locale coherence,serve()stealthy CDP endpoint +clearcote-mcp+ Docker, render-vs-string font coherence, mobile/Android persona, Edge coherence, TLS network persona (tlsProfile), Widevine / EME (DRM), the per-origin canvas bridge, real-fingerprint import, and the stealth-coherence gate that runs every release. Experimental pre-release.
- What it is · The 12-second tour
- Quick start — SDK · Direct · Docker
- Why patch the engine, not the page
- Why Clearcote instead of the others
- Configure the persona
- Drive a page with an AI agent
- Proof & verify
- Build from source · Reference · Credits · License
An open-source Chromium distribution built on ungoogled-chromium (Google services + telemetry removed) plus a transparent stack of 32 source patches that move fingerprint control into the engine. Two promises:
- A coherent, private identity — one plausible machine per session instead of an accidentally hyper-unique one, coherent down to the network layer and across the long-tail surfaces detectors love: WebGL
getParameterlimits,navigator.getBattery()/connection/keyboard.getLayoutMap(), AudioContext,getScreenDetails(), and CSS@media. - Radical verifiability — no magic binary. Read every patch, rebuild it yourself, and confirm what you run matches what's published.
It's a drop-in for Playwright / Puppeteer — the same APIs you already use, pointed at the Clearcote binary.
pip install clearcote # or: npm install clearcotefrom clearcote import launch
browser = launch(fingerprint="user-7423", platform="windows") # returns a standard Playwright Browser
page = browser.new_page()
page.goto("https://example.com")
browser.close()Same fingerprint seed ⇒ a stable identity across launches; a new seed ⇒ a fresh, unlinkable one. The SDK auto-downloads + SHA-256-verifies the right binary for your OS on first use, then caches it.
Published on npm and PyPI. Each launch() returns a standard Playwright Browser.
import { launch } from "clearcote";
const browser = await launch({
fingerprint: "user-7423", // same seed ⇒ same identity, different ⇒ unlinkable
platform: "windows", // "windows" | "linux" | "macos" | "android"
brand: "Edge", // Chrome (default) | Edge — UA-CH + Sec-CH-UA kept coherent
timezone: "America/New_York",
});
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.close();from clearcote import launch
# inside an asyncio loop, use: from clearcote.async_api import launch
browser = launch(fingerprint="user-7423", platform="windows", timezone="America/New_York")
page = browser.new_page()
page.goto("https://example.com")
browser.close()Match a proxy automatically — geoip: true resolves the proxy's exit region and sets a coherent timezone + navigator.languages + Accept-Language + WebRTC egress:
await launch({ fingerprint: "u1", proxy: { server: "http://host:8080", username: "u", password: "p" }, geoip: true });Full option list: sdk/node · sdk/python.
Download the signed build from the Releases page, unzip, and drive chrome / chrome.exe from stock Playwright (or any CDP client) via executable_path + --fingerprint switches:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
executable_path=r"C:\clearcote\chrome.exe",
args=["--fingerprint=seed-123", "--fingerprint-platform=windows"],
)
page = browser.new_page(); page.goto("https://example.com"); browser.close()Or run a standing CDP endpoint any existing framework attaches to unchanged — connect_over_cdp, puppeteer.connect, browser-use / Crawl4AI / Stagehand. It launches the binary directly (no --enable-automation), so navigator.webdriver stays false — stealthy by construction:
clearcote-serve --port 9222 --fingerprint seed-123 --platform windows # prints http://127.0.0.1:9222from clearcote import serve
srv = serve(fingerprint="seed-123", platform="windows") # -> srv.cdp_url; attach any CDP clientPoint Claude Desktop / Cursor / Cline at the Clearcote MCP server — ~20 tools (read_page, page_elements, click, fill_field, screenshot, save_profile, get_cdp_endpoint, …) over one shared stealth browser. The persona is set via env, so the tool surface stays clean:
{ "mcpServers": { "clearcote": { "command": "npx", "args": ["-y", "clearcote-mcp"],
"env": { "CLEARCOTE_FINGERPRINT": "acct-1", "CLEARCOTE_PLATFORM": "windows" } } } }Official image — a stealth browser as a CDP endpoint. Pull it and go; any Playwright / Puppeteer / browser-use / Crawl4AI / Stagehand client attaches over CDP, no code change:
docker run -d --rm -p 9222:9222 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.new_page(); page.goto("https://example.com"); print(page.title())The image bakes in the signed Linux binary (SHA-256 verified), a base font set and the Windows metric-clone fonts, and defaults to a coherent native Linux persona. Configure it with env vars — CC_PLATFORM (windows/linux/macos/android), CC_FINGERPRINT (seed), CC_BRAND (Edge…), CC_ACCEPT_LANGUAGE, CC_TIMEZONE, CC_TLS_PROFILE:
docker run -d -p 9222:9222 -e CC_PLATFORM=windows -e CC_FINGERPRINT=user-7423 -e CC_BRAND=Edge teamflatearth/clearcoteSecurity: the CDP endpoint is full browser control — publish it only to trusted networks (
-p 127.0.0.1:9222:9222keeps it host-local). Thedocker/Dockerfileis auditable — rebuild + verify it yourself.
Or build your own image (SDK-driven, run your own script). Clearcote ships a Linux x64 binary, so it runs headless in a container. The image needs the browser's runtime libraries, a base font set (so canvas/text hashes are coherent — the #1 Linux tell), and the SDK. On Linux the persona defaults to a coherent native Linux identity; WebRTC leak-proofing and Privacy-Sandbox-disable are on by default.
FROM node:20-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 — one coherent Linux persona, every stealth surface on
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, // real, 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();
--shm-size=1gavoids/dev/shmcrashes on heavy pages. Python is identical (from clearcote import launch_persistent_context,snake_caseoptions).
The usual approach patches navigator.webdriver, spoofs the WebGL vendor, and overrides navigator.plugins from script. Detectors still flag it — and the reason is structural, not one more property left uncovered. A JavaScript spoof is a function standing where a native one belongs. A detector sets the returned value aside and interrogates whether the thing returning it is native:
| The tell | Why it catches a JS spoof |
|---|---|
toString self-reveal |
A native method stringifies to function get vendor() { [native code] }; an override stringifies to its own source — one .toString() catches it. |
Descriptor / hasOwnProperty |
getOwnPropertyDescriptor exposes redefined props, and hasOwnProperty('toString') returns true on a tampered function where a native one returns false. |
Wrong-this TypeError |
Native getters throw a specific TypeError on the wrong receiver; a naive shim stays quiet, and the silence is the signal. |
| Realm re-acquisition | A detector grabs a pristine Function.prototype.toString from a fresh iframe or Web Worker and turns it on your getter — a different realm from your main-world patch. It returns your source. Caught. |
Clearcote has no such layer. The getter for navigator.vendor is the C++ getter: it reports [native code] because it is native code, identical across every realm — main frame, iframe, and worker. There is no JavaScript hijacking to detect.
Modern anti-bot systems read three structurally different surfaces, in three separate places. One tool rarely fixes all three:
| Layer | The tells | Where the fix lives | Clearcote |
|---|---|---|---|
| A · driver / binary artifacts | cdc_ ChromeDriver vars, the WebDriver protocol surface |
Drive raw CDP, skip chromedriver | ✅ a plain Chromium binary — no driver artifacts |
| B · CDP side-effects | Runtime.enable leaks, injected init-scripts, main-world execution, automation-default viewport |
The control / CDP-client layer | ✅ the SDK's launch defaults hold these back (isolated worlds, non-default viewport) |
| C · fingerprint surface | canvas, WebGL, audio, fonts, navigator, TLS — across main frame, iframes, workers |
The engine (C++), because JS overrides self-reveal (above) | ✅ this is Clearcote |
Because the controls live in the engine, the JavaScript a page sees and the network handshake underneath it come from one real Chromium. There is no spoofed-JS-over-real-TLS seam for a cross-check to catch — the exact failure mode that gives injection-based tools away. One --fingerprint seed produces a single, internally consistent machine across canvas, WebGL, audio, fonts, locale, hardware — and the TLS/HTTP-2 fingerprint underneath. And when the noise itself is the tell, switch it off (fingerprintNoise: false): canvas/WebGL/audio return their natural values while the identity spoof stays on.
Most "anti-detect" / stealth browsers are closed, paid binaries that rewrite your fingerprint with injected JavaScript or CDP hooks — brittle, self-revealing, and asking you to trust code you can't read. Clearcote inverts every one of those choices:
| Clearcote | Typical anti-detect browser | |
|---|---|---|
| Source | ✅ 100% open — every change is a readable patch | ❌ Closed binary |
| Price | ✅ Free | 💸 Paid subscription |
| How signals change | ✅ Compiled into the C++ engine — invisible to the page | |
| Coherence | ✅ One seed → a whole consistent machine; the JS identity and the real TLS/JA3/JA4 + HTTP/2 stack agree | |
| Trust model | ✅ Signed, checksummed, reproducible from source | ❌ "Trust us" |
| Automation | ✅ Drop-in Playwright / Puppeteer — returns a standard Browser |
|
| Real identities | ✅ Import a real machine (or the curated profile library) and verify it loaded | |
| Privacy | ✅ De-Googled, zero telemetry / phone-home |
From one --fingerprint seed or an imported real-machine profile, all kept coherent together:
- Identity — UA + UA-CH brand / platform / version + high-entropy hints (
bitness/wow64/model); a real "Google Chrome" or "Microsoft Edge" brand set — JSnavigator.userAgentDataand the HTTPSec-CH-UAheaders aligned. - GPU — WebGL unmasked vendor/renderer + the full
getParametertable & extension list, and WebGPU (navigator.gpu) limits/features kept coherent with that same GPU; session-constant. - Rendering — deterministic per-site canvas / WebGL / audio noise, or off — plus an experimental real-GPU canvas bridge that renders on a real GPU host for hardware-accurate readbacks.
- Fonts — the claimed OS's font families render present with correct advance widths (metric-compatible clones bundled with the Linux release), so a Windows persona on a Linux server has no absent-font or wrong-width tell.
- Hardware & screen —
hardwareConcurrency,deviceMemory,storageQuota, screen geometry / depth / DPR +getScreenDetails(), a realisticjsHeapSizeLimit, touch points. - Locale & network — timezone +
navigator.languages+Accept-Language+ the ICU /Intllocale all pinned to one language, geolocation, a coherent WebRTC egress IP (no STUN/LAN leak), and the TLS/HTTP-2 shape following the claimed Chrome version — all auto-matched to your proxy viageoip. - Long-tail — speech-synthesis voices, installed fonts,
MediaCapabilities.decodingInfo()codecs,enumerateDevices(), CSS@media(pointer / hover / color-gamut), battery, connection, keyboard layout. - Behavior — humanized, trusted bezier mouse input that keeps
navigator.webdriver = false.
Import a real machine — adopt the exact identity of a real Chrome (GPU + getParameter table, screen, fonts, voices, audio). Grab one from the curated clearcote-profiles library or capture your own with the collector — then prove it loaded with verify_profile.py.
Clearcote ships an in-browser AI agent: it runs inside the browser process, perceives the live page, asks an LLM what to do, and executes steps as real, trusted input via Chrome's native Actor framework — not a synthetic-event shim. Point it at OpenRouter (default) and switch any model with one slug.
import { launchAgent, runAgentTask } from "clearcote";
const ctx = await launchAgent({ agentLlmKey: process.env.OPENROUTER_API_KEY, agentModel: "openai/gpt-4o-mini" });
const page = ctx.pages()[0] ?? (await ctx.newPage());
await page.goto("https://news.ycombinator.com");
const result = await runAgentTask(page, "Open the top story and summarize it.", { maxSteps: 12 });
await ctx.close();It combines naturally with the fingerprint spoofing and humanize input above — an agent that looks human while it works. (Python: launch_agent() + run_agent_task().)
Every build is audited with scripts/creepjs_audit.py — it reads the signals the browser actually exposes, cross-checks them for internal consistency (e.g. UA vs UA-CH), confirms the WebRTC mock leaks no LAN address, and checks it isn't flagged as headless/automated.
Build 149.0.7827.114 · seed demo · platform windows
| Signal | Value | Verdict |
|---|---|---|
navigator.webdriver |
False | ✅ hidden |
| User-Agent ↔ UA-CH | Chrome/149 ↔ 149.0.7827.x |
✅ consistent |
| UA-CH platform | Windows 19.0.0 | ✅ |
| WebGL vendor / renderer | Google Inc. (Intel) / ANGLE (Intel, Intel(R) UHD Graphics 770 … Direct3D11 …) | ✅ spoofed |
| Canvas 2D | deterministic per seed | ✅ noised |
| Timezone | America/New_York | ✅ |
| WebRTC host (LAN) candidate | none | ✅ no LAN leak |
| WebRTC srflx (public) | = mocked egress IP | ✅ |
| Headless (hard) / Stealth-detect | 0% / 0% | ✅ |
Beyond the per-build audit, Clearcote is exercised against independent, third-party detection services and comes back clean across every category below. Service names are omitted by policy; the categories are what matter.
| Detection category | What it verifies | Result |
|---|---|---|
| 🤖 Webdriver / headless suites | navigator.webdriver, headless heuristics, plugin / UA tells |
✅ Hidden · normal headful Chrome |
| 🧩 Automation-framework leaks | CDP Runtime.enable leak, injected init-scripts, main-world execution |
✅ No leaks · isolated world |
| 🔒 TLS / JA4 client fingerprint | Handshake matches a real Chrome — no spoofed-JS-over-tooling-TLS seam | ✅ Genuine Chrome 149 JA4 |
| 📡 WebRTC leak tests | STUN / host candidates exposing a real LAN or ISP IP | ✅ Only the egress IP |
| 🎨 Canvas / WebGL / fonts / audio | Per-surface fingerprints render coherently and deterministically per seed | ✅ Coherent GPU + font metrics |
| 🌐 Locale / timezone coherence | JS Intl / timezone ↔ navigator.languages ↔ network egress all agree |
✅ Aligned end-to-end via geoip |
Honest scope. This is an experimental pre-release. The above is open-source, adversarial coherence auditing (a persona measured against a real Chrome on the same probe) — not published pass-rates against commercial services. And detection is only half the picture: a clean fingerprint over a burned proxy IP can still be blocked on IP reputation alone. Treat IP quality as a separate axis from browser identity.
Every release is GPG-signed, SHA-256-checksummed, and reproducible from source. Pin the Clearcote release signing key (it does not change between releases) and check every download against it:
CA96 F185 F96A 693A EDB3 AC1F CB00 D851 B7A8 6B0F
- docs/VERIFY.md — verify a release: signature, checksums, reproducibility, and diffing the patch set against pinned upstream.
- docs/STEALTH-COHERENCE.md — the regression gate that launches the shipped binary on every release.
Build the Windows (cross-compiled) or Linux (native) binary yourself on a Linux host:
git clone https://github.com/clearcotelabs/clearcote-browser.git
cd clearcote-browser && WORK=~/clearcote-build ./build.sh- docs/BUILDING.md — full build-from-source guide · patches/ — the 32 diffs · docs/PATCHES.md — what each one does.
Clearcote is free and open source, and the free build always will be — fully functional, and reproducible from source. Pro is simply how you support the project and get a maintained build.
Let me be blunt about what you're paying for. Keeping a Chromium fork current — tracking upstream, porting the anti-detection patches to every new Chromium version, testing, and building for Windows and Linux — is a lot of ongoing work, mostly mine. $49/month funds that work. In return you get:
- A maintained, always-current build — the latest Chromium and the newest anti-detection patches, kept up to date for you (no manual rebuilds).
- A few extra stealth patches I keep private so they aren't trivially copied. This means the Pro binary is not reproducible from public source — unlike the free build, which is, and stays that way.
- Unlimited concurrent instances.
- Direct email support from me, the owner. You email, I answer.
No lock-in, no dark patterns. The free build is not crippled to sell you Pro. Pro is a maintained build, a handful of patches I don't publish, and a direct line to the person who makes it.
→ Get Pro at clearcotelabs.com/pricing
| SDK options | sdk/node · sdk/python |
| Docs | VERIFY · BUILDING · CANVAS-BRIDGE · STEALTH-COHERENCE · PATCHES |
| For agents | AGENTS.md · llms.txt |
| Profiles | clearcote-profiles library · collector |
| Roadmap | ROADMAP.md — macOS, ARM64, more coherence |
Clearcote stands on excellent open-source work: Chromium (BSD-3), ungoogled-chromium (de-Googled base), fingerprint-chromium (engine-level fingerprint controls), Brave (the per-site "farbling" model), and Camoufox (a sibling open anti-detect browser). It's an independent project — not affiliated with or derived from any commercial product, and ships no proprietary code. Full attributions: CREDITS.md.
- ROADMAP.md — what's next (macOS, ARM64, more coherence, profile manager). ⭐ Star + watch to follow along.
- License — Clearcote's code and patches are BSD-3-Clause (LICENSE); upstream components keep their licenses (CREDITS.md).
- Responsible use — a privacy + automation tool for lawful purposes (privacy, QA/testing, research, authorized automation). Respect site terms and the law. Provided "as is." See DISCLAIMER.md.
Contributions welcome — see CONTRIBUTING.md and AGENTS.md.
Questions, feedback, or want to get involved? Join the Clearcote Discord.