One browser engine to rule them all Stealth Chromium engine Fortress is a stealth Chromium engine that stops your scrapers and browser agents from getting blocked, with one line of code change. Bot detectors flag automation by reading the browser fingerprint; Fortress corrects that fingerprint inside Chromium's C++, so the browser presents as an ordinary Chrome install. Scrapers finish their runs, agents reach the pages they were sent to, and CreepJS, Sannysoft, BrowserScan, and live Cloudflare Turnstile all read it as human. Point your existing Playwright or Puppeteer at Fortress over CDP, and nothing else in your code changes. Blink · V8 · BoringSSL patched in-tree · ANGLE / D3D11-backed WebGL · JA3/JA4-coherent TLS · monthly upstream rebase · reproducible, gauntlet-gated releases 34single-surfaceC++ patches 0%CreepJSheadless / stealth [native code]across everyrealm BSD-3open engine,rebuild it yourself Unedited capture of the Fortress binary in a real window: it clears a live Cloudflare challenge, turns bot.sannysoft.com all green, then reads BrowserScan “Normal”. Reproduce with tools/gauntlet.py. Native-code parity Every spoofed getter is a C++ getter: toString returns [native code], realm-invariant across main frame, iframes, and Web Workers. Drop-in CDP nodriver-style raw CDP on :9222, with no Runtime.enable leak. Keep Playwright, Puppeteer, or any CDP client; swap the browser, keep your code. Clears the gauntlet 0% headless on CreepJS; Sannysoft, BrowserScan, and live Cloudflare Turnstile cleared, all as a stock Chrome install. Auditable patches 34 small single-purpose diffs in patches/. Read one in a minute; rebuild the engine with one script. Coherent by construction Real V8, Blink, and BoringSSL keep engine, user-agent, and JA3/JA4 TLS shape in agreement: a Windows persona on a matching stack. Tunable persona One binary, a coherence-checked Windows identity; --uxr-* switches override any surface: GPU, screen, timezone, hardware, Client-Hints. What's new — 151.0.7908.0 · Engine Refresh Released. Per-launch coherent personas, hardened. Per-locale keyboard (QWERTY / QWERTZ / AZERTY) · per-persona media devices · a full delivery-parity coherence pass. Platform ↔ GPU ↔ timezone ↔ language ↔ voices ↔ keyboard move as one coherent real device — on every launch, from a single binary. Native-code parity (toString() stays [native code]), realm-invariant (main / worker / iframe) — coherence compiled into the browser, not patched in JavaScript. pip install -U tilion-fortress # or: docker run --rm -p 9222:9222 tilion/fortress:latest → full release notes Contents What it is · Quick start what it is, install, first script, AI-agent setup The Fortress MCP 29 stealth-browser tools for AI agents (Beta) Why patch the engine, not the page the self-revealing-JS thesis + the three detection layers How Fortress compares vs puppeteer-stealth · Camoufox · CloakBrowser · closed vendors Proof: live-detector results CreepJS / Sannysoft / BrowserScan / Cloudflare, with screenshots Configure the persona the --uxr-* fingerprint surface Works with your stack browser-use · Crawl4AI · Stagehand · LangChain Build & verify reproduce from source, verify provenance Reference troubleshooting · FAQ · roadmap · repo layout What it is Fortress is a Chromium fork that spoofs the browser fingerprint from inside the engine. The surfaces bot detectors read (canvas, WebGL, audio, fonts, navigator, and about thirty more) are corrected in Chromium's C++, with no JavaScript patch layer sitting on top for a page to catch. It ships as an ordinary browser binary that exposes a CDP endpoint. Point Playwright, Puppeteer, or any CDP client at it and your existing automation runs unchanged. A JavaScript stealth patch leaves an extra layer the page can find: .toString() shows the override's source, and re-grabbing the same primitive from an iframe or worker reaches past it. Fortress corrects the surface in the engine instead, so navigator.vendor resolves to the real C++ getter, reports [native code], and reads the same from every realm. A page inspecting itself sees stock Chromium. That is why your automation gets through where it used to get flagged, and whatever blocking is left traces to your proxies and behavior rather than the browser. Why patch the engine, not the page covers the detection mechanics in full. from tilion_fortress import Fortress from playwright.sync_api import sync_playwright with Fortress() as f: # launches the stealth engine on a CDP endpoint with sync_playwright() as p: browser = p.chromium.connect_over_cdp(f.cdp_url) page = browser.new_page() page.goto("https://bot.sannysoft.com") page.screenshot(path="all-green.png") import { Fortress } from "tilion-fortress"; import { chromium } from "playwright"; const f = await Fortress.launch(); // stealth engine on a CDP endpoint const browser = await chromium.connectOverCDP(f.cdpUrl); const page = await browser.newPage(); await page.goto("https://browserscan.net"); await browser.close(); await f.close(); The 12-second tour One loop, all real captures: passes CreepJS / Sannysoft / BrowserScan / rebrowser → scrapes structured data over CDP → clears Akamai on aa.com · lowes · macys · kohls (same residential IP). Real scraping, fully headless Unedited captures of the Fortress engine driven over CDP. No stealth plugins, no JS patches: the fingerprint is corrected in the binary. Reproduce any of these with examples/scrape_demos.py. Structured extraction: records build into typed JSON as each item is read. Auto-pagination: 30 quotes across 3 pages. Deep detail crawl: UPC · price · tax · stock · reviews. Clears real Akamai — before / after Same residential IP, same site (aa.com · Akamai Bot Manager). A stock/headless browser gets Access Denied (Reference #); Fortress loads the real page and Akamai issues its _abck sensor cookie — the Bot Manager accepts it as a real browser. The variable is the fingerprint, not the IP. lowes.com · blocked → cleared macys.com · blocked → cleared kohls.com · blocked → cleared Not a one-site fluke — same before/after on major Akamai-protected retailers, every run from the same residential IP. Quick start # Python / Node: prebuilt native binary auto-fetched (Linux x64 & Windows x64), SHA-256 verified pip install tilion-fortress npm install tilion-fortress # Any OS via Docker: raw CDP on :9222 (~302 MB pull / 851 MB on disk, stripped single-layer) docker run --rm -p 9222:9222 tilion/fortress:latest # Portable bundle (extract-and-run, like a Chromium snapshot) tar xzf tilion-fortress-linux-x64.tar.gz # Linux ./tilion-fortress/tilion --headless=new --remote-debugging-port=9222 --user-data-dir=/tmp/p # Debian / Ubuntu sudo apt install ./tilion-fortress_151.0.7908.0_amd64.deb && tilion https://example.com TipThe SDK ships the compiled build plus patches/, so you can rebuild the engine yourself and verify every surface correction against the source. Downloads are SHA-256-verified against the release SHA256SUMS automatically. Versions Fortress ships on two Chromium bases — pick your trade-off between blend-in and currency: Channel Chromium When to use stable (default) 149 Recommended — matches the Chrome version the mass of real users run, so it blends in best latest 151 Newest engine (reports a version slightly ahead of stable) Fortress().start() # Python: stable (149) by default Fortress(channel="latest").start() # opt into 151 await Fortress.launch(); // Node: stable (149) by default await Fortress.launch({ channel: "latest" }); docker run --rm -p 9222:9222 tilion/fortress:149 # or :151 # or set FORTRESS_CHANNEL=latest for either SDK Native binaries: Linux x64 (both versions) + Windows x64 (151); Windows-149 and macOS run via the Docker image. Drop it into your AI agent Fortress is the browser your agent drives: raw CDP on :9222, no stealth plugins to wire up. There are two ways in. Option 1: open it pre-loaded in a chat assistant. One click; it reads our AGENTS.md and walks you through the whole setup: Option 2: Copy for agent (everything, to your clipboard). Hit the copy icon at the top-right of the box below. It puts the entire setup context on your clipboard: what it is, install, connect, persona, and rules, all of AGENTS.md condensed. Paste it into Cursor, Claude Code, Copilot, ChatGPT, or any agent and it takes it from there: You're setting up Fortress, an open-source STEALTH Chromium engine, for browser automation. It corrects the browser fingerprint (canvas, WebGL, audio, fonts, navigator, +30 more) in Chromium's C++ and exposes raw CDP on http://localhost:9222, a drop-in for Playwright/Puppeteer. Do NOT add puppeteer-stealth or any JS fingerprint patching (it self-reveals and undoes Fortress). LAUNCH (pick one; all expose CDP on http://localhost:9222): Docker: docker run -d --rm -p 9222:9222 tilion/fortress:latest Python: pip install tilion-fortress then from tilion_fortress import Fortress; f=Fortress(); f.start() Node: npm install tilion-fortress then import {Fortress} from "tilion-fortress"; const f=await Fortress.launch() CONNECT (keep my existing automation code): Playwright(py): browser = p.chromium.connect_over_cdp("http://localhost:9222") Playwright(js): const browser = await chromium.connectOverCDP("http://localhost:9222") Puppeteer(js): const browser = await puppeteer.connect({ browserURL: "http://localhost:9222" }) browser-use / Crawl4AI / Stagehand / LangChain: point their CDP endpoint at http://localhost:9222 PERSONA (optional; default is a coherent Windows identity). Override any surface with --uxr-* flags: --uxr-timezone=America/New_York --uxr-hw-concurrency=16 --uxr-languages=en-US,en RULES: 1) Drive over raw CDP (:9222); don't spawn chromedriver. 2) Never pass --user-agent (use --uxr-ua-*); it desyncs UA vs UA-Client-Hints. 3) No puppeteer-stealth / undetected-chromedriver / JS fingerprint patches. 4) Blocked ~90% = my IP (datacenter), not the fingerprint. Use a residential/mobile proxy, then retry. Now walk me through launching Fortress and wiring my automation to it. Full guide: https://github.com/tiliondev/fortress/blob/main/AGENTS.md The Fortress MCP — stealth browsing as agent tools Beta Raw CDP is for code you write. The Fortress MCP is for agents that call tools: a Model Context Protocol server that hands Claude, Cursor, or any MCP client a stealth browser, so the moment a fetch is blocked it just calls a tool and gets the page. 29 tools, local and free — fetch_protected_page, extract_page, crawl_site, recon_site_apis, search_web, run_browser_task, save_profile, get_stealth_cdp_endpoint, and more. Real, dated run against stockx.com (PerimeterX). A stock browser gets HTTP 403 — “Access denied”; an agent with the Fortress MCP returns clean JSON — same site, same prompt. Reproduce it from the framework repo. Set it up in 30 seconds Two runners — pick one. npx needs Python on PATH; pip installs it directly: pip install "tilion[mcp]" # command: tilion-mcp # —or, zero-install— npx -y tilion-mcp # auto-runs the server via uv (no global install) Claude Desktop — Settings → Developer → Edit Config (claude_desktop_config.json): { "mcpServers": { "fortress": { "command": "tilion-mcp" } } } Prefer npx? Use "command": "npx", "args": ["-y", "tilion-mcp"]. Restart Claude, and the fortress tools appear. Claude Code (CLI) — one line: claude mcp add fortress -- tilion-mcp # or: claude mcp add fortress -- npx -y tilion-mcp Cursor (~/.cursor/mcp.json) · Cline / Windsurf (VS Code → MCP servers) — same block: { "mcpServers": { "fortress": { "command": "tilion-mcp" } } } Then just ask your agent — “get the price off this StockX page” — and it calls fetch_protected_page on its own.

