Humanized actions could fail with an element-not-attached error after a
navigation driven by a click or form submit, since the checks only refreshed
on goto. Now refresh on any main-frame navigation. Python, JS
Playwright/Puppeteer, and .NET. Regression from 0.5.6.
Wire the existing launch()-time geoip resolver into the info/doctor command
across Python, JS, and .NET. With --proxy, info resolves the exit IP and the
timezone/locale a launch would apply (caching the GeoIP DB if absent) and prints
them in text and --json. Plain info is unchanged (no network) and now hints at
the flag. Adds diagnostics tests in all three suites.
An element scrolled into view can be pushed off screen again while we wait
for a reflowing page to settle. Nothing scrolled a second time, so the click
was dispatched outside the viewport and hit nothing, with no error raised.
Also stop the pointer-events check from turning a confirmed miss back into
'undetermined' when a late probe times out, which let that click through.
Measured on a page reflowing 10-25s: silent miss at ~32s before, clean click
now. Static pages and pages reflowing past the timeout are unchanged.
A concurrent-session denial resolves after the CDP handshake, so the browser
exits with a live connection already established. The launch-failure path never
sees it and the user gets a bare TargetClosedError on their first call (#477).
The binary records the license exit code (76-79) to a per-launch file whose path
the wrapper passes via CLOAKBROWSER_LICENSE_STATUS_FILE. The wrapper reads it
when a guarded call throws and re-raises the correct CloakBrowserLicenseError.
Discrimination is on the file, not the error type, so a genuine crash is never
mislabelled. Fail-safe (no key or unwritable dir -> feature off) and
backward-compatible (old binaries never write the file).
Guarded surfaces: new_page/new_context, a persistent context's already-open
pages (goto + the wait family), and Puppeteer user-created contexts. Orphaned
denial files are swept at mint time; an observed code is cached in-process so a
concurrent second call can't miss it; the .NET reader parses as tolerantly as
Python/JS.
Implemented across Python, JavaScript (Playwright + Puppeteer), and .NET, with
unit tests. Reproduced end-to-end with a real over-cap denial.
Node pools HTTPS connections by destination, so a second launch() in the
same process reused the first proxy's tunnel to the echo service and
inherited its exit IP, timezone and locale.
cmd.exe defaults to cp850/cp1252, which carry no check mark or arrow.
Printing one raised UnicodeEncodeError and aborted the report at the
Launch line, so everything after it was lost — including on the success
path, once the launch probe stopped failing.
Marks now degrade to plain text per glyph when the console cannot
encode them. UTF-8 consoles (Linux, macOS, Windows Terminal) keep the
original output byte for byte.
.NET substitutes rather than throwing here (verified on the reference
box), so only the Python wrapper needed the change.
Chromium only handles --version on POSIX, so on Windows the switch is
ignored and a browser starts instead of printing. The 10s probe then
timed out and a healthy install was reported as broken, flashing a
window on screen each run.
Probe with --no-startup-window there: it exits immediately, opens no
window, and a broken binary still exits non-zero. No version is
reported on Windows, as nothing is printed. Linux and macOS unchanged.
Test uses a stub that hangs unless the flag is passed, mirroring the
real binary rather than a print-and-exit stub.
Add a preview release channel system to all wrappers (Python, JavaScript, .NET),
allowing users to opt into newer binary builds before they go stable.
- Python: preview/stable channel resolution in download, launch, CLI
(install, update, clear-cache), and license validation
- JavaScript: preview/stable channel in CLI, launch, license, and config
- .NET: preview/stable channel in CLI, license, diagnostics, and config
- All wrappers: channel fallback indicator, auto-update gate,
CLOAKBROWSER_RELEASE_CHANNEL env var support
- Harden channel resolution: reuse the resolution sidecar on offline lookups,
defensive marker/JSON parsing, atomic version-marker writes, a launch-time
preview-to-stable fallback notice, channel-aware info download URL, and
Python/JS/.NET parity for the fallback default
- Binary 150.0.7871.114.4 changelog (Linux x64 + arm64)
- Updated READMEs, CHANGELOG, and tests for all wrappers
A raw --fingerprint-timezone/--lang/--fingerprint-locale in args is now
promoted to an explicit value in maybe_resolve_geoip, so geoip only fills
the values the user did not set. Mirrors the timezone=/locale= param path.
Python, JS, and .NET, with tests.
Points the READMEs at 150 as the latest Pro binary (71 patches, all five
platforms) and bumps the Pro major in the launch banner and the info
upgrade hint across Python, JS, and .NET.
The Pro binary exits with a distinct code per license failure; the wrappers ignored it, so a user got a bare "browser closed" error with no reason.
Add CloakBrowserLicenseError plus a launch-error parser that maps the exit code to a clear message, mirrored across the Python, JS, and .NET wrappers. Non-license failures pass through unchanged.
Route authenticated HTTP/HTTPS proxies through the browser's native proxy
authentication only on binaries that support it, resolved per platform and
binary version via a capability gate (sibling to the existing viewport and
window-geometry gates). Older binaries, including the free macOS and ARM
builds, fall back to the standard Playwright proxy path instead of emitting
credentials the binary cannot parse, so authenticated proxies keep working on
macOS and ARM instead of silently failing. Applied across the Python,
JavaScript, Puppeteer, and .NET wrappers.
With humanize=True, Locator/frame actions on an element inside an iframe
(frame.locator("#btn").click(), fill(), hover(), the frame.click(...)
equivalents) raised ElementNotAttachedError because the humanize layer
resolved every selector against the main frame. Route sub-frame locators
and frame-level actions through the owning frame's own document, keeping
humanized mouse motion inside the iframe; native fallback when the box
can't be read or the frame is detached. Python only (JS and .NET were
already frame-correct).
Adds mocked routing unit tests (sub-frame -> owning frame, main-frame ->
page, unpatched -> native), the human_click arg-order + _frame_fill
fallback guards, and @slow real-binary iframe integration tests.
Entry-point guard compared import.meta.url to an unresolved process.argv[1];
Node resolves import.meta.url through symlinks but argv[1] stays as invoked,
so npm/pnpm/npx bin symlinks never matched and no subcommand ran. Realpath
the invoked path before comparing.
Free-tier launch banner and 'cloakbrowser info' upgrade hint now advertise
the 7-day free Pro trial (Chromium 148) across Python, JS, and .NET; same
CTA added to both READMEs. Also surface binary verification failures verbatim
instead of falling back to a cached build (transient-only fallback).
info (plus a doctor alias) now reports the binary that will actually
launch for the resolved license instead of whatever is cached on disk:
it resolves and validates the license, shows the real tier, and on a
keyless or invalid key reports the free binary. Adds a launch test
(chrome --version) with a Linux missing-shared-library probe, a
Windows-font check (Linux only), GeoIP DB presence, and optional-dep
checks. --quick skips the launch test; --json emits machine output.
Python, JS, and .NET, with tests.
One-time, suppressible startup warning when spoofing Windows on a Linux host
with no Windows fonts detected (fc-list probe of the documented base set),
across Python, JS, and .NET. The first-launch banner now re-shows to free
users every 3 days; Pro users still see it once.
- .NET 8 / C# client published to NuGet (PR #385, @evelaa123)
- macOS Pro binary now available (darwin arm64 + Intel), so Pro downloads
the latest build on every platform
- README: Platforms table split into Free/Pro; drop the stale Roadmap and the
macOS-fingerprint troubleshooting note
Replace the same-origin checksum with a detached Ed25519 signature
(SHA256SUMS.sig) verified against a pinned public key before extraction,
closing #308: a compromised download mirror can no longer certify a
tampered binary. The signed manifest also binds the release version,
rejecting a forced downgrade to an older signed build.
Verification is mandatory and non-bypassable on the official download path;
custom CLOAKBROWSER_DOWNLOAD_URL mirrors keep the legacy skippable checksum.
Silent auto-update is preserved for everyone because only a constant public
key is pinned, not per-version hashes. Older installed wrappers are
unaffected — the version= line is ignored by their checksum parser.
Python uses cryptography; JS uses node:crypto. Adds tamper, downgrade, and
fail-closed tests in both languages.
Headed launches applied a fixed emulated viewport on top of the real
browser window, yielding outerWidth < innerWidth (an impossible window).
Default headed new_page()/new_context() to no_viewport so the page tracks
the real window; headless keeps a deterministic viewport. Covers Python
launch/launch_context/launch_persistent_context (+async) and the JS
Playwright/Puppeteer wrappers. Explicit viewport still honored.
Patchright scored identically to plain Playwright on reCAPTCHA v3 (the
binary handles stealth at C++ level) while breaking proxy auth and
add_init_script (#27). Removed the backend param, CLOAKBROWSER_BACKEND
env var, the patchright extra, and the two backend-specific tests.
Stock Playwright is now the only backend.