Drive the Chromix stealth Chromium engine with a CloakBrowser-compatible API —
function names, keyword arguments, return types (Playwright Browser / BrowserContext)
and CLOAKBROWSER_* env-var names all match the cloakbrowser
wrapper, so existing CloakBrowser scripts run on Chromix by changing only the import:
- from cloakbrowser import launch
+ from chromix import launchfrom chromix import launch
browser = launch(proxy="http://user:pass@proxy:8080", geoip=True, humanize=True)
page = browser.new_page()
page.goto("https://example.com")
browser.close()pip install chromix playwrightThe distribution and import package are both named chromix. To install the
SDK directly from a repository checkout instead, run:
pip install ./sdk/python playwrightOn first launch the stealth Chromium binary is downloaded from this repo's GitHub
Release, SHA256-verified, and cached under ~/.cache/chromix. Point
CLOAKBROWSER_BINARY_PATH at a local build (e.g. your own chrome.exe) to skip
the download.
| Function | Description |
|---|---|
launch(**opts) |
Returns a Playwright Browser |
launch_async(**opts) |
Async variant |
launch_context(**opts) |
Returns a BrowserContext (native viewport by default) |
launch_context_async(**opts) |
Async variant |
launch_persistent_context(user_data_dir, **opts) |
Persistent profile |
launch_persistent_context_async(user_data_dir, **opts) |
Async variant |
build_args / get_default_stealth_args |
Arg assembly (32-bit random seed + native platform claim) |
maybe_resolve_geoip(geoip, proxy, tz, locale, args) |
Egress IP → (tz, locale, exit_ip) |
ensure_binary / clear_cache / binary_info / check_for_update |
Binary management |
HumanConfig / resolve_human_config |
Behavioral-layer config (default / careful presets) |
ProxySettings |
Playwright-shaped proxy TypedDict |
Options (headless, proxy, args, stealth_args, timezone, locale, geoip, humanize, human_preset, human_config, extension_paths, license_key, browser_version, release_channel, user_agent, viewport, color_scheme) match CloakBrowser
name-for-name; **kwargs passes through to playwright.chromium.launch() /
browser.new_context().
Persistent contexts create .chromix-fingerprint-seed inside
user_data_dir on first stealth launch and reuse it thereafter. The file is
one decimal 32-bit seed followed by a newline, uses the same format as the
Node SDK, and is published atomically for concurrent first launches. An
explicit --fingerprint=... in args wins without creating or rewriting the
file; stealth_args=False also skips seed I/O. Defaults claim the native
persona: linux, windows, or macos. Default viewport geometry is native.
The browser's public fingerprint mode supplies CPU/RAM 8/8, platform-specific
screen/taskbar defaults and a 102400 MiB quota. The older seeded synthetic
viewport/hardware pools require args=["--uxr-synthetic-device-tests=true"];
that separate test mode retains deterministic cross-SDK templates. Explicit
viewport options still win outside measured mode.
Explicit synthetic seeds accept nonzero decimal uint64 values, including values
above 2**32; Python and Node derive identical geometry. Malformed seeds, conflicting
screen/taskbar aliases, invalid work areas and incomplete viewport pairs fail instead
of silently choosing another template. --uxr-viewport-width/--uxr-viewport-height
override the UI-strip template. Screen dimensions and DPR (including 1) are sent
together with a configured viewport; viewport=None keeps native context geometry.
The launch display backend requires
a browser rebuilt from the current patch stack.
All listed public flags are passed through args: GPU vendor/renderer,
hardware concurrency, device memory, screen/taskbar, brand/version/platform
version, timezone/locale, storage quota, Windows font metrics, WebRTC IP/auto,
noise/off, third-party cookies, Windows voice tables and FakeShadowRoot.
See the complete flag contract for defaults
and native-versus-SDK boundaries. These source changes require a rebuilt browser;
updating this Python package alone does not upgrade an older executable.
browser = launch(args=[
"--fingerprint=42",
"--fingerprint-brand=Edge",
"--fingerprint-brand-version=152.0.0.0",
"--fingerprint-noise=false",
"--fingerprint-allow-3p-cookies",
"--enable-blink-features=FakeShadowRoot",
])--fingerprint=off also accepts false/0/disable/disabled and strips the
injected platform. Explicit timezone/locale and geoip=True still apply their
regional settings; omit them for a native-persona comparison. noise=false
keeps identity seeds and disables existing perturbation paths, not four new
Canvas/WebGL/audio/client-rect noise implementations.
launch_context(device_pool={"host": "record.json", "records": ["record.json"], "seed": "42"}) validates whole evidence bundles and native host capabilities,
then checks five live contexts before returning. Async and persistent context
variants support the same option; the async persistent directory is keyword-only.
Point CLOAKBROWSER_BINARY_PATH at the collected executable. Evidence defaults to
a 24-hour maximum age, and extra launch/context overrides are rejected. Persistent
profiles bind record and seed rather than rotating identities. Browser-returning
launch does not support this option. See device pool documentation
for collection, configuration, native fallback and remaining acceptance limits.
fonts_dir="path/to/fonts" parses .ttf / .otf / .ttc family names and,
on Linux, configures the actual Fontconfig directory. It does not install fonts
into the Windows/macOS font backend or prove the file used for each glyph.
Family whitelisting, substitution and persona fallback now require
--uxr-synthetic-device-tests=true; normal launches keep native font selection.
An explicit whitelist overrides SDK-generated names only in that test mode.
Measured device mode rejects fonts_dir and other per-field overrides.
browser = launch(fonts_dir="C:/fontsets/win11-segoe-only")CLOAKBROWSER_BINARY_PATH— use a local chrome binary instead of downloadingCLOAKBROWSER_VERSION/CLOAKBROWSER_RELEASE_CHANNEL— pin a version/channelCLOAKBROWSER_GEOIP_TIMEOUT_SECONDS— geoip lookup timeoutCLOAKBROWSER_WIDEVINE_CDM— explicit Widevine CDM dir (DRM);CLOAKBROWSER_WIDEVINE=0disables DRMCHROMIX_CACHE_DIR/CHROMIX_DOWNLOAD_HOST— cache location / release host override
High-risk engine ports are available only through explicit browser args:
browser = launch(args=[
"--fingerprint-devtools-runtime-suppression",
"--fingerprint-canvas-bridge=127.0.0.1:9228",
"--fingerprint-canvas-bridge-unsafe",
])Runtime suppression can break console/binding-based automation. Canvas Bridge removes the sandbox from bridge renderer processes and forwards canvas/WebGL operations to the configured endpoint.
GeoIP is metadata, not a routing mechanism. The lookup uses the effective
HTTP/HTTPS/SOCKS proxy and does not inherit environment proxies or NO_PROXY
bypasses. Failed lookups do not fall back to the host connection. Metadata
transport supports SOCKS4/4a/5/5h, including SOCKS5 credentials. This does not
add SOCKS authentication or every URL alias to Chromium/Playwright's proxy
backend. SOCKS5/4a resolve destination names at the proxy; SOCKS4 uses local
IPv4 DNS. Single raw --proxy-server routes are supported for lookup;
PAC/auto-detect, route lists, empty raw proxies, raw proxy credentials and
conflicting --no-proxy-server are rejected. If raw --proxy-server and a
high-level proxy are both supplied, their endpoints must match (default ports
and equivalent IPv6 spellings are normalized); use the high-level option for credentials.
With a proxy, the SDK defaults to the native
--force-webrtc-ip-handling-policy=disable_non_proxied_udp unless an explicit
native policy was supplied. This does not guarantee the routing of all DNS,
HTTP, QUIC or operating-system traffic.
--fingerprint-webrtc-ip=<IPv4|IPv6|auto> is supported. Auto resolves before
launch through the same effective proxy; geoip=True reuses its one lookup to
append the exit IP unless an explicit IP wins. Off mode skips IP injection.
The browser changes local candidate/SDP/stats presentation, not sockets or
STUN success; remote addresses, zero placeholders and relay allocations remain
native. webrtc-fake-srflx and webrtc-fake-srflx-allow-udp (including uxr
equivalents) remain rejected. The SDK's HTTP metadata service is unauthenticated
and is not proof of an exit route. Bare-browser auto uses its own bounded HTTPS
startup resolver; see the full resolution contract.
GeoIP lookup failures now raise ValueError. The timeout defaults to 10
seconds and accepts values greater than zero and at most 60. Python's
synchronous DNS/connection setup cannot always be interrupted at that
deadline; a late connection is rejected before sending the GeoIP request.
IANA timezone data must be installed for timezone validation. Creating a
later context with another proxy does not recompute browser-level locale
or timezone/IP.
python -m chromix install # pre-download the binary
python -m chromix info # binary / cache info
python -m chromix widevine # fetch the Widevine CDM (Linux x64)
python -m chromix clear-cachelicense_keyis accepted and ignored (one open tier).geoipqueries ip-api.com over HTTP instead of a local GeoLite2 database; explicittimezone=/locale=always win.- No
cloakbrowser/puppeteersubpath — use the Playwright surface. - Widevine is enabled automatically when a CDM is present (installed Chrome,
CLOAKBROWSER_WIDEVINE_CDM, orpython -m chromix widevine).
The Python SDK is available under the BSD 3-Clause License. See
LICENSE.
Point CLOAKBROWSER_BINARY_PATH at a matching rebuilt browser with native sync support. Previously published
browser releases lack the native sync protocol. Use one headed browser window per
instance, with matching page state, tab order and window geometry.
from chromix import launch_async, SyncGroup
leader = await launch_async(headless=False, sync=True)
follower = await launch_async(headless=False, sync=True)
await leader.new_page()
await follower.new_page()
group = SyncGroup(leader=leader, followers=[follower])
group.on("member_error", lambda event: print(event["error"]))
await group.start()
# await group.pause(); await group.resume()
# await group.add_follower(another_browser)
# await group.set_leader(follower)
# await group.remove_follower(old_follower)
await group.close() # browsers remain open
await leader.close()
await follower.close()launch_context_async and launch_persistent_context_async accept sync=True
as well. The synchronous launch APIs and measured device_pool launches are not
supported by this async synchronization API. SyncGroup can also be used with
async with; always close the group before closing its browsers.
Events are state_changed (state string) and member_error (dictionary with
browser and error). members gives follower snapshots. Failures or excessive
queue lag pause the affected follower; capture failure pauses the group. After
fixing the cause, explicitly pause/resume to rejoin. Old operations are not replayed
on reconnect. A group exclusively owns its endpoints until removal or close.
For custom launches, pass a SyncEndpoint's args to Chromium and pass that
endpoint to SyncGroup. The low-level request(method, **params) interface follows
the native protocol; manual clients own ordering,
heartbeats and cleanup. Use the default Windows Proactor event loop. A capture
iterator and synchronous group API are not included in v1.
Run python sdk/python/examples/sync.py <rebuilt-chrome.exe> from the checkout.
This is an experimental native module; complete a matching build and the native
manual verification checklist before relying on real input replay.