Stealth-Chromium CDP farm: per-seed browser fingerprints over a patched CDP multiplexer.
Project description
cuttle
A stealth-Chromium CDP farm. cuttle runs a patched Chrome DevTools Protocol
(CDP) multiplexer that spawns one stealth Chrome per fingerprint seed, giving
each seed its own coherent browser identity - fingerprint, proxy, geoip, locale,
and timezone - behind a single CDP endpoint. Point any CDP client
(Playwright, Puppeteer, chromium.connectOverCDP) at it and select a seed with
a query parameter.
The Chrome engine is a free, redistributable stealth-Chromium fork baked into
the image - clark (MIT) by
default, clearcote
(BSD-3) as a fallback - so there is no proprietary binary and no license to
manage. The multiplexer is a patched derivative of CloakHQ's MIT-licensed
cloakserve.
Maintained by glim.sh.
Why
The stealth-scraping stack normally reconciles several independently-drifting upstreams by hand: the CDP multiplexer, the base image, and the Chrome fork binary - each of which moves on its own schedule, and Chrome ships a new major roughly every four weeks. cuttle owns the orchestration in one repo and consumes the browser as a pinned prebuilt, turning "always check what still works" into "pick a binary release, run the harness, ship or don't." One decision, one test.
Quickstart
docker run --rm -p 9222:9222 ghcr.io/glim-sh/cuttle:latest
Then connect a CDP client and pass a fingerprint seed:
http://127.0.0.1:9222?fingerprint=12345
http://127.0.0.1:9222?fingerprint=12345&timezone=America/New_York&locale=en-US
Each distinct fingerprint seed gets its own isolated Chrome with a stable,
coherent identity. To route a seed through an authenticated residential proxy,
pass it on the connect URL; cuttle strips the inline credentials and answers the
proxy's 407 over CDP, so fork binaries that reject inline credentials still
work.
The image runs headed by default (the default command is
cuttleserve --headless=false, on a built-in Xvfb): headed Chrome clears
escalated anti-bot challenges that headless cannot. Override the command only to
change flags or the port.
CLI (daily driver + login handoff)
For a persistent local browser you can watch and log into via VNC - then drive
over CDP - install the host CLI, published on PyPI as cuttle-browser (the
command it installs is cuttle):
uv tool install cuttle-browser # or: pipx install cuttle-browser
uvx --from cuttle-browser cuttle up # or one-off with no install
cuttle up # start the container + VNC viewer
cuttle login https://accounts.google.com # sign in once via the viewer; the CDP session stays logged in
cuttle down # graceful stop, keeps the profile
cuttle skill # print the full agent usage guide
cuttle up is idempotent and profile-preserving (logins survive down/up).
The CLI shells out to Docker and defaults to image cuttle:local; use the
published image with --image ghcr.io/glim-sh/cuttle:latest. See
SKILL.md (or cuttle skill) for the full workflow.
Engine swap
Both fork binaries are baked in and selected by CLOAKBROWSER_BINARY_PATH:
/opt/clark/chrome- clark, Chrome 148 (default)/opt/clearcote/chrome- clearcote, Chrome 149 (fallback)
docker run --rm -p 9222:9222 \
-e CLOAKBROWSER_BINARY_PATH=/opt/clearcote/chrome \
ghcr.io/glim-sh/cuttle:latest
Bumping Chrome
Update the pinned CLARK_* / CLEARCOTE_* build args in the Dockerfile,
rebuild, and run the harness. See docs/UPGRADE.md. Building
a binary from source is documented as break-glass only in
docs/BUILD-FROM-SOURCE.md.
Testing
test/harness.py is a neutral, self-contained smoke (raw CDP over websockets)
that drives a running cuttle and checks per-seed fingerprint isolation, stealth
coherence, and connection stability under cold-cycle load. Run it before
publishing any bump. End-to-end validation against live sites is done separately
against a real amd64 deployment. See test/README.md.
To confirm a running seed presents a coherent identity (WebGL GPU string,
WebRTC/WebGPU, navigator.webdriver) and to tell benign Chrome log noise from a
real problem, see docs/STEALTH-VERIFICATION.md.
Architecture
bin/cuttleserve- the patched CDP multiplexer. Per-seed Chrome pool, transparent proxy-auth over CDP, a service_workerbrowserContextIdstamp (so CDP clients do not crash on service workers), and fork launch-parity flags.cuttle/- a trimmed MIT subset of thecloakbrowserwrapper: the CDP argument-builders plus geoip/config helpers. No license, widevine, or behavioral-automation code.scripts/-rename-fonts.py(Windows font pack builder: metric-compatible free fonts renamed to Windows family names, so a Windows-claiming fingerprint is coherent) andsync.sh(re-sync helper for the vendored upstream subset).docs/- the upgrade runbook, build-from-source break-glass, andUPSTREAM.md(provenance of the vendored subset).
Notes and limits
- The image is linux/amd64 only: the clark/clearcote prebuilts ship linux-x64 binaries. On an Apple Silicon host it runs emulated (fine for local dev and the smoke); production runs it native on an amd64 server. The Python multiplexer itself is arch-agnostic.
- cuttle does not include a browser-automation client library - use any CDP client. It is the farm, not the scraper.
Licensing
cuttle is MIT (LICENSE). It vendors and redistributes third-party
software under their own terms - CloakHQ's cloakserve/cloakbrowser (MIT),
clark (MIT), and clearcote (BSD-3). No proprietary CloakBrowser binary is used
or redistributed. Full attributions and license texts are in
THIRD-PARTY.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cuttle_browser-0.2.0.tar.gz.
File metadata
- Download URL: cuttle_browser-0.2.0.tar.gz
- Upload date:
- Size: 31.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cd58081862dd2dcd3fb77dcba3ecce60547ebbad9c3e4f1c677d022fb300864
|
|
| MD5 |
1621f7d37ff6ed20af0f7f6a3cad637d
|
|
| BLAKE2b-256 |
4e3ef17defe13d288507b067c147b01e66246799bb234fa8bd21903e1fbf4326
|
File details
Details for the file cuttle_browser-0.2.0-py3-none-any.whl.
File metadata
- Download URL: cuttle_browser-0.2.0-py3-none-any.whl
- Upload date:
- Size: 33.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
271f241990e7f607cae10e169eb3b9c9fc7d44c9e70e04db9a79b86fb3253896
|
|
| MD5 |
850d8c62dc538ba0fdf042589d22a9f8
|
|
| BLAKE2b-256 |
5c5ca2b16a36c1def507781555035b70bea995e5c6896547f927821996ac5e47
|