Own your browser.
One stealth headless Chromium in a container, exposing Chrome DevTools Protocol on port 9222 with the two things raw CDP never had: authentication and a trust boundary you can read. Connect from Playwright, Puppeteer, an MCP client, or any agent that wants a real browser without bundling one.
docker run --rm -p 127.0.0.1:9222:9222 --shm-size=512m ghcr.io/askalf/browser-bridge:latestimport { chromium } from 'playwright';
const browser = await chromium.connectOverCDP('http://localhost:9222');That is the whole integration. Everything below is about what you are trusting when you do it.
Most "headless Chrome in Docker" images are a Dockerfile around a browser. browser-bridge is what you get when the CDP port is treated as production infrastructure:
- The stealth score is measured, not asserted. On every relevant push and PR, CI builds the image, drives it as an ordinary CDP client, and evaluates the bot-detection vectors that sannysoft and CreepJS probe, in-page, with no network (
stealth-score.mjs). The stealth badge above is that live number, and the build fails if it drops below the floor. - CDP gets an auth story. Set
BRIDGE_TOKENand every request and WebSocket upgrade must present it. The compare is constant-time over a SHA-256 digest, the token is stripped before anything reaches Chromium, and failures are counted in/metrics. Off by default, and the docs say so rather than hiding it. - The trust boundary is fuzzed. Jazzer.js fuzzes two targets weekly and on every PR that touches them (
fuzz.yml; ClusterFuzzLite adds a coverage report) against the proxy's pure request guards and the user-agent picker (fuzz/): the DNS-rebinding gate never passes a hostname,?token=never survives into the forwarded path, auth headers never leak upstream. OpenSSF Scorecard Fuzzing, Pinned-Dependencies, and Token-Permissions all score 10. - Authenticated proxies just work. Chromium discards the
user:passin--proxy-serverand expects a human to answer the407. browser-bridge stands up a loopback relay that addsProxy-Authorizationon the browser's behalf, withoutpage.authenticate(), so your CDP client keeps theFetchdomain to itself. The password never reaches the logs. - Failover is a deliberate choice, off by default.
PROXY_FALLBACK=directretries an unreachable proxy straight out of the container. It never fails over on a407or any other answer the proxy sends, because turning a wrong password into a silent change of exit address is worse than an outage. - Isolated sessions and an MCP endpoint.
BRIDGE_SESSION_MODE=isolatedgives each connection its own stealth Chromium;mcp-server.mjsexposes nine browser tools to any MCP client, and its clicks and keystrokes are trusted input events, notel.click(). - The container has to boot, not just build. CI runs the image and waits for the post-launch marker. This exists because v0.3.0 shipped an image that built clean and crashed on start; the guard has been there since.
- The browser's own chatter stays home. GCM, component update, domain-reliability beacons, and Sync are disabled at launch, so a metered or residential proxy carries only the traffic your client asked for.
- Unit tests with no Docker required.
npm testruns the proxy, relay, broker, MCP server, profile lock, and UA suites against fakes and stubs, in seconds.
In the CI our own repositories share, browser-bridge is the browser a job checks a page against. A job that has to see what a user would see connects over CDP, as in the two lines above, and drives it: render a page's JavaScript, take a screenshot (browser_screenshot for an MCP client), or check that a front end loads and behaves.
It is allow-listed at both ends. The bridge sits on a private network and, with BRIDGE_TOKEN set, answers only a client that presents it; the pages a job sends it to are our own, which let it in by allow-list, and an agent that drives it through fieldpass navigates only to the hosts in PICKET_ALLOWLIST. It does not solve third-party challenges: a CAPTCHA or bot check on a site that has not allow-listed it is a result to report, not something to retry. Stealth makes a page render as it would for a person; it is not a way past a site that says no.
The pull requests behind those jobs are gated by askalf/ci, the reusable workflows and Redline review every pull request passes, and the jobs run on pitlane, the lab where ci-wizard's method is proven: self-hosted runners whose start and run times are published live on the lab page. This repository's own pull requests pass the same gate.
- Security model: who can do what on the path, every guarantee with a command to check it against a running container, and the four honest caveats (
--no-sandbox, CDP open by default, the loopback relay, CRLSet). - Connect: Playwright, Puppeteer, token auth, raw CDP, other Own Your Stack tools, session isolation, and the MCP endpoint.
- Egress through a proxy: VPN sidecar, authenticated proxies, and when to fail over.
- Configuration: every env var, the ports,
--shm-size, health and metrics. - Architecture: the launcher, proxy, broker, reaper and health check, with a diagram.
- Releases and supply chain: tags, provenance verification, pins, analysis.
- CHANGELOG.md · SECURITY.md
- Not a queue. One container is one browser (or, in isolated mode, one browser per connection up to the cap). For throughput, run several containers behind a queue.
- Not internet-facing. CDP was never designed for that, and a token does not change it. Private network, always.
- Not a Chrome extension host. Headless Chromium does not load extensions reliably.
- Not egress governance. It gives you a browser and tells you honestly what that browser can do. Policy over what an agent may fetch is fieldpass.
fieldpass's source is the policy/ directory of this repository. The npm package is unchanged: npm i @askalf/fieldpass (or npx -y @askalf/fieldpass scan <url>). Same bins, env vars and MCP tool names; only the repo moved. See policy/README.md.
MIT. See LICENSE.
Part of Own Your Stack: open tools for owning your AI infrastructure instead of renting it by the token. One subscription. Your box. Your terms.
- dario: own your routing
- browser-bridge: own your browser (you are here)
- redstamp: own your agent security
- truecopy: own your agent skills · truecopy-action gates them in CI
- cordon: own your prompts
- plumbline: own your agent trajectory
- fieldpass: own your agent browser
- amnesia: own your search
- ci: own your CI · gating review in CI and retrying checkouts
- askalf: own your operation: the AI operation that runs Sprayberry Labs
Built by Thomas Sprayberry.