CloakBrowser

CloakHQMIT活跃维护

基于 Chromium 源码级指纹补丁的隐身浏览器,可直接替换 Playwright,用于绕过 Cloudflare 等机器人检测与验证码,适合自动化采集和 AI Agent 场景。

Stealth Chromium that passes every bot detection test. Drop-in Playwright replacement with source-level fingerprint patches. 50+ tests passed.

chromium-v156.0.8078.47.1-pro发布于 2026-11-03 18:16 UTC32,820star +45 / 7 天2,727fork同步于 2026-11-10 17:21 UTC

怎么上手

由 README 提炼,执行前请确认
pip install cloakbrowser
npm install cloakbrowser playwright-core
硬件要求按 README 说明

README 未说明显存或 GPU 型号要求;二进制支持 Linux x64/ARM64、Windows x64、macOS(Apple Silicon 与 Intel)。无显示器时可用 Xvfb 虚拟显示配合 headless=False 运行。

支持 Apple Silicon有 Docker 镜像
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

源码级改指纹的隐身 Chromium,可直接替换 Playwright 绕过机器人检测

基于 Chromium 源码级指纹补丁的隐身浏览器,可直接替换 Playwright,用于绕过 Cloudflare 等机器人检测与验证码,适合自动化采集和 AI Agent 场景。

核心能力

  • 87 处 C++ 源码级补丁改 canvas、WebGL、字体、WebRTC 等指纹
  • humanize=True 生成类人鼠标轨迹、键盘时序与滚动
  • 保持 Playwright/Puppeteer 相同 API,改一行 import 即可迁移
  • 首次运行自动下载对应平台的 Chromium 二进制
  • 支持 HTTP/SOCKS5 代理与 geoip 自动匹配时区语言

容易踩的坑

每次启动都需要 license key,无终端环境要设 CLOAKBROWSER_LICENSE_KEY 环境变量;首次运行会额外下载约 200MB 的 Chromium 二进制;部分站点即使打了补丁也会识别 headless,需配住宅代理、geoip=True 和 headless=False,Linux 精简环境还需补装字体包。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本chromium-v156.0.8078.47.1-pro
  1. chromium-v156.0.8078.47.1-proChromium v156.0.8078.47.1 — Stealth Build (Pro)最新正式版2026-11-03 · 2026-11-03 18:16 UTC

    CloakBrowser Pro: Stable advances to Chromium 156.0.8078.47.1 (all platforms)

    Chromium 156.0.8078.47.1 is now Stable on Linux (x64 and ARM64), Windows (x64), and macOS (Apple Silicon and Intel).

    With a valid CloakBrowser key, the wrapper automatically selects the Stable build for your platform. No version pin is required.

    What's new

    • The newest Chromium, 156, on every platform.
    • License connection that finds another way through. When a license call can't get through, each retry now takes a different route to our servers instead of repeating the same one. This covers launch, heartbeat, and close. Seats are also released more reliably on close.
    • Real window geometry. The window, the page viewport, and the window position match a real maximized Chrome window for the Windows and macOS personas, in both headed and headless. The viewport is a bit shorter than before, so check scripts that rely on fixed screen coordinates.
    • WebRTC through your SOCKS5 proxy. With geoip=True, WebRTC traffic goes through your SOCKS5 proxy when the proxy supports UDP.
    • Popup blocking and navigation limits stay on, as in real Chrome, even when an automation tool asks to turn them off.
    • A much more convincing macOS persona on Linux, and closer to real Chrome everywhere: canvas (including inside workers), graphics card names, math, and Windows colors and fonts. On Linux, install the Mac fonts for the macOS persona.
    • New flag --fingerprint-max-touch-points=<N> to report a touch screen, like a Windows touch laptop.
    • On Windows and macOS, this also brings what Linux Stable already had: the more resilient license connection, request interception that no longer crashes the network process, more Windows fonts, correct Web Audio speed, and Google as the default search engine (--fingerprint-search-engine=google|bing|duckduckgo|none).

    Your profiles, cookies, and seeds are untouched. Only the browser itself is replaced.

    Current wrapper: v0.7.0

    Update the wrapper before launching:

    pip install -U cloakbrowser
    npm update cloakbrowser
    dotnet add package CloakBrowser --version 0.7.0
    

    Roll back if needed

    If a workload regresses, pin the previous Stable build for your platform:

    export CLOAKBROWSER_VERSION=155.0.8059.39.2   # Linux
    export CLOAKBROWSER_VERSION=155.0.8059.39.1   # Windows, macOS
    

    Remove the pin to return to the newest Stable build.

    If you hit a regression, please tell us. Open an issue or email [email protected] with the site and what you saw. Pinning the old build gets you unblocked; a report gets it fixed for everyone.

    Checksums (SHA-256)

    version=156.0.8078.47.1
    46f8361deb898019ef1a529da22b2c9a8f0e482c7a29600b39d932249c84a4b2  cloakbrowser-linux-x64.tar.gz
    c3f0ff8d2eca247ca28b3bc0a53cc37d69cde3878aeb4197bee61bda97c99559  cloakbrowser-linux-arm64.tar.gz
    74dd15bd8af28704f52e23ad55145c0b8c83ffeab4d9283a1779d89bd8bcc434  cloakbrowser-windows-x64.zip
    c29ba20dfe53b048760ebccb9a816eda08d0424e430208000d01d7bb216197c8  cloakbrowser-darwin-arm64.tar.gz
    1a260c6d31e26695f321a143977b175e7a72295357949da445e7a7a3a384bb5e  cloakbrowser-darwin-x64.tar.gz
    

    The signed manifest (SHA256SUMS and SHA256SUMS.sig) is attached. The wrapper verifies its Ed25519 signature and each archive's SHA-256 checksum automatically.

  2. chromium-v155.0.8059.39.2-proChromium v155.0.8059.39.2 — Stealth Build (Pro)2026-10-27 · 2026-10-27 21:02 UTC
    查看更新说明

    CloakBrowser Pro: Linux Stable advances to Chromium 155.0.8059.39.2

    Chromium 155.0.8059.39.2 is now Stable on Linux (x64 and ARM64). Windows and macOS Stable stay on 155.0.8059.39.1.

    With a valid CloakBrowser key, the wrapper automatically selects the Stable build for your platform. No version pin is required.

    What's new since 155.0.8059.39.1 (Linux)

    • A more resilient license connection. Launch and close now ride out brief network or server hiccups by retrying, and startup is a bit quicker. Seats are also released more reliably when you close the browser.
    • Request interception that holds up. Using page.route or other request interception no longer randomly crashes Chrome's network process.
    • More Windows fonts. Windows personas on Linux now include more app fonts, plus language-pack fonts that follow the locale. A fixed Windows seed will report more fonts than before.
    • Audio at the right speed. Web Audio now plays at the correct speed on 44.1 kHz and 96 kHz audio devices, and a page's own sample rate is respected.
    • Closer to real Chrome. The reported window position stays inside the screen's work area, a short GPU vendor flag such as intel reports the full vendor name, and one more popular fingerprint test now passes.
    • Google is the default search engine again when you use the browser directly. Choose another with --fingerprint-search-engine=google|bing|duckduckgo|none, or pass your own search URL.

    Your profiles, cookies, and seeds are untouched. Only the browser itself is replaced.

    Current wrapper: v0.6.4

    Update the wrapper before launching:

    pip install -U cloakbrowser
    npm update cloakbrowser
    dotnet add package CloakBrowser --version 0.6.4
    

    Roll back if needed

    If a workload regresses, pin the previous Linux Stable build:

    export CLOAKBROWSER_VERSION=155.0.8059.39.1
    

    Remove the pin to return to the newest Stable build.

    If you hit a regression, please tell us. Open an issue or email [email protected] with the site and what you saw. Pinning the old build gets you unblocked; a report gets it fixed for everyone.

    Checksums (SHA-256)

    version=155.0.8059.39.2
    d54521088fd2ca0a6584c490c7ce43d02d6e1190013a759517632d9b7d0a1c0d  cloakbrowser-linux-x64.tar.gz
    f9a2e4666de97f98e3bfdb5d96f9c3c32ae2aa09573b811226a3ddbad1f08430  cloakbrowser-linux-arm64.tar.gz
    

    The signed manifest (SHA256SUMS and SHA256SUMS.sig) is attached. The wrapper verifies its Ed25519 signature and each archive's SHA-256 checksum automatically.

  3. chromium-v155.0.8059.39.1-proChromium v155.0.8059.39.1 — Stealth Build (Pro)2026-10-20 · 2026-10-20 18:15 UTC
    查看更新说明

    CloakBrowser Pro: Stable advances to Chromium 155.0.8059.39.1 (all platforms)

    Chromium 155.0.8059.39.1 is now Stable on Linux (x64 and ARM64), Windows (x64), and macOS (Apple Silicon and Intel).

    With a valid CloakBrowser key, the wrapper automatically selects the Stable build for your platform. No version pin is required.

    What's new

    • The newest Chromium, 155, on every platform.
    • Windows and macOS catch up with Linux: safer proxy handling, the more patient license connection with the --license-route flag, and the refined Windows persona.
    • Closer to real Chrome everywhere: graphics checks, canvas exports, network timing, the reported CPU architecture on ARM hosts, and a few more Windows font names all behave the way real Chrome does on real hardware.
    • DNS that follows your proxy: with --fingerprint-transparent-proxy, sites are resolved with Cloudflare's DNS over HTTPS, sent through your proxy. Use your own with --fingerprint-transparent-proxy-dns=<url>, or local for the old behavior.
    • Clear license errors everywhere, a more stable macOS persona, quieter Windows security logs, and a smaller Linux download.

    Your profiles, cookies, and seeds are untouched. Only the browser itself is replaced.

    Current wrapper: v0.6.3

    Update the wrapper before launching:

    pip install -U cloakbrowser
    npm update cloakbrowser
    dotnet add package CloakBrowser --version 0.6.3
    

    Roll back if needed

    If a workload regresses, pin the previous Stable build for your platform:

    export CLOAKBROWSER_VERSION=154.0.8037.57.2   # Linux
    export CLOAKBROWSER_VERSION=154.0.8037.57.1   # Windows, macOS
    

    Remove the pin to return to the newest Stable build.

    If you hit a regression, please tell us. Open an issue or email [email protected] with the site and what you saw. Pinning the old build gets you unblocked; a report gets it fixed for everyone.

    Checksums (SHA-256)

    version=155.0.8059.39.1
    a345d8420712b4feb1db093c6f75b87b3a712dbe63d5e19ec56cac44683a1a65  cloakbrowser-linux-x64.tar.gz
    3f452084485957af8050f575a9347c002d1601cc61d2f2ec18d479d2f6471dff  cloakbrowser-linux-arm64.tar.gz
    3cd304226e0c75699368144428d07b3bff1c2b387951310f3f94b6e7dfd650b0  cloakbrowser-windows-x64.zip
    d13481c2d69e188e5f2ef12cd0a5403fe1634fe78f94b3c7b3e0086f79ae8473  cloakbrowser-darwin-arm64.tar.gz
    ebc078e492ad2d730cbad368e8ef0185b98aa2185998cf1b4c77a3f288231dac  cloakbrowser-darwin-x64.tar.gz
    

    The signed manifest (SHA256SUMS and SHA256SUMS.sig) is attached. The wrapper verifies its Ed25519 signature and each archive's SHA-256 checksum automatically.

  4. chromium-v154.0.8037.57.2-proChromium v154.0.8037.57.2 — Stealth Build (Pro)2026-10-13 · 2026-10-13 18:29 UTC
    查看更新说明

    CloakBrowser Pro: Linux Stable advances to Chromium 154.0.8037.57.2

    Chromium 154.0.8037.57.2 is now Stable on Linux (x64 and ARM64). Windows and macOS Stable stay on 154.0.8037.57.1.

    With a valid CloakBrowser key, the wrapper automatically selects the Stable build for your platform. No version pin is required.

    What's new since 154.0.8037.57.1 (Linux)

    • 3 to 6 times less CPU when running headed in Docker or on a GPU-less Linux server. Headless mode and machines with a real GPU are not affected.
    • Safer proxy handling. Proxy passwords with special characters now work, and a proxy setting the browser cannot read stops the connection instead of going out without the proxy.
    • A more patient license connection, with a new --license-route=auto|direct|proxy flag. auto is the default and works as before.
    • Windows persona hardware follows the graphics model. On Intel graphics profiles, a fixed seed may report different core and memory values than before.
    • Windows persona fonts match real Windows by default when the real Windows fonts are installed, so --fingerprint-windows-font-metrics is no longer needed.
    • The macOS persona on Linux matches a real Mac in two more details.

    Your profiles, cookies, and seeds are untouched. Only the browser itself is replaced.

    Current wrapper: v0.6.2

    Update the wrapper before launching:

    pip install -U cloakbrowser
    npm update cloakbrowser
    dotnet add package CloakBrowser --version 0.6.2
    

    Roll back if needed

    If a workload regresses, pin the previous Linux Stable build:

    export CLOAKBROWSER_VERSION=154.0.8037.57.1
    

    Remove the pin to return to the newest Stable build.

    If you hit a regression, please tell us. Open an issue or email [email protected] with the site and what you saw. Pinning the old build gets you unblocked; a report gets it fixed for everyone.

    Checksums (SHA-256)

    version=154.0.8037.57.2
    cee9eeda5d64b0a477b3a3f2ea6c99edb6fdd3ef840b91eca90ff4f37e538a63  cloakbrowser-linux-x64.tar.gz
    4a648032b2a1f96fc30bc1dcb73c608abe1c09654e92d28844c50e50e915fb61  cloakbrowser-linux-arm64.tar.gz
    

    The signed manifest (SHA256SUMS and SHA256SUMS.sig) is attached. The wrapper verifies its Ed25519 signature and each archive's SHA-256 checksum automatically.

  5. chromium-v154.0.8037.57.1-proChromium v154.0.8037.57.1 — Stealth Build (Pro)2026-10-06 · 2026-10-06 18:13 UTC
    查看更新说明

    CloakBrowser Pro: Stable advances to Chromium 154.0.8037.57.1 (all platforms)

    Chromium 154.0.8037.57.1 is now Stable on Linux (x64 and ARM64), Windows (x64), and macOS (Apple Silicon and Intel). This is the first Stable on Chromium 154, and every platform now runs the same engine.

    With a valid CloakBrowser key, the wrapper automatically selects the Stable build for your platform. No version pin is required.

    What's new

    • The newest Chromium, 154. The engine, its features, and the version it reports all step up to the current major, so you stay current with what real browsers ship.
    • Every platform on the same engine. Linux, Windows, and macOS now all run 154.
    • A big step for macOS. Mac Stable moves straight from 151 to 154 and picks up everything the 152 line brought to Linux and Windows.
    • Windows catches up with Linux. The language, rendering, and text improvements that reached Linux Stable last week are now on Windows too.

    Current wrapper: v0.5.12

    Update the wrapper before launching:

    pip install -U cloakbrowser
    npm update cloakbrowser
    dotnet add package CloakBrowser --version 0.5.12
    

    Roll back if needed

    If a workload regresses, pin the previous Stable build for your platform:

    export CLOAKBROWSER_VERSION=152.0.7977.82.2   # Linux
    export CLOAKBROWSER_VERSION=152.0.7977.82.1   # Windows
    export CLOAKBROWSER_VERSION=151.0.7922.108.3  # macOS
    

    Remove the pin to return to the newest Stable build.

    If you hit a regression, please tell us. Open an issue or email [email protected] with the site and what you saw. Pinning the old build gets you unblocked; a report gets it fixed for everyone.

    Checksums (SHA-256)

    version=154.0.8037.57.1
    0d31b5113ce4a3dab8edd2278e69472cde70ff90d841c73fa065c073c8b46a1b  cloakbrowser-linux-x64.tar.gz
    d0f7b19816869297bff25527d25a7bb08b3bfec98ddeaed52912cd693d7236fb  cloakbrowser-linux-arm64.tar.gz
    dd855c7325cd7a348e45c3638102b72325d7f9907bcdb5c7075274bcb2205321  cloakbrowser-windows-x64.zip
    08526e46462ef0b23aa0deb2e97fe320aa1e9b66dd70fff18a8424b80b5e4073  cloakbrowser-darwin-arm64.tar.gz
    90cafc5ba8bc295117d8bcd02036d30aa874bd5309e3fa2864f01cc15f7eacca  cloakbrowser-darwin-x64.tar.gz
    

    The signed manifest (SHA256SUMS and SHA256SUMS.sig) is attached. The wrapper verifies its Ed25519 signature and each archive's SHA-256 checksum automatically.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译
    • 87 source-level C++ patches — canvas, WebGL, audio, fonts, GPU, screen, WebRTC, network timing, automation signals, CDP input behavior
    • humanize=True — human-like mouse curves, keyboard timing, and scroll patterns. One flag, behavioral detection passes
    • Pro: 0.9 reCAPTCHA v3 score — human-level, server-verified
    • Passes Cloudflare Turnstile, FingerprintJS, BrowserScan — tested against 50+ detection sites
    • Auto-downloads the right binary — the latest build for your platform
    • pip install cloakbrowser or npm install cloakbrowser — binary auto-downloads, zero config
    • Latest binary, free to try — get a free key with your email (or just launch: the first run asks), point the newest build at your hardest target, scale to thousands of sessions on Pro

    Try it now — no install needed. The first run asks for a key: get one free with your email, or paste yours:

    docker run --rm -it cloakhq/cloakbrowser cloaktest
    

    Python:

    from cloakbrowser import launch
    
    browser = launch()
    page = browser.new_page()
    page.goto("https://example.com")
    browser.close()
    

    JavaScript (Playwright):

    import { launch } from 'cloakbrowser';
    
    const browser = await launch();
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await browser.close();
    

    Also works with Puppeteer: import { launch } from 'cloakbrowser/puppeteer' (details)

    For sites with anti-bot protection, add a residential proxy and these flags:

    browser = launch(
        proxy="http://user:pass@residential-proxy:port",  # residential IP, not datacenter
        geoip=True,       # match timezone + locale to proxy IP
        headless=False,    # some sites detect headless even with C++ patches
        humanize=True,     # human-like mouse, keyboard, scroll
    )
    
    const browser = await launch({
        proxy: 'http://user:pass@residential-proxy:port',
        geoip: true,
        headless: false,
        humanize: true,
    });
    

    See Troubleshooting for site-specific issues (Kasada, Akamai, reCAPTCHA).

    Install

    Python:

    pip install cloakbrowser
    

    JavaScript / Node.js:

    # With Playwright
    npm install cloakbrowser playwright-core
    
    # With Puppeteer
    npm install cloakbrowser puppeteer-core
    

    .NET / C#:

    dotnet add package CloakBrowser
    

    Community-maintained .NET client built on Microsoft.Playwright. See dotnet/README.md for the full API.


    On first run, the stealth Chromium binary is automatically downloaded (~200MB, cached locally).

    License key: every launch needs one, and a free key takes one email. The first launch in a terminal asks: get a free key (opens the signup page and continues once you confirm your email) or paste a key you have. In CI, Docker, or any run without a terminal, set CLOAKBROWSER_LICENSE_KEY (get one with cloakbrowser login or at cloakbrowser.dev/free).

    Optional: Auto-detect timezone/locale from proxy IP:

    pip install 'cloakbrowser[geoip]'
    

    Migrating from Playwright? One-line change:

    - from playwright.sync_api import sync_playwright
    - pw = sync_playwright().start()
    - browser = pw.chromium.launch()
    + from cloakbrowser import launch
    + browser = launch()
    
    page = browser.new_page()
    page.goto("https://example.com")
    # ... rest of your code works unchanged
    

    ⭐ Star to show support — Watch releases to get notified when new builds drop.


    Latest: v0.7.1 — 87 source-level stealth patches (Chromium 156.0.8078.47.1)

    • CloakBrowser Pro Stable — Chromium 156.0.8078.47.1 on Linux x64, Linux ARM64, Windows x64, and macOS (Apple Silicon and Intel). Set a license_key (licenseKey in JS) or the CLOAKBROWSER_LICENSE_KEY env var and the wrapper fetches the latest Stable build for your platform automatically. See CloakBrowser Pro
    • .NET 8 / C# client — CloakBrowser now ships as a NuGet package (CloakBrowser), mirroring the Python and JS wrappers.
    • Chromium 156 upgrade — rebased the full patch set onto Chromium 156 on every platform
    • 87 fingerprint patches — rendering consistency improvements across Linux and Windows, corrected GPU/display/graphics parameters to match stock Chrome profiles
    • Windows native GPU passthrough — real hardware values pass through directly instead of being spoofed, matching real browser behavior
    • HTTP proxy inline credentials — new network-layer support for proxies with inline authentication
    • extension_paths — load Chrome extensions in all launch functions
    • Humanize actionability — auto-wait for visible, enabled, stable elements before humanized actions
    • Per-call human_config — override humanize settings on individual method calls
    • Composable JS helpers — buildLaunchOptions() and humanizeBrowser() for custom Playwright integrations
    • Native SOCKS5 proxy — proxy="socks5://user:pass@host:port" works directly in all launch functions, Python + JS. QUIC/HTTP3 tunnels through SOCKS5 via UDP ASSOCIATE
    • Proxy signal removal — DNS/connect/SSL timing zeroed, proxy cache headers stripped, Proxy-Connection header leak removed
    • WebRTC IP spoofing — --fingerprint-webrtc-ip=auto resolves your proxy's exit IP and spoofs WebRTC ICE candidates. Auto-injected when using geoip=True (no extra network call)
    • humanize=True — one flag makes all mouse, keyboard, and scroll interactions behave like a real user. Bézier curves, per-character typing, realistic scroll patterns
    • Stealthy with zero flags — binary auto-generates a random fingerprint seed at startup. No configuration required
    • Timezone & locale from proxy IP — launch(proxy="...", geoip=True) auto-detects timezone and locale
    • Persistent profiles — launch_persistent_context() keeps cookies and localStorage across sessions

    See the full CHANGELOG.md for details.

    Why CloakBrowser?

    • Config-level patches break — playwright-stealth, undetected-chromedriver, and puppeteer-extra inject JavaScript or tweak flags. Every Chrome update breaks them. Antibot systems detect the patches themselves.
    • CloakBrowser patches Chromium source code — fingerprints are modified at the C++ level, compiled into the binary. Detection sites see a real browser because it is a real browser.
    • Source-level stealth — C++ patches handle fingerprints (GPU, screen, UA, hardware reporting) at the binary level. No JavaScript injection, no config-level hacks. Most stealth tools only patch at the surface.
    • Same behavior everywhere — works identically local, in Docker, and on VPS. No environment-specific patches or config needed.
    • Works with AI agents and automation frameworks — drop-in stealth for browser-use, Crawl4AI, Scrapling, Stagehand, LangChain, Selenium, and more. See integrations.

    CloakBrowser doesn't solve CAPTCHAs — it prevents them from appearing. No CAPTCHA-solving services, no proxy rotation built in — bring your own proxies, use the Playwright API you already know.

    CloakBrowser Pro

    Anti-bot systems change every week and an older binary quietly degrades. The latest build is the one that keeps passing. Try it free, then upgrade when you're running for real.

    • Free, latest build (Chromium 156) — the newest binary, the exact one that stays green against live detection. Free with your email, one concurrent session. Just launch (the first run asks), run cloakbrowser login, or grab your key, then throw it at your hardest target.
    • Pro — when it's part of production scraping, QA, monitoring, or automation: scale to 5, 20, 200, 2,000, or more concurrent sessions, always first on the newest patches, with hands-on support. Linux, Windows, macOS. See plans and pricing →
    cloakbrowser login          # get a free key by email, or paste a key you have
    # ...or set it directly (env var, license_key= param, or ~/.cloakbrowser/license.key):
    export CLOAKBROWSER_LICENSE_KEY=cb_xxxxxxxx
    

    Try the latest free → cloakbrowser.dev/free · Scale up on Pro → cloakbrowser.dev

    CloakBrowser Manager

    The anti-detect browser, with a GUI. A self-hosted alternative to Multilogin, GoLogin, and AdsPower, running on this same engine, on your own machine, not someone else's cloud.

    Every profile is a genuinely separate computer: its own fingerprint, GPU, screen, timezone, proxy, cookies, and history. Nothing bleeds between them. Close a profile, reopen it next month, and it's the same person, warmed up and ready.

    • Unlimited profiles — the big brands charge per profile and push you up a tier when you hit the ceiling. Here profiles are unlimited and you pay only for how many run at the same time. A drawer full of dormant accounts costs nothing.
    • Native desktop app — profiles open as normal windows on Windows and macOS. On a Linux server they run in Docker and stream to your browser.
    • The real engine — most profile managers inject JavaScript into a stock browser. Every profile here runs the patched Chromium binary this repo ships.
    • Automate what you can see — every running profile exposes a CDP endpoint. Drive it with Playwright or Puppeteer while you watch the exact same window live.
    • One key, both products — your CloakBrowser key works in the Manager too. Free with your email for one profile at a time.

    It's also the fastest way to try the browser without writing any code: download, create a profile, click Launch.

    Get the Manager → · Manager repo — the GUI is open source (MIT)

    Test Results

    All tests verified against live detection services. Results below are for the latest Pro/current build unless noted. Last tested: Nov 2026 (Chromium 156).

    Detection ServiceStock PlaywrightCloakBrowserNotes
    reCAPTCHA v30.1 (bot)0.9 (human)Pro/current build; server-side verified
    Cloudflare Turnstile (non-interactive)FAILPASSAuto-resolve
    Cloudflare Turnstile (managed)FAILPASSSingle click
    ShieldSquareBLOCKEDPASSProduction site
    FingerprintJS bot detectionDETECTEDPASSPro/current build; demo.fingerprint.com
    BrowserScan bot detectionDETECTEDNORMAL (4/4)browserscan.net
    bot.incolumitas.com13 fails1 failWEBDRIVER spec only
    deviceandbrowserinfo.com6 true flags0 true flagsisBot: false
    navigator.webdrivertruefalseSource-level patch
    navigator.plugins.length05Real plugin list
    window.chromeundefinedobjectPresent like real Chrome
    UA stringHeadlessChromeChrome/156.0.0.0No headless leak
    CDP detectionDetectedNot detectedisAutomatedWithCDP: false
    TLS fingerprintMismatchIdentical to Chromeja3n/ja4/akamai match
    Tested against 50+ detection sites

    Proof

    Comparison

    FeaturePlaywrightplaywright-stealthundetected-chromedriverCloakBrowser
    reCAPTCHA v3 score (Pro/current)0.10.3-0.50.3-0.70.9
    Cloudflare TurnstileFailSometimesSometimesPass
    Headless / Docker detectionFlaggedFlaggedFlaggedPasses
    Patch levelNoneJS injectionConfig patchesC++ (Chromium)
    Survives Chrome updatesN/ABreaks oftenBreaks oftenYes
    MaintainedYesStaleStaleActive
    Browser engineChromiumChromiumChromeChromium
    Playwright APINativeNativeNo (Selenium)Native

    How It Works

    CloakBrowser is a thin wrapper (Python + JavaScript) around a custom-built Chromium binary:

    1. You install → pip install cloakbrowser or npm install cloakbrowser
    2. First launch → asks for a license key if you have none (free by email), then the latest build auto-downloads for your platform
    3. Every launch → Playwright or Puppeteer starts with our binary + stealth args
    4. You write code → standard Playwright/Puppeteer API, nothing new to learn

    The binary includes 87 source-level patches covering canvas, WebGL, audio, fonts, GPU, screen properties, WebRTC, network timing, hardware reporting, automation signal removal, and CDP input behavior mimicking.

    These are compiled into the Chromium binary — not injected via JavaScript, not set via flags.

    Binary downloads are verified against a pinned Ed25519 signature on the published checksums before extraction, so the download is confirmed authentic (genuinely ours) and not just intact. A compromised mirror cannot serve a tampered or downgraded binary.

    API

    launch()

    from cloakbrowser import launch
    
    # Basic — headless, default stealth config
    browser = launch()
    
    # Headed mode (see the browser window)
    browser = launch(headless=False)
    
    # Pass a key explicitly (free via `cloakbrowser login`, or paid); otherwise the env var or saved key is used
    browser = launch(license_key="cb_xxxxxxxx")
    
    # With proxy (HTTP or SOCKS5)
    browser = launch(proxy="http://user:pass@proxy:8080")
    browser = launch(proxy="socks5://user:pass@proxy:1080")
    
    # With proxy dict (bypass, separate auth fields)
    browser = launch(proxy={"server": "http://proxy:8080", "bypass": ".google.com", "username": "user", "password": "pass"})
    
    # With extra Chrome args
    browser = launch(args=["--disable-gpu"])
    
    # Auto-detect timezone/locale from proxy IP (requires: pip install cloakbrowser[geoip])
    # Also auto-injects --fingerprint-webrtc-ip to prevent WebRTC IP leaks (no extra cost)
    # Note: makes HTTP calls through your proxy to resolve exit IP (ipify.org, checkip.amazonaws.com)
    browser = launch(proxy="http://proxy:8080", geoip=True)
    
    # WebRTC IP spoofing only (no geoip dep needed — resolves exit IP via HTTP call through proxy)
    browser = launch(proxy="http://proxy:8080", args=["--fingerprint-webrtc-ip=auto"])
    
    # Explicit WebRTC IP (no network call)
    browser = launch(proxy="http://proxy:8080", args=["--fingerprint-webrtc-ip=1.2.3.4"])
    
    # Human-like mouse, keyboard, and scroll behavior
    browser = launch(humanize=True)
    
    # With slower, more deliberate movements
    browser = launch(humanize=True, human_preset="careful")
    
    # Without default stealth args (bring your own fingerprint flags)
    browser = launch(stealth_args=False, args=["--fingerprint=12345"])
    

    Returns a standard Playwright Browser object. All Playwright methods work: new_page(), new_context(), close(), etc.

    launch_async()

    import asyncio
    from cloakbrowser import launch_async
    
    async def main():
        browser = await launch_async()
        page = await browser.new_page()
        await page.goto("https://example.com")
        print(await page.title())
        await browser.close()
    
    asyncio.run(main())
    

    launch_context()

    Convenience function that creates browser + context in one call:

    from cloakbrowser import launch_context
    
    context = launch_context(
        proxy="http://user:pass@residential-proxy:port",
        geoip=True,
        headless=False,
        humanize=True,
    )
    page = context.new_page()
    page.goto("https://protected-site.com")
    context.close()
    

    Extra kwargs are forwarded to Playwright's browser.new_context() — use this for storage_state, permissions, extra_http_headers, etc. without needing a persistent profile folder:

    from cloakbrowser import launch_context
    
    # Restore a saved session (cookies, localStorage) from a JSON file
    context = launch_context(storage_state="state.json")
    page = context.new_page()
    page.goto("https://example.com")
    # Save state back for next run
    context.storage_state(path="state.json")
    context.close()
    

    launch_context_async()

    Async counterpart to launch_context(). Same signature and kwargs forwarding:

    import asyncio
    from cloakbrowser import launch_context_async
    
    async def main():
        ctx = await launch_context_async(storage_state="state.json")
        page = await ctx.new_page()
        await page.goto("https://example.com")
        await ctx.storage_state(path="state.json")
        await ctx.close()
    
    asyncio.run(main())
    

    launch_persistent_context()

    Same as launch_context(), but with a persistent user profile. Cookies, localStorage, and cache persist across sessions.

    A persistent profile keeps its fingerprint seed across launches (stored in .cloakbrowser-seed inside the profile; an explicit --fingerprint= in args overrides it, and a corrupt file is replaced with a warning). To rotate the identity, delete .cloakbrowser-seed and the next launch picks a new seed.

    Use this when you need to:

    • Stay logged in across runs (cookies/sessions survive restarts)
    • Load Chrome extensions (extensions only work from a real user data dir)
    • Build natural browsing history (cached fonts, service workers, IndexedDB accumulate over time, making the profile look more realistic)
    from cloakbrowser import launch_persistent_context
    
    # First run — creates the profile
    ctx = launch_persistent_context("./my-profile", headless=False)
    page = ctx.new_page()
    page.goto("https://protected-site.com")
    ctx.close()  # profile saved
    
    # Next run — cookies, localStorage restored automatically
    ctx = launch_persistent_context("./my-profile", headless=False)
    
    # Load Chrome extensions
    ctx = launch_persistent_context(
        "./my-profile",
        headless=False,
        extension_paths=["./my-extension"],
    )
    

    Supports all the same options as launch_context(): proxy, user_agent, viewport, locale, timezone, color_scheme, geoip, extension_paths.

    Async version: launch_persistent_context_async().

    CLI

    Pre-download the binary, diagnose your setup, or manage the cache from the command line:

    python -m cloakbrowser login        # Get a free key by email, or save a key you have
    python -m cloakbrowser logout       # Remove the saved key
    python -m cloakbrowser install      # Download binary with progress output
    python -m cloakbrowser info         # Diagnostics: binary that will launch, license tier, env checks
    python -m cloakbrowser update       # Check for and download newer binary
    python -m cloakbrowser clear-cache  # Remove cached binaries
    

    login with no argument shows the same menu as a first launch without a key: 1) get a free key (opens the signup page in your browser, then waits until you confirm your email) or 2) paste a key you have. login <key> saves a key directly. Keys are validated, then stored at ~/.cloakbrowser/license.key (readable by you only) so every launch picks them up.

    info reports the binary that will actually launch given your license, runs a quick launch test (and flags missing system libraries on Linux), shows your license tier, and checks fonts, GeoIP, and optional dependencies. Add --quick to skip the launch test or --json for machine-readable output. Add --proxy <url> to resolve the exit IP, timezone, and locale a launch would apply through that proxy (the same geoip=True resolution; downloads the GeoIP DB if not cached) — useful for confirming a proxy hands you a timezone/locale that matches its exit IP.

    CLOAKBROWSER_RELEASE_CHANNEL=preview also applies to install, info, and update. info shows the exact version that will launch and whether Preview resolved to Stable for the current platform.

    The same commands are available via npx cloakbrowser <command> (JS) and the cloakbrowser CLI (.NET).

    Utility Functions

    from cloakbrowser import binary_info, clear_cache, ensure_binary
    
    # Check binary installation status
    print(binary_info())
    # {'version': '156.0.8078.47.1', 'platform': 'linux-x64', 'installed': True, ...}
    # ('version' is None until a build has been downloaded)
    
    # Force re-download
    clear_cache()
    
    # Pre-download binary (e.g., during Docker build; needs CLOAKBROWSER_LICENSE_KEY set)
    ensure_binary()
    

    JavaScript / Node.js API

    CloakBrowser ships a TypeScript package with full type definitions. Choose Playwright or Puppeteer — same stealth binary underneath.

    Playwright (default)

    import { launch, launchContext, launchPersistentContext } from 'cloakbrowser';
    
    // Recommended
    const browser = await launch({
      proxy: 'http://user:pass@residential-proxy:port',
      geoip: true,      // match timezone + locale to proxy IP
      headless: false,
      humanize: true,
    });
    
    // Pro — use the latest binary (or set CLOAKBROWSER_LICENSE_KEY env var)
    const browser = await launch({
      licenseKey: 'cb_xxxxxxxx',
      proxy: 'http://user:pass@residential-proxy:port',
      geoip: true,
      headless: false,
      humanize: true,
    });
    
    // Convenience: browser + context in one call
    const context = await launchContext({
      proxy: 'http://user:pass@residential-proxy:port',
      geoip: true,
      headless: false,
      humanize: true,
    });
    const page = await context.newPage();
    
    // Persistent profile — cookies/localStorage survive restarts
    const ctx = await launchPersistentContext({
      userDataDir: './chrome-profile',
      proxy: 'http://user:pass@residential-proxy:port',
      geoip: true,
      headless: false,
      humanize: true,
    });
    

    Note: Each example above is standalone — not meant to run as one block.

    All Python options work in JS: stealthArgs: false to disable defaults, geoip: true to auto-detect timezone/locale from proxy IP.

    Puppeteer

    Note: The Playwright wrapper is recommended for sites with reCAPTCHA Enterprise. Puppeteer's CDP protocol leaks automation signals that reCAPTCHA Enterprise can detect, causing intermittent 403 errors. This is a known Puppeteer limitation, not specific to CloakBrowser. Use Playwright for best results.

    import { launch } from 'cloakbrowser/puppeteer';
    
    const browser = await launch({
      proxy: 'http://user:pass@residential-proxy:port',
      geoip: true,
      headless: false,
      humanize: true,
    });
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await browser.close();
    

    Utility Functions (JS)

    import { ensureBinary, clearCache, binaryInfo } from 'cloakbrowser';
    
    // Pre-download binary (e.g., during Docker build)
    await ensureBinary();
    
    // Check installation status
    console.log(binaryInfo());
    
    // Force re-download
    clearCache();
    

    Human Behavior

    Pass humanize=True to make all mouse, keyboard, scroll and element-read interactions indistinguishable from real users. All Playwright calls (page.click(), page.fill(), page.type(), page.mouse.*, page.keyboard.*, page.input_value(), page.text_content(), page.inner_text(), page.inner_html(), page.get_attribute(), Locator API) and Puppeteer calls (page.click(), page.type(), page.mouse.*, page.keyboard.*, ElementHandle API) are automatically replaced with human-like equivalents. No code changes needed.

    browser = launch(humanize=True)
    page = browser.new_page()
    page.goto("https://example.com")
    page.locator("#email").fill("[email protected]")  # per-character timing, thinking pauses
    page.locator("button[type=submit]").click()       # Bézier curve, realistic aim point
    
    // Playwright
    import { launch } from 'cloakbrowser';
    const browser = await launch({ humanize: true });
    
    // Puppeteer
    import { launch } from 'cloakbrowser/puppeteer';
    const browser = await launch({ humanize: true });
    

    What changes:

    InteractionDefaultWith humanize=True
    Mouse movementInstant teleportBézier curve with easing and slight overshoot
    ClicksInstantRealistic aim point + hold duration
    KeyboardInstant fillPer-character timing, thinking pauses, occasional typos with self-correction
    ScrollJumpAccelerate → cruise → decelerate micro-steps
    fill()Instant value setClears existing content, types character by character

    Presets — default (normal speed) or careful (slower, more deliberate, idle micro-movements between actions):

    browser = launch(humanize=True, human_preset="careful")
    
    const browser = await launch({ humanize: true, humanPreset: 'careful' });
    

    Custom config — override any parameter:

    browser = launch(humanize=True, human_config={
        "mistype_chance": 0.05,              # 5% typo rate with self-correction
        "typing_delay": 200,                 # slower typing (ms between keys)
        "idle_between_actions": True,        # micro-movements between clicks
        "idle_between_duration": [0.3, 0.8], # idle duration range (seconds)
    })
    
    const browser = await launch({
        humanize: true,
        humanConfig: {
            mistype_chance: 0.05,
            typing_delay: 200,
            idle_between_actions: true,
            idle_between_duration: [0.3, 0.8],
        }
    });
    

    Access the original un-patched Playwright page at page._original if you need raw speed for a specific call — this includes the reads (page._original.input_value(...), text_content, inner_text, inner_html, get_attribute), which are humanized by default.

    For an arbitrary expression, page._stealth_world.evaluate("…") evaluates it in the isolated world the humanize engine uses.

    Note (Playwright): Always use page.click(selector), page.type(selector, text), page.hover(selector), or page.locator(selector).* — these go through the full humanize pipeline. Avoid page.query_selector() — ElementHandle objects bypass all patches, so mouse movement teleports, keyboard events fire without timing, and scroll has no human curve.

    Note (Puppeteer): Both selector-based methods (page.click(), page.type()) and ElementHandle methods (el.click(), el.type()) are fully humanized. page.$(), page.$$(), and page.waitForSelector() return patched handles automatically.

    Contributed by @evelaa123 — full Playwright and Puppeteer API coverage.

    Configuration

    Env VariableDefaultDescription
    CLOAKBROWSER_LICENSE_KEY—Your license key (free or paid). Overrides ~/.cloakbrowser/license.key. Required wherever there is no terminal to ask (CI, Docker)
    CLOAKBROWSER_BINARY_PATH—Skip download, use a local Chromium binary
    CLOAKBROWSER_CACHE_DIR~/.cloakbrowserBinary cache directory
    CLOAKBROWSER_AUTO_UPDATEtrueSet to false to keep the cached build and skip update checks
    CLOAKBROWSER_GEOIP_TIMEOUT_SECONDS5Max seconds for GeoIP resolution before continuing without it
    CLOAKBROWSER_VERSION—Pin to an exact Chromium version for rollback (e.g. 155.0.8059.39.1). Paid Pro key only
    CLOAKBROWSER_RELEASE_CHANNELstableSet to preview to opt into the Preview binary channel

    Fingerprint Management

    The binary is stealthy by default — no flags needed. It auto-generates a random fingerprint seed at startup and spoofs all detectable values (GPU, hardware specs, screen dimensions, canvas, WebGL, audio, fonts). Every launch produces a fresh, coherent identity.

    How fingerprinting works:

    ScenarioWhat happens
    No flagsRandom seed auto-generated at startup. GPU, screen, hardware specs, and all noise patches are spoofed automatically. Fresh identity each launch.
    --fingerprint=seedDeterministic identity from the seed. Same seed = same fingerprint across launches. For a returning visitor, use a persistent profile instead (it keeps its own seed).
    --fingerprint=seed + explicit flagsExplicit flags override individual auto-generated values. The seed fills in everything else.

    On Linux and Windows the wrapper presents as a Windows desktop (more common fingerprint, harder to cluster); on macOS it runs as a native Mac.

    macOS persona (a second identity). Alongside the Windows persona, pass --fingerprint-platform=macos to present as a Mac — lined up with real Mac hardware across graphics, media, fonts, text, screen, and device features. Two things to set up: install the Mac fonts (the same way the Windows persona needs Windows fonts — see Font Setup on Linux; a persona without its fonts is a common cause of blocks), and for the most realistic result give it a large display — on a 4K screen it reports at the DPR most real Macs use. Having both the Windows and macOS personas gives you two strong identities to rotate between.

    Tip: revisiting the same site? Use a persistent profile. A persistent profile saves its own seed on first launch and reuses it, so you come back as the same device with your cookies and storage intact. No seed flag needed. A fixed --fingerprint= with plain launch() is the same device with an empty profile every time.

    ctx = launch_persistent_context("./my-profile")
    
    const ctx = await launchPersistentContext({ userDataDir: './my-profile' });
    

    Default Fingerprint

    Every launch() call sets these automatically. The wrapper applies platform-aware defaults — on Linux it spoofs as Windows for a more common fingerprint, on macOS it runs as a native Mac browser:

    FlagLinux/Windows DefaultmacOS DefaultControls
    --fingerprintRandom (10000–99999)Random (10000–99999)Master seed for canvas, WebGL, audio, fonts
    --fingerprint-platformwindowsmacosnavigator.platform, User-Agent OS, GPU pool selection

    The binary auto-generates everything else from the seed: GPU, hardware concurrency, device memory, and screen dimensions. Each seed produces a unique, consistent fingerprint: those values are drawn together as one coherent package. Keep the seed as the source of identity, since changing single values by hand can break that coherence.

    Additional Flags

    Supported by the binary but not set by default — pass via args to customize:

    FlagControls
    --fingerprint-gpu-vendorSwitch the GPU family — NVIDIA or Intel. The binary reports the matching Chrome vendor value, Google Inc. (NVIDIA) or Google Inc. (Intel). Auto-generated from seed + platform when unset
    --fingerprint-hardware-concurrencynavigator.hardwareConcurrency (seed-derived when unset)
    --fingerprint-device-memorynavigator.deviceMemory in GB (seed-derived when unset)
    --fingerprint-screen-widthScreen width (seed-derived when unset)
    --fingerprint-screen-heightScreen height (seed-derived when unset)
    --fingerprint-platform-versionClient Hints platform version
    --fingerprint-timezoneTimezone (e.g. America/New_York)
    --fingerprint-localeLocale (e.g. en-US)
    --fingerprint-storage-quotaStorage headroom in MB, reported on top of current usage — affects storage.estimate(), storageBuckets, and legacy webkit APIs. Default 10 GiB, like a regular Chrome profile
    --fingerprint-taskbar-heightOverride taskbar height (binary defaults: Win=48, Mac=95, Linux=0)
    --fingerprint-webrtc-ipWebRTC ICE candidate IP replacement. Use auto to resolve from proxy exit IP (makes an HTTP call through the proxy), or pass an explicit IP. Auto-injected when geoip=True
    --fingerprint-noise=falseDisable noise injection (canvas, WebGL, audio) while keeping the deterministic fingerprint seed active
    --fingerprint=offPass-through debug mode — turns spoofing off and presents the machine's real native fingerprint (keeps only the baseline any Chrome needs). The binary strips the injected seed and --fingerprint-platform, so there's no mixed OS profile. Most useful on a genuine Windows machine to check whether an issue is our spoofing or the environment. Accepts off/false/0/disable/disabled. For a pure pass-through don't combine it with geoip=True / explicit timezone / locale — those stay applied.
    --fingerprint-allow-3p-cookiesRe-enable third-party cookies for embedded flows that need them (reCAPTCHA v3, SSO, some payment challenges). Off by default; turn on only where a login/payment/embedded challenge loads but never finishes.
    --fingerprint-sapi-voices=falseOpt out of the Windows speech-voice tables when spoofing Windows. On by default (the voice set matches a real Chrome install); turn off only if a target reacts badly to the Windows voice list.
    --fingerprint-max-touch-points=<N>Report a touch screen with N touch points, like a Windows touch laptop. Default 0 (no touch). 156+
    --fingerprint-search-engine=google|bing|duckduckgo|noneDefault search engine when you use the browser directly. Default google; you can also pass your own search URL. 155.0.8059.39.2+ on Linux, 156+ on all platforms
    --license-route=auto|direct|proxyHow the Pro license and session calls leave the browser. auto (default): direct to cloakbrowser.dev first, and one retry through your --proxy-server if direct can't reach it. direct: never through the proxy. proxy: only through the proxy (needs --proxy-server).
    --license-through-proxyOlder spelling of --license-route=proxy: route the Pro license/session calls through your --proxy-server instead of direct to cloakbrowser.dev. Still works; prefer --license-route=proxy.
    --fingerprint-transparent-proxyA stronger way of connecting through your --proxy-server, for sites and providers that block every proxy you try. Off by default; enable it alongside --proxy-server.
    --fingerprint-transparent-proxy-dns=<url>|localLinux and Windows. DNS for --fingerprint-transparent-proxy mode. By default sites are resolved with Cloudflare's DNS over HTTPS, sent through your proxy. Pass your own DNS over HTTPS address, or local to resolve on your own machine as before.
    --fingerprint-portable-cookiesEncrypt cookies with a machine-independent key so a copied profile keeps its logins across machines. Turn it on from the first launch — it changes how cookies are written, so a cookie is only portable if this was set when it was saved.
    --enable-blink-features=FakeShadowRootAccess closed shadow DOM elements

    Note: All stealth tests were verified with the default fingerprint config above. Changing these flags may affect detection results — test your configuration before using in production.

    Font Setup on Linux

    On Linux, CloakBrowser spoofs the Windows platform by default. Two font layers matter, and most setups only do the first:

    1. Baseline (minimal) — emoji + CJK canvas fonts. Aggressive anti-bot systems (Kasada, Akamai) render emoji on a hidden canvas and hash the pixel output. Minimal Linux environments (Docker, cloud VMs) lack these, producing hashes that don't match any real browser. This is the floor, not the finish line:

    sudo apt install -y fonts-noto-color-emoji fonts-freefont-ttf fonts-unifont \
        fonts-ipafont-gothic fonts-wqy-zenhei fonts-tlwg-loma-otf
    

    The Docker image (cloakhq/cloakbrowser) ships with these pre-installed. If you run the binary directly on a Linux server or in a custom Docker image, install them manually.

    2. Real Windows fonts — strongly recommended. Since the Linux default persona is Windows, a Windows browser with no Windows fonts is itself a bot tell: font-fingerprinting anti-bot (FingerprintJS) flags the mismatch, and CreepJS font enumeration scores poorly. The apt packages above do not provide these — they are Microsoft-proprietary and cannot be installed from a package repo, and ttf-mscorefonts-installer only has old XP-era fonts (not enough).

    Copy the fonts from a real Windows machine's C:\Windows\Fonts\ directory. The wrapper keeps warning until it finds all of: Segoe UI, Segoe UI Light, Calibri, Marlett, MS UI Gothic, Franklin Gothic, Consolas, Courier New (copying the whole Fonts folder covers these and more):

    mkdir -p ~/.local/share/fonts/windows
    cp -r /path/to/windows/Fonts/. ~/.local/share/fonts/windows/
    fc-cache -f
    

    In Docker or an image build, copy to a system font dir instead — it is user-independent and matches where the image's own fonts live (our published image installs its fonts under /usr/share/fonts/):

    COPY windows-fonts/ /usr/local/share/fonts/windows/
    RUN fc-cache -f
    

    Confirm they registered with fc-list | grep -i "segoe\|calibri\|consolas". Once all are present the warning stops on its own; set CLOAKBROWSER_SUPPRESS_FONT_WARNING=1 to silence it if you accept the tradeoff.

    3. Real Mac fonts — for the macOS persona (--fingerprint-platform=macos). If you run the macOS persona, install the real Mac fonts, the same way the Windows persona needs Windows fonts — a Mac browser with no Mac fonts is a bot tell. Copy them from a real Mac's font folders (/System/Library/Fonts/, /System/Library/Fonts/Supplemental/, /Library/Fonts/) into ~/.local/share/fonts, then run fc-cache -f:

    mkdir -p ~/.local/share/fonts/mac
    cp -r /path/to/mac/Fonts/. ~/.local/share/fonts/mac/
    fc-cache -f
    

    In Docker or an image build, copy to a system font dir instead (user-independent, matches where the image's own fonts live under /usr/share/fonts/):

    COPY mac-fonts/ /usr/local/share/fonts/mac/
    RUN fc-cache -f
    

    cloakbrowser info reports how many it finds (Mac fonts: N/total) and names the ones it looks for (Helvetica Neue, Menlo, and the SF/Apple system fonts among them). Several Mac fonts (Arial, Georgia, Times New Roman, Courier New, Tahoma) also ship on Windows, so a partial count on a Windows-provisioned host is normal.

    Examples

    # Pin a specific seed
    browser = launch(args=["--fingerprint=42069"])
    
    # Full control — disable defaults, set everything yourself
    browser = launch(stealth_args=False, args=[
        "--fingerprint=42069",
        "--fingerprint-platform=windows",
    ])
    
    # Switch the GPU family
    browser = launch(args=[
        "--fingerprint=42069",
        "--fingerprint-gpu-vendor=Intel",
    ])
    

    Examples

    Python — see examples/:

    JavaScript — see js/examples/:

    Framework Integrations

    CloakBrowser works with any framework that uses Playwright or Chromium:

    # Option 1: Framework launches our binary directly (Selenium, Stagehand, UC)
    from cloakbrowser.download import ensure_binary
    from cloakbrowser.config import get_default_stealth_args
    binary_path = ensure_binary()          # auto-downloads if needed
    stealth_args = get_default_stealth_args()  # all fingerprint flags
    
    # Option 2: CloakBrowser launches first, framework connects via CDP (browser-use, Crawl4AI, Scrapling)
    from cloakbrowser import launch_async
    browser = await launch_async(args=["--remote-debugging-port=9242"])
    # Connect your framework to http://127.0.0.1:9242 — all stealth flags are set
    # Note: humanize requires the wrapper (see below)
    

    Humanize over CDP: Stealth fingerprint patches work automatically over CDP, but humanize=True is a wrapper-level feature. If you connect to CloakBrowser via CDP from a separate script, import the patching functions to add humanization:

    import { patchBrowser, resolveConfig } from 'cloakbrowser/human';
    patchBrowser(browser, resolveConfig('default'));
    
    FrameworkStarsLanguageExample
    browser-use120KPythonbrowser_use_example.py
    Crawl4AI87KPythoncrawl4ai_example.py
    Crawlee9.6KPythoncrawlee_example.py
    Scrapling91KPythonscrapling_example.py
    Stagehand26KTypeScriptstagehand.ts
    LangChain149KPythonlangchain_loader.py
    Selenium—Pythonselenium_example.py
    undetected-chromedriver13KPythonundetected_chromedriver.py
    agent-browser45KShellagent_browser.sh

    Deployment Integrations

    PlatformExample
    AWS Lambdaaws_lambda/ — One-shot scrapes in Lambda (container image)

    Platforms

    PlatformBinaryStatus
    Linux x86_64Chromium 156 (87 patches)✅
    Linux arm64 (RPi, Graviton)Chromium 156 (87 patches)✅
    macOS arm64 (Apple Silicon)Chromium 156 (87 patches)✅
    macOS x86_64 (Intel)Chromium 156 (87 patches)✅
    Windows x86_64Chromium 156 (87 patches)✅

    The wrapper auto-downloads the correct binary for your platform. Free and Pro keys get the same build; Pro raises the number of concurrent sessions.

    macOS first launch: The binary is ad-hoc signed. On first run, macOS Gatekeeper will block it. Right-click the app → Open → click Open in the dialog. This is only needed once.

    Docker

    Pre-built image on Docker Hub — no install, no setup.

    License key: the image has no binary inside; the latest build downloads on the first launch with your key. Run with -it and the first launch asks for one, as in the quick test below (the key and binary live in the container, so --rm discards them). For scripts, servers and Compose, pass the key instead: export CLOAKBROWSER_LICENSE_KEY=cb_xxx on the host, then -e CLOAKBROWSER_LICENSE_KEY (as below), or set it in Compose. A free key takes one email: cloakbrowser login or cloakbrowser.dev/free.

    Quick test

    # Interactive: asks for a key (free by email, or paste yours)
    docker run --rm -it cloakhq/cloakbrowser cloaktest
    
    # With your key in the environment (scripts, CI)
    docker run --rm -e CLOAKBROWSER_LICENSE_KEY cloakhq/cloakbrowser cloaktest
    

    Run a script

    # Inline script
    docker run --rm -e CLOAKBROWSER_LICENSE_KEY cloakhq/cloakbrowser python -c "
    from cloakbrowser import launch
    browser = launch()
    page = browser.new_page()
    page.goto('https://example.com')
    print(page.title())
    browser.close()
    "
    
    # Mount your own script
    docker run --rm -e CLOAKBROWSER_LICENSE_KEY -v ./my_script.py:/app/my_script.py cloakhq/cloakbrowser python my_script.py
    
    # With a proxy
    docker run --rm -e CLOAKBROWSER_LICENSE_KEY cloakhq/cloakbrowser python -c "
    from cloakbrowser import launch
    browser = launch(proxy='http://user:pass@proxy:8080', geoip=True)
    page = browser.new_page()
    page.goto('https://example.com')
    print(page.title())
    browser.close()
    "
    

    CDP server mode

    Start a persistent stealth browser and connect to it remotely via Chrome DevTools Protocol:

    docker run -d --name cloak -e CLOAKBROWSER_LICENSE_KEY -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser cloakserve
    

    Then connect from your host machine:

    from playwright.sync_api import sync_playwright
    
    pw = sync_playwright().start()
    browser = pw.chromium.connect_over_cdp("http://localhost:9222")
    page = browser.new_page()
    page.goto("https://example.com")
    print(page.title())
    browser.close()  # Disconnects from CDP; cloakserve keeps Chrome running
    

    With connect_over_cdp(), Playwright does not own the remote Chrome process. browser.close() only disconnects the client, so Chrome keeps running and continues holding its Pro session seat. To terminate it immediately, connect with a named fingerprint seed and call the close endpoint:

    curl -X POST http://localhost:9222/fingerprint/11111/close
    

    If your framework needs a direct WebSocket endpoint, fetch Chrome's discovery document and use the rewritten webSocketDebuggerUrl. The URL points back through cloakserve so the CDP proxy can keep per-seed routing intact:

    curl http://localhost:9222/json/version | jq -r .webSocketDebuggerUrl
    # ws://localhost:9222/devtools/browser/<browser-id>
    
    curl 'http://localhost:9222/json/version?fingerprint=11111' | jq -r .webSocketDebuggerUrl
    # ws://localhost:9222/fingerprint/11111/devtools/browser/<browser-id>
    

    When cloakserve runs behind a reverse proxy or TLS terminator, forward the public host/protocol headers so generated WebSocket URLs use the address clients can actually reach:

    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    

    With those headers, /json/version returns public endpoints such as wss://cdp.example.com/fingerprint/11111/devtools/browser/<browser-id> instead of an internal container host.

    Pass extra flags to the browser:

    # With proxy
    docker run -d --name cloak -e CLOAKBROWSER_LICENSE_KEY -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser \
      cloakserve --proxy-server=http://proxy:8080
    
    # Headed mode (renders to Xvfb inside container)
    docker run -d --name cloak -e CLOAKBROWSER_LICENSE_KEY -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser \
      cloakserve --headless=false
    
    # Reap disconnected per-seed browser processes after 5 minutes
    docker run -d --name cloak -e CLOAKBROWSER_LICENSE_KEY -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser \
      cloakserve --idle-timeout=300
    
    # Keep per-seed profiles (cookies, logins) across idle cleanup and container restarts
    docker run -d --name cloak -e CLOAKBROWSER_LICENSE_KEY -p 127.0.0.1:9222:9222 -v ./cloak-profiles:/profiles cloakhq/cloakbrowser \
      cloakserve --idle-timeout=300 --data-dir=/profiles --keep-profiles
    
    # Per-job container: reap Chrome 60s after disconnect, exit (status 0) after 5 minutes with no connections
    docker run --rm --name cloak -e CLOAKBROWSER_LICENSE_KEY -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser \
      cloakserve --idle-timeout=60 --exit-after-idle=300
    

    Stop the server:

    docker stop cloak && docker rm cloak
    

    Security: CDP gives full control over the browser (execute JS, read pages, access files). The examples bind to 127.0.0.1 so only your machine can connect. Never expose port 9222 to the public internet without additional authentication.

    Docker Compose

    services:
      cloakbrowser:
        image: cloakhq/cloakbrowser
        command: cloakserve
        restart: unless-stopped
        environment:
          - CLOAKBROWSER_LICENSE_KEY   # passed through from the host
        ports:
          - "127.0.0.1:9222:9222"
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9222/json/version"]
          interval: 30s
          timeout: 5s
          retries: 3
          start_period: 10s
    

    Per-connection fingerprint seeds — run multiple browser identities from a single container. Each unique seed spawns a separate Chrome process with its own fingerprint:

    # Each seed gets unique canvas noise and other browser signals
    b1 = pw.chromium.connect_over_cdp("http://localhost:9222?fingerprint=11111")
    b2 = pw.chromium.connect_over_cdp("http://localhost:9222?fingerprint=22222")
    
    # Auto-detect timezone/locale from proxy exit IP
    b3 = pw.chromium.connect_over_cdp(
        "http://localhost:9222?fingerprint=33333"
        "&proxy=http://proxy:8080&geoip=true"
    )
    

    Supported query params: fingerprint, timezone, locale, platform, platform-version, gpu-vendor, hardware-concurrency, device-memory, screen-width, screen-height, proxy, geoip. Same seed reuses the same process (first connection's params win). No seed = shared default process (backward compatible).

    By default, per-seed processes stay alive until cloakserve exits; idle cleanup is disabled (0). If clients create many unique seeds, set --idle-timeout=SECONDS or CLOAKSERVE_IDLE_TIMEOUT=SECONDS to automatically terminate a seed's Chrome process after its last CDP WebSocket disconnects. 0, off, false, none, or disabled disable idle cleanup. When cleanup runs, the seed's temporary profile directory under --data-dir is removed too, unless you pass --keep-profiles (the profile then survives, and reopening the seed restores its cookies and logins). Check active processes at GET / (returns JSON with PIDs, ports, connection counts, idle timeout, and pending cleanup status).

    For a server that runs one job and goes away (e.g. a per-job container), set --exit-after-idle=SECONDS or CLOAKSERVE_EXIT_AFTER_IDLE=SECONDS: cloakserve shuts down with exit status 0 once no CDP WebSocket has been connected for that long, counted from startup if nobody connects. It is off by default and takes the same disable values as --idle-timeout.

    Persistent profiles — mount a volume to keep cookies and sessions across container restarts:

    docker run --rm -e CLOAKBROWSER_LICENSE_KEY -v ./my-profile:/profile cloakhq/cloakbrowser python -c "
    from cloakbrowser import launch_persistent_context
    ctx = launch_persistent_context('/profile')
    page = ctx.new_page()
    page.goto('https://example.com')
    ctx.close()
    "
    

    Run again with the same volume — cookies, localStorage, and cache are restored automatically.

    Resource usage: ~190MB RAM idle, ~280MB with 3 tabs. ~30MB per additional tab.

    Extend with your own image

    FROM cloakhq/cloakbrowser
    COPY your_script.py /app/
    CMD ["python", "your_script.py"]
    

    Building your own image from pip — use python -m cloakbrowser install to download the binary during build with visible progress:

    FROM python:3.12-slim
    RUN pip install cloakbrowser && python -m cloakbrowser install
    COPY your_script.py /app/
    CMD ["python", "/app/your_script.py"]
    

    Building from source — a Dockerfile is also included if you prefer to build your own image:

    docker build -t cloakbrowser .
    

    CloakBrowser works identically local, in Docker, and on VPS. No environment-specific config needed.

    Note: If you run CloakBrowser inside a web server with uvloop (e.g., uvicorn[standard]), use --loop asyncio to avoid subprocess pipe hangs.

    Troubleshooting


    Still getting blocked on aggressive sites (DataDome, Turnstile)?

    Some sites detect headless mode even with our C++ patches. Run in headed mode with a virtual display:

    # Install Xvfb (virtual framebuffer)
    sudo apt install xvfb
    
    # Start virtual display
    Xvfb :99 -screen 0 1920x1080x24 &
    export DISPLAY=:99
    

    This runs a real headed browser rendered on a virtual display — no physical monitor needed. Then launch with headless=False using the recommended config below.


    Recommended config for anti-bot sites

    Most blocks come from missing one of these three things, not from browser fingerprint detection:

    browser = launch(
        proxy="http://your-residential-proxy:port",  # residential IP — datacenter IPs get blocked by reputation alone
        geoip=True,      # matches timezone + locale to proxy exit IP (without this: UTC + en-US = bot signal)
        headless=False,   # headed mode — some sites detect headless even with C++ patches
        humanize=True,    # human-like mouse, keyboard, scroll behavior
    )
    
    const browser = await launch({
        proxy: 'http://your-residential-proxy:port',
        geoip: true,
        headless: false,
        humanize: true,
    });
    

    If your proxy supports SOCKS5, use it for better compatibility — SOCKS5 tunnels raw TCP, avoiding HTTP CONNECT issues that some proxies have with HTTP/2:

    browser = launch(proxy="socks5://user:pass@proxy:1080", geoip=True, headless=False, humanize=True)
    

    If you're still blocked after this, check the font setup below.


    Blocked on Kasada / Akamai sites despite correct config?

    On minimal Linux environments, missing font packages cause canvas emoji rendering to produce hashes that anti-bot systems don't recognize. This is the most common cause of blocks on aggressive sites after proxy, geoip, and headed mode are already set up correctly.

    Install the font packages listed in Font Setup on Linux above.


    Sites challenge fresh sessions but work after first visit

    Some sites challenge first-time visitors with no cookies over HTTP/2. This affects all Chromium browsers, not just CloakBrowser. Use a persistent profile to warm up cookies once, then reuse across sessions:

    from cloakbrowser import launch_persistent_context
    
    # First run: warm up with --disable-http2
    ctx = launch_persistent_context("./profile", args=["--disable-http2"])
    page = ctx.new_page()
    page.goto("https://example.com")  # warms up cookies
    ctx.close()
    
    # Future runs — no --disable-http2 needed
    ctx = launch_persistent_context("./profile")
    page = ctx.new_page()
    page.goto("https://example.com")  # passes with saved cookies
    
    import { launchPersistentContext } from 'cloakbrowser';
    
    // First run: warm up with --disable-http2
    let ctx = await launchPersistentContext({ userDataDir: './profile', args: ['--disable-http2'] });
    let page = await ctx.newPage();
    await page.goto('https://example.com');
    await ctx.close();
    
    // Future runs — no --disable-http2 needed
    ctx = await launchPersistentContext({ userDataDir: './profile' });
    

    For stateless/ephemeral use cases, launch(args=["--disable-http2"]) forces HTTP/1.1 which bypasses the check. Only use this flag for sites that require it — most work fine with HTTP/2. If your proxy supports SOCKS5, use proxy="socks5://user:pass@host:port" instead — SOCKS5 bypasses HTTP CONNECT entirely.


    Something not working? Make sure you're on the latest version

    Older versions may use outdated stealth args or download an older binary:

    pip install -U cloakbrowser    # Python
    npm install cloakbrowser@latest # JavaScript
    docker pull cloakhq/cloakbrowser:latest  # Docker
    

    Preview release channel

    Stable is the default. Opt into Preview per launch:

    browser = launch(license_key="cb_xxxxxxxx", release_channel="preview")
    
    const browser = await launch({ licenseKey: 'cb_xxxxxxxx', releaseChannel: 'preview' });
    
    await using var browser = await CloakLauncher.LaunchAsync(new LaunchOptions
    {
        LicenseKey = "cb_xxxxxxxx",
        ReleaseChannel = "preview",
    });
    

    Or enable Preview for all wrappers and CLI commands:

    export CLOAKBROWSER_RELEASE_CHANNEL=preview
    

    Preview availability is platform-specific. Preview always selects the newest build available for your platform: a newer Preview when one exists, otherwise Stable (including when Stable is newer). cloakbrowser info shows Preview → Stable fallback when that happens. An exact version pin overrides the release channel.

    New update broke something? Roll back

    Two ways to go back to a working version:

    Pin the binary (keep current wrapper, just use an older Chromium) — paid Pro key only. A free key cannot pin: it ignores the pin and always gets the latest build.

    browser = launch(license_key="cb_xxxxxxxx", browser_version="155.0.8059.39.1")
    
    export CLOAKBROWSER_VERSION=155.0.8059.39.1   # env var for all launches
    
    const browser = await launch({ licenseKey: 'cb_xxxxxxxx', browserVersion: '155.0.8059.39.1' });
    

    The pin is never sticky — unpinned launches always use the latest available version.

    Or downgrade the wrapper (if a new wrapper release broke something). With a license key you still get the latest binary; pin it as above to roll that back too:

    pip install cloakbrowser==0.6.3