diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c29343..bd65c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,20 @@ Changes are tagged: **[wrapper]** for Python/JS wrapper, **[binary]** for Chromi ## [0.3.0] — Unreleased -Chromium v145 upgrade. 26 fingerprint patches (up from 16). New download verification and fallback system. Pending: macOS v145 binary builds. +Chromium v145 upgrade. 25 fingerprint patches (up from 16). New download verification and fallback system. Pending: macOS v145 binary builds. ### Breaking - **[wrapper]** Python dependency changed from `playwright` to `patchright` (CDP stealth fork). Patchright is API-compatible, but if you import `playwright` directly elsewhere, add it as a separate dependency. Replace `from playwright.sync_api` with `from patchright.sync_api` (or keep using `cloakbrowser.launch()` which handles this automatically). -- **[wrapper]** `launch_context()` / `launchContext()` now defaults viewport to 1920x955 (realistic maximized Chrome on 1080p Windows) instead of Playwright's default 1280x720. Pass `viewport={"width": 1280, "height": 720}` explicitly to restore old behavior. +- **[wrapper]** `launch_context()` / `launchContext()` now defaults viewport to 1920×947 (realistic maximized Chrome on 1080p Windows with 48px taskbar) instead of Playwright's default 1280×720. Pass `viewport={"width": 1280, "height": 720}` explicitly to restore old behavior. + +### 2026-03-02 + +- **[binary]** Full stealth audit — multiple detection vectors eliminated, improved cross-API consistency +- **[binary]** Platform-aware fingerprint defaults: screen dimensions, taskbar, and layout auto-adjust per spoofed platform +- **[binary]** Stability and performance improvements across fingerprint patches +- **[binary]** New optional flags: `--fingerprint-fonts-dir`, `--fingerprint-taskbar-height` +- **[wrapper]** Sync wrapper with latest binary changes: updated flag names, viewport, and defaults ### 2026-03-01 diff --git a/README.md b/README.md index a35f309..f4c77bf 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ Drop-in Playwright/Puppeteer replacement for Python and JavaScript.
Same API, same code — just swap the import. 3 lines of code, 30 seconds to unblock.

-- 🔒 **26 source-level C++ patches** — not JS injection, not config flags -- 🛡️ **CDP stealth built-in** — powered by [Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright), hides Playwright's automation signals +- 🔒 **25 source-level C++ patches** — not JS injection, not config flags +- 🛡️ **CDP stealth built-in** — uses [Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright) to reduce Playwright's automation footprint - 🎯 **0.9 reCAPTCHA v3 score** — human-level, server-verified - ☁️ **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — 30/30 tests - 🔄 **Drop-in replacement** — works with Playwright (Python & JS) and Puppeteer (JS) @@ -102,14 +102,15 @@ page.goto("https://example.com") # ... rest of your code works unchanged ``` -> ⭐ **Like what you see?** [Star this repo](https://github.com/CloakHQ/CloakBrowser) to get notified when new builds drop. +> ⭐ **Star** to show support — **[Watch releases](https://github.com/CloakHQ/CloakBrowser/subscription)** to get notified when new builds drop. ## What's New in v0.3.0 -- **Chromium 145** — latest stable, 26 fingerprint patches (up from 16) -- **10 new patches** — screen dimensions, device memory, audio, WebGL, and more +- **Chromium 145** (Linux) — latest stable, 25 fingerprint patches (up from 16). macOS v145 coming soon +- **9 new patches** — screen dimensions, device memory, audio, WebGL, and more - **SHA-256 checksum verification** — binary downloads are verified for integrity - **CDP hardening** — audited and patched known automation detection vectors +- **Full stealth audit** — every patch reviewed for detection vectors, multiple fixes shipped - **Timezone & locale from proxy IP** — `launch(proxy="...", geoip=True)` auto-detects timezone and locale See the full [CHANGELOG.md](CHANGELOG.md) for details. @@ -118,7 +119,7 @@ See the full [CHANGELOG.md](CHANGELOG.md) for details. - **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. -- **Two layers of stealth** — C++ patches handle fingerprints (GPU, screen, UA, hardware reporting), while the Patchright driver eliminates CDP automation leaks. Most stealth tools only do one or the other. +- **Two layers of stealth** — C++ patches handle fingerprints (GPU, screen, UA, hardware reporting), while the Patchright driver defers Playwright's binding registration and randomizes internal world names. Most stealth tools only do one or the other. - **Same behavior everywhere** — works identically local, in Docker, and on VPS. No environment-specific patches or config needed. - **Works with AI browser agents** — drop-in stealth binary for [browser-use](https://github.com/browser-use/browser-use), [agent-browser](https://github.com/nichochar/agent-browser), Claude computer use, and OpenAI Operator - **One line to switch** — same Playwright API, no new abstractions, no CAPTCHA-solving services. @@ -174,11 +175,11 @@ All tests verified against live detection services. Last tested: Mar 2026 (Chrom 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** → binary auto-downloads for your platform (Linux x64, macOS arm64/x64) +2. **First launch** → binary auto-downloads for your platform (Linux x64: Chromium 145, macOS: Chromium 142) 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 26 source-level patches covering canvas, WebGL, audio, fonts, GPU, screen properties, hardware reporting, and automation signal removal. +The binary includes 25 source-level patches covering canvas, WebGL, audio, fonts, GPU, screen properties, hardware reporting, and automation signal removal. These are compiled into the Chromium binary — not injected via JavaScript, not set via flags. @@ -365,10 +366,9 @@ Every `launch()` call sets these automatically. Defaults are **platform-aware** | `--fingerprint-device-memory` | `8` | *(not set)* | `navigator.deviceMemory` | | `--fingerprint-screen-width` | `1920` | *(not set)* | Screen width reporting | | `--fingerprint-screen-height` | `1080` | *(not set)* | Screen height reporting | -| `--fingerprint-taskbar-height` | `40` | *(not set)* | Windows taskbar height | | `--window-size` | `1920,1080` | *(not set)* | Browser window dimensions | -> **Important:** `--fingerprint-platform` must always be set. The binary defaults to `windows` internally when this flag is missing, which causes GPU/UA mismatches on non-Windows systems. The wrapper handles this automatically. +> **Important:** `--fingerprint-platform` should always be set. Without it, platform-specific patches (GPU, UA, screen, taskbar) won't activate. The wrapper handles this automatically. ### Additional Flags @@ -380,7 +380,10 @@ Supported by the binary but **not set by default** — pass via `args` to custom | `--fingerprint-brand-version` | Brand version (UA + Client Hints) | | `--fingerprint-platform-version` | Client Hints platform version | | `--fingerprint-location` | Geolocation coordinates | -| `--timezone` | Timezone (e.g. `America/New_York`) | +| `--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 | > **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. @@ -420,14 +423,14 @@ browser = launch(args=[ ## Platforms -| Platform | Status | -|---|---| -| Linux x86_64 | ✅ Available | -| macOS arm64 (Apple Silicon) | ✅ Available | -| macOS x86_64 (Intel) | ✅ Available | -| Windows | Planned | +| Platform | Chromium | Patches | Status | +|---|---|---|---| +| Linux x86_64 | 145 | 25 | ✅ Latest | +| macOS arm64 (Apple Silicon) | 142 | 16 | ✅ Available (v145 coming soon) | +| macOS x86_64 (Intel) | 142 | 16 | ✅ Available (v145 coming soon) | +| Windows | — | — | Planned | -**macOS (early access):** macOS builds are new — tested but not yet battle-tested at scale like Linux. If you hit any issues, [please open a GitHub issue](https://github.com/CloakHQ/CloakBrowser/issues). +The wrapper auto-downloads the correct binary for your platform. Linux gets Chromium 145 with all 25 patches. macOS currently runs Chromium 142 (16 patches) — the v145 macOS build is in progress. **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. @@ -450,10 +453,9 @@ browser = launch(args=[ | Feature | Status | |---------|--------| -| Linux x64 binary | ✅ Released | -| macOS arm64 (Apple Silicon) | ✅ Released | -| macOS x64 (Intel) | ✅ Released | -| Chromium 145 build (26 patches) | ✅ Released | +| Linux x64 — Chromium 145 (25 patches) | ✅ Released | +| macOS arm64/x64 — Chromium 142 (16 patches) | ✅ Released | +| macOS arm64/x64 — Chromium 145 | 🔨 In progress | | JavaScript/Puppeteer + Playwright support | ✅ Released | | Fingerprint rotation per session | ✅ Released | | Built-in proxy rotation | 📋 Planned | diff --git a/cloakbrowser/browser.py b/cloakbrowser/browser.py index 7b127d3..94b6a7f 100644 --- a/cloakbrowser/browser.py +++ b/cloakbrowser/browser.py @@ -42,7 +42,7 @@ def launch( args: Additional Chromium CLI arguments to pass. stealth_args: Include default stealth fingerprint args (default True). Set to False if you want to pass your own --fingerprint flags. - timezone: IANA timezone (e.g. 'America/New_York'). Sets --timezone binary flag. + timezone: IANA timezone (e.g. 'America/New_York'). Sets --fingerprint-timezone binary flag. locale: BCP 47 locale (e.g. 'en-US'). Sets --lang binary flag. geoip: Auto-detect timezone/locale from proxy IP (default False). Requires ``pip install cloakbrowser[geoip]``. Downloads ~70 MB @@ -108,7 +108,7 @@ async def launch_async( proxy: Proxy server URL (e.g. 'http://proxy:8080' or 'socks5://proxy:1080'). args: Additional Chromium CLI arguments to pass. stealth_args: Include default stealth fingerprint args (default True). - timezone: IANA timezone (e.g. 'America/New_York'). Sets --timezone binary flag. + timezone: IANA timezone (e.g. 'America/New_York'). Sets --fingerprint-timezone binary flag. locale: BCP 47 locale (e.g. 'en-US'). Sets --lang binary flag. geoip: Auto-detect timezone/locale from proxy IP (default False). **kwargs: Passed directly to playwright.chromium.launch(). @@ -270,7 +270,7 @@ def _build_args( result.extend(extra_args) # Timezone/locale flags are independent of stealth_args — always inject when set if timezone: - result.append(f"--timezone={timezone}") + result.append(f"--fingerprint-timezone={timezone}") if locale: result.append(f"--lang={locale}") return result diff --git a/cloakbrowser/config.py b/cloakbrowser/config.py index 3f5ee4b..c055c52 100644 --- a/cloakbrowser/config.py +++ b/cloakbrowser/config.py @@ -56,7 +56,6 @@ def get_default_stealth_args() -> list[str]: "--fingerprint-device-memory=8", "--fingerprint-gpu-vendor=NVIDIA Corporation", "--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070", - "--fingerprint-taskbar-height=40", "--fingerprint-screen-width=1920", "--fingerprint-screen-height=1080", "--window-size=1920,1080", @@ -65,10 +64,10 @@ def get_default_stealth_args() -> list[str]: # --------------------------------------------------------------------------- # Default viewport — realistic maximized Chrome on 1080p Windows -# screen=1920x1080, availHeight=1040 (minus 40px taskbar), -# innerHeight=955 (minus ~85px Chrome UI: tabs + address bar + bookmarks) +# screen=1920x1080, availHeight=1032 (minus 48px taskbar, binary default), +# innerHeight=947 (minus ~85px Chrome UI: tabs + address bar + bookmarks) # --------------------------------------------------------------------------- -DEFAULT_VIEWPORT = {"width": 1920, "height": 955} +DEFAULT_VIEWPORT = {"width": 1920, "height": 947} # --------------------------------------------------------------------------- # Platform detection diff --git a/examples/fingerprint_scan_test.py b/examples/fingerprint_scan_test.py index 53bf7e7..4282136 100644 --- a/examples/fingerprint_scan_test.py +++ b/examples/fingerprint_scan_test.py @@ -191,7 +191,7 @@ def main(): args=[ "--fingerprint-screen-width=1920", "--fingerprint-screen-height=1080", - "--timezone=Asia/Jerusalem", + "--fingerprint-timezone=Asia/Jerusalem", ], ) page = context.new_page() diff --git a/js/README.md b/js/README.md index 91b3b47..7372ab6 100644 --- a/js/README.md +++ b/js/README.md @@ -11,7 +11,7 @@ Drop-in Playwright/Puppeteer replacement. Same API — just swap the import. Scores **0.9 on reCAPTCHA v3**, passes **Cloudflare Turnstile**, and clears **30/30** stealth detection tests. -- 🔒 **26 source-level C++ patches** — not JS injection, not config flags +- 🔒 **25 source-level C++ patches** — not JS injection, not config flags - 🎯 **0.9 reCAPTCHA v3 score** — human-level, server-verified - ☁️ **Passes Cloudflare Turnstile**, FingerprintJS, BrowserScan — 30/30 tests - 🔄 **Drop-in replacement** — works with both Playwright and Puppeteer @@ -75,7 +75,7 @@ const browser = await launch({ args: ['--window-size=1920,1080'], }); -// With timezone and locale (sets --timezone and --lang binary flags) +// With timezone and locale (sets --fingerprint-timezone and --lang binary flags) const browser = await launch({ timezone: 'America/New_York', locale: 'en-US', @@ -155,6 +155,7 @@ if (newVersion) console.log(`Updated to ${newVersion}`); | `CLOAKBROWSER_CACHE_DIR` | `~/.cloakbrowser` | Binary cache directory | | `CLOAKBROWSER_DOWNLOAD_URL` | `cloakbrowser.dev` | Custom download URL | | `CLOAKBROWSER_AUTO_UPDATE` | `true` | Set to `false` to disable background update checks | +| `CLOAKBROWSER_SKIP_CHECKSUM` | `false` | Set to `true` to skip SHA-256 verification after download | ## Migrate From Playwright diff --git a/js/src/config.ts b/js/src/config.ts index c338846..0313a2d 100644 --- a/js/src/config.ts +++ b/js/src/config.ts @@ -168,9 +168,9 @@ export function getLocalBinaryOverride(): string | undefined { // Default stealth arguments // --------------------------------------------------------------------------- // Default viewport — realistic maximized Chrome on 1080p Windows -// screen=1920x1080, availHeight=1040 (minus 40px taskbar), -// innerHeight=955 (minus ~85px Chrome UI: tabs + address bar + bookmarks) -export const DEFAULT_VIEWPORT = { width: 1920, height: 955 }; +// screen=1920x1080, availHeight=1032 (minus 48px taskbar, binary default), +// innerHeight=947 (minus ~85px Chrome UI: tabs + address bar + bookmarks) +export const DEFAULT_VIEWPORT = { width: 1920, height: 947 }; export function getDefaultStealthArgs(): string[] { const seed = Math.floor(Math.random() * 90000) + 10000; // 10000-99999 @@ -195,7 +195,6 @@ export function getDefaultStealthArgs(): string[] { "--fingerprint-device-memory=8", "--fingerprint-gpu-vendor=NVIDIA Corporation", "--fingerprint-gpu-renderer=NVIDIA GeForce RTX 3070", - "--fingerprint-taskbar-height=40", "--fingerprint-screen-width=1920", "--fingerprint-screen-height=1080", "--window-size=1920,1080", diff --git a/js/src/playwright.ts b/js/src/playwright.ts index f0bc4e7..465e31c 100644 --- a/js/src/playwright.ts +++ b/js/src/playwright.ts @@ -121,7 +121,7 @@ function buildArgs(options: LaunchOptions): string[] { } // Timezone/locale flags — always inject when set if (options.timezone) { - args.push(`--timezone=${options.timezone}`); + args.push(`--fingerprint-timezone=${options.timezone}`); } if (options.locale) { args.push(`--lang=${options.locale}`); diff --git a/js/src/puppeteer.ts b/js/src/puppeteer.ts index afab62d..31bbcde 100644 --- a/js/src/puppeteer.ts +++ b/js/src/puppeteer.ts @@ -90,7 +90,7 @@ function buildArgs(options: LaunchOptions): string[] { args.push(...options.args); } if (options.timezone) { - args.push(`--timezone=${options.timezone}`); + args.push(`--fingerprint-timezone=${options.timezone}`); } if (options.locale) { args.push(`--lang=${options.locale}`); diff --git a/js/src/types.ts b/js/src/types.ts index bf7f3fe..089a59a 100644 --- a/js/src/types.ts +++ b/js/src/types.ts @@ -11,7 +11,7 @@ export interface LaunchOptions { args?: string[]; /** Include default stealth fingerprint args (default: true). Set false to use custom --fingerprint flags. */ stealthArgs?: boolean; - /** IANA timezone, e.g. "America/New_York". Sets --timezone binary flag. */ + /** IANA timezone, e.g. "America/New_York". Sets --fingerprint-timezone binary flag. */ timezone?: string; /** BCP 47 locale, e.g. "en-US". Sets --lang binary flag. */ locale?: string; diff --git a/js/tests/config.test.ts b/js/tests/config.test.ts index ca994b2..d910b13 100644 --- a/js/tests/config.test.ts +++ b/js/tests/config.test.ts @@ -69,9 +69,9 @@ describe("config", () => { }); describe("buildArgs timezone/locale", () => { - it("injects --timezone when timezone is set", () => { + it("injects --fingerprint-timezone when timezone is set", () => { const args = _buildArgsForTest({ timezone: "America/New_York" }); - expect(args).toContain("--timezone=America/New_York"); + expect(args).toContain("--fingerprint-timezone=America/New_York"); }); it("injects --lang when locale is set", () => { @@ -81,20 +81,20 @@ describe("buildArgs timezone/locale", () => { it("injects both when both are set", () => { const args = _buildArgsForTest({ timezone: "Europe/Berlin", locale: "de-DE" }); - expect(args).toContain("--timezone=Europe/Berlin"); + expect(args).toContain("--fingerprint-timezone=Europe/Berlin"); expect(args).toContain("--lang=de-DE"); }); it("injects timezone/locale even when stealthArgs=false", () => { const args = _buildArgsForTest({ stealthArgs: false, timezone: "America/New_York", locale: "en-US" }); - expect(args).toContain("--timezone=America/New_York"); + expect(args).toContain("--fingerprint-timezone=America/New_York"); expect(args).toContain("--lang=en-US"); expect(args.some(a => a.startsWith("--fingerprint="))).toBe(false); }); it("does not inject flags when not set", () => { const args = _buildArgsForTest({}); - expect(args.some(a => a.startsWith("--timezone="))).toBe(false); + expect(args.some(a => a.startsWith("--fingerprint-timezone="))).toBe(false); expect(args.some(a => a.startsWith("--lang="))).toBe(false); }); }); diff --git a/tests/test_build_args.py b/tests/test_build_args.py index af10ebc..bcb0433 100644 --- a/tests/test_build_args.py +++ b/tests/test_build_args.py @@ -4,9 +4,9 @@ from cloakbrowser.browser import _build_args def test_timezone_injected(): - """--timezone flag should appear when timezone is set.""" + """--fingerprint-timezone flag should appear when timezone is set.""" args = _build_args(stealth_args=True, extra_args=None, timezone="America/New_York") - assert "--timezone=America/New_York" in args + assert "--fingerprint-timezone=America/New_York" in args def test_locale_injected(): @@ -18,14 +18,14 @@ def test_locale_injected(): def test_both_injected(): """Both flags should appear when both are set.""" args = _build_args(stealth_args=True, extra_args=None, timezone="Europe/Berlin", locale="de-DE") - assert "--timezone=Europe/Berlin" in args + assert "--fingerprint-timezone=Europe/Berlin" in args assert "--lang=de-DE" in args def test_timezone_independent_of_stealth_args(): - """--timezone should be injected even when stealth_args=False.""" + """--fingerprint-timezone should be injected even when stealth_args=False.""" args = _build_args(stealth_args=False, extra_args=None, timezone="America/New_York", locale="en-US") - assert "--timezone=America/New_York" in args + assert "--fingerprint-timezone=America/New_York" in args assert "--lang=en-US" in args # No stealth fingerprint args assert not any(a.startswith("--fingerprint=") for a in args) @@ -34,7 +34,7 @@ def test_timezone_independent_of_stealth_args(): def test_no_flags_when_not_set(): """No timezone/lang flags when params are None.""" args = _build_args(stealth_args=True, extra_args=None) - assert not any(a.startswith("--timezone=") for a in args) + assert not any(a.startswith("--fingerprint-timezone=") for a in args) assert not any(a.startswith("--lang=") for a in args) @@ -42,5 +42,5 @@ def test_extra_args_preserved(): """Extra args should still be included alongside timezone/locale.""" args = _build_args(stealth_args=True, extra_args=["--disable-gpu"], timezone="Asia/Tokyo", locale="ja-JP") assert "--disable-gpu" in args - assert "--timezone=Asia/Tokyo" in args + assert "--fingerprint-timezone=Asia/Tokyo" in args assert "--lang=ja-JP" in args