{"id":51228916,"url":"https://github.com/yfedoseev/browser_oxide","last_synced_at":"2026-06-28T14:01:45.882Z","repository":{"id":364668671,"uuid":"1208108955","full_name":"yfedoseev/browser_oxide","owner":"yfedoseev","description":"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.","archived":false,"fork":false,"pushed_at":"2026-06-14T00:57:40.000Z","size":3613,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T01:22:02.346Z","etag":null,"topics":["ai-agents","anti-bot","anti-detect-browser","boringssl","browser-fingerprint","camoufox-alternative","headless-browser","ja4","mcp","puppeteer-alternative","rust","stealth-browser","tls-fingerprint","undetected-browser","web-scraping"],"latest_commit_sha":null,"homepage":"https://github.com/yfedoseev/browser_oxide","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yfedoseev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":"audit.toml","citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-11T20:40:09.000Z","updated_at":"2026-06-14T00:57:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/yfedoseev/browser_oxide","commit_stats":null,"previous_names":["yfedoseev/browser_oxide"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/yfedoseev/browser_oxide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yfedoseev%2Fbrowser_oxide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yfedoseev%2Fbrowser_oxide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yfedoseev%2Fbrowser_oxide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yfedoseev%2Fbrowser_oxide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yfedoseev","download_url":"https://codeload.github.com/yfedoseev/browser_oxide/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yfedoseev%2Fbrowser_oxide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34890795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","anti-bot","anti-detect-browser","boringssl","browser-fingerprint","camoufox-alternative","headless-browser","ja4","mcp","puppeteer-alternative","rust","stealth-browser","tls-fingerprint","undetected-browser","web-scraping"],"created_at":"2026-06-28T14:01:41.356Z","updated_at":"2026-06-28T14:01:45.871Z","avatar_url":"https://github.com/yfedoseev.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BrowserOxide — Headless Stealth Browser with Rust Core\n\n*A from-scratch stealth browser engine in Rust — own BoringSSL TLS/JA4 fingerprint, real JS, no Chromium, no CDP. Python + MCP bindings.*\n\n[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)]()\n[![Built with Rust](https://img.shields.io/badge/built%20with-Rust-orange.svg)]()\n[![Status: pre-1.0](https://img.shields.io/badge/status-research--grade%20pre--1.0-yellow.svg)]()\n[![Anti-bot corpus: routed 118/126](https://img.shields.io/badge/anti--bot%20corpus-routed%20118%2F126-brightgreen.svg)]()\n[![Memory: ~15x lighter than Chrome](https://img.shields.io/badge/memory-~15%C3%97%20lighter%20than%20Chrome-brightgreen.svg)]()\n[![Bindings: Rust · Python · MCP](https://img.shields.io/badge/bindings-Rust%20%C2%B7%20Python%20%C2%B7%20MCP-informational.svg)]()\n\n**BrowserOxide is a stealth headless browser engine written from scratch in\nRust** for web scraping, archival, and AI agents. It implements a real\nHTML/CSS/DOM/JS browser — including its own BoringSSL TLS stack and a *native*\n(not injected) browser fingerprint — with **no Chromium and no Chrome DevTools\nProtocol (CDP) driver** underneath. You control every surface from the TLS\nhandshake through WASM to canvas, so the fingerprint is native rather than\ninjected.\n\n\u003e **TL;DR.** Every other native-fingerprint stealth browser is either Python-only\n\u003e (camoufox, a Firefox fork) or drives Chrome over CDP (nodriver, Obscura), where\n\u003e the automation is itself detectable. **As of 2026 there is no Rust equivalent to\n\u003e camoufox** — BrowserOxide is built to be exactly that. In a same-machine,\n\u003e same-IP cleanroom run it routed **118 of 126** commercially-protected sites\n\u003e (Cloudflare, Akamai, DataDome, PerimeterX, Kasada) to a real render with **zero\n\u003e per-vendor bypass code**. Kasada is the one honest open gap. And because it's a\n\u003e single Rust process with no Chromium underneath, it renders pages in **tens of\n\u003e MB — roughly 15× lighter than a headless-Chrome process tree** (see\n\u003e [Memory](#memory-15-lighter-than-headless-chrome)).\n\n**Get started:** [Rust](docs/getting-started-rust.md) · [Python](docs/getting-started-python.md) (`pip install browser-oxide`) · [MCP for AI agents](#mcp-server-for-ai-agents) · [Benchmark](docs/BENCHMARK.md) · [How it compares](#how-it-compares)\n\n\u003e **Status: research-grade, pre-1.0.** API surfaces are not stable. License is MIT OR Apache-2.0.\n\n## Why this exists\n\nMost stealth tooling today wraps a real browser and hides the puppet strings.\nCDP-driver stealth plugins patch a handful of JS properties at runtime and\nlose to `Function.prototype.toString` checks. Patched-Chromium forks still\ninherit Chromium's CDP detection vectors. Patched-Firefox forks ride a\nbrowser engine with low market share, which is itself a fingerprint signal.\n\nBrowserOxide is a different bet: build the engine from the parser up so\nthe fingerprint properties are *native*, not *injected*. There is no\nChrome process, no CDP client, no WebDriver, no patched-fork inheritance.\nWhether that's the *right* bet is empirical — see the numbers section.\n\n## What it is\n\nA complete browser engine for scraping, archival, and AI agent workloads:\n\n- **V8 JavaScript** via `deno_core` 0.403 — full ES2024+, WASM, JIT\n- **Arena-allocated DOM** with `NodeId` (Copy, u32) handles, Shadow DOM, iframes\n- **Own CSS engine** — Syntax L3 tokenizer, Selectors L4 matcher, cascade,\n  `@layer`/`@media`/`@container`, computed styles\n- **Real Canvas** — 2D rendering via `tiny-skia`, WebGL stubs, AudioContext\n- **Layout** via `taffy` with font metrics for `getBoundingClientRect()`\n- **Stealth HTTP** — own TLS stack (`boring2`/BoringSSL), Chrome-matched\n  ClientHello, HTTP/1.1 + HTTP/2 (HTTP/3 wired but disabled by default —\n  vanilla `quinn-proto` emits randomized transport parameters which is a\n  worse fingerprint than not speaking h3)\n- **CDP-compatible debugging surface** — drop-in target for Puppeteer/\n  Playwright via WebSocket\n- **EventSource (SSE)** for streaming endpoints\n- **Configurable browser identity** — load profiles from YAML or JSON at\n  runtime, or use the built-in `chrome_148_*` / `firefox_135_*` /\n  `pixel_9_pro_chrome_148` / `iphone_15_pro_safari_18` presets\n\n## How it compares\n\nThe native-fingerprint stealth-browser field, and where BrowserOxide sits:\n\n\u003e **BrowserOxide is the only one built from scratch** — a Rust/Python engine\n\u003e with **no Chromium, no Chrome/CDP, and no browser fork** underneath. Every\n\u003e other tool is either a fork (camoufox = Firefox), a Chrome driver (nodriver,\n\u003e Obscura, undetected-chromedriver), or not a browser at all (curl_cffi).\n\n| Tool | Language | Engine | No CDP/WebDriver | Native fingerprint | Runs JS | TLS impersonation |\n|---|---|---|:--:|:--:|:--:|:--:|\n| **BrowserOxide** | **Rust/Python** | **from-scratch** | ✅ | ✅ | ✅ (V8) | ✅ (JA3/JA4) |\n| camoufox | Python | Firefox fork | ✅ | ✅ (patched into Firefox) | ✅ (Gecko) | partial (Firefox NSS) |\n| nodriver / Obscura | Python | real Chrome (CDP) | ❌ (uses CDP) | ❌ (injected) | ✅ (Chrome) | ❌ (real Chrome TLS) |\n| undetected-chromedriver | Python | real Chrome (WebDriver) | ❌ (WebDriver) | ❌ (injected) | ✅ (Chrome) | ❌ |\n| curl_cffi | Python | none (HTTP/TLS only) | n/a | n/a | ❌ | ✅ (JA3/JA4) |\n\n**The takeaway:** camoufox proved native-fingerprint stealth works, but it's a\nPython-only Firefox fork. CDP-driven tools (nodriver, Obscura) inherit Chrome's\nautomation-detection surface. curl_cffi nails the TLS handshake but runs no\nJavaScript, so it loses to any JS challenge. **As of 2026 there is no Rust\nequivalent to camoufox** — BrowserOxide fills that gap: native fingerprint, no\nCDP, real JS, and a Rust core with Python + MCP bindings.\n\n## What it can do (measured, not estimated)\n\nAnti-bot coverage measured against a 126-site corpus of commercially-\nprotected pages (Cloudflare, Akamai, DataDome, PerimeterX, Kasada,\nShape/F5, etc.), release build. These numbers are from the\nvendor-stripped open-source engine — no per-vendor bypass code in the\ntree. Same machine, same IP, same hour, same classifier\n(`browser_oxide::engine_classify`).\n\n| BrowserOxide profile        | **Pass** (real render, ≥15 KB) | loose `L3` tag |\n|------------------------------|--:|--:|\n| `chrome_148_macos`           | **114** | 118 |\n| `firefox_135_macos`          | **111** | 115 |\n| `pixel_9_pro_chrome_148`     | **114** | 118 |\n| `iphone_15_pro_safari_18`    | **118** | 121 |\n| **best-of-4 routed**         | **118** | 121 |\n\nThe headline `Pass` column is the honest gate: the engine's `L3-RENDERED`\ntag **and** `≥15 KB` of actual content (`ChallengeVerdict::Pass`, the rule\nthe engine's own audit harness uses). The loose column counts the\n`L3-RENDERED` tag alone — it over-counts by ~4, because the corpus has\n10–15 SPA-bootstrap sites that ship a 2–13 KB shell to *any* HTTP client\nand get tagged `L3-RENDERED` by the *absence* of a challenge marker even\nthough no real render happened (e.g. `duolingo` returns a 13.5 KB shell —\n**not** a pass). \"Routed\" = the caller picks the best profile per domain,\nwhich most real scraping pipelines do naturally. Full breakdown and the\nscoring caveats (the strict gate also has a few false *negatives*) are in\n[`docs/BENCHMARK.md`](docs/BENCHMARK.md).\n\n(Profile labels reflect the actual emitted User-Agent. All presets ship a\ncurrent Chrome 148 / Firefox 135 / Safari 18 identity.)\n\n**The hard residual** is seven sites that returned no real content on any\nprofile: three Kasada pages (`canadagoose.com`, `hyatt.com`,\n`realtor.com` — no OSS tool publicly passes Kasada from scratch),\n`etsy.com` (DataDome interactive Device-Check, human-gated, out of\nscope), `duolingo.com` (CSR SPA that only reaches its shell),\n`wildberries.ru` (WBAAS), and `homedepot.com` (Akamai sec-cpt — flaky;\nrenders on a good risk-roll). `adidas.com` is *not* in this set — it\npasses via routing (chrome + iphone render the 1.5 MB storefront; firefox\n+ pixel stay at the interstitial). `adidas`/`homedepot` are both flaky\nAkamai, so the exact residual shifts ±1–2 sites run to run.\n\n\u003e **The engine carries the number, not bypass code.** A/B measurements\n\u003e with per-vendor challenge solvers enabled vs fully removed from the\n\u003e tree show no difference in routed pass rate. Every site that renders,\n\u003e renders on the from-scratch TLS + fingerprint + V8 engine alone. The\n\u003e open-source engine ships no solver implementations (see \"Challenge\n\u003e solving\" below).\n\n### Things to know before believing the numbers\n\n- **Anti-bot responses are noisy.** Single sweep runs vary by ±5 sites\n  from WAF lottery alone (measured per-site 3× re-tests: amazon variants\n  have ~1-in-3 pass rate per fetch). The routed `118` is the central\n  tendency of one cleanroom run, not a guaranteed per-run result.\n- **Kasada is the OSS-wide gap.** No open-source tool publicly passes\n  Kasada from scratch.\n\n### Memory: ~15× lighter than headless Chrome\n\nBrowserOxide is a **single Rust process** — no Chromium, no CDP, no renderer\nsubprocesses — so it renders a page in **tens of MB** while a headless Chrome\ninstance spins up a multi-process tree that runs into the **gigabytes**. Peak\nresident set size (RSS), **5-run median**, same box, same pages — BO\nsingle-process `VmHWM` vs Chrome's *full* process tree (browser + renderers +\nGPU + utility, summed):\n\n| Page | BrowserOxide | headless Chrome 147 | |\n|---|--:|--:|--:|\n| example.com (528 B) | **49 MB** | 1,028 MB | **~21× lighter** |\n| wikipedia (~230 KB) | **63 MB** | 1,111 MB | **~18× lighter** |\n| x.com (SPA) | **87 MB** | 1,302 MB | **~15× lighter** |\n| nytimes.com | **133 MB** | 1,743 MB | **~13× lighter** |\n\nAcross the full 126-site corpus, BO's median per-page RSS is ~79 MB. This is\nthe practical edge for fleets: where one Chrome wants ~1–2 GB/page, you can run\n**10–20+ BrowserOxide pages in the same footprint**.\n\n### Per-page performance\n\nPer-page wall-clock, 5-run median, same box, single IP, warm binary cache:\n\n| Path | example.com (528 B) | hacker news (~35 KB) | wikipedia (~230 KB) |\n|---|--:|--:|--:|\n| cold (`Page::navigate`) | 244 ms | 444 ms | 849 ms |\n| **warm pool (`PagePool::navigate`)** | **141 ms** | **333 ms** | **724 ms** |\n\nA warm `PagePool` amortizes V8 isolate + snapshot setup across\nnavigations (the `PagePool::navigate(url)` API).\n\nFull per-profile + per-site breakdown: [`docs/BENCHMARK.md`](docs/BENCHMARK.md).\n\n## FAQ\n\n### Is there a Rust equivalent to camoufox?\nBrowserOxide is built to be exactly that. camoufox is a native-fingerprint\nstealth browser, but it's a Python-only Firefox fork. As of 2026 there is no other\nfrom-scratch stealth browser engine in Rust — BrowserOxide provides a native\nfingerprint, no CDP, real JavaScript execution, and a Rust core with Python and\nMCP bindings.\n\n### Is BrowserOxide a Chromium or Firefox fork?\nNo. The HTML parser, CSS engine, DOM, layout, and TLS stack are written from\nscratch in Rust; JavaScript runs on V8 via `deno_core`. There is no Chrome\nprocess and no CDP driver, so it doesn't inherit Chromium's automation-detection\nvectors (`navigator.webdriver`, `cdc_*` variables, CDP WebSocket fingerprints).\n\n### How is it different from nodriver, Obscura, or undetected-chromedriver?\nThose drive a real Chrome over CDP or WebDriver. BrowserOxide is its own engine\n— no automation protocol underneath — so the fingerprint is native rather than\npatched onto an automated Chrome that vendors can detect.\n\n### How is it different from curl_cffi?\ncurl_cffi impersonates a browser's TLS handshake but doesn't run JavaScript, so it\nfails any site needing JS or a real DOM. BrowserOxide ships a full V8 runtime,\nreal DOM/CSS/layout/canvas **and** a Chrome-matched TLS fingerprint.\n\n### Does it pass Cloudflare, Akamai, and DataDome?\nIn a measured 126-site cleanroom run it routed 118/126 commercially-protected\nsites to a real render, including most Cloudflare, Akamai, AWS WAF, and DataDome\npages — with no per-vendor bypass code. DataDome's interactive Device-Check\n(human-gated, e.g. etsy.com) is not cleared.\n\n### Does it pass Kasada?\nNo. Kasada (e.g. canadagoose.com, hyatt.com, realtor.com) is the standing open\ngap; no open-source tool publicly passes Kasada from scratch, and BrowserOxide\nships no Kasada solver.\n\n### Can I use it from Python?\nYes — `pip install browser-oxide`, then `Browser` / `Page` / `Profile` / `Verdict`\n(the GIL is released during navigation). There's also an MCP server so AI agents\ncan drive the engine. See [docs/getting-started-python.md](docs/getting-started-python.md).\n\n### Does it work with Puppeteer or Playwright?\nYes, via a CDP-compatible WebSocket server (`CdpServer::start_navigable`) as a\ndrop-in target — but nothing drives a real browser underneath. There is no\nSelenium/WebDriver support.\n\n### Is it production-ready?\nIt's research-grade and pre-1.0; APIs are not stable and the crates aren't on\ncrates.io yet. Anti-bot pass rates are point-in-time and vary ±5 sites per run\nfrom WAF noise. MIT OR Apache-2.0.\n\n## Challenge solving\n\nThe engine exposes a `ChallengeSolver` trait + a\n`Page::navigate_with_solvers(url, profile, n, solvers)` entry point so\nembedders can plug in per-vendor challenge handling (Akamai BMP\nsensor_data, Kasada PoW, DataDome interstitial round-trip, Cloudflare\norchestrator). **The open-source engine ships no solver\nimplementations** — `Page::navigate` registers an empty set, so a\nchallenged page resolves to `ChallengeVerdict::ChallengeIncomplete`\nrather than being auto-cleared. This is deliberate (see `SCOPE.md`):\nsite-specific bypass code is out of scope here, and — per the A/B\nmeasurement above — it isn't what produces the corpus pass rate\nanyway.\n\n## Architecture\n\n```\nHTML → DOM (+ Shadow DOM) → CSS → Layout → JS (V8 + WASM) ← Stealth profile\n  ↑          ↑                       ↓\n  │       iframes              Canvas 2D (tiny-skia)\n  │                                  ↓\n  └────── HTTP/1+2 (stealth TLS) ────┘\n```\n\n15 crates, MIT OR Apache-2.0. No GPL/LGPL/AGPL. The only MPL-2.0 in\nthe default tree is `cooked-waker`, pulled in transitively via\n`deno_core` → `v8` and linked unmodified; MPL-2.0 is file-scope\ncopyleft so this does not infect downstream code. An optional\n`blocker` Cargo feature (off by default) adds Brave's MPL-2.0\n`adblock` crate. Both are explicit per-crate exceptions in\n`deny.toml`. Full crate inventory in `docs/ARCHITECTURE.md`.\n\n| Crate | Description |\n|---|---|\n| `css_parser` | CSS Syntax Level 3 tokenizer + parser (with nesting) |\n| `css_selectors` | Selectors Level 4 parser + matcher |\n| `css_values` | CSS property value parsing + computed values |\n| `css_cascade` | Cascade, `@layer`, `@media`, `@container`, inheritance |\n| `dom` | Arena DOM + Shadow DOM + iframe contexts |\n| `html_parser` | `html5ever` integration → DOM |\n| `js_runtime` | V8 (`deno_core`) + DOM bindings + WASM + Web APIs |\n| `canvas` | Canvas 2D (`tiny-skia`) + WebGL stubs + AudioContext |\n| `layout` | Box model via `taffy` (`getBoundingClientRect`) |\n| `net` | HTTP/1+2+3 + stealth TLS (`boring2`/BoringSSL) + WebSocket + SSE |\n| `event_loop` | Timers, microtasks, Promises, rAF |\n| `workers` | Web Workers + Service Workers (separate V8 isolates) |\n| `stealth` | Fingerprint profiles (100+ properties), navigator spoofing |\n| `protocol` | CDP server (Puppeteer/Playwright drop-in) |\n| `browser` | Top-level `Browser`/`Page` API + `ChallengeSolver` trait |\n\n## Quick start\n\nThe engine is `!Send` (V8 isolates are per-thread), so run it on a current-thread\nruntime + `LocalSet`:\n\n```rust\nuse browser::{ChallengeVerdict, Page};\n\nfn main() {\n    let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();\n    tokio::task::LocalSet::new().block_on(\u0026rt, async {\n        let profile = stealth::presets::chrome_148_macos();   // built-in identity\n        let mut page = Page::navigate(\"https://example.com\", profile, 5).await.unwrap();\n\n        println!(\"{}\", page.title());\n        println!(\"{}\", page.evaluate(\"document.querySelectorAll('a').length\").unwrap());\n\n        // challenge pages return HTTP 200 — trust the verdict, not the status:\n        if page.challenge_verdict() == ChallengeVerdict::Pass {\n            println!(\"real content rendered\");\n        }\n    });\n}\n```\n\nRunnable: `cargo run --release -p browser_oxide --example getting_started -- https://example.com`.\nFull walkthrough: [docs/getting-started-rust.md](docs/getting-started-rust.md).\n\n### Configurable browser identity\n\nThe browser identity (UA string, Chrome version, screen, locale, TLS\nimpersonation label, etc.) is a `StealthProfile`. Load one from disk:\n\n```rust\nuse stealth::StealthProfile;\n\nlet profile = StealthProfile::load_from_file(\"profiles/chrome_148_macos.yaml\")?;\nprofile.validate()?;\nlet mut page = Page::navigate(\"https://example.com\", profile, 5).await?;\n```\n\nYAML and JSON are both supported; format is picked by extension. See\n`crates/browser_oxide/profiles/chrome_148_macos.yaml` for the full field\nschema. The struct definition (`StealthProfile` in `crates/browser_oxide/src/stealth/\nprofile.rs`) is the source of truth — every field is documented there.\n\n### Python\n\n```python\nfrom browser_oxide import Browser, Profile, Verdict\n\nwith Browser(profile=Profile.chrome()) as b:\n    page = b.navigate(\"https://example.com\")\n    print(page.title, len(page.html), page.verdict)\n    if page.verdict == Verdict.PASS:\n        print(page.evaluate(\"navigator.userAgent\"))\n```\n\n`pip install browser-oxide` (or `maturin develop` from source). Full guide:\n[docs/getting-started-python.md](docs/getting-started-python.md).\n\n### MCP server (for AI agents)\n\nA Model Context Protocol server (`browser-oxide-mcp`) lets an AI agent drive the\nstealth engine — tools: `fetch_page`, `evaluate`, and `check_protection` (*\"is\nthis URL behind Akamai/DataDome/Kasada, and did a real render get through?\"*).\n\n```json\n{ \"mcpServers\": { \"browser-oxide\": { \"command\": \"browser-oxide-mcp\" } } }\n```\n\n### CDP server (Puppeteer/Playwright drop-in)\n\n```rust\nuse protocol::CdpServer;\n\nlet server = CdpServer::start_navigable(9222)?;\n// Connect with Puppeteer to ws://127.0.0.1:9222\n```\n\n## Build and test\n\n```bash\ncargo test --workspace -- --test-threads=1    # V8 isolates are per-thread\ncargo clippy --workspace -- -D warnings\ncargo fmt --all -- --check\n\n# Live anti-bot sweep (needs internet, --release for fair timing)\ncargo test --release -p browser_oxide --test holistic_sweep -- --ignored --test-threads=1 --nocapture\n\n# Sweep your own URL list with rich per-site metrics (timing, tag, body len):\ncargo run --release -p browser_oxide --example sweep_metrics -- \u003cprofile\u003e \u003ccorpus.json\u003e \u003cout.json\u003e\n```\n\n`\u003ccorpus.json\u003e` is a JSON array of `{ \"cat\", \"name\", \"url\" }` entries.\nRuntime tuning (navigation budgets, the `BROWSER_OXIDE_SECCPT_BUDGET_MS`\nsec-cpt budget, stealth, snapshot, debug) is documented in\n[docs/CONFIGURATION.md](docs/CONFIGURATION.md).\n\nThe browser-comparison harness (`crates/browser_oxide/tests/browser_comparison\n.rs`) compares against locally-installed Chrome / Lightpanda when those\nbinaries are present; it is `#[ignore]` by default.\n\n## Documentation\n\n**Using it**\n\n| Guide | Description |\n|---|---|\n| [Getting started (Rust)](docs/getting-started-rust.md) | Install, navigate, read the page, verdicts, pooling |\n| [Getting started (Python)](docs/getting-started-python.md) | `pip install browser-oxide`; the `Browser`/`Page`/`Profile` API |\n| [Profiles](docs/guides/PROFILES.md) | Choosing \u0026 customizing browser identities; routing |\n| [Challenges](docs/guides/CHALLENGES.md) | Verdict semantics + the `ChallengeSolver` extension point |\n| [Stealth FAQ](docs/guides/STEALTH_FAQ.md) | What's native vs. not — the honest boundary |\n| [Debugging](docs/guides/DEBUGGING.md) | Thin renders, fetch logs, JS errors, the probes |\n| [Configuration](docs/CONFIGURATION.md) | Environment variables — navigation budgets, stealth, snapshot, debug, sweep harness |\n| [CDP server](docs/guides/CDP.md) | Puppeteer/Playwright drop-in |\n| [Benchmark](docs/BENCHMARK.md) | Measured anti-bot pass rates |\n| [Memory](docs/MEMORY.md) | Footprint vs headless Chrome (~15× lighter) + reproduction steps |\n\n**Engine internals**\n\n| Doc | Description |\n|---|---|\n| [Architecture](docs/ARCHITECTURE.md) | Workspace layout, dependency graph, external deps |\n| [Stealth profiles](docs/STEALTH.md) | Custom browser identity — fields, loading from YAML/JSON, consistency rules |\n| [Networking](docs/NETWORKING.md) | HTTP/1+2+3 + stealth TLS + WebSocket + SSE |\n| [CDP Protocol](docs/PROTOCOL.md) | Puppeteer/Playwright drop-in surface |\n| [CSS Parser](docs/CSS_PARSER.md) / [Selectors](docs/CSS_SELECTORS.md) / [Values](docs/CSS_VALUES.md) / [Cascade](docs/CSS_CASCADE.md) | The CSS engine |\n| [DOM](docs/DOM.md) | Arena DOM + Shadow DOM + iframes + Web APIs |\n| [JS Runtime](docs/JS_RUNTIME.md) | V8 + `deno_core` + WASM + API surface |\n| [Canvas](docs/CANVAS.md) | Canvas 2D + WebGL stubs + AudioContext |\n| [Layout](docs/LAYOUT.md) | Box model via `taffy` |\n| [Event Loop](docs/EVENT_LOOP.md) | Timers, microtasks, rAF, Promises |\n| [Workers](docs/WORKERS.md) | Dedicated/Shared/Service Workers |\n\n## Use, scope, what this is not for\n\nThis is engine-side research. The intended use is automated browsing for\narchival, accessibility, AI agents, security research, and CTF-style\nchallenges where you have legitimate authorization to access the target\nsite. The repository ships an engine, not a \"circumvent paywalls\" recipe\nlist; site-specific recipes and reverse-engineering notes are kept in a\nprivate companion repository.\n\nIf you build a product on top of this, respect the target site's terms,\nrobots policy, and rate limits. The maintainer is not responsible for\ndownstream misuse.\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))\n- MIT license ([LICENSE-MIT](LICENSE-MIT))\n\nat your option. Unless explicitly stated otherwise, any contribution\nintentionally submitted for inclusion shall be dual-licensed as above,\nwithout any additional terms or conditions.\n\n## Citation\n\n```bibtex\n@software{browseroxide,\n  title  = {BrowserOxide: A From-Scratch Stealth Headless Browser Engine in Rust},\n  author = {Yury Fedoseev},\n  year   = {2026},\n  url    = {https://github.com/yfedoseev/browser_oxide}\n}\n```\n\n---\n\n**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\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyfedoseev%2Fbrowser_oxide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyfedoseev%2Fbrowser_oxide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyfedoseev%2Fbrowser_oxide/lists"}