obscura

Project Url: h4ckf0r0day/obscura
Introduction: The headless browser for AI agents and web scraping
More: Author   ReportBugs   
Tags:

Obscura

Obscura

The open-source headless browser for AI agents and web scraping.
Lightweight, stealthy, and built in Rust.


Obscura is a headless browser engine written in Rust, built for web scraping and AI agent automation. It runs real JavaScript via V8, supports the Chrome DevTools Protocol, and acts as a drop-in replacement for headless Chrome with Puppeteer and Playwright.

Why Obscura over headless Chrome?

Designed for automation at scale, not desktop browsing.

Metric Obscura Headless Chrome
Memory 30 MB 200+ MB
Binary size 70 MB 300+ MB
Anti-detect Built-in None
Page load 85 ms ~500 ms
Startup Instant ~2s
Puppeteer Yes Yes
Playwright Yes Yes

🎉 10,000 stars and what's next

I'm working on Obscura Cloud the hosted version, with managed infrastructure, residential proxies, and dedicated support. For people who want the engine without operating it themselves.

The open-source engine stays Apache-2.0, fully featured. No feature gating, ever.

Get on the waitlist →

Install

Download

Grab the latest binary from Releases:

# Linux x86_64
curl -LO https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-x86_64-linux.tar.gz
tar xzf obscura-x86_64-linux.tar.gz
./obscura fetch https://example.com --eval "document.title"

# Arch Linux (AUR)
yay -S obscura-browser

# macOS Apple Silicon
curl -LO https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-aarch64-macos.tar.gz
tar xzf obscura-aarch64-macos.tar.gz

# macOS Intel
curl -LO https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-x86_64-macos.tar.gz
tar xzf obscura-x86_64-macos.tar.gz

# Windows
Download the `.zip` from the releases page and extract it manually.

No Chrome, no Node.js, no dependencies. Release archives include both obscura and obscura-worker; keep them in the same directory for the parallel scrape command.

Linux release builds target Ubuntu 22.04 so the downloaded binary remains usable on common LTS servers with glibc 2.35+.

Docker

docker run -d --name obscura -p 127.0.0.1:9222:9222 h4ckf0r0day/obscura

Image on Docker Hub. Multi-stage build on distroless/cc, no shell, no package manager, ~57 MB compressed.

Build from source

git clone https://github.com/h4ckf0r0day/obscura.git
cd obscura
cargo build --release

# With stealth mode (anti-detection + tracker blocking)
cargo build --release --features stealth

Requires Rust 1.75+ (rustup.rs). First build takes ~5 min (V8 compiles from source, cached after).

Quick Start

Fetch a page

# Get the page title
obscura fetch https://example.com --eval "document.title"

# Extract all links
obscura fetch https://example.com --dump links

# Render JavaScript and dump HTML
obscura fetch https://news.ycombinator.com --dump html

# Write dump or eval output to a file
obscura fetch https://example.com --dump text --output page.txt

# Fetch through an HTTP or SOCKS proxy
obscura --proxy socks5://127.0.0.1:1080 fetch https://example.com --dump text

# Wait for dynamic content
obscura fetch https://example.com --wait-until networkidle0

# Bound navigation time for slow or broken pages
obscura fetch https://example.com --timeout 10

Start the CDP server

obscura serve --port 9222

# With stealth mode (anti-detection + tracker blocking)
obscura serve --port 9222 --stealth

Scrape in parallel

obscura scrape url1 url2 url3 ... \
  --concurrency 25 \
  --eval "document.querySelector('h1').textContent" \
  --format json

# Suppress scrape progress on stderr for script-friendly output
obscura scrape https://example.com --quiet --format json

# Scrape workers inherit the global proxy
obscura --proxy http://127.0.0.1:8080 scrape https://example.com https://news.ycombinator.com

Puppeteer / Playwright

Puppeteer

npm install puppeteer-core
import puppeteer from 'puppeteer-core';

const browser = await puppeteer.connect({
  browserWSEndpoint: 'ws://127.0.0.1:9222/devtools/browser',
});

const page = await browser.newPage();
await page.goto('https://news.ycombinator.com');

const stories = await page.evaluate(() =>
  Array.from(document.querySelectorAll('.titleline > a'))
    .map(a => ({ title: a.textContent, url: a.href }))
);
console.log(stories);

await browser.disconnect();

Playwright

npm install playwright-core
import { chromium } from 'playwright-core';

const browser = await chromium.connectOverCDP({
  endpointURL: 'ws://127.0.0.1:9222',
});

const page = await browser.newContext().then(ctx => ctx.newPage());
await page.goto('https://en.wikipedia.org/wiki/Web_scraping');
console.log(await page.title());

await browser.close();

Form submission & login

await page.goto('https://quotes.toscrape.com/login');
await page.evaluate(() => {
  document.querySelector('#username').value = 'admin';
  document.querySelector('#password').value = 'admin';
  document.querySelector('form').submit();
});
// Obscura handles the POST, follows the 302 redirect, maintains cookies

Benchmarks

Page load:

Page Obscura Chrome
Static HTML 51 ms ~500 ms
JS + XHR + fetch 84 ms ~800 ms
Dynamic scripts 78 ms ~700 ms

Stealth Mode

Enable with --features stealth.

Anti-fingerprinting

  • Per-session fingerprint randomization (GPU, screen, canvas, audio, battery)
  • Realistic navigator.userAgentData (Chrome 145, high-entropy values)
  • event.isTrusted = true for dispatched events
  • Hidden internal properties (Object.keys(window) safe)
  • Native function masking (Function.prototype.toString()[native code])
  • navigator.webdriver = undefined (matches real Chrome)

Tracker Blocking

  • 3,520 domains blocked
  • Blocks analytics, ads, telemetry, and fingerprinting scripts
  • Prevents trackers from loading entirely
  • Enabled automatically with --stealth

CDP API

Obscura implements the Chrome DevTools Protocol for Puppeteer/Playwright compatibility.

Domain Methods
Target createTarget, closeTarget, attachToTarget, createBrowserContext, disposeBrowserContext
Page navigate, getFrameTree, addScriptToEvaluateOnNewDocument, lifecycleEvents
Runtime evaluate, callFunctionOn, getProperties, addBinding
DOM getDocument, querySelector, querySelectorAll, getOuterHTML, resolveNode
Network enable, setCookies, getCookies, setExtraHTTPHeaders, setUserAgentOverride
Fetch enable, continueRequest, fulfillRequest, failRequest (live interception)
Storage getCookies, setCookies, deleteCookies
Input dispatchMouseEvent, dispatchKeyEvent
LP getMarkdown (DOM-to-Markdown conversion)

CLI Reference

obscura serve

Start a CDP WebSocket server.

Flag Default Description
--port 9222 WebSocket port
--proxy HTTP/SOCKS5 proxy URL
--stealth off Enable anti-detection + tracker blocking
--workers 1 Number of parallel worker processes
--obey-robots off Respect robots.txt

obscura fetch <URL>

Fetch and render a single page.

Flag Default Description
--dump html Output: html, text, or links
--eval JavaScript expression to evaluate
--wait-until load Wait: load, domcontentloaded, networkidle0
--timeout 30 Maximum navigation time in seconds
--selector Wait for CSS selector
--stealth off Anti-detection mode
--output Write dump or eval output to a file
--quiet off Suppress banner
--proxy Inherited global HTTP/SOCKS5 proxy URL

obscura scrape <URL...>

Scrape multiple URLs in parallel with worker processes.

Flag Default Description
--concurrency 10 Parallel workers
--eval JS expression per page
--format json Output: json or text
--quiet off Suppress scrape progress on stderr
--proxy Inherited global HTTP/SOCKS5 proxy URL for all workers

MCP (Model Context Protocol)

Obscura ships an MCP server that exposes browser automation tools to AI agents (Claude Desktop, Cursor, etc.).

Start

stdio (default) — for Claude Desktop and MCP clients that launch a subprocess:

obscura mcp

HTTP — for clients that connect over the network:

obscura mcp --http --port 8080
# endpoint: http://127.0.0.1:8080/mcp

Optional flags (both transports):

Flag Description
--proxy <URL> HTTP/SOCKS5 proxy
--user-agent <UA> Custom User-Agent string
--stealth Enable anti-detection mode

Claude Desktop config

{
  "mcpServers": {
    "obscura": {
      "command": "obscura",
      "args": ["mcp"]
    }
  }
}

Tools

Tool Description
browser_navigate Navigate to a URL (url, optional waitUntil: load / domcontentloaded / networkidle0)
browser_snapshot Return the current page URL, title, and body text
browser_click Click an element by CSS selector
browser_fill Set an input value (triggers input + change events)
browser_type Append text to an input
browser_press_key Dispatch a keyboard event (key, optional selector)
browser_select_option Select an <option> by value or text
browser_evaluate Evaluate a JavaScript expression and return the result
browser_wait_for Wait for a CSS selector to appear (selector, optional timeout in seconds)
browser_network_requests List network requests made by the current page
browser_console_messages Return console messages logged by the page
browser_close Close the page and reset browser state

License

Apache 2.0


Apps
About Me
GitHub: Trinea
Facebook: Dev Tools