tiliondev/fortress: a stealth Chromium engine that patches the fingerprint in C++
Stealth Chromium engine that stops scrapers and browser agents from getting blocked, with one line of code change.
At a glance
- What is it?
- Fortress is a Chromium fork that corrects the surfaces bot detectors read from inside the engine, then exposes a CDP endpoint on port 9222 so existing Playwright or Puppeteer code runs unchanged. The trade-off is a browser binary you have to trust and keep in step with upstream Chromium.
- Who is it for?
- Adopt Fortress if you already run Playwright or Puppeteer over CDP and your failures trace back to fingerprint checks rather than to rate limits or IP reputation; the README's claim that nothing else in your code changes is the part that makes it cheap to try. Do not adopt it if you need a signed, vendor-supported browser, or if you cannot run a third-party binary against the sites you scrape.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 56 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What Fortress is for, and who ends up using it
Automation gets blocked because detectors read the browser itself, not the script. Canvas rendering, WebGL output, audio behaviour, font enumeration, navigator properties and roughly thirty other surfaces form a fingerprint, and a headless Chrome driven by Playwright or Puppeteer produces one that stands out. The usual fix is a JavaScript patch layer injected before page scripts run. Fortress takes the other route: it is a Chromium fork that corrects those surfaces in the engine's C++, so there is no patch layer for a page to find. The README's framing is that a JavaScript override leaves an extra layer the page can catch, because toString() shows the override's source and re-grabbing the same primitive from an iframe or worker reaches past it.
The intended users are teams running scrapers and browser agents at a scale where blocks cost real time: data collection pipelines, QA runs against bot-protected staging sites, and agent frameworks that need to reach pages behind a challenge. It is a Python-first project by packaging, but the interface is CDP, so the client language matters less than whether your tooling speaks Chrome DevTools Protocol.
How the engine-level spoofing actually works
Fortress is a Chromium build with a patch series applied. The repository carries 34 single-purpose diffs under patches/, and the README describes them as small enough to read individually. The project claims native-code parity: a spoofed getter is a C++ getter, so toString() returns [native code], and the behaviour is realm-invariant across the main frame, iframes and Web Workers. That claim is the whole point of the design. If the override lives in C++, there is no injected script object to inspect, and no realm boundary to cross to reach the real primitive.
The second half is transport coherence. Because the V8, Blink and BoringSSL layers are the real ones, the engine version, the user agent and the JA3/JA4 TLS shape stay in agreement. A Windows persona is presented on a Windows-shaped stack rather than a Linux headless build wearing a Windows user agent string. Fortress ships as a browser binary that opens a CDP endpoint, documented on port 9222, and the README notes it avoids a Runtime.enable leak. You point an existing client at that endpoint; the client keeps doing what it did.
Persona selection is exposed through --uxr-* switches, which the README lists as covering GPU, screen, timezone, hardware and Client-Hints. The 151.0.7908.0 release notes add per-launch coherent personas: platform, GPU, timezone, language, voices and keyboard layout move together as one device profile, from a single binary. The build also carries an ANGLE/D3D11-backed WebGL path and a fonts/ directory in the repository, which is consistent with font enumeration being treated as a spoofable surface rather than a fixed set.
Install and first run: pip, Docker, then a CDP client
The README gives two install paths. The Python package is tilion-fortress on PyPI, and the Docker image is tilion/fortress. Both are quoted in the release notes as a single command.
pip install -U tilion-fortressOr, if you would rather not install the binary on the host, run the container and publish the CDP port:
docker run --rm -p 9222:9222 tilion/fortress:latestThe repository also ships an examples/ directory, including examples/scrape_demos.py, which is the place to look for a working client. The README's stated pattern is to point Playwright or Puppeteer at Fortress over CDP and change nothing else, so the connection step is a browser endpoint rather than a browser launch. What you should see is a normal CDP endpoint answering on port 9222 and your existing script completing its navigation and extraction steps.
For verification, the project provides tools/gauntlet.py, which the README says reproduces the recorded detector run. The Makefile wraps it:
make gauntlet BUNDLE=/path/to/tilion-fortressThat target runs the live detection gauntlet against a bundle you point it at. Running it yourself is the only way to see detector results on your own network and with your own persona settings, since the README's screenshots are a fixed capture.
Where Fortress does not help, and what it costs you
Fortress corrects the browser fingerprint. It does not change your IP address, your request rate, or your account behaviour. A site that blocks you because a single address is issuing thousands of requests per hour will keep blocking you after the swap, and the README does not claim otherwise. Teams that read "stops your scrapers from getting blocked" as a general anti-blocking guarantee will be disappointed; the mechanism is specifically fingerprint correction.
The second cost is provenance. Fortress is a third-party Chromium binary. You are running an engine that has been modified in ways that affect what a page observes, and the LICENSE file is present but the repository metadata does not resolve to a standard SPDX identifier, while the README's own summary table lists BSD-3. Anyone in a regulated environment should read LICENSE and NOTICE directly rather than rely on either label. The repository does ship build/apply-patches.sh and a Makefile apply target, so the patch series can be applied to a Chromium checkout you control, which is the honest answer to the trust question.
The third cost is cadence. Releases track Chromium closely: the recent tags are 149.0.7827.232, 150.0.7871.114 and 151.0.7908.0, and the README describes a monthly upstream rebase. Staying current is a recurring task, not a one-time install. The last push to the repository was on 2026-07-23, so the project is not dormant, but a browser fork that lags upstream accumulates both detection drift and unpatched security fixes.
Fortress against puppeteer-stealth and Camoufox
The README positions Fortress against puppeteer-stealth, Camoufox and CloakBrowser, and the difference is architectural rather than a matter of tuning. puppeteer-stealth is a JavaScript layer: it rewrites properties in the page context before site scripts run. That is cheap to install and easy to inspect, and it is also exactly the shape Fortress argues against, since the override is reachable and its source is visible to toString(). If your target sites do not check for the patch layer, puppeteer-stealth costs you nothing and requires no new binary.
Camoufox takes a middle position: a modified Firefox rather than a modified Chromium, with the spoofing built into the browser rather than injected. The practical difference is the engine. A site that fingerprints Chromium-specific behaviour will read Fortress as an ordinary Chrome install, while Camoufox presents as Firefox and inherits Firefox's own fingerprint distribution. Which of those is better depends on what your targets expect to see, and neither is universally safer.
Closed commercial vendors occupy the same niche with a support contract and no source. Fortress's counter-argument is the patches/ directory and the build scripts: you can read the diffs and rebuild the engine. That is a real difference in kind, but it only pays off if someone on your team will actually read C++ diffs and maintain a Chromium build.
Maintenance, licensing and upgrade cost
Two maintenance tracks run in parallel. The engine track follows Chromium: the README describes a monthly upstream rebase, and the release tags show Chromium versions moving from 149 to 151 across roughly three weeks in July 2026. Each rebase means re-applying the 34 patches in patches/ against a new upstream tree, which is what build/apply-patches.sh and the Makefile apply target exist for. The client track is lighter: the SDK ships Python tests, and make check runs the patch-set linter plus those tests, which is what the README says CI gates on.
make checkThat target is the cheapest way to confirm a checkout is internally consistent before you build anything.
On licensing, the README's summary table says BSD-3 and describes the engine as open and rebuildable, but the repository metadata reports NOASSERTION, meaning no standard identifier was detected. LICENSE and NOTICE are both present at the top level and should be read before redistribution. Note the split: the browser engine and the Python and npm packages are separate artifacts, and a permissive engine licence does not automatically settle the terms of the SDK or the MCP server. This is a description of the files, not legal advice.
Editorial conclusion
Adopt Fortress if you already run Playwright or Puppeteer over CDP and your failures trace back to fingerprint checks rather than to rate limits or IP reputation; the README's claim that nothing else in your code changes is the part that makes it cheap to try. Do not adopt it if you need a signed, vendor-supported browser, or if you cannot run a third-party binary against the sites you scrape. Before committing, point your own detector set at a Fortress instance, confirm the CDP endpoint behaves the way your client expects, and read the patch series in patches/ to see which surfaces are actually covered.
Frequently asked questions
How do I install Fortress?
The README gives two paths: pip install -U tilion-fortress for the Python package, or docker run --rm -p 9222:9222 tilion/fortress:latest to run the published image with the CDP port exposed.
How do I use Fortress with my existing browser automation code?
The README states that you point your existing Playwright or Puppeteer at Fortress over CDP and nothing else in your code changes. The engine exposes a CDP endpoint on port 9222, so the swap is at the browser connection rather than in the script.
How do I access Fortress from a client?
Fortress ships as a browser binary that opens a CDP endpoint on port 9222. Any CDP client can connect to it, and the repository's examples/ directory, including examples/scrape_demos.py, is where the README points for working client code.
Community notes