The Problem
Web scraping and AI agent automation typically require a full Chrome instance, which consumes 200+ MB of memory per browser and carries a large attack surface. Obscura replaces headless Chrome with a lightweight Rust browser engine that speaks the Chrome DevTools Protocol (CDP), so existing Puppeteer and Playwright tooling works without modification.
What This Does
Obscura is a Rust workspace (crates/) containing five components: obscura-browser (page lifecycle and fetch logic), obscura-cdp (CDP server implementation), obscura-dom (DOM tree and CSS selector engine), obscura-js (V8 JavaScript runtime with a bootstrap.js shim), and obscura-net (HTTP client, cookie jar, robots.txt, and blocklist). The CLI in obscura-cli/src/main.rs exposes fetch, serve, and scrape commands.
The README claims 30 MB memory usage, 85 ms page loads, and drop-in compatibility with Puppeteer/Playwright via puppeteer-core and playwright-core. A stealth feature flag enables anti-detection and tracker blocking.
How It Is Wired
Execution starts in main at crates/obscura-cli/src/main.rs:120, which reaches 81 functions. For the CDP server path, start in crates/obscura-cdp/src/server.rs:26 spawns cdp_processor, which routes through handle in crates/obscura-cdp/src/domains/browser.rs — the most-connected entry point, reaching 86 functions. The shortest path to an outbound network call is start -> start_with_options -> cdp_processor -> process_with_interception -> navigate_with_wait -> navigate_single, which hits self.http_client.fetch in obscura-net/src/client.rs. The CLI run_fetch path reaches the network in one hop from main.
The hottest functions carry the widest blast radius: evaluate (called from 40 places) and setup_runtime (40 places) in obscura-js/src/runtime.rs, plus execute_script (23), parse_html (22), and document (20). The obscura-dom/src/selector.rs file is the most-imported module, used by 11 other files. obscura-js/src/runtime.rs is the largest at 86 functions and routes through the JS engine, DOM, cookies, and HTTP client.
How To Use It
git clone https://github.com/moses-y/obscura
cd obscura
cargo build --release
# Fetch a page
./target/release/obscura fetch https://example.com --eval "document.title"
# Start CDP server
./target/release/obscura serve --port 9222
Connect via Puppeteer or Playwright using the README's puppeteer.connect({ browserWSEndpoint: 'ws://127.0.0.1:9222/devtools/browser' }) pattern.
Real-World Use
A scraping pipeline that needs concurrent page loads with JavaScript rendering and anti-bot evasion. Run obscura scrape url1 url2 url3 --concurrency 25 --eval "document.querySelector('h1').textContent" --format json to batch-extract data. The CDP server mode lets you point existing Puppeteer scripts at ws://127.0.0.1:9222 without rewriting them, and the --stealth flag adds tracker blocking and anti-detection.
Code Health & Issues
Static analysis found 30 issues (16 high, 14 medium) across 5 kinds. The dominant problems are deep nesting (22 instances, max depth 9 in page.rs and CDP domain files) and duplicated code blocks (24 repeated 6-line blocks across 10 files in obscura-cdp/src/domains/). Three files exceed 2,700 lines: bootstrap.js, page.rs, and runtime.rs. The bootstrap.js file also has an empty catch {} block that silently discards errors.
SDLC concerns: no test suite exists across 39 source files, and the GitHub Actions workflow uses unpinned tags (dtolnay/rust-toolchain@stable) and continue-on-error on a correctness-gating step. No Dependabot or dependency vulnerability scanning is configured.
The Bottom Line
This is a serious attempt at a lightweight Chrome replacement with genuine CDP compatibility, and the architecture is cleanly split by responsibility. The lack of tests is the critical gap — a browser engine with zero test coverage is risky for production scraping workloads. Use it for controlled scraping tasks, but budget for writing tests before trusting it at scale.