CloakBrowser
Use this guide to run PinchTab with a CloakBrowser Chromium binary. PinchTab stays the API and automation control plane. CloakBrowser supplies the browser executable and native fingerprint patches.
agent -> PinchTab API -> PinchTab bridge -> CloakBrowser Chromium
What PinchTab Supports
PinchTab can launch a user-installed CloakBrowser binary with:
browsers.default=cloakbrowser.binary=/absolute/path/to/cloakbrowser/chrome- structured fingerprint settings under
browser.cloak - PinchTab profile directories, tab lifecycle, screenshots, snapshots, actions, downloads, uploads, clipboard, and evaluate endpoints
/stealth/statusreporting for the active browser, native Cloak mode, and PinchTab overlay status
When browser.cloak.disableDefaultStealthArgs=true, PinchTab disables its
overlapping JavaScript stealth overlays and automation-hiding launch flags.
PinchTab still controls browser lifecycle, user data directories,
headless/headed mode, remote debugging, tab limits, and action humanization.
PinchTab does not bundle CloakBrowser in release binaries, npm packages, Homebrew formulae, or the default published Docker image.
Console log capture
CloakBrowser’s native patches suppress CDP Runtime domain events after the
first navigation (enabling that domain is a well-known bot-detection vector),
so the standard Runtime.consoleAPICalled stream PinchTab uses on Chrome
never delivers page console output. PinchTab detects this via the browser
capability registry and instead attaches a second, read-only CDP session per
tab that listens on the deprecated-but-functional Console domain. Console
logs (/console, audit consoleLogs) and uncaught page errors (/errors)
work on Cloak through that fallback. Nothing is injected into the page, so
the fallback adds no fingerprint surface.
Licensing
CloakBrowser has two relevant pieces:
- wrapper packages and source code
- the compiled CloakBrowser Chromium binary
The wrapper source is MIT licensed. The compiled Chromium binary has a separate license. Do not vendor, copy, or redistribute that binary in PinchTab release artifacts or public Docker images unless the license explicitly permits that use.
PinchTab’s distribution policy for CloakBrowser is:
- PinchTab does not bundle any CloakBrowser binary in released artifacts —
not in
./dev binaries, not in the npm package, not in the Homebrew formula, not in the publishedpinchtab/pinchtaborghcr.io/pinchtab/pinchtabDocker images. - Users supply their own CloakBrowser binary on disk and point
browser.binary(orbrowser.targets.<name>.binary) at it. - The local Docker file
tests/tools/docker/cloakbrowser-smoke.Dockerfileexists for local smoke/test purposes only. It is not pushed to any registry and is not a release artifact. - There is no public CloakBrowser-bundled PinchTab release image and no hosted service. None are planned until redistribution, OEM, or SaaS terms are clear with the upstream CloakBrowser maintainers.
The safe default is: install or download CloakBrowser yourself, then point
PinchTab at that local binary path if it is not discoverable. PinchTab
automatically prefers a discoverable local CloakBrowser installation when
browsers.default is omitted, including in a newly generated config. Existing
configs that explicitly choose Chrome continue to use Chrome.
Review:
Install CloakBrowser
Install CloakBrowser through one of its official package paths, then use the
reported Chromium binary path as PinchTab’s browser.binary.
Python:
pip install cloakbrowserpython -m cloakbrowser installpython -m cloakbrowser info
pip install cloakbrowserpython -m cloakbrowser installpython -m cloakbrowser info
JavaScript:
npm install cloakbrowser playwright-corenode -e "import('cloakbrowser').then(async m => { await m.ensureBinary(); console.log(m.binaryInfo()); })"
npm install cloakbrowser playwright-corenode -e "import('cloakbrowser').then(async m => { await m.ensureBinary(); console.log(m.binaryInfo()); })"
Use an absolute path to the chrome executable reported by the installer.
Configure PinchTab
Create or update your PinchTab config:
pinchtab config initpinchtab config set browsers.default cloak # CLI: --browser=cloakpinchtab config set browser.binary /absolute/path/to/cloakbrowser/chromepinchtab config set browser.cloak.fingerprintSeed 42069pinchtab config set browser.cloak.platform windowspinchtab config set browser.cloak.timezone Europe/Londonpinchtab config set browser.cloak.locale en-GB
pinchtab config initpinchtab config set browsers.default cloak # CLI: --browser=cloakpinchtab config set browser.binary /absolute/path/to/cloakbrowser/chromepinchtab config set browser.cloak.fingerprintSeed 42069pinchtab config set browser.cloak.platform windowspinchtab config set browser.cloak.timezone Europe/Londonpinchtab config set browser.cloak.locale en-GB
Example config fragment:
{
"browsers": {
"default": "cloak"
},
"browser": {
"binary": "/absolute/path/to/cloakbrowser/chrome",
"cloak": {
"fingerprintSeed": "42069",
"platform": "windows",
"timezone": "Europe/London",
"locale": "en-GB",
"webrtcIP": "auto",
"disableDefaultStealthArgs": true
}
},
"instanceDefaults": {
"mode": "headless",
"humanize": true
}
}
Use a fixed browser.cloak.fingerprintSeed when revisiting the same site from
the same profile. Keep browser.cloak.disableDefaultStealthArgs set to true
unless you intentionally want to layer PinchTab’s legacy stealth behavior over
CloakBrowser’s native patches.
Cloak Options
PinchTab maps these browser.cloak fields to CloakBrowser launch flags:
| Config field | Launch flag |
|---|---|
fingerprintSeed | --fingerprint=<seed> |
platform | `—fingerprint-platform=<windows |
timezone | --fingerprint-timezone=<iana timezone> |
locale | --fingerprint-locale=<locale> |
webrtcIP | `—fingerprint-webrtc-ip=<ip |
fontsDir | --fingerprint-fonts-dir=<path> |
storageQuotaMB | --fingerprint-storage-quota=<mb> |
Use browser.extraFlags only for advanced CloakBrowser flags that do not have a
structured PinchTab field.
{
"browsers": {
"default": "cloak"
},
"browser": {
"binary": "/absolute/path/to/cloakbrowser/chrome",
"cloak": {
"fingerprintSeed": "42069",
"timezone": "Europe/London",
"locale": "en-GB"
},
"extraFlags": "--fingerprint-brand=Chrome"
}
}
Be conservative with raw flags. PinchTab owns lifecycle flags such as remote debugging port, user data dir, headless mode, window size, extension paths, and user agent.
Start PinchTab
Start the server:
pinchtab serverpinchtab server In another shell, check that the server is healthy and can drive a page:
pinchtab healthpinchtab nav https://example.com --snap
pinchtab healthpinchtab nav https://example.com --snap
If your security policy blocks public navigation, add the exact host to
security.allowedDomains before using a public URL.
Verify Configuration With pinchtab doctor
Before starting the server, run the read-only diagnostic command. It checks the configured binary, executes it briefly, and validates fingerprint flags without mutating any state:
pinchtab doctor # human-readable reportpinchtab doctor --json # machine-readable JSONpinchtab doctor browser cloak-eu # scope to one browser.targets entrypinchtab doctor --check binary_exists # run a single check by name
pinchtab doctor # human-readable reportpinchtab doctor --json # machine-readable JSONpinchtab doctor browser cloak-eu # scope to one browser.targets entrypinchtab doctor --check binary_exists # run a single check by name
Exit codes: 0 all checks passed or skipped, 1 at least one check failed,
2 config or usage error. See the Troubleshooting section
below for how to react to specific failures.
Verify CloakBrowser Is Active
Check /stealth/status after the managed browser instance starts:
TOKEN="$(pinchtab config get server.token)"curl -sS -H "Authorization: Bearer ${TOKEN}" \ http://127.0.0.1:9867/stealth/status
TOKEN="$(pinchtab config get server.token)"curl -sS -H "Authorization: Bearer ${TOKEN}" \ http://127.0.0.1:9867/stealth/status
Look for these fields:
{
"provider": "cloak",
"native": true,
"pinchtabOverlaysDisabled": true,
"fingerprintSeed": "42069"
}
If launch fails, inspect the instance:
pinchtab instancespinchtab instance logs <instance-id>
pinchtab instancespinchtab instance logs <instance-id>
Common causes:
- the configured binary path does not exist
- the binary is not executable
- the CloakBrowser binary was downloaded for a different operating system
- the profile directory is locked by another browser process
- a raw extra flag conflicts with PinchTab-owned lifecycle behavior
Docker
The published pinchtab/pinchtab and ghcr.io/pinchtab/pinchtab images include
Alpine Chromium. They do not include CloakBrowser.
For local Docker use with CloakBrowser, build the dedicated local image:
docker build \ -f tests/tools/docker/cloakbrowser-smoke.Dockerfile \ -t pinchtab-cloakbrowser:local \ .
docker build \ -f tests/tools/docker/cloakbrowser-smoke.Dockerfile \ -t pinchtab-cloakbrowser:local \ .
Create a config that points PinchTab at the CloakBrowser binary inside that image:
{
"server": {
"bind": "0.0.0.0",
"port": "9867",
"token": "replace-me",
"stateDir": "/data"
},
"browsers": {
"default": "cloak"
},
"browser": {
"binary": "/opt/cloakbrowser/chrome",
"cloak": {
"fingerprintSeed": "42069",
"platform": "linux",
"timezone": "UTC",
"locale": "en-US",
"disableDefaultStealthArgs": true
}
},
"instanceDefaults": {
"mode": "headless",
"humanize": true
},
"profiles": {
"baseDir": "/data/profiles",
"defaultProfile": "default"
}
}
Run the container with the config mounted read-only:
docker run -d \ --name pinchtab-cloak \ -p 127.0.0.1:9867:9867 \ --shm-size=2g \ -v pinchtab-cloak-data:/data \ -v "$PWD/pinchtab-cloak.json":/config/pinchtab.json:ro \ -e PINCHTAB_CONFIG=/config/pinchtab.json \ pinchtab-cloakbrowser:local
docker run -d \ --name pinchtab-cloak \ -p 127.0.0.1:9867:9867 \ --shm-size=2g \ -v pinchtab-cloak-data:/data \ -v "$PWD/pinchtab-cloak.json":/config/pinchtab.json:ro \ -e PINCHTAB_CONFIG=/config/pinchtab.json \ pinchtab-cloakbrowser:local
Do not publish or push a CloakBrowser-bundled image unless the CloakBrowser binary license explicitly permits redistribution for your use case.
Maintainer Validation
Project maintainers can validate the Docker integration with:
./dev e2e --browser=cloak./dev e2e --browser=cloak That command swaps the runtime browser to browsers.default=cloak
(/opt/cloakbrowser/chrome, fingerprintSeed=42069,
disableDefaultStealthArgs=true), reuses the prebuilt
pinchtab-cloakbrowser:test image (build it once via
tests/tools/docker/cloakbrowser-smoke.Dockerfile — the runner does not
auto-build it), asserts /stealth/status reports
provider=cloak, native=true, pinchtabOverlaysDisabled=true, fingerprintSeed=42069, and runs the full E2E suite against the cloak
container.
Use ./dev smoke --browser=cloak for the full local CloakBrowser smoke set.
Use ./dev smoke cloakbrowser when you only need the specialized parity legs,
including --multi-target, --profile-persistence, and
--profile-lock-recovery.
Attaching a running CloakBrowser
If CloakBrowser is already running with remote debugging enabled (for example,
under CloakBrowser Manager), you can attach it to PinchTab through the normal
CDP attach path. PinchTab spawns a child pinchtab bridge --cdp-attach ... wrapper
around the external endpoint and exposes the standard API on a local port.
curl -X POST http://localhost:9867/instances/attach \ -H "Content-Type: application/json" \ -d '{ "name": "cloak-manager-profile", "cdpUrl": "ws://127.0.0.1:9222/devtools/browser/abc123", "provider": "cloak", "browser": "cloak-1" }'
curl -X POST http://localhost:9867/instances/attach \ -H "Content-Type: application/json" \ -d '{ "name": "cloak-manager-profile", "cdpUrl": "ws://127.0.0.1:9222/devtools/browser/abc123", "provider": "cloak", "browser": "cloak-1" }'
For a remote CloakBrowser attach:
browsershould name a CloakBrowser target (or thecloakprovider) whenbrowser.targetsis configured; if omitted, the configured default target is usedproviderin the JSON body must becloakwhen no browser target is configured, or must match the selected target when both fields are present/stealth/statusreportsprovider=cloak,launchMode=remote-cdp,native=true, andpinchtabOverlaysDisabled=true— PinchTab does not inject its JS fingerprint overlays, on the assumption the external browser owns native fingerprint behavior- stopping the attached PinchTab instance shuts down the wrapper bridge only; the external CloakBrowser process is left running
The opt-in smoke ./dev smoke cdp-attach exercises this path against a
locally-built CloakBrowser image.
Troubleshooting
Most CloakBrowser launch failures fall into one of the buckets below. Run
pinchtab doctor first — it isolates the failure to a specific named check
and removes the need to guess.
Missing binary
Symptom: pinchtab doctor reports binary_exists: FAIL, or the server logs
stat /path/to/cloakbrowser/chrome: no such file or directory when starting an
instance.
Fix: set browser.binary (or browser.targets.<name>.binary for named
targets) to an absolute path that exists and is executable:
pinchtab config set browser.binary /absolute/path/to/cloakbrowser/chrome# or, for a named target:pinchtab config set browser.targets.cloak-eu.binary /absolute/path/to/cloakbrowser/chrome
pinchtab config set browser.binary /absolute/path/to/cloakbrowser/chrome# or, for a named target:pinchtab config set browser.targets.cloak-eu.binary /absolute/path/to/cloakbrowser/chrome
PinchTab does not search $PATH for CloakBrowser. Use the absolute path
reported by python -m cloakbrowser info or cloakbrowser.binaryInfo().
Unsupported platform build
Symptom: pinchtab doctor reports binary_starts: FAIL with a non-zero
exit code, a segfault, or an exec format error.
Fix: the CloakBrowser binary is platform-specific (CPU architecture and operating system). A Linux x86_64 binary will not run on macOS arm64 and vice versa. Reinstall CloakBrowser for the platform you are actually running on, and refer to the upstream CloakBrowser release notes for the matrix of supported builds.
The PinchTab smoke image
(tests/tools/docker/cloakbrowser-smoke.Dockerfile) is built for the host
architecture; if you build it on arm64 and try to run the resulting image on
x86_64 (or vice versa) the inner CloakBrowser binary will fail the same way.
Profile lock conflicts
Symptom: launch fails with profile in use, or PinchTab logs a warning that
the profile lock is held.
PinchTab’s stale-SingletonLock recovery (P3b) automatically removes the
lock when the owning PID no longer exists:
- if the lock points to a live non-PinchTab process, PinchTab refuses to
steal the profile and logs
chrome profile lock appears active and owned by another pinchtab; leaving singleton files in place - if the lock points to a dead process, PinchTab logs
chrome profile lock appears active but pinchtab owner is deadand cleans up the stale files - if the lock points to a live process owned by another PinchTab, PinchTab refuses to steal it
If recovery does not happen automatically, check the container or host
logs for the chrome profile lock appears active but pinchtab owner is dead
line:
docker logs pinchtab-cloak | grep "profile lock"docker logs pinchtab-cloak | grep "profile lock" Manual recovery (only when you are sure no real CloakBrowser process is running against that profile):
rm -f /path/to/profile/{SingletonLock,SingletonCookie,SingletonSocket}rm -f /path/to/profile/{SingletonLock,SingletonCookie,SingletonSocket} Bad fingerprint / proxy / timezone combinations
Symptom: target site flags the session as automated even though
/stealth/status reports provider=cloak, native=true.
CloakBrowser’s fingerprint flags and proxy geo must be coherent. A US
residential proxy paired with cloak.timezone=Europe/London and
cloak.locale=en-GB looks suspicious to any detector that cross-checks
client locale against egress IP. Align them:
- match
browser.proxy.geo.timezoneto the proxy’s actual location - match
browser.proxy.geo.localeandbrowser.cloak.locale - match
browser.cloak.platformto a believable device for the locale - if you set
browser.cloak.webrtcIP, ensure it is not leaking the host’s real LAN range
If you cannot set the proxy’s geo by hand, leave the browser.proxy.geo
block out and let PinchTab use the proxy without geo overrides — better to
have a missing signal than a contradictory one.
Proxy geo alignment is CloakBrowser-only. Plain Chrome targets keep their normal
Chrome launch behavior and do not receive proxy-derived --lang, TZ, or
WebRTC flags.
Detection sites still flagging automation
Symptom: bot-detection demo pages (CreepJS, BrowserScan, Sannysoft, etc.) report a non-zero detection score even with CloakBrowser native stealth enabled.
This is expected to vary. Detection score is a moving target: detector heuristics change outside PinchTab releases, CloakBrowser ships new patches, Chromium versions drift, and per-site signals evolve independently of any single component.
To investigate, re-run the live-detection smoke against the configured browser:
./dev smoke live-detection # Chrome leg (baseline)./dev smoke live-detection --browser=chrome./dev smoke live-detection --browser=cloak
./dev smoke live-detection # Chrome leg (baseline)./dev smoke live-detection --browser=chrome./dev smoke live-detection --browser=cloak
The smoke captures per-site screenshots and an extracted summary into
./tests/e2e/results/live-detection/<browser>-<timestamp>/. Compare the cloak run
against the chrome baseline: a non-zero cloak score that matches the
Chrome baseline indicates a generic Chromium signal, not a CloakBrowser
regression. Re-run the smoke after upstream CloakBrowser or detector
updates rather than treating one run as authoritative.
Results from the live-detection smoke are advisory and never gate CI.
Related Guides
- docker.md — the local CloakBrowser smoke image and persistent profile volume
- attach-chrome.md — attach to an externally managed CloakBrowser via CDP
- headed-mode.md — manual headed setup (the bundled and smoke images are headless-only)
- security.md — the underlying security model, attach policy, IDPI, and token handling
Security
CloakBrowser changes browser fingerprint behavior. It does not change PinchTab’s security model.
Keep these rules:
- leave PinchTab bound to localhost unless you intentionally operate a secured remote deployment
- keep
server.tokenset when reachable outside localhost - keep
security.allowedDomainsnarrow - do not expose CDP endpoints publicly
- do not use automation against systems you do not own or have authorization to test
If a target site blocks automation, treat that as a policy and reliability signal, not just a technical obstacle.