2026-02-22 23:23:53 +01:00
<p align="center">
2026-02-26 06:17:57 +01:00
<img src="https://i.imgur.com/cqkp6fG.png" width="500" alt="CloakBrowser">
2026-02-22 23:23:53 +01:00
</p>
2026-02-27 02:56:49 +01:00
<p align="center">
<a href="https://pypi.org/project/cloakbrowser/"><img src="https://img.shields.io/pypi/v/cloakbrowser" alt="PyPI"></a>
<a href="https://www.npmjs.com/package/cloakbrowser"><img src="https://img.shields.io/npm/v/cloakbrowser" alt="npm"></a>
2026-03-05 04:54:56 +01:00
<a href="LICENSE"><img src="https://img.shields.io/github/license/cloakhq/cloakbrowser?v=1" alt="License"></a>
<a href="https://github.com/CloakHQ/CloakBrowser"><img src="https://img.shields.io/github/last-commit/cloakhq/cloakbrowser" alt="Last Commit"></a>
2026-02-27 02:56:49 +01:00
<br>
2026-03-05 04:54:56 +01:00
<a href="https://github.com/CloakHQ/CloakBrowser"><img src="https://img.shields.io/github/stars/cloakhq/cloakbrowser" alt="Stars"></a>
2026-03-06 05:16:21 +01:00
<a href="https://pypi.org/project/cloakbrowser/"><img src="https://img.shields.io/pepy/dt/cloakbrowser?label=pypi&logo=pypi&logoColor=white" alt="PyPI Downloads"></a>
2026-03-02 01:01:40 +01:00
<a href="https://www.npmjs.com/package/cloakbrowser"><img src="https://img.shields.io/npm/dt/cloakbrowser?label=npm&logo=npm&logoColor=white" alt="npm Downloads"></a>
2026-02-27 02:56:49 +01:00
</p>
2026-02-22 09:01:10 +01:00
2026-03-02 09:41:41 +01:00
<br>
2026-02-22 09:01:10 +01:00
2026-03-02 09:41:41 +01:00
<h3 align="center">Stealth Chromium that passes every bot detection test.</h3>
<table><tr><td>
Not a patched config. Not a JS injection. A real Chromium binary with fingerprints modified at the C++ source level. Antibot systems score it as a normal browser — because it <em>is</em> a normal browser.
</td></tr></table>
<br>
<p align="center">
<img src="https://i.imgur.com/IvB0It7.gif" width="600" alt="Cloudflare Turnstile — 3 Tests Passing">
<br><em>Cloudflare Turnstile — 3 live tests passing (headed mode, macOS)</em>
</p>
<br>
<p align="center">
Drop-in Playwright/Puppeteer replacement for Python and JavaScript.<br>
Same API, same code — just swap the import. <strong>3 lines of code, 30 seconds to unblock.</strong>
</p>
2026-02-22 09:01:10 +01:00
2026-03-05 03:41:36 +01:00
- **26 source-level C++ patches** — canvas, WebGL, audio, fonts, GPU, screen, automation signals
- **0.9 reCAPTCHA v3 score** — human-level, server-verified
- **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — tested against 30+ detection sites
- **Auto-updating binary** — background update checks, always on the latest stealth build
- **`pip install cloakbrowser` ** or ** `npm install cloakbrowser` ** — binary auto-downloads, zero config
- **Free and open source** — no subscriptions, no usage limits
2026-02-22 09:01:10 +01:00
2026-03-05 04:54:56 +01:00
**Try it now** — no install needed:
```bash
docker run --rm cloakhq/cloakbrowser cloaktest
```
2026-02-23 19:57:19 +01:00
**Python:**
2026-02-22 09:01:10 +01:00
```python
from cloakbrowser import launch
browser = launch ()
page = browser . new_page ()
page . goto ( "https://protected-site.com" ) # no more blocks
browser . close ()
```
2026-02-23 19:57:19 +01:00
**JavaScript (Playwright):**
```javascript
import { launch } from 'cloakbrowser' ;
const browser = await launch ();
const page = await browser . newPage ();
await page . goto ( 'https://protected-site.com' );
await browser . close ();
```
2026-03-02 09:41:41 +01:00
Also works with Puppeteer: `import { launch } from 'cloakbrowser/puppeteer'` ([details ](#puppeteer ))
2026-02-23 19:57:19 +01:00
2026-02-22 09:01:10 +01:00
## Install
2026-02-23 19:57:19 +01:00
**Python:**
2026-02-22 09:01:10 +01:00
```bash
pip install cloakbrowser
```
2026-02-23 19:57:19 +01:00
**JavaScript / Node.js:**
```bash
# With Playwright
npm install cloakbrowser playwright-core
# With Puppeteer
npm install cloakbrowser puppeteer-core
```
2026-02-22 09:01:10 +01:00
On first run, the stealth Chromium binary is automatically downloaded (~200MB, cached locally).
2026-03-02 09:41:41 +01:00
**Optional:** Auto-detect timezone/locale from proxy IP:
```bash
pip install cloakbrowser[ geoip]
```
**Migrating from Playwright?** One-line change:
```diff
- 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
```
2026-03-02 18:20:57 +01:00
> ⭐ **Star** to show support — **[Watch releases](https://github.com/CloakHQ/CloakBrowser/subscription)** to get notified when new builds drop.
2026-03-02 09:41:41 +01:00
2026-03-05 05:53:51 +01:00
## Latest: v0.3.8 (Chromium 145.0.7632.159)
2026-03-02 02:35:13 +01:00
2026-03-04 01:11:50 +01:00
- **All 4 platforms** — Linux x64, macOS arm64, macOS x64, and Windows x64 all on Chromium 145
- **26 fingerprint patches** — 10 new patches since v142 (screen, device memory, audio, WebGL, auto-spoof, and more)
- **Stealthy with zero flags** — binary auto-generates a random fingerprint seed at startup. No configuration required
2026-03-02 18:20:57 +01:00
- **Full stealth audit** — every patch reviewed for detection vectors, multiple fixes shipped
2026-03-04 01:11:50 +01:00
- **CDP hardening** — audited and patched known automation detection vectors
2026-03-05 03:41:36 +01:00
- **Timezone & locale from proxy IP** — `launch(proxy="...", geoip=True)` auto-detects timezone and locale
- **Playwright + Puppeteer from one package** — `import from 'cloakbrowser'` or `import from 'cloakbrowser/puppeteer'` . Same binary, your choice of API
- **Persistent profiles** — `launch_persistent_context()` keeps cookies and localStorage across sessions, bypasses incognito detection
2026-03-02 02:35:13 +01:00
See the full [CHANGELOG.md ](CHANGELOG.md ) for details.
2026-02-22 09:01:10 +01:00
## Why CloakBrowser?
2026-02-22 23:23:53 +01:00
- **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.
2026-03-05 18:33:47 +01:00
- **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.
2026-03-02 09:41:41 +01:00
- **Same behavior everywhere** — works identically local, in Docker, and on VPS. No environment-specific patches or config needed.
2026-03-05 03:41:36 +01:00
- **Works with any browser automation framework** — tested and passing stealth checks with Playwright, Puppeteer, Selenium, undetected-chromedriver, browser-use, Crawl4AI, and agent-browser. Just point any Chromium-based framework at the binary path.
2026-02-22 09:01:10 +01:00
2026-03-05 03:41:36 +01:00
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.
2026-03-02 09:41:41 +01:00
2026-02-22 09:01:10 +01:00
## Test Results
2026-03-02 09:41:41 +01:00
All tests verified against live detection services. Last tested: Mar 2026 (Chromium 145).
2026-02-22 09:01:10 +01:00
| Detection Service | Stock Playwright | CloakBrowser | Notes |
|---|---|---|---|
| **reCAPTCHA v3** | 0.1 (bot) | **0.9** (human) | Server-side verified |
| **Cloudflare Turnstile** (non-interactive) | FAIL | **PASS** | Auto-resolve |
| **Cloudflare Turnstile** (managed) | FAIL | **PASS** | Single click |
2026-03-02 09:41:41 +01:00
| **ShieldSquare** | BLOCKED | **PASS** | Production site |
2026-02-22 09:01:10 +01:00
| **FingerprintJS** bot detection | DETECTED | **PASS** | demo.fingerprint.com |
| **BrowserScan** bot detection | DETECTED | **NORMAL** (4/4) | browserscan.net |
| **bot.incolumitas.com** | 13 fails | **1 fail** | WEBDRIVER spec only |
| **deviceandbrowserinfo.com** | 6 true flags | **0 true flags** | `isBot: false` |
| `navigator.webdriver` | `true` | ** `false` ** | Source-level patch |
| `navigator.plugins.length` | 0 | **5** | Real plugin list |
| `window.chrome` | `undefined` | ** `object` ** | Present like real Chrome |
2026-02-27 03:56:54 +01:00
| UA string | `HeadlessChrome` | ** `Chrome/145.0.0.0` ** | No headless leak |
2026-02-22 09:01:10 +01:00
| CDP detection | Detected | **Not detected** | `isAutomatedWithCDP: false` |
| TLS fingerprint | Mismatch | **Identical to Chrome** | ja3n/ja4/akamai match |
2026-03-05 03:41:36 +01:00
| | | **Tested against 30+ detection sites** | |
2026-02-22 09:01:10 +01:00
### Proof
2026-02-22 20:19:27 +01:00
<p align="center">
2026-02-26 06:17:57 +01:00
<img src="https://i.imgur.com/hvIQyMv.png" width="600" alt="reCAPTCHA v3 — Score 0.9">
2026-02-22 20:19:27 +01:00
<br><em>reCAPTCHA v3 score 0.9 — server-side verified (human-level)</em>
</p>
2026-02-22 09:01:10 +01:00
<p align="center">
2026-02-26 06:17:57 +01:00
<img src="https://i.imgur.com/qMIRfhq.png" width="600" alt="Cloudflare Turnstile — Success">
2026-02-22 09:01:10 +01:00
<br><em>Cloudflare Turnstile non-interactive challenge — auto-resolved</em>
</p>
<p align="center">
2026-02-26 06:17:57 +01:00
<img src="https://i.imgur.com/PRsw6rT.png" width="600" alt="BrowserScan — Normal">
2026-02-22 09:01:10 +01:00
<br><em>BrowserScan bot detection — NORMAL (4/4 checks passed)</em>
</p>
<p align="center">
2026-02-26 06:17:57 +01:00
<img src="https://i.imgur.com/9n2C7tu.png" width="600" alt="FingerprintJS — Passed">
2026-02-22 09:01:10 +01:00
<br><em>FingerprintJS web-scraping demo — data served, not blocked</em>
</p>
2026-03-05 03:41:36 +01:00
## Comparison
| Feature | Playwright | playwright-stealth | undetected-chromedriver | Camoufox | CloakBrowser |
|---|---|---|---|---|---|
| reCAPTCHA v3 score | 0.1 | 0.3-0.5 | 0.3-0.7 | 0.7-0.9 | **0.9** |
| Cloudflare Turnstile | Fail | Sometimes | Sometimes | Pass | **Pass** |
| Patch level | None | JS injection | Config patches | C++ (Firefox) | **C++ (Chromium)** |
| Survives Chrome updates | N/A | Breaks often | Breaks often | Yes | **Yes** |
| Maintained | Yes | Stale | Stale | Unstable | **Active** |
| Browser engine | Chromium | Chromium | Chrome | Firefox | **Chromium** |
| Playwright API | Native | Native | No (Selenium) | No | **Native** |
2026-02-22 09:01:10 +01:00
## How It Works
2026-02-23 19:57:19 +01:00
CloakBrowser is a thin wrapper (Python + JavaScript) around a custom-built Chromium binary:
2026-02-22 09:01:10 +01:00
2026-02-23 19:57:19 +01:00
1. **You install** → `pip install cloakbrowser` or `npm install cloakbrowser`
2026-03-03 06:31:07 +01:00
2. **First launch** → binary auto-downloads for your platform (Chromium 145)
2026-02-23 19:57:19 +01:00
3. **Every launch** → Playwright or Puppeteer starts with our binary + stealth args
4. **You write code** → standard Playwright/Puppeteer API, nothing new to learn
2026-02-22 09:01:10 +01:00
2026-03-04 01:11:50 +01:00
The binary includes 26 source-level patches covering canvas, WebGL, audio, fonts, GPU, screen properties, hardware reporting, and automation signal removal.
2026-02-22 09:01:10 +01:00
These are compiled into the Chromium binary — not injected via JavaScript, not set via flags.
2026-03-02 09:41:41 +01:00
Binary downloads are verified with SHA-256 checksums to ensure integrity.
2026-02-22 09:01:10 +01:00
## API
### `launch()`
```python
from cloakbrowser import launch
# Basic — headless, default stealth config
browser = launch ()
# Headed mode (see the browser window)
browser = launch ( headless = False )
# With proxy
browser = launch ( proxy = "http://user:pass@proxy:8080" )
2026-03-04 20:11:30 +01:00
# With proxy dict (bypass, separate auth fields)
browser = launch ( proxy = { "server" : "http://proxy:8080" , "bypass" : ".google.com" , "username" : "user" , "password" : "pass" })
2026-02-22 09:01:10 +01:00
# With extra Chrome args
2026-03-03 21:19:34 +01:00
browser = launch ( args = [ "--disable-gpu" ])
2026-02-22 09:01:10 +01:00
2026-03-01 01:07:11 +01:00
# With timezone and locale (sets both binary flags and Playwright context)
browser = launch ( timezone = "America/New_York" , locale = "en-US" )
# Auto-detect timezone/locale from proxy IP (requires: pip install cloakbrowser[geoip])
browser = launch ( proxy = "http://proxy:8080" , geoip = True )
2026-03-02 09:41:41 +01:00
# Explicit timezone/locale always win over auto-detection
browser = launch ( proxy = "http://proxy:8080" , geoip = True , timezone = "Europe/London" )
2026-02-22 09:01:10 +01:00
# 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()`
```python
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()`
2026-03-04 19:23:16 +01:00
Convenience function that creates browser + context in one call with user agent, viewport, locale, and timezone:
2026-02-22 09:01:10 +01:00
```python
from cloakbrowser import launch_context
context = launch_context (
user_agent = "Custom UA" ,
viewport = { "width" : 1920 , "height" : 1080 },
locale = "en-US" ,
2026-03-05 02:13:46 +01:00
timezone = "America/New_York" ,
2026-02-22 09:01:10 +01:00
)
page = context . new_page ()
2026-03-04 19:23:16 +01:00
page . goto ( "https://protected-site.com" )
context . close ()
2026-02-22 09:01:10 +01:00
```
2026-03-04 19:23:16 +01:00
### `launch_persistent_context()`
Same as `launch_context()` , but with a persistent user profile. Cookies, localStorage, and cache persist across sessions. Also avoids incognito detection by services like BrowserScan.
2026-03-04 20:11:30 +01:00
Use this when you need to:
- **Stay logged in** across runs (cookies/sessions survive restarts)
- **Bypass incognito detection** (some sites flag empty, ephemeral profiles)
- **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)
2026-03-04 19:23:16 +01:00
```python
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 )
```
2026-03-05 02:13:46 +01:00
Supports all the same options as `launch_context()` : `proxy` , `user_agent` , `viewport` , `locale` , `timezone` , `color_scheme` , `geoip` .
2026-03-04 19:23:16 +01:00
Async version: `launch_persistent_context_async()` .
2026-02-22 09:01:10 +01:00
### Utility Functions
```python
from cloakbrowser import binary_info , clear_cache , ensure_binary
# Check binary installation status
print ( binary_info ())
2026-03-05 05:53:51 +01:00
# {'version': '145.0.7632.159', 'platform': 'linux-x64', 'installed': True, ...}
2026-02-22 09:01:10 +01:00
# Force re-download
clear_cache ()
# Pre-download binary (e.g., during Docker build)
ensure_binary ()
```
2026-02-23 19:57:19 +01:00
## JavaScript / Node.js API
CloakBrowser ships a TypeScript package with full type definitions. Choose Playwright or Puppeteer — same stealth binary underneath.
### Playwright (default)
```javascript
2026-03-04 19:23:16 +01:00
import { launch , launchContext , launchPersistentContext } from 'cloakbrowser' ;
2026-02-23 19:57:19 +01:00
// Basic
const browser = await launch ();
// With options
const browser = await launch ({
headless : false ,
proxy : 'http://user:pass@proxy:8080' ,
2026-03-03 21:19:34 +01:00
args : [ '--fingerprint=12345' ],
2026-03-02 09:41:41 +01:00
timezone : 'America/New_York' ,
locale : 'en-US' ,
2026-02-23 19:57:19 +01:00
});
// Convenience: browser + context in one call
const context = await launchContext ({
userAgent : 'Custom UA' ,
viewport : { width : 1920 , height : 1080 },
locale : 'en-US' ,
2026-03-05 02:13:46 +01:00
timezone : 'America/New_York' ,
2026-02-23 19:57:19 +01:00
});
const page = await context . newPage ();
2026-03-04 19:23:16 +01:00
// Persistent profile — cookies/localStorage survive restarts, avoids incognito detection
const ctx = await launchPersistentContext ({
userDataDir : './chrome-profile' ,
headless : false ,
proxy : 'http://user:pass@proxy:8080' ,
});
2026-02-23 19:57:19 +01:00
```
> **Note:** Each example above is standalone — not meant to run as one block.
2026-03-02 09:41:41 +01:00
All Python options work in JS: `stealthArgs: false` to disable defaults, `geoip: true` to auto-detect timezone/locale from proxy IP.
2026-02-23 19:57:19 +01:00
### Puppeteer
2026-02-25 18:32:09 +01:00
> **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.
2026-02-23 19:57:19 +01:00
```javascript
import { launch } from 'cloakbrowser/puppeteer' ;
const browser = await launch ({ headless : true });
const page = await browser . newPage ();
await page . goto ( 'https://example.com' );
await browser . close ();
```
### Utility Functions (JS)
```javascript
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 ();
```
2026-02-22 09:01:10 +01:00
## Configuration
| Env Variable | Default | Description |
|---|---|---|
| `CLOAKBROWSER_BINARY_PATH` | — | Skip download, use a local Chromium binary |
| `CLOAKBROWSER_CACHE_DIR` | `~/.cloakbrowser` | Binary cache directory |
2026-02-27 02:56:49 +01:00
| `CLOAKBROWSER_DOWNLOAD_URL` | `cloakbrowser.dev` | Custom download URL for binary |
2026-02-25 19:20:57 +01:00
| `CLOAKBROWSER_AUTO_UPDATE` | `true` | Set to `false` to disable background update checks |
2026-03-02 09:03:57 +01:00
| `CLOAKBROWSER_SKIP_CHECKSUM` | `false` | Set to `true` to skip SHA-256 verification after download |
2026-02-22 09:01:10 +01:00
2026-02-26 08:31:10 +01:00
## Fingerprint Management
2026-03-03 20:05:16 +01:00
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:**
| Scenario | What happens |
|----------|-------------|
| **No flags** | Random seed auto-generated at startup. GPU, screen, hardware specs, and all noise patches are spoofed automatically. Fresh identity each launch. |
| ** `--fingerprint=seed` ** | Deterministic identity from the seed. Same seed = same fingerprint across launches. Use this for session persistence (returning visitor). |
| ** `--fingerprint=seed` + explicit flags** | Explicit flags override individual auto-generated values. The seed fills in everything else. |
2026-03-04 01:11:50 +01:00
The binary detects its platform at compile time — a macOS binary reports as macOS with Apple GPU, a Linux binary reports as Linux with NVIDIA GPU. The **wrapper** overrides this on Linux by passing `--fingerprint-platform=windows` , so sessions appear as Windows desktops (more common fingerprint, harder to cluster). Use `--fingerprint-platform` for cross-platform spoofing when running the binary directly.
2026-02-26 08:31:10 +01:00
2026-02-28 04:38:27 +01:00
> **Tip: Use a fixed seed when revisiting the same site.** A random seed makes every session look like a different device — which can be suspicious when hitting the same site repeatedly from the same IP. For reCAPTCHA v3 Enterprise and similar scoring systems, a fixed seed produces a consistent fingerprint across sessions, making you look like a returning visitor:
> ```python
> browser = launch(args=["--fingerprint=12345"])
> ```
> ```javascript
> const browser = await launch({ args: ['--fingerprint=12345'] });
> ```
2026-02-26 08:31:10 +01:00
### Default Fingerprint
2026-03-04 01:11:50 +01:00
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:
2026-02-26 08:31:10 +01:00
2026-03-03 06:31:07 +01:00
| Flag | Linux/Windows Default | macOS Default | Controls |
2026-02-27 02:15:36 +01:00
|------|--------------|---------------|----------|
| `--fingerprint` | Random (10000– 99999) | Random (10000– 99999) | Master seed for canvas, WebGL, audio, fonts, client rects |
| `--fingerprint-platform` | `windows` | `macos` | `navigator.platform` , User-Agent OS, GPU pool selection |
2026-03-03 05:09:10 +01:00
| `--fingerprint-gpu-vendor` | `NVIDIA Corporation` | `Google Inc. (Apple)` | WebGL `UNMASKED_VENDOR_WEBGL` |
| `--fingerprint-gpu-renderer` | `NVIDIA GeForce RTX 3070` | `ANGLE (Apple, ANGLE Metal Renderer: Apple M3, Unspecified Version)` | WebGL `UNMASKED_RENDERER_WEBGL` |
2026-03-03 21:19:34 +01:00
The binary auto-generates hardware concurrency (8), device memory (8), and screen dimensions (1920x1080 on Windows/Linux, 1440x900 on macOS) from the seed. Override with explicit flags if needed.
2026-02-27 02:15:36 +01:00
2026-03-03 20:05:16 +01:00
> **Using the binary directly?** It works out of the box with zero flags — the binary auto-spoofs everything. Pass `--fingerprint=seed` for a persistent identity, or use explicit flags like `--fingerprint-gpu-renderer` to override any auto-generated value.
2026-02-26 08:31:10 +01:00
2026-03-03 20:05:16 +01:00
> **Production tip:** For better stealth at scale, pass your own GPU, screen, and hardware values instead of relying on defaults. Custom parameters make your sessions harder to cluster by anti-bot systems that look for uniform fingerprint profiles.
2026-03-03 05:09:10 +01:00
2026-02-26 08:31:10 +01:00
### Additional Flags
Supported by the binary but **not set by default** — pass via `args` to customize:
| Flag | Controls |
|------|----------|
2026-03-03 21:19:34 +01:00
| `--fingerprint-hardware-concurrency` | `navigator.hardwareConcurrency` (auto-generated: `8` ) |
| `--fingerprint-device-memory` | `navigator.deviceMemory` in GB (auto-generated: `8` ) |
| `--fingerprint-screen-width` | Screen width (auto-generated: `1920` Win/Linux, `1440` macOS) |
| `--fingerprint-screen-height` | Screen height (auto-generated: `1080` Win/Linux, `900` macOS) |
2026-02-26 08:31:10 +01:00
| `--fingerprint-brand` | Browser brand: `Chrome` , `Edge` , `Opera` , `Vivaldi` |
| `--fingerprint-brand-version` | Brand version (UA + Client Hints) |
| `--fingerprint-platform-version` | Client Hints platform version |
| `--fingerprint-location` | Geolocation coordinates |
2026-03-02 18:20:57 +01:00
| `--fingerprint-timezone` | Timezone (e.g. `America/New_York` ) |
| `--fingerprint-taskbar-height` | Override taskbar height (binary defaults: Win=48, Mac=95, Linux=0) |
| `--fingerprint-fonts-dir` | Path to cross-platform font directory |
| `--enable-blink-features=FakeShadowRoot` | Access closed shadow DOM elements |
2026-02-26 08:31:10 +01:00
> **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.
### Examples
```python
# Pin a seed for a persistent identity
browser = launch ( args = [ "--fingerprint=42069" ])
# Full control — disable defaults, set everything yourself
browser = launch ( stealth_args = False , args = [
"--fingerprint=42069" ,
"--fingerprint-platform=windows" ,
"--fingerprint-gpu-vendor=NVIDIA Corporation" ,
"--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070" ,
])
# Override GPU to look like a different machine
browser = launch ( args = [
"--fingerprint-gpu-vendor=Intel Inc." ,
"--fingerprint-gpu-renderer=Intel Iris OpenGL Engine" ,
])
```
2026-03-05 03:41:36 +01:00
## Examples
**Python** — see [`examples/` ](examples/ ):
- [`basic.py` ](examples/basic.py ) — Launch and load a page
- [`persistent_context.py` ](examples/persistent_context.py ) — Persistent profile with cookie/localStorage persistence
- [`recaptcha_score.py` ](examples/recaptcha_score.py ) — Check your reCAPTCHA v3 score
- [`stealth_test.py` ](examples/stealth_test.py ) — Run against 6 detection sites
- [`fingerprint_scan_test.py` ](examples/fingerprint_scan_test.py ) — Test against fingerprint-scan.com and CreepJS
**JavaScript** — see [`js/examples/` ](js/examples/ ):
- [`basic-playwright.ts` ](js/examples/basic-playwright.ts ) — Playwright launch and load
- [`basic-puppeteer.ts` ](js/examples/basic-puppeteer.ts ) — Puppeteer launch and load
- [`stealth-test.ts` ](js/examples/stealth-test.ts ) — Run against 6 detection sites
2026-02-22 09:01:10 +01:00
## Platforms
2026-03-02 18:20:57 +01:00
| Platform | Chromium | Patches | Status |
|---|---|---|---|
2026-03-04 01:11:50 +01:00
| Linux x86_64 | 145 | 26 | ✅ Latest |
| macOS arm64 (Apple Silicon) | 145 | 26 | ✅ Latest |
| macOS x86_64 (Intel) | 145 | 26 | ✅ Latest |
| Windows x86_64 | 145 | 26 | ✅ Latest |
2026-02-22 09:01:10 +01:00
2026-03-03 06:31:07 +01:00
The wrapper auto-downloads the correct binary for your platform.
2026-02-27 09:20:56 +01:00
2026-02-27 02:56:49 +01:00
**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.
2026-02-25 19:20:57 +01:00
2026-02-23 07:16:02 +01:00
## Docker
2026-03-06 05:16:21 +01:00
Pre-built image on Docker Hub — no install, no setup.
### Quick test
2026-02-23 07:16:02 +01:00
```bash
2026-03-05 04:54:56 +01:00
docker run --rm cloakhq/cloakbrowser cloaktest
2026-03-06 05:16:21 +01:00
```
2026-02-23 07:16:02 +01:00
2026-03-06 05:16:21 +01:00
### Run a script
```bash
# Inline script
2026-03-05 04:54:56 +01:00
docker run --rm cloakhq/cloakbrowser python -c "
from cloakbrowser import launch
browser = launch()
page = browser.new_page()
page.goto('https://example.com')
print(page.title())
browser.close()
"
2026-02-23 07:16:02 +01:00
2026-03-06 05:16:21 +01:00
# Mount your own script
docker run --rm -v ./my_script.py:/app/my_script.py cloakhq/cloakbrowser python my_script.py
2026-03-05 04:54:56 +01:00
# With a proxy
docker run --rm cloakhq/cloakbrowser python -c "
2026-03-02 09:41:41 +01:00
from cloakbrowser import launch
browser = launch(proxy='http://user:pass@proxy:8080')
page = browser.new_page()
page.goto('https://example.com')
print(page.title())
browser.close()
"
```
2026-03-06 05:16:21 +01:00
### CDP server mode
Start a persistent stealth browser and connect to it remotely via Chrome DevTools Protocol:
```bash
docker run -d --name cloak -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser cloakserve
```
Then connect from your host machine:
```python
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 ()
```
Pass extra flags to the browser:
```bash
# With proxy
docker run -d --name cloak -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 -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser \
cloakserve --headless= false
```
Stop the server:
```bash
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.
### Extend with your own image
2026-03-05 04:54:56 +01:00
```dockerfile
FROM cloakhq/cloakbrowser
COPY your_script.py /app/
CMD [ "python" , "your_script.py" ]
```
**Building from source** — a [`Dockerfile` ](Dockerfile ) is also included if you prefer to build your own image:
```bash
docker build -t cloakbrowser .
```
2026-03-02 09:41:41 +01:00
CloakBrowser works identically local, in Docker, and on VPS. No environment-specific config needed.
2026-02-23 07:16:02 +01:00
**Note:** If you run CloakBrowser inside a web server with uvloop (e.g., `uvicorn[standard]` ), use `--loop asyncio` to avoid subprocess pipe hangs.
2026-03-05 03:41:36 +01:00
## Troubleshooting
2026-02-23 18:11:28 +01:00
2026-03-05 03:41:36 +01:00
**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:
2026-02-23 18:11:28 +01:00
```bash
# Install Xvfb (virtual framebuffer)
sudo apt install xvfb
# Start virtual display
Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY = :99
```
```python
from cloakbrowser import launch
# Headed mode + residential proxy for maximum stealth
browser = launch ( headless = False , proxy = "http://your-residential-proxy:port" )
page = browser . new_page ()
page . goto ( "https://heavily-protected-site.com" ) # passes DataDome, etc.
browser . close ()
```
2026-03-05 03:41:36 +01:00
This runs a real headed browser rendered on a virtual display — no physical monitor needed. Combined with a residential proxy, this passes even the most aggressive detection services. Datacenter IPs are often flagged by IP reputation regardless of browser fingerprint — a residential proxy makes the difference.
2026-02-22 23:23:53 +01:00
2026-03-05 07:25:49 +01:00
**Sites challenge fresh sessions but work after first visit**
2026-02-27 03:56:54 +01:00
2026-03-05 07:25:49 +01:00
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:
2026-02-27 03:56:54 +01:00
```python
2026-03-05 07:25:49 +01:00
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
2026-02-27 03:56:54 +01:00
```
```javascript
2026-03-05 07:25:49 +01:00
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' });
2026-02-27 03:56:54 +01:00
```
2026-03-05 07:25:49 +01:00
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.
2026-02-27 03:56:54 +01:00
2026-03-05 04:54:56 +01:00
**Something not working? Make sure you're on the latest version**
2026-03-03 05:09:10 +01:00
Older versions may use outdated stealth args or download an older binary:
```bash
pip install -U cloakbrowser # Python
npm install cloakbrowser@latest # JavaScript
2026-03-05 04:54:56 +01:00
docker pull cloakhq/cloakbrowser:latest # Docker
2026-03-03 05:09:10 +01:00
```
2026-02-22 23:23:53 +01:00
**Binary download fails / timeout**
Set a custom download URL or use a local binary:
```bash
export CLOAKBROWSER_BINARY_PATH = /path/to/your/chrome
```
2026-03-05 03:41:36 +01:00
**New update broke something? Roll back to the previous version**
When auto-update downloads a newer binary, the previous version stays in `~/.cloakbrowser/` . Point `CLOAKBROWSER_BINARY_PATH` to the older cached binary:
```bash
# Linux
2026-03-05 05:53:51 +01:00
export CLOAKBROWSER_BINARY_PATH = ~/.cloakbrowser/chromium-145.0.7632.159/chrome
2026-03-05 03:41:36 +01:00
# macOS
2026-03-05 05:53:51 +01:00
export CLOAKBROWSER_BINARY_PATH = ~/.cloakbrowser/chromium-145.0.7632.109.2/Chromium.app/Contents/MacOS/Chromium
2026-03-05 03:41:36 +01:00
# Windows
2026-03-05 05:53:51 +01:00
set CLOAKBROWSER_BINARY_PATH = %USERPROFILE%\. cloakbrowser\c hromium-145.0.7632.109.2\c hrome.exe
2026-03-05 03:41:36 +01:00
```
2026-02-27 04:12:49 +01:00
**macOS: "App is damaged" or Gatekeeper blocks launch**
The binary is ad-hoc signed. macOS quarantines downloaded files. Run once to clear it:
```bash
xattr -cr ~/.cloakbrowser/chromium-*/Chromium.app
```
2026-02-22 23:23:53 +01:00
** "playwright install" vs CloakBrowser binary**
You do NOT need `playwright install chromium` . CloakBrowser downloads its own binary. You only need Playwright's system deps:
```bash
2026-03-05 18:33:47 +01:00
playwright install-deps chromium
2026-02-22 23:23:53 +01:00
```
2026-03-04 03:51:05 +01:00
**macOS: Blocked on some sites that pass on Linux**
The macOS fingerprint profile has known inconsistencies that aggressive bot detection catches. If a site blocks you on macOS but works on Linux, switch to a Windows fingerprint profile by passing `stealth_args=False` and manually setting `--fingerprint-platform=windows` with matching GPU flags (see [Fingerprint Management ](#fingerprint-management ) for the full flag list).
2026-03-04 20:11:30 +01:00
**Site detects incognito / private browsing mode**
By default, `launch()` opens an incognito context. Some sites (like BrowserScan) detect this. Use `launch_persistent_context()` instead — it runs with a real user profile, so incognito detection passes:
```python
from cloakbrowser import launch_persistent_context
ctx = launch_persistent_context ( "./my-profile" , headless = False )
page = ctx . new_page ()
```
```javascript
import { launchPersistentContext } from 'cloakbrowser' ;
const ctx = await launchPersistentContext ({
userDataDir : './my-profile' ,
headless : false ,
});
```
This also gives you cookie and localStorage persistence across sessions.
2026-03-01 06:10:23 +01:00
**reCAPTCHA v3 scores are low (0.1– 0.3)**
Avoid `page.wait_for_timeout()` — it sends CDP protocol commands that reCAPTCHA detects. Use native sleep instead:
```python
# Bad — sends CDP commands, reCAPTCHA detects this
page . wait_for_timeout ( 3000 )
# Good — invisible to the browser
import time
time . sleep ( 3 )
```
```javascript
// Bad — sends CDP commands
await page . waitForTimeout ( 3000 );
// Good — invisible to the browser
await new Promise ( r => setTimeout ( r , 3000 ));
```
Other tips for maximizing reCAPTCHA scores:
2026-03-05 18:33:47 +01:00
- **Try the Patchright backend** — suppresses CDP automation signals that reCAPTCHA Enterprise detects. Install with `pip install cloakbrowser[patchright]` , then use `launch(backend="patchright")` or set `CLOAKBROWSER_BACKEND=patchright` globally. Note: Patchright breaks proxy auth and `add_init_script` — only use it when you need the extra CDP stealth
2026-03-01 06:10:23 +01:00
- **Use Playwright, not Puppeteer** — Puppeteer sends more CDP protocol traffic that reCAPTCHA detects ([details ](#puppeteer ))
- **Use residential proxies** — datacenter IPs are flagged by IP reputation, not browser fingerprint
- **Spend 15+ seconds on the page** before triggering reCAPTCHA — short visits score lower
- **Space out requests** — back-to-back `grecaptcha.execute()` calls from the same session get penalized. Wait 30+ seconds between pages with reCAPTCHA
2026-03-02 09:41:41 +01:00
- **Use a fixed fingerprint seed** for consistent device identity across sessions (see [Fingerprint Management ](#fingerprint-management ))
2026-03-01 06:10:23 +01:00
- **Use `page.type()` instead of `page.fill()` ** for form filling — `fill()` sets values directly without keyboard events, which reCAPTCHA's behavioral analysis flags. `type()` with a delay simulates real keystrokes:
```python
page.type("#email", "user@example.com", delay=50)
` ``
- **Minimize ` page.evaluate()` calls** before the reCAPTCHA check fires — each one sends CDP traffic
2026-02-22 09:01:10 +01:00
## FAQ
**Q: Is this legal?**
2026-03-05 03:41:36 +01:00
A: CloakBrowser is a browser built on open-source Chromium. We do not condone illegal use. Automating systems without authorization, credential stuffing, and account creation abuse are expressly prohibited. See [BINARY-LICENSE.md](https://github.com/CloakHQ/CloakBrowser/blob/main/BINARY-LICENSE.md) for full terms.
2026-02-22 09:01:10 +01:00
**Q: How is this different from Camoufox?**
2026-03-02 09:41:41 +01:00
A: Camoufox patches Firefox. We patch Chromium. Chromium means native Playwright support, larger ecosystem, and TLS fingerprints that match real Chrome. Camoufox returned in early 2026 but is in unstable beta — CloakBrowser is production-ready.
2026-02-22 09:01:10 +01:00
**Q: Will detection sites eventually catch this?**
A: Possibly. Bot detection is an arms race. Source-level patches are harder to detect than config-level patches, but not impossible. We actively monitor and update when detection evolves.
**Q: Can I use my own proxy?**
A: Yes. Pass ` proxy="http://user:pass@host:port "` to ` launch()`.
2026-03-05 03:41:36 +01:00
## Roadmap
| Feature | Status |
|---------|--------|
| Linux x64 — Chromium 145 (26 patches) | ✅ Released |
| macOS arm64/x64 — Chromium 145 (26 patches) | ✅ Released |
| Windows x64 — Chromium 145 (26 patches) | ✅ Released |
| JavaScript/Puppeteer + Playwright support | ✅ Released |
| Fingerprint rotation per session | ✅ Released |
| Built-in proxy rotation | 📋 Planned |
2026-02-27 02:56:49 +01:00
## Links
2026-03-02 02:35:13 +01:00
- 📋 **Changelog** — [CHANGELOG.md ](CHANGELOG.md )
2026-02-27 02:56:49 +01:00
- 🌐 **Website** — [cloakbrowser.dev ](https://cloakbrowser.dev )
- 🐛 **Bug reports & feature requests** — [GitHub Issues ](https://github.com/CloakHQ/CloakBrowser/issues )
- 📦 **PyPI** — [pypi.org/project/cloakbrowser ](https://pypi.org/project/cloakbrowser/ )
- 📦 **npm** — [npmjs.com/package/cloakbrowser ](https://www.npmjs.com/package/cloakbrowser )
- 📧 **Contact** — cloakhq@pm .me
2026-02-22 09:01:10 +01:00
## License
2026-03-03 08:07:51 +01:00
- **Wrapper code** (this repository) — MIT. See [LICENSE ](https://github.com/CloakHQ/CloakBrowser/blob/main/LICENSE ).
- **CloakBrowser binary** (compiled Chromium) — free to use, no redistribution. See [BINARY-LICENSE.md ](https://github.com/CloakHQ/CloakBrowser/blob/main/BINARY-LICENSE.md ).
2026-02-22 09:01:10 +01:00
## Contributing
2026-02-27 02:56:49 +01:00
Issues and PRs welcome. If something isn't working, [open an issue ](https://github.com/CloakHQ/CloakBrowser/issues ) — we respond fast.