h4ckf0r0day/obscuraPublic

The headless browser for AI agents and web scraping

AI summary: A highly evasive, custom headless browser engine written entirely in Rust for undetectable web scraping.

Stars
28.3K
+110 today
Forks
2.1K
Watchers
81
Open issues
95
Open PRs
87
Contributors
~72
Commits
1.2K
Branches
1

RustApache-2.0Created Apr 13, 2026Last push 3d agoLatest release v0.2.3+479 stars this week+4.4K this month

Quick answers

What is obscura?
A highly evasive, custom headless browser engine written entirely in Rust for undetectable web scraping.
What does obscura do?
Obscura is a highly specialized, deeply evasive headless browser engine built entirely from the ground up in Rust to aggressively bypass highly advanced bot detection and anti-scraping systems. Unlike typical, easily detectable wrappers built heavily around Chromium or Firefox, Obscura natively implements a completely custom networking stack and deeply tuned JavaScript runtime specifically designed to flawlessly mimic organic human traffic. It dynamically and intelligently alters complex TLS fingerprints, intricate Canvas renderings, and deep hardware concurrency metrics to effortlessly evade the extremely common fingerprinting techniques massively used by enterprise Web Application Firewalls. The extensive project deeply focuses on absolutely providing a completely, undeniably undetectable automated browsing experience for incredibly complex data extraction.
Who is obscura for?
Security researchers, advanced data engineers, and expert penetration testers who require a highly sophisticated, completely undetectable tool for web automation.
How do I get started with obscura?
cargo build --release
How popular is obscura on GitHub?
h4ckf0r0day/obscura has 28,258 stars and 2,103 forks on GitHub, and gained 479 stars in the last 7 days.
What license does obscura use?
h4ckf0r0day/obscura is released under the Apache-2.0 license.

Star history

since Jul 29, 2026
010K20KJul 2026Aug 2026Sep 2026Oct 2026
28.3K stars as of Oct 2, 2026. Measured daily since Jul 29, 2026; GitHub no longer exposes earlier star timestamps.

Contribution activity

commits per day, last 52 weeks
SepOctNovDecJanFebMarAprMayJunJulAugSepMonWedFri2025-09-28: 0 commits2025-09-29: 0 commits2025-09-30: 0 commits2025-10-01: 0 commits2025-10-02: 0 commits2025-10-03: 0 commits2025-10-04: 0 commits2025-10-05: 0 commits2025-10-06: 0 commits2025-10-07: 0 commits2025-10-08: 0 commits2025-10-09: 0 commits2025-10-10: 0 commits2025-10-11: 0 commits2025-10-12: 0 commits2025-10-13: 0 commits2025-10-14: 0 commits2025-10-15: 0 commits2025-10-16: 0 commits2025-10-17: 0 commits2025-10-18: 0 commits2025-10-19: 0 commits2025-10-20: 0 commits2025-10-21: 0 commits2025-10-22: 0 commits2025-10-23: 0 commits2025-10-24: 0 commits2025-10-25: 0 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 0 commits2025-10-29: 0 commits2025-10-30: 0 commits2025-10-31: 0 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 0 commits2025-11-05: 0 commits2025-11-06: 0 commits2025-11-07: 0 commits2025-11-08: 0 commits2025-11-09: 0 commits2025-11-10: 0 commits2025-11-11: 0 commits2025-11-12: 0 commits2025-11-13: 0 commits2025-11-14: 0 commits2025-11-15: 0 commits2025-11-16: 0 commits2025-11-17: 0 commits2025-11-18: 0 commits2025-11-19: 0 commits2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 0 commits2025-11-26: 0 commits2025-11-27: 0 commits2025-11-28: 0 commits2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 0 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 0 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 0 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 0 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 0 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 0 commits2026-01-15: 0 commits2026-01-16: 0 commits2026-01-17: 0 commits2026-01-18: 0 commits2026-01-19: 0 commits2026-01-20: 0 commits2026-01-21: 0 commits2026-01-22: 0 commits2026-01-23: 0 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 0 commits2026-01-27: 0 commits2026-01-28: 0 commits2026-01-29: 0 commits2026-01-30: 0 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 0 commits2026-02-03: 0 commits2026-02-04: 0 commits2026-02-05: 0 commits2026-02-06: 0 commits2026-02-07: 0 commits2026-02-08: 0 commits2026-02-09: 0 commits2026-02-10: 0 commits2026-02-11: 0 commits2026-02-12: 0 commits2026-02-13: 0 commits2026-02-14: 0 commits2026-02-15: 0 commits2026-02-16: 0 commits2026-02-17: 0 commits2026-02-18: 0 commits2026-02-19: 0 commits2026-02-20: 0 commits2026-02-21: 0 commits2026-02-22: 0 commits2026-02-23: 0 commits2026-02-24: 0 commits2026-02-25: 0 commits2026-02-26: 0 commits2026-02-27: 0 commits2026-02-28: 0 commits2026-03-01: 0 commits2026-03-02: 0 commits2026-03-03: 0 commits2026-03-04: 0 commits2026-03-05: 0 commits2026-03-06: 0 commits2026-03-07: 0 commits2026-03-08: 0 commits2026-03-09: 0 commits2026-03-10: 0 commits2026-03-11: 0 commits2026-03-12: 0 commits2026-03-13: 0 commits2026-03-14: 0 commits2026-03-15: 0 commits2026-03-16: 0 commits2026-03-17: 0 commits2026-03-18: 0 commits2026-03-19: 0 commits2026-03-20: 0 commits2026-03-21: 0 commits2026-03-22: 0 commits2026-03-23: 0 commits2026-03-24: 0 commits2026-03-25: 0 commits2026-03-26: 0 commits2026-03-27: 0 commits2026-03-28: 0 commits2026-03-29: 0 commits2026-03-30: 0 commits2026-03-31: 0 commits2026-04-01: 0 commits2026-04-02: 0 commits2026-04-03: 0 commits2026-04-04: 0 commits2026-04-05: 0 commits2026-04-06: 0 commits2026-04-07: 0 commits2026-04-08: 0 commits2026-04-09: 0 commits2026-04-10: 0 commits2026-04-11: 0 commits2026-04-12: 0 commits2026-04-13: 5 commits2026-04-14: 0 commits2026-04-15: 0 commits2026-04-16: 0 commits2026-04-17: 0 commits2026-04-18: 0 commits2026-04-19: 0 commits2026-04-20: 0 commits2026-04-21: 0 commits2026-04-22: 0 commits2026-04-23: 0 commits2026-04-24: 2 commits2026-04-25: 5 commits2026-04-26: 0 commits2026-04-27: 3 commits2026-04-28: 0 commits2026-04-29: 0 commits2026-04-30: 0 commits2026-05-01: 0 commits2026-05-02: 0 commits2026-05-03: 18 commits2026-05-04: 0 commits2026-05-05: 1 commit2026-05-06: 0 commits2026-05-07: 0 commits2026-05-08: 0 commits2026-05-09: 10 commits2026-05-10: 1 commit2026-05-11: 0 commits2026-05-12: 0 commits2026-05-13: 11 commits2026-05-14: 10 commits2026-05-15: 9 commits2026-05-16: 3 commits2026-05-17: 0 commits2026-05-18: 2 commits2026-05-19: 0 commits2026-05-20: 0 commits2026-05-21: 0 commits2026-05-22: 0 commits2026-05-23: 0 commits2026-05-24: 9 commits2026-05-25: 3 commits2026-05-26: 1 commit2026-05-27: 1 commit2026-05-28: 0 commits2026-05-29: 5 commits2026-05-30: 2 commits2026-05-31: 6 commits2026-06-01: 0 commits2026-06-02: 5 commits2026-06-03: 9 commits2026-06-04: 2 commits2026-06-05: 5 commits2026-06-06: 9 commits2026-06-07: 5 commits2026-06-08: 8 commits2026-06-09: 5 commits2026-06-10: 11 commits2026-06-11: 9 commits2026-06-12: 1 commit2026-06-13: 3 commits2026-06-14: 1 commit2026-06-15: 0 commits2026-06-16: 0 commits2026-06-17: 5 commits2026-06-18: 5 commits2026-06-19: 0 commits2026-06-20: 0 commits2026-06-21: 0 commits2026-06-22: 7 commits2026-06-23: 8 commits2026-06-24: 9 commits2026-06-25: 1 commit2026-06-26: 2 commits2026-06-27: 1 commit2026-06-28: 0 commits2026-06-29: 3 commits2026-06-30: 7 commits2026-07-01: 8 commits2026-07-02: 13 commits2026-07-03: 10 commits2026-07-04: 0 commits2026-07-05: 0 commits2026-07-06: 2 commits2026-07-07: 2 commits2026-07-08: 0 commits2026-07-09: 5 commits2026-07-10: 5 commits2026-07-11: 11 commits2026-07-12: 0 commits2026-07-13: 1 commit2026-07-14: 12 commits2026-07-15: 0 commits2026-07-16: 18 commits2026-07-17: 0 commits2026-07-18: 0 commits2026-07-19: 5 commits2026-07-20: 5 commits2026-07-21: 1 commit2026-07-22: 14 commits2026-07-23: 71 commits2026-07-24: 4 commits2026-07-25: 1 commit2026-07-26: 51 commits2026-07-27: 1 commit2026-07-28: 2 commits2026-07-29: 3 commits2026-07-30: 29 commits2026-07-31: 64 commits2026-08-01: 7 commits2026-08-02: 3 commits2026-08-03: 44 commits2026-08-04: 82 commits2026-08-05: 6 commits2026-08-06: 0 commits2026-08-07: 17 commits2026-08-08: 7 commits2026-08-09: 6 commits2026-08-10: 13 commits2026-08-11: 8 commits2026-08-12: 3 commits2026-08-13: 0 commits2026-08-14: 11 commits2026-08-15: 3 commits2026-08-16: 3 commits2026-08-17: 0 commits2026-08-18: 0 commits2026-08-19: 1 commit2026-08-20: 3 commits2026-08-21: 3 commits2026-08-22: 2 commits2026-08-23: 9 commits2026-08-24: 8 commits2026-08-25: 6 commits2026-08-26: 3 commits2026-08-27: 2 commits2026-08-28: 1 commit2026-08-29: 7 commits2026-08-30: 2 commits2026-08-31: 4 commits2026-09-01: 5 commits2026-09-02: 8 commits2026-09-03: 3 commits2026-09-04: 12 commits2026-09-05: 3 commits2026-09-06: 6 commits2026-09-07: 0 commits2026-09-08: 10 commits2026-09-09: 2 commits2026-09-10: 5 commits2026-09-11: 0 commits2026-09-12: 12 commits2026-09-13: 6 commits2026-09-14: 3 commits2026-09-15: 0 commits2026-09-16: 3 commits2026-09-17: 4 commits2026-09-18: 5 commits2026-09-19: 4 commits2026-09-20: 1 commit2026-09-21: 0 commits2026-09-22: 0 commits2026-09-23: 0 commits2026-09-24: 0 commits2026-09-25: 0 commits2026-09-26: 0 commits
922 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Widely adopted

    28,258 stars

  • Very active

    922 commits in 52 weeks

  • Outside contributions

    97% of recent commits from the community

  • Well documented

    High community health score

  • Permissive license

    Apache-2.0

  • Continuous integration

    Automated checks passing

  • Repeat trending

    7 trending appearances

What obscura does

Obscura is a highly specialized, deeply evasive headless browser engine built entirely from the ground up in Rust to aggressively bypass highly advanced bot detection and anti-scraping systems. Unlike typical, easily detectable wrappers built heavily around Chromium or Firefox, Obscura natively implements a completely custom networking stack and deeply tuned JavaScript runtime specifically designed to flawlessly mimic organic human traffic. It dynamically and intelligently alters complex TLS fingerprints, intricate Canvas renderings, and deep hardware concurrency metrics to effortlessly evade the extremely common fingerprinting techniques massively used by enterprise Web Application Firewalls. The extensive project deeply focuses on absolutely providing a completely, undeniably undetectable automated browsing experience for incredibly complex data extraction.

Security researchers, advanced data engineers, and expert penetration testers who require a highly sophisticated, completely undetectable tool for web automation.

  • Custom Rust Engine: Built completely from scratch in Rust, entirely avoiding the massively identifiable signatures highly inherent to standard Chromium-based headless browsers.
  • Dynamic Fingerprinting: Automatically and intelligently rotates complex TLS fingerprints, highly specific user agents, and deep hardware capabilities to effectively defeat bot detection algorithms.
  • WAF Evasion: Deeply implements highly specialized, totally custom networking techniques heavily designed specifically to easily bypass massive enterprise Web Application Firewalls.
  • Canvas Spoofing: Expertly generates mathematically sound but incredibly unique Canvas and complex WebGL rendering outputs to absolutely prevent massive cross-session tracking.
  • Headless Optimization: Aggressively strips out entirely unnecessary visual rendering components to effortlessly provide extremely high-performance, massive data extraction capabilities.

Where teams use it

Stealth Web Scraping

Massively extracting complex data from highly protected, heavily defended targets that actively and aggressively block standard automation tools like Puppeteer or Playwright.

Automated Testing Evasion

Continuously running complex automated security tests aggressively against massive applications without ever triggering automated, heavily enforced IP bans from the WAF.

Market Intelligence

Rapidly gathering incredibly massive amounts of competitive pricing data at massive scale without ever being detected or highly identified as an automated bot network.

Bot Detection Research

Deeply analyzing the massive effectiveness of various complex fingerprinting and deep anti-bot techniques by rigorously testing them against an actively evasive engine.

Getting started: cargo build --release

README

main branch

Obscura

Obscura

h4ckf0r0day%2Fobscura | Trendshift

Documentation Website Obscura on Twitter/X Book a demo Releases

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

Native rendering is here. No Chromium required. 🎉

Capture screenshots, screencast live pages, and export PDFs directly with Obscura.


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?

Metric Obscura Headless Chrome
Memory 30 MB 200+ MB
Binary size ~70 MiB 300+ MB
Anti-detect Built-in None
Page load 85 ms ~500 ms
Startup Instant ~2s
Puppeteer Yes Yes
Playwright Yes Yes
Cloudflare Obscura inspired Cloudflare Kitesurf’s first prototype
Cloudflare began by porting Obscura to Workers while developing its new agent-first browser.
Read Cloudflare’s engineering story →

Obscura Cloud

We are 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 →
📅 Book a demo →

Sponsors

Obscura is supported by organizations helping us build independent open-source browser infrastructure.

Want to sponsor? Email hello@obscura.sh.

NodeMaven NodeMaven: The most efficient proxy provider for Web Scraping and Automation with the Highest Quality IP on the market.

Why NodeMaven?
ZIP targeting
99.9% uptime
IP filtering: all proxies have fraud score <97%
No KYC required
Unique free tools: Proxy Bandwidth Checker, Meta Tag Checker, IP Lookup and others!

🎁 Special codes for Obscura users:
OBSCURA35 - 35% off to Mobile and Residential Proxies
OBSCURA40 - 40% off to ISP (Static) Proxies
ProxyEmpire 🚀 Obscura × ProxyEmpire
Using Obscura for AI agents, browser automation, or web scraping? Power it with reliable residential and mobile proxies from ProxyEmpire.

🌍 30M+ residential IPs in 170+ countries
📱 4G/5G mobile proxies
🔄 Rotating & sticky sessions
🎯 City, region & ISP targeting
🔐 HTTP, HTTPS & SOCKS5 support

🎁 Use code OBSCURA35 for a 35% recurring discount.

Better proxies. Fewer blocks. More scalable automation.
NiuProxy NiuProxy Rotating Residential Proxies — Special Offer: 10TB at $0.35/GB | 1TB at $0.50/GB.

🎁 Use code PAY2 for 10% off your recharge.
Masklabs Obscura + Masklabs

Obscura masks the browser. Masklabs masks the traffic.

Mobile proxies for scrapers, bots, and AI agents that need to look human. Real carrier IPs across a rotating pool, zero shared-IP baggage.

Pair Obscura's stealth rendering with Masklabs' mobile network and your requests blend into everyday traffic.

💸 Try it free for 30 days.

🎁 Use code OBSCURA25 for 25% off your first month.

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"

# Linux ARM64 (aarch64)
curl -LO https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-aarch64-linux.tar.gz
tar xzf obscura-aarch64-linux.tar.gz

# NixOS
nix-env -iA nixpkgs.obscura

# 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.

Archive suffix Rendering Stealth transport
none Yes No
-stealth Yes Yes
-no-render No No
-no-render-stealth No Yes

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 \
  -e OBSCURA_CDP_TOKEN="$(openssl rand -hex 32)" \
  h4ckf0r0day/obscura

Image on Docker Hub. Multi-stage build on distroless/cc:nonroot — no shell, no package manager, runs as uid 65532, ~57 MB compressed. A mounted --storage-dir must be writable by uid 65532. Publish to host loopback as above; -p 9222:9222 exposes the port on every interface.

Build from source

git clone https://github.com/h4ckf0r0day/obscura.git
cd obscura

# Rendering
cargo build --release -p obscura-cli --bins --features render

# Rendering and stealth
cargo build --release -p obscura-cli --bins --features render,stealth

# No rendering
cargo build --release -p obscura-cli --bins --no-default-features

# No rendering, with stealth
cargo build --release -p obscura-cli --bins --no-default-features --features stealth

Requires Rust 1.75+ (rustup.rs). First build takes ~5 min (V8 compiles from source, cached after). The stealth build also compiles BoringSSL and generates bindings, so it needs CMake, Clang, and the libclang/LLVM development libraries. On Ubuntu/Debian:

sudo apt-get install build-essential cmake clang libclang-dev llvm-dev

The rendering build uses rustls. The rendering-and-stealth build uses wreq/BoringSSL and therefore needs the additional build tools above.

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

# Stream the raw response body verbatim (binary-safe; bypasses the JS/DOM layer).
# Use this for images, JSON, JS, CSS, or any non-HTML resource.
obscura fetch https://picsum.photos/200/300 --dump original > photo.jpg

# List every sub-resource URL the page would fetch (NDJSON; one record per asset)
obscura fetch https://example.com --dump assets

# 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

# Capture the settled page as PNG
obscura fetch https://example.com --screenshot page.png

# The screenshot flag also has a short form
obscura fetch https://example.com -s page.png

### Testing against localhost / LAN dev servers

Obscura blocks fetches to private/internal IPs by default (SSRF protection).
To point it at a local dev server, pass `--allow-private-network` (or set
`OBSCURA_ALLOW_PRIVATE_NETWORK=1`):

```bash
obscura fetch http://127.0.0.1:3000 --allow-private-network --dump text

# Works on any subcommand, e.g. the CDP server for local Puppeteer/Playwright:
obscura serve --port 9222 --allow-private-network

See docs/Environment-variables.md for the full allow/deny rules (DNS-resolution-time checks included).


## Rendering

Official release archives and the Docker image include the rendering engine.
It provides CSS layout and paint, viewport and full-page screenshots,
scroll-aware fixed and sticky geometry, activity-driven CDP screencasting, and
raster PDF export without starting Chromium.

```javascript
await page.setViewport({ width: 1440, height: 1000 });
await page.goto('https://example.com', { waitUntil: 'load' });
await page.screenshot({ path: 'page.png', fullPage: true });
await page.pdf({ path: 'page.pdf', format: 'A4', printBackground: true });

The current implementation covers block, inline, flex, grid, table, float, positioning, overflow, transform, text, image, SVG, canvas, background, border, and animation paths. It remains an evolving independent engine: long-tail CSS, some Web APIs, media playback, compositor effects, and platform font rasterization may differ from Chromium. The existing Puppeteer, Playwright, and MCP guides cover their capture APIs and limits.

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

The full benchmark suite (WPT conformance, obstacle course, real-world corpus, and vs-Chrome speed) lives in a separate repo: https://github.com/h4ckf0r0day/obscura-benchmark

Stealth Mode

Build with --features render,stealth, then enable stealth at runtime with the global --stealth flag. The stealth build includes the complete rendering engine; enabling stealth does not remove screenshot, screencast, PDF, CDP, or MCP functionality.

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, lifecycleEvents, captureScreenshot, start/stopScreencast, printToPDF
Runtime evaluate, callFunctionOn, getProperties, addBinding
DOM getDocument, querySelector, querySelectorAll, getOuterHTML, resolveNode
Network enable, setCookies, getCookies, setExtraHTTPHeaders, setUserAgentOverride
Fetch enable, continueRequest, fulfillRequest, failRequest (live interception), takeResponseBodyAsStream
IO read, close (stream a large response body in chunks)
Storage getCookies, setCookies, deleteCookies
Input dispatchMouseEvent, dispatchKeyEvent
LP getMarkdown (DOM-to-Markdown conversion)

To download a large resource without one giant Network.getResponseBody blob, call Fetch.takeResponseBodyAsStream then read it in chunks with IO.read / IO.close. Response bodies over the cache limit (OBSCURA_NETWORK_BODY_BUFFER_BYTES, default 2 MiB) are not retained, so raise that limit when you intend to stream large downloads.

CLI Reference

Tuning V8

Obscura embeds V8 directly. Use --v8-flags to pass raw flags through to V8, same syntax as Chromium's --js-flags and Node's command-line flags. Most common use is raising the heap cap to fix JavaScript heap out of memory on JS-heavy pages:

obscura --v8-flags "--max-old-space-size=4096" fetch <url>

Heavy SPAs (script execution budget)

Obscura caps the page's script-execution phase so one slow or hung page cannot stall a worker. The default budget is 30s; pages that finish sooner return immediately, so the cap only affects pages that keep running. A very heavy React/Vue/Angular SPA on a slow network can need more time to boot before it fires its data requests. Raise the budget with OBSCURA_SCRIPT_DEADLINE_MS (milliseconds), and pair it with a matching navigation timeout in your CDP client:

OBSCURA_SCRIPT_DEADLINE_MS=60000 obscura serve --port 9222

Modules that enhance an already-rendered page have a separate 3s per-module budget so one non-essential module cannot hold navigation open. Raise it for legitimate long-running modules such as a Vite HMR client:

OBSCURA_MODULE_BUDGET_MS=10000 obscura serve --port 9222

An unmounted SPA shell already gives its app modules the full OBSCURA_SCRIPT_DEADLINE_MS budget. OBSCURA_FETCH_TIMEOUT_MS controls the module's network request, not its evaluation time. See Environment variables for the complete timeout model.

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
--font-dir — Recursively load fonts once per worker (repeatable; render build)
--obey-robots off Respect robots.txt

obscura fetch <URL>

Fetch and render a single page.

Flag Default Description
--dump html Output: html, text, links, markdown, assets (NDJSON of every sub-resource URL the page references), or original (raw response body)
--eval — JavaScript expression to evaluate
--wait-until load Wait: load, domcontentloaded, networkidle0
--timeout 30 Maximum navigation time in seconds
--wait adaptive, up to 5 Post-load settling; an explicit value is a fixed delay in seconds
--selector — Wait for CSS selector
-s, --screenshot — Write a PNG screenshot (single URL; render-enabled build)
--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, readable body text, and element references
browser_screenshot Return the current page as an MCP PNG image (render-enabled build)
browser_pdf Return the current page as an embedded PDF resource (render-enabled build)
browser_click Click by current snapshot reference or CSS selector
browser_fill Set an input value by reference or selector (triggers input + change)
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

The MCP server exposes still-image and PDF output. Use CDP when you need the streaming Page.startScreencast protocol.

Integrations

  • Hermes agent plugin: run Hermes agent browser tasks on Obscura. The plugin spawns obscura serve per session (or connects to an already running server) and drives it over CDP, with optional --stealth.

License

Apache 2.0


View on GitHub

Recent activity

commits and pull requests

Releases and announcements

16 total
  1. v0.2.3v0.2.3Sep 20, 20266.1K downloads

    # v0.2.3 Security, concurrency, and browser compatibility are the focus of this release. The JavaScript engine has been updated, exposed CDP and MCP servers now have built-in authentication, concurrent sessions are more reliable, and rendering gained another broad correctness and performance pass. 114 commits since v0.2.2. ## Highlights • **CDP and MCP now protect exposed control ports.** Non-loopback binds require a bearer token of at least 32 bytes. Browser-origin requests and invalid Host headers are rejected, request sizes and connection counts are bounded, and multiworker CDP preserves the same security checks (#1030, #1048). • **Deno and V8 have been updated.** `deno_core` moves from 0.350 to 0.412 and V8 to 150.4, removing the old advisory exceptions while retaining Obscura's runtime behavior and performance (#1031). • **Concurrent automation is faster and more reliable.** Concurrent pages keep independent live isolates, disconnected clients release their state, browser attachments receive unique sessions, and the multiworker server now starts immediately, uses OS-assigned ports, and avoids proxy latency (#872, #873, #978, #1048). • **Rendering is faster and more

  2. v0.2.2v0.2.2Sep 5, 202634.9K downloads

    # v0.2.2 A wide compatibility and robustness pass: generated CDP clients (chromiumoxide, spider) now work end to end, Playwright form filling and context setup complete, one page script can no longer starve or crash the engine, and the stealth transport closes its remaining SSRF gaps. 126 commits since v0.2.1. ## Highlights • **Generated CDP clients work.** Page.enable emits the initial load sequence once per page with a schema-complete frame, so chromiumoxide's new_page no longer hangs before the first navigation and its strict Frame parser accepts every payload (#833, #703). • **Playwright form filling and context setup complete.** Input.insertText is implemented, Element.labels and HTMLLabelElement.control follow the HTML labelable-element rules so getByLabel resolves, Browser.grantPermissions is accepted during context init, and PerformanceObserver.supportedEntryTypes reports the types the engine emits (#577). • **One bad script cannot starve a page.** A throwing script or unhandled rejection is logged and the event loop keeps scheduling, matching Chrome; the bounded, quiescent, autonomous, and load-delaying pumps all continue (#699). • **Worker processes survive de

  3. v0.2.1v0.2.1Aug 23, 202630K downloads

    # v0.2.1 Child frames now run their own scripts and talk to the parent page, MCP keeps driving the page between tool calls, and rendering, CDP, and stealth all gained fidelity and consistency fixes. 122 commits since v0.2.0. ## Highlights • **iframes run their own scripts.** Child frames get their own V8 realm, a page can reach into its same-origin frames, postMessage flows between a page and its frames, and CDP reports the real child frame tree. Frame realms are released before the isolate they point into, fixing a class of crashes on frame-heavy pages (#600). • **MCP drives the page between tool calls.** The active page's task queue is pumped while the transport waits, so timers, fetches, and queued navigations (form submits, location changes, clicks) complete instead of stranding until the next tool call (#618, #640). • **Rendering keeps closing on Chrome.** Webfont icons and color emoji render, outset box shadows clip correctly, and textarea gets an intrinsic control box and its own JS interface, so Playwright visibility checks, clicks, and fills work on textareas. • **SPA routes are reported.** Same-document navigations surface after clicks and `location` coerces a

  4. v0.2.0v0.2.0Aug 8, 202629K downloads

    # v0.2.0 Obscura can now render and capture modern web pages directly, without bundling or launching Chromium. This release adds a native Rust rendering engine, screenshots, scrolling, screencasting, and PDF export through the CLI, MCP, Puppeteer, and Playwright. 449 commits since v0.1.11. ## Highlights * Native rendering: block and inline layout, Flexbox, Grid, tables, floats, positioning, scrolling, transforms, text shaping, images, SVG, Canvas, forms, gradients, shadows, and animations. * Modern websites: external stylesheets, JavaScript modules, dynamic imports, hydration, responsive images, web fonts, observers, Shadow DOM, and custom elements. * Screenshots: viewport, clipped, scrolled, and full-page capture with PNG, JPEG, and WebP output through CDP. * Screencasting: activity-driven PNG or JPEG frames with sizing, quality controls, acknowledgement backpressure, and isolated CDP sessions. * PDF export: print styles, pagination, paper sizes, margins, scale, landscape mode, backgrounds, page ranges, and streamed output. ## CLI and automation Capture a page directly: ```sh obscura fetch https://example.com --screenshot page.png ``` Puppeteer and Playw

  5. v0.1.11v0.1.11Jul 26, 202620.1K downloads

    # v0.1.11 CDP sessions are now isolated and safe to run concurrently, DOM traversal and template handling are substantially more browser-compatible, sequential embedded Browser sessions no longer share fetch state, and the MCP and release paths received additional hardening. 81 commits since v0.1.10. ## Highlights • **Concurrent CDP sessions no longer share V8 state.** Each connection owns its runtime and browser context, preventing cross-isolate aborts and stopping cookies, headers, targets, and User-Agent overrides from leaking between clients (#435, #456). • **TreeWalker, NodeIterator, templates, and fragments now behave like real DOM APIs.** Traversal follows document order in both directions, filters handle `FILTER_SKIP` and `FILTER_REJECT` correctly, `<template>.content` exposes parsed markup, and inserting a `DocumentFragment` moves its children rather than attaching the fragment itself (#447, #454, #464, #465, #466, #471, #472, #476). • **Network activity is observable and isolated.** Scripted `fetch()`/XHR requests emit CDP Network events, passive request/response callbacks can be detached, and callbacks stay scoped to the page that registered them (#414, #415

Code frequency

additions and deletions
+77.9K-77.9KWeek of 2026-04-12: +20,012 linesWeek of 2026-04-12: -16 linesWeek of 2026-04-19: +357 linesWeek of 2026-04-19: -105 linesWeek of 2026-04-26: +620 linesWeek of 2026-04-26: -43 linesWeek of 2026-05-03: +1,497 linesWeek of 2026-05-03: -129 linesWeek of 2026-05-10: +3,382 linesWeek of 2026-05-10: -339 linesWeek of 2026-05-17: +307 linesWeek of 2026-05-17: -153 linesWeek of 2026-05-24: +4,422 linesWeek of 2026-05-24: -745 linesWeek of 2026-05-31: +9,184 linesWeek of 2026-05-31: -1,475 linesWeek of 2026-06-07: +3,029 linesWeek of 2026-06-07: -645 linesWeek of 2026-06-14: +399 linesWeek of 2026-06-14: -15 linesWeek of 2026-06-21: +1,934 linesWeek of 2026-06-21: -225 linesWeek of 2026-06-28: +6,181 linesWeek of 2026-06-28: -765 linesWeek of 2026-07-05: +7,555 linesWeek of 2026-07-05: -662 linesWeek of 2026-07-12: +4,229 linesWeek of 2026-07-12: -881 linesWeek of 2026-07-19: +11,036 linesWeek of 2026-07-19: -976 linesWeek of 2026-07-26: +77,851 linesWeek of 2026-07-26: -4,436 linesWeek of 2026-08-02: +74,915 linesWeek of 2026-08-02: -12,542 linesWeek of 2026-08-09: +8,158 linesWeek of 2026-08-09: -652 linesWeek of 2026-08-16: +1,454 linesWeek of 2026-08-16: -398 linesWeek of 2026-08-23: +5,316 linesWeek of 2026-08-23: -327 linesWeek of 2026-08-30: +5,448 linesWeek of 2026-08-30: -738 linesWeek of 2026-09-06: +5,434 linesWeek of 2026-09-06: -610 linesWeek of 2026-09-13: +4,729 linesWeek of 2026-09-13: -957 linesWeek of 2026-09-20: +3,071 linesWeek of 2026-09-20: -1,460 linesApr 12, 2026Sep 20, 2026
+260.5K lines added, -29.3K removed over the last year.

Commits per week

last 52 weeks
1590Week of 2025-09-28: 0 commitsWeek of 2025-10-05: 0 commitsWeek of 2025-10-12: 0 commitsWeek of 2025-10-19: 0 commitsWeek of 2025-10-26: 0 commitsWeek of 2025-11-02: 0 commitsWeek of 2025-11-09: 0 commitsWeek of 2025-11-16: 0 commitsWeek of 2025-11-23: 0 commitsWeek of 2025-11-30: 0 commitsWeek of 2025-12-07: 0 commitsWeek of 2025-12-14: 0 commitsWeek of 2025-12-21: 0 commitsWeek of 2025-12-28: 0 commitsWeek of 2026-01-04: 0 commitsWeek of 2026-01-11: 0 commitsWeek of 2026-01-18: 0 commitsWeek of 2026-01-25: 0 commitsWeek of 2026-02-01: 0 commitsWeek of 2026-02-08: 0 commitsWeek of 2026-02-15: 0 commitsWeek of 2026-02-22: 0 commitsWeek of 2026-03-01: 0 commitsWeek of 2026-03-08: 0 commitsWeek of 2026-03-15: 0 commitsWeek of 2026-03-22: 0 commitsWeek of 2026-03-29: 0 commitsWeek of 2026-04-05: 0 commitsWeek of 2026-04-12: 5 commitsWeek of 2026-04-19: 7 commitsWeek of 2026-04-26: 3 commitsWeek of 2026-05-03: 29 commitsWeek of 2026-05-10: 34 commitsWeek of 2026-05-17: 2 commitsWeek of 2026-05-24: 21 commitsWeek of 2026-05-31: 36 commitsWeek of 2026-06-07: 42 commitsWeek of 2026-06-14: 11 commitsWeek of 2026-06-21: 28 commitsWeek of 2026-06-28: 41 commitsWeek of 2026-07-05: 25 commitsWeek of 2026-07-12: 31 commitsWeek of 2026-07-19: 101 commitsWeek of 2026-07-26: 157 commitsWeek of 2026-08-02: 159 commitsWeek of 2026-08-09: 44 commitsWeek of 2026-08-16: 12 commitsWeek of 2026-08-23: 36 commitsWeek of 2026-08-30: 37 commitsWeek of 2026-09-06: 35 commitsWeek of 2026-09-13: 25 commitsWeek of 2026-09-20: 1 commitsSep 28, 2025Sep 20, 2026
922 commits in the last 52 weeks.

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 0 commitsSun 1:00 — 4 commitsSun 2:00 — 1 commitsSun 3:00 — 0 commitsSun 4:00 — 0 commitsSun 5:00 — 0 commitsSun 6:00 — 0 commitsSun 7:00 — 0 commitsSun 8:00 — 4 commitsSun 9:00 — 3 commitsSun 10:00 — 4 commitsSun 11:00 — 12 commitsSun 12:00 — 12 commitsSun 13:00 — 5 commitsSun 14:00 — 6 commitsSun 15:00 — 10 commitsSun 16:00 — 6 commitsSun 17:00 — 12 commitsSun 18:00 — 4 commitsSun 19:00 — 9 commitsSun 20:00 — 14 commitsSun 21:00 — 12 commitsSun 22:00 — 10 commitsSun 23:00 — 4 commitsMon 0:00 — 0 commitsMon 1:00 — 0 commitsMon 2:00 — 0 commitsMon 3:00 — 0 commitsMon 4:00 — 1 commitsMon 5:00 — 0 commitsMon 6:00 — 0 commitsMon 7:00 — 6 commitsMon 8:00 — 0 commitsMon 9:00 — 4 commitsMon 10:00 — 6 commitsMon 11:00 — 12 commitsMon 12:00 — 9 commitsMon 13:00 — 14 commitsMon 14:00 — 11 commitsMon 15:00 — 7 commitsMon 16:00 — 6 commitsMon 17:00 — 7 commitsMon 18:00 — 5 commitsMon 19:00 — 4 commitsMon 20:00 — 4 commitsMon 21:00 — 7 commitsMon 22:00 — 6 commitsMon 23:00 — 3 commitsTue 0:00 — 6 commitsTue 1:00 — 0 commitsTue 2:00 — 1 commitsTue 3:00 — 1 commitsTue 4:00 — 2 commitsTue 5:00 — 1 commitsTue 6:00 — 3 commitsTue 7:00 — 6 commitsTue 8:00 — 13 commitsTue 9:00 — 9 commitsTue 10:00 — 11 commitsTue 11:00 — 13 commitsTue 12:00 — 9 commitsTue 13:00 — 10 commitsTue 14:00 — 7 commitsTue 15:00 — 10 commitsTue 16:00 — 17 commitsTue 17:00 — 10 commitsTue 18:00 — 4 commitsTue 19:00 — 5 commitsTue 20:00 — 5 commitsTue 21:00 — 6 commitsTue 22:00 — 2 commitsTue 23:00 — 4 commitsWed 0:00 — 3 commitsWed 1:00 — 1 commitsWed 2:00 — 1 commitsWed 3:00 — 3 commitsWed 4:00 — 0 commitsWed 5:00 — 0 commitsWed 6:00 — 2 commitsWed 7:00 — 0 commitsWed 8:00 — 3 commitsWed 9:00 — 5 commitsWed 10:00 — 5 commitsWed 11:00 — 2 commitsWed 12:00 — 5 commitsWed 13:00 — 1 commitsWed 14:00 — 2 commitsWed 15:00 — 8 commitsWed 16:00 — 2 commitsWed 17:00 — 1 commitsWed 18:00 — 3 commitsWed 19:00 — 11 commitsWed 20:00 — 11 commitsWed 21:00 — 10 commitsWed 22:00 — 8 commitsWed 23:00 — 10 commitsThu 0:00 — 1 commitsThu 1:00 — 0 commitsThu 2:00 — 1 commitsThu 3:00 — 0 commitsThu 4:00 — 2 commitsThu 5:00 — 0 commitsThu 6:00 — 0 commitsThu 7:00 — 1 commitsThu 8:00 — 5 commitsThu 9:00 — 3 commitsThu 10:00 — 13 commitsThu 11:00 — 8 commitsThu 12:00 — 21 commitsThu 13:00 — 3 commitsThu 14:00 — 6 commitsThu 15:00 — 11 commitsThu 16:00 — 9 commitsThu 17:00 — 6 commitsThu 18:00 — 7 commitsThu 19:00 — 14 commitsThu 20:00 — 16 commitsThu 21:00 — 26 commitsThu 22:00 — 18 commitsThu 23:00 — 9 commitsFri 0:00 — 10 commitsFri 1:00 — 8 commitsFri 2:00 — 12 commitsFri 3:00 — 13 commitsFri 4:00 — 7 commitsFri 5:00 — 0 commitsFri 6:00 — 3 commitsFri 7:00 — 6 commitsFri 8:00 — 5 commitsFri 9:00 — 4 commitsFri 10:00 — 12 commitsFri 11:00 — 9 commitsFri 12:00 — 10 commitsFri 13:00 — 0 commitsFri 14:00 — 1 commitsFri 15:00 — 6 commitsFri 16:00 — 4 commitsFri 17:00 — 13 commitsFri 18:00 — 5 commitsFri 19:00 — 7 commitsFri 20:00 — 10 commitsFri 21:00 — 4 commitsFri 22:00 — 3 commitsFri 23:00 — 4 commitsSat 0:00 — 3 commitsSat 1:00 — 2 commitsSat 2:00 — 2 commitsSat 3:00 — 0 commitsSat 4:00 — 0 commitsSat 5:00 — 0 commitsSat 6:00 — 0 commitsSat 7:00 — 4 commitsSat 8:00 — 3 commitsSat 9:00 — 1 commitsSat 10:00 — 11 commitsSat 11:00 — 3 commitsSat 12:00 — 1 commitsSat 13:00 — 0 commitsSat 14:00 — 5 commitsSat 15:00 — 10 commitsSat 16:00 — 9 commitsSat 17:00 — 5 commitsSat 18:00 — 11 commitsSat 19:00 — 5 commitsSat 20:00 — 4 commitsSat 21:00 — 5 commitsSat 22:00 — 4 commitsSat 23:00 — 2 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.

Who is committing

last 52 weeks
Maintainer commits33 (3%)
Community commits1,144 (97%)

1,177 commits in total over the last year.

DateListRankStars gained
Jun 30, 2026daily#23+15
May 1, 2026daily#20+67
Apr 30, 2026daily#24+41
Apr 27, 2026daily#12+113
Apr 26, 2026daily#7+357
Apr 25, 2026daily#3+584
Apr 24, 2026daily#9+151
  • ultraworkers/claw-code

    An agent-managed museum exhibit, built in Rust with Gajae-Code / LazyCodex — developed and maintained with no human intervention.

    195.2K stars · Rust

  • vercel/next.js

    The React Framework

    143.2K stars · JavaScript

  • farion1231/cc-switch

    A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

    140K stars · Rust

  • openai/codex

    Lightweight coding agent that runs in your terminal

    127.8K stars · Rust

  • browser-use/browser-use

    Agents that use the browser.

    117.1K stars · Python

  • denoland/deno

    A modern runtime for JavaScript and TypeScript.

    108.6K stars · Rust