browser_oxide
Health Gecti
- License — License: NOASSERTION
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 48 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Stealth headless browser engine in Rust — native BoringSSL TLS/JA4 fingerprint, real JS via deno_core, no Chromium, no CDP. Python + MCP bindings. A camoufox alternative.
BrowserOxide — Headless Stealth Browser with Rust Core
A from-scratch stealth browser engine in Rust — own BoringSSL TLS/JA4 fingerprint, real JS, no Chromium, no CDP. Python + MCP bindings.
BrowserOxide is a stealth headless browser engine written from scratch in
Rust for web scraping, archival, and AI agents. It implements a real
HTML/CSS/DOM/JS browser — including its own BoringSSL TLS stack and a native
(not injected) browser fingerprint — with no Chromium and no Chrome DevTools
Protocol (CDP) driver underneath. You control every surface from the TLS
handshake through WASM to canvas, so the fingerprint is native rather than
injected.
TL;DR. Every other native-fingerprint stealth browser is either Python-only
(camoufox, a Firefox fork) or drives Chrome over CDP (nodriver, Obscura), where
the automation is itself detectable. As of 2026 there is no Rust equivalent to
camoufox — BrowserOxide is built to be exactly that. In a same-machine,
same-IP cleanroom run it routed 118 of 126 commercially-protected sites
(Cloudflare, Akamai, DataDome, PerimeterX, Kasada) to a real render with zero
per-vendor bypass code. Kasada is the one honest open gap. And because it's a
single Rust process with no Chromium underneath, it renders pages in tens of
MB — roughly 15× lighter than a headless-Chrome process tree (see
Memory).
Get started: Rust · Python (pip install browser-oxide) · MCP for AI agents · Benchmark · How it compares
Status: research-grade, pre-1.0. API surfaces are not stable. License is MIT OR Apache-2.0.
Why this exists
Most stealth tooling today wraps a real browser and hides the puppet strings.
CDP-driver stealth plugins patch a handful of JS properties at runtime and
lose to Function.prototype.toString checks. Patched-Chromium forks still
inherit Chromium's CDP detection vectors. Patched-Firefox forks ride a
browser engine with low market share, which is itself a fingerprint signal.
BrowserOxide is a different bet: build the engine from the parser up so
the fingerprint properties are native, not injected. There is no
Chrome process, no CDP client, no WebDriver, no patched-fork inheritance.
Whether that's the right bet is empirical — see the numbers section.
What it is
A complete browser engine for scraping, archival, and AI agent workloads:
- V8 JavaScript via
deno_core0.403 — full ES2024+, WASM, JIT - Arena-allocated DOM with
NodeId(Copy, u32) handles, Shadow DOM, iframes - Own CSS engine — Syntax L3 tokenizer, Selectors L4 matcher, cascade,
@layer/@media/@container, computed styles - Real Canvas — 2D rendering via
tiny-skia, WebGL stubs, AudioContext - Layout via
taffywith font metrics forgetBoundingClientRect() - Stealth HTTP — own TLS stack (
boring2/BoringSSL), Chrome-matched
ClientHello, HTTP/1.1 + HTTP/2 (HTTP/3 wired but disabled by default —
vanillaquinn-protoemits randomized transport parameters which is a
worse fingerprint than not speaking h3) - CDP-compatible debugging surface — drop-in target for Puppeteer/
Playwright via WebSocket - EventSource (SSE) for streaming endpoints
- Configurable browser identity — load profiles from YAML or JSON at
runtime, or use the built-inchrome_148_*/firefox_135_*/pixel_9_pro_chrome_148/iphone_15_pro_safari_18presets
How it compares
The native-fingerprint stealth-browser field, and where BrowserOxide sits:
BrowserOxide is the only one built from scratch — a Rust/Python engine
with no Chromium, no Chrome/CDP, and no browser fork underneath. Every
other tool is either a fork (camoufox = Firefox), a Chrome driver (nodriver,
Obscura, undetected-chromedriver), or not a browser at all (curl_cffi).
| Tool | Language | Engine | No CDP/WebDriver | Native fingerprint | Runs JS | TLS impersonation |
|---|---|---|---|---|---|---|
| BrowserOxide | Rust/Python | from-scratch | ✅ | ✅ | ✅ (V8) | ✅ (JA3/JA4) |
| camoufox | Python | Firefox fork | ✅ | ✅ (patched into Firefox) | ✅ (Gecko) | partial (Firefox NSS) |
| nodriver / Obscura | Python | real Chrome (CDP) | ❌ (uses CDP) | ❌ (injected) | ✅ (Chrome) | ❌ (real Chrome TLS) |
| undetected-chromedriver | Python | real Chrome (WebDriver) | ❌ (WebDriver) | ❌ (injected) | ✅ (Chrome) | ❌ |
| curl_cffi | Python | none (HTTP/TLS only) | n/a | n/a | ❌ | ✅ (JA3/JA4) |
The takeaway: camoufox proved native-fingerprint stealth works, but it's a
Python-only Firefox fork. CDP-driven tools (nodriver, Obscura) inherit Chrome's
automation-detection surface. curl_cffi nails the TLS handshake but runs no
JavaScript, so it loses to any JS challenge. As of 2026 there is no Rust
equivalent to camoufox — BrowserOxide fills that gap: native fingerprint, no
CDP, real JS, and a Rust core with Python + MCP bindings.
What it can do (measured, not estimated)
Anti-bot coverage measured against a 126-site corpus of commercially-
protected pages (Cloudflare, Akamai, DataDome, PerimeterX, Kasada,
Shape/F5, etc.), release build. These numbers are from the
vendor-stripped open-source engine — no per-vendor bypass code in the
tree. Same machine, same IP, same hour, same classifier
(browser_oxide::engine_classify).
| BrowserOxide profile | Pass (real render, ≥15 KB) | loose L3 tag |
|---|---|---|
chrome_148_macos |
114 | 118 |
firefox_135_macos |
111 | 115 |
pixel_9_pro_chrome_148 |
114 | 118 |
iphone_15_pro_safari_18 |
118 | 121 |
| best-of-4 routed | 118 | 121 |
The headline Pass column is the honest gate: the engine's L3-RENDERED
tag and ≥15 KB of actual content (ChallengeVerdict::Pass, the rule
the engine's own audit harness uses). The loose column counts theL3-RENDERED tag alone — it over-counts by ~4, because the corpus has
10–15 SPA-bootstrap sites that ship a 2–13 KB shell to any HTTP client
and get tagged L3-RENDERED by the absence of a challenge marker even
though no real render happened (e.g. duolingo returns a 13.5 KB shell —
not a pass). "Routed" = the caller picks the best profile per domain,
which most real scraping pipelines do naturally. Full breakdown and the
scoring caveats (the strict gate also has a few false negatives) are indocs/BENCHMARK.md.
(Profile labels reflect the actual emitted User-Agent. All presets ship a
current Chrome 148 / Firefox 135 / Safari 18 identity.)
The hard residual is seven sites that returned no real content on any
profile: three Kasada pages (canadagoose.com, hyatt.com,realtor.com — no OSS tool publicly passes Kasada from scratch),etsy.com (DataDome interactive Device-Check, human-gated, out of
scope), duolingo.com (CSR SPA that only reaches its shell),wildberries.ru (WBAAS), and homedepot.com (Akamai sec-cpt — flaky;
renders on a good risk-roll). adidas.com is not in this set — it
passes via routing (chrome + iphone render the 1.5 MB storefront; firefox
- pixel stay at the interstitial).
adidas/homedepotare both flaky
Akamai, so the exact residual shifts ±1–2 sites run to run.
The engine carries the number, not bypass code. A/B measurements
with per-vendor challenge solvers enabled vs fully removed from the
tree show no difference in routed pass rate. Every site that renders,
renders on the from-scratch TLS + fingerprint + V8 engine alone. The
open-source engine ships no solver implementations (see "Challenge
solving" below).
Things to know before believing the numbers
- Anti-bot responses are noisy. Single sweep runs vary by ±5 sites
from WAF lottery alone (measured per-site 3× re-tests: amazon variants
have ~1-in-3 pass rate per fetch). The routed118is the central
tendency of one cleanroom run, not a guaranteed per-run result. - Kasada is the OSS-wide gap. No open-source tool publicly passes
Kasada from scratch.
Memory: ~15× lighter than headless Chrome
BrowserOxide is a single Rust process — no Chromium, no CDP, no renderer
subprocesses — so it renders a page in tens of MB while a headless Chrome
instance spins up a multi-process tree that runs into the gigabytes. Peak
resident set size (RSS), 5-run median, same box, same pages — BO
single-process VmHWM vs Chrome's full process tree (browser + renderers +
GPU + utility, summed):
| Page | BrowserOxide | headless Chrome 147 | |
|---|---|---|---|
| example.com (528 B) | 49 MB | 1,028 MB | ~21× lighter |
| wikipedia (~230 KB) | 63 MB | 1,111 MB | ~18× lighter |
| x.com (SPA) | 87 MB | 1,302 MB | ~15× lighter |
| nytimes.com | 133 MB | 1,743 MB | ~13× lighter |
Across the full 126-site corpus, BO's median per-page RSS is ~79 MB. This is
the practical edge for fleets: where one Chrome wants ~1–2 GB/page, you can run
10–20+ BrowserOxide pages in the same footprint.
Per-page performance
Per-page wall-clock, 5-run median, same box, single IP, warm binary cache:
| Path | example.com (528 B) | hacker news (~35 KB) | wikipedia (~230 KB) |
|---|---|---|---|
cold (Page::navigate) |
244 ms | 444 ms | 849 ms |
warm pool (PagePool::navigate) |
141 ms | 333 ms | 724 ms |
A warm PagePool amortizes V8 isolate + snapshot setup across
navigations (the PagePool::navigate(url) API).
Full per-profile + per-site breakdown: docs/BENCHMARK.md.
FAQ
Is there a Rust equivalent to camoufox?
BrowserOxide is built to be exactly that. camoufox is a native-fingerprint
stealth browser, but it's a Python-only Firefox fork. As of 2026 there is no other
from-scratch stealth browser engine in Rust — BrowserOxide provides a native
fingerprint, no CDP, real JavaScript execution, and a Rust core with Python and
MCP bindings.
Is BrowserOxide a Chromium or Firefox fork?
No. The HTML parser, CSS engine, DOM, layout, and TLS stack are written from
scratch in Rust; JavaScript runs on V8 via deno_core. There is no Chrome
process and no CDP driver, so it doesn't inherit Chromium's automation-detection
vectors (navigator.webdriver, cdc_* variables, CDP WebSocket fingerprints).
How is it different from nodriver, Obscura, or undetected-chromedriver?
Those drive a real Chrome over CDP or WebDriver. BrowserOxide is its own engine
— no automation protocol underneath — so the fingerprint is native rather than
patched onto an automated Chrome that vendors can detect.
How is it different from curl_cffi?
curl_cffi impersonates a browser's TLS handshake but doesn't run JavaScript, so it
fails any site needing JS or a real DOM. BrowserOxide ships a full V8 runtime,
real DOM/CSS/layout/canvas and a Chrome-matched TLS fingerprint.
Does it pass Cloudflare, Akamai, and DataDome?
In a measured 126-site cleanroom run it routed 118/126 commercially-protected
sites to a real render, including most Cloudflare, Akamai, AWS WAF, and DataDome
pages — with no per-vendor bypass code. DataDome's interactive Device-Check
(human-gated, e.g. etsy.com) is not cleared.
Does it pass Kasada?
No. Kasada (e.g. canadagoose.com, hyatt.com, realtor.com) is the standing open
gap; no open-source tool publicly passes Kasada from scratch, and BrowserOxide
ships no Kasada solver.
Can I use it from Python?
Yes — pip install browser-oxide, then Browser / Page / Profile / Verdict
(the GIL is released during navigation). There's also an MCP server so AI agents
can drive the engine. See docs/getting-started-python.md.
Does it work with Puppeteer or Playwright?
Yes, via a CDP-compatible WebSocket server (CdpServer::start_navigable) as a
drop-in target — but nothing drives a real browser underneath. There is no
Selenium/WebDriver support.
Is it production-ready?
It's research-grade and pre-1.0; APIs are not stable and the crates aren't on
crates.io yet. Anti-bot pass rates are point-in-time and vary ±5 sites per run
from WAF noise. MIT OR Apache-2.0.
Challenge solving
The engine exposes a ChallengeSolver trait + aPage::navigate_with_solvers(url, profile, n, solvers) entry point so
embedders can plug in per-vendor challenge handling (Akamai BMP
sensor_data, Kasada PoW, DataDome interstitial round-trip, Cloudflare
orchestrator). The open-source engine ships no solver
implementations — Page::navigate registers an empty set, so a
challenged page resolves to ChallengeVerdict::ChallengeIncomplete
rather than being auto-cleared. This is deliberate (see SCOPE.md):
site-specific bypass code is out of scope here, and — per the A/B
measurement above — it isn't what produces the corpus pass rate
anyway.
Architecture
HTML → DOM (+ Shadow DOM) → CSS → Layout → JS (V8 + WASM) ← Stealth profile
↑ ↑ ↓
│ iframes Canvas 2D (tiny-skia)
│ ↓
└────── HTTP/1+2 (stealth TLS) ────┘
15 crates, MIT OR Apache-2.0. No GPL/LGPL/AGPL. The only MPL-2.0 in
the default tree is cooked-waker, pulled in transitively viadeno_core → v8 and linked unmodified; MPL-2.0 is file-scope
copyleft so this does not infect downstream code. An optionalblocker Cargo feature (off by default) adds Brave's MPL-2.0adblock crate. Both are explicit per-crate exceptions indeny.toml. Full crate inventory in docs/ARCHITECTURE.md.
| Crate | Description |
|---|---|
css_parser |
CSS Syntax Level 3 tokenizer + parser (with nesting) |
css_selectors |
Selectors Level 4 parser + matcher |
css_values |
CSS property value parsing + computed values |
css_cascade |
Cascade, @layer, @media, @container, inheritance |
dom |
Arena DOM + Shadow DOM + iframe contexts |
html_parser |
html5ever integration → DOM |
js_runtime |
V8 (deno_core) + DOM bindings + WASM + Web APIs |
canvas |
Canvas 2D (tiny-skia) + WebGL stubs + AudioContext |
layout |
Box model via taffy (getBoundingClientRect) |
net |
HTTP/1+2+3 + stealth TLS (boring2/BoringSSL) + WebSocket + SSE |
event_loop |
Timers, microtasks, Promises, rAF |
workers |
Web Workers + Service Workers (separate V8 isolates) |
stealth |
Fingerprint profiles (100+ properties), navigator spoofing |
protocol |
CDP server (Puppeteer/Playwright drop-in) |
browser |
Top-level Browser/Page API + ChallengeSolver trait |
Quick start
The engine is !Send (V8 isolates are per-thread), so run it on a current-thread
runtime + LocalSet:
use browser::{ChallengeVerdict, Page};
fn main() {
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
tokio::task::LocalSet::new().block_on(&rt, async {
let profile = stealth::presets::chrome_148_macos(); // built-in identity
let mut page = Page::navigate("https://example.com", profile, 5).await.unwrap();
println!("{}", page.title());
println!("{}", page.evaluate("document.querySelectorAll('a').length").unwrap());
// challenge pages return HTTP 200 — trust the verdict, not the status:
if page.challenge_verdict() == ChallengeVerdict::Pass {
println!("real content rendered");
}
});
}
Runnable: cargo run --release -p browser_oxide --example getting_started -- https://example.com.
Full walkthrough: docs/getting-started-rust.md.
Configurable browser identity
The browser identity (UA string, Chrome version, screen, locale, TLS
impersonation label, etc.) is a StealthProfile. Load one from disk:
use stealth::StealthProfile;
let profile = StealthProfile::load_from_file("profiles/chrome_148_macos.yaml")?;
profile.validate()?;
let mut page = Page::navigate("https://example.com", profile, 5).await?;
YAML and JSON are both supported; format is picked by extension. Seecrates/browser_oxide/profiles/chrome_148_macos.yaml for the full field
schema. The struct definition (StealthProfile in crates/browser_oxide/src/stealth/ profile.rs) is the source of truth — every field is documented there.
Python
from browser_oxide import Browser, Profile, Verdict
with Browser(profile=Profile.chrome()) as b:
page = b.navigate("https://example.com")
print(page.title, len(page.html), page.verdict)
if page.verdict == Verdict.PASS:
print(page.evaluate("navigator.userAgent"))
pip install browser-oxide (or maturin develop from source). Full guide:
docs/getting-started-python.md.
MCP server (for AI agents)
A Model Context Protocol server (browser-oxide-mcp) lets an AI agent drive the
stealth engine — tools: fetch_page, evaluate, and check_protection ("is
this URL behind Akamai/DataDome/Kasada, and did a real render get through?").
{ "mcpServers": { "browser-oxide": { "command": "browser-oxide-mcp" } } }
CDP server (Puppeteer/Playwright drop-in)
use protocol::CdpServer;
let server = CdpServer::start_navigable(9222)?;
// Connect with Puppeteer to ws://127.0.0.1:9222
Build and test
cargo test --workspace -- --test-threads=1 # V8 isolates are per-thread
cargo clippy --workspace -- -D warnings
cargo fmt --all -- --check
# Live anti-bot sweep (needs internet, --release for fair timing)
cargo test --release -p browser_oxide --test holistic_sweep -- --ignored --test-threads=1 --nocapture
# Sweep your own URL list with rich per-site metrics (timing, tag, body len):
cargo run --release -p browser_oxide --example sweep_metrics -- <profile> <corpus.json> <out.json>
<corpus.json> is a JSON array of { "cat", "name", "url" } entries.
Runtime tuning (navigation budgets, the BROWSER_OXIDE_SECCPT_BUDGET_MS
sec-cpt budget, stealth, snapshot, debug) is documented in
docs/CONFIGURATION.md.
The browser-comparison harness (crates/browser_oxide/tests/browser_comparison .rs) compares against locally-installed Chrome / Lightpanda when those
binaries are present; it is #[ignore] by default.
Documentation
Using it
| Guide | Description |
|---|---|
| Getting started (Rust) | Install, navigate, read the page, verdicts, pooling |
| Getting started (Python) | pip install browser-oxide; the Browser/Page/Profile API |
| Profiles | Choosing & customizing browser identities; routing |
| Challenges | Verdict semantics + the ChallengeSolver extension point |
| Stealth FAQ | What's native vs. not — the honest boundary |
| Debugging | Thin renders, fetch logs, JS errors, the probes |
| Configuration | Environment variables — navigation budgets, stealth, snapshot, debug, sweep harness |
| CDP server | Puppeteer/Playwright drop-in |
| Benchmark | Measured anti-bot pass rates |
| Memory | Footprint vs headless Chrome (~15× lighter) + reproduction steps |
Engine internals
| Doc | Description |
|---|---|
| Architecture | Workspace layout, dependency graph, external deps |
| Stealth profiles | Custom browser identity — fields, loading from YAML/JSON, consistency rules |
| Networking | HTTP/1+2+3 + stealth TLS + WebSocket + SSE |
| CDP Protocol | Puppeteer/Playwright drop-in surface |
| CSS Parser / Selectors / Values / Cascade | The CSS engine |
| DOM | Arena DOM + Shadow DOM + iframes + Web APIs |
| JS Runtime | V8 + deno_core + WASM + API surface |
| Canvas | Canvas 2D + WebGL stubs + AudioContext |
| Layout | Box model via taffy |
| Event Loop | Timers, microtasks, rAF, Promises |
| Workers | Dedicated/Shared/Service Workers |
Use, scope, what this is not for
This is engine-side research. The intended use is automated browsing for
archival, accessibility, AI agents, security research, and CTF-style
challenges where you have legitimate authorization to access the target
site. The repository ships an engine, not a "circumvent paywalls" recipe
list; site-specific recipes and reverse-engineering notes are kept in a
private companion repository.
If you build a product on top of this, respect the target site's terms,
robots policy, and rate limits. The maintainer is not responsible for
downstream misuse.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option. Unless explicitly stated otherwise, any contribution
intentionally submitted for inclusion shall be dual-licensed as above,
without any additional terms or conditions.
Citation
@software{browseroxide,
title = {BrowserOxide: A From-Scratch Stealth Headless Browser Engine in Rust},
author = {Yury Fedoseev},
year = {2026},
url = {https://github.com/yfedoseev/browser_oxide}
}
Rust + Python + MCP | MIT OR Apache-2.0 | from-scratch stealth headless browser engine — no Chromium, no CDP, no fork | routed 118/126 on a 126-site anti-bot corpus
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi