537 lines
23 KiB
Markdown
537 lines
23 KiB
Markdown
<p align="center">
|
||
<img src="https://raw.githubusercontent.com/h4ckf0r0day/obscura/main/assets/icon.png" alt="Obscura" width="80" />
|
||
</p>
|
||
<h2 align="center">Obscura</h2>
|
||
<p align="center">
|
||
<a href="https://trendshift.io/repositories/25837?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-25837" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/25837/daily" alt="h4ckf0r0day%2Fobscura | Trendshift" width="250" height="55"/></a>
|
||
</p>
|
||
<p align="center">
|
||
<a href="https://docs.obscura.sh"><img src="https://img.shields.io/badge/Docs-1a1a1a?style=for-the-badge&logo=gitbook&logoColor=white" alt="Documentation" /></a>
|
||
<a href="https://obscura.sh"><img src="https://img.shields.io/badge/Website-1a1a1a?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjE5MCAxNzAgNDIwIDQyMCI+PHBhdGggZmlsbD0iI0ZGRkZGRiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNDA2LDE3NS4wMDA0MTIgQzQ0MC40OTg5MzIsMTc1LjAwMDM1MSA0NzQuNDk4MTA4LDE3NS4wODA5OTQgNTA4LjQ5NjczNSwxNzQuOTc1NjYyIEM1MzcuNzMzNjQzLDE3NC44ODUwODYgNTYxLjI3MDY5MSwxODcuMjIwNTUxIDU3OS45Mzk2MzYsMjA4Ljc4NjYyMSBDNTkwLjg0MTA2NCwyMjEuMzc5Nzc2IDU5Ny44ODM1NDUsMjM2LjM1MjY2MSA1OTkuOTgxODczLDI1My4yMjAzNjcgQzYwMC40NDU1NTcsMjU2Ljk0NzU0MCA2MDAuOTUxMTExLDI2MC43MDQ0MzcgNjAwLjk1NjYwNCwyNjQuNDQ4MzY0IEM2MDEuMDIyNjQ0LDMwOS42MTM1MjUgNjAxLjA3NTgwNiwzNTQuNzc5MDIyIDYwMC45NTE3ODIsMzk5Ljk0MzkzOSBDNjAwLjkxMzE0Nyw0MTQuMDMyMzQ5IDYwMC42NjMyNjksNDI4LjE0MDEwNiA1OTkuNzgyMjg4LDQ0Mi4xOTMzNTkgQzU5OS41NDEwMTYsNDQ2LjA0MDg5NCA1OTcuNTYwNzkxLDQ1MC42MTU2MDEgNTk0Ljg1MzIxMCw0NTMuMzQxMzA5IEM1NzEuMTc3NTUxLDQ3Ny4xNzUzMjMgNTQ3LjE4MDcyNSw1MDAuNjkwNzk2IDUyMy4yMjc5NjYsNTI0LjI0ODc3OSBDNTA2Ljc5OTgzNSw1NDAuNDA2MTI4IDQ5MC4yMDk5OTEsNTU2LjM5OTkwMiA0NzMuODY0NTYzLDU3Mi42NDAxMzcgQzQ2OC44MDA4NDIsNTc3LjY3MTIwNCA0NjMuMDgyODg2LDU4MC4wNTQxOTkgNDU1Ljk3MDYxMiw1ODAuMDQzODIzIEM0MDAuOTcyNDQzLDU3OS45NjM1MDEgMzQ1Ljk3MzY2Myw1ODAuMTMyMDE5IDI5MC45NzYwNDQsNTc5LjkzNjc2OCBDMjY3LjU4MDQxNCw1NzkuODUzNjk5IDI0Ni41NTEyMDgsNTcyLjA0MzU3OSAyMjguOTM5NzQzLDU1Ni44Mjc1MTUgQzIxMi44NDk2MjUsNTQyLjkyNTg0MiAyMDIuNzUxOTY4LDUyNC45MDIxMDAgMTk4LjE1NjE1OCw1MDQuMDM5NjczIEMxOTcuMjgyMTk2LDUwMC4wNzIyOTYgMTk3LjA1MjQxNCw0OTUuODk1Mzg2IDE5Ny4wNDczMzMsNDkxLjgxNDQ4NCBDMTk2Ljk3ODE0OSw0MzYuMTQ5NjU4IDE5Ny4wNTA3MjAsMzgwLjQ4NDYxOSAxOTYuOTMyNjE3LDMyNC44MTk5NDYgQzE5Ni45MTkxNDQsMzE4LjQ3MDkxNyAxOTkuMTg0ODQ1LDMxMy40MTYxOTkgMjAzLjQ5NTU3NSwzMDkuMTAwNTI1IEMyNDAuNTg3OTk3LDI3MS45NjU0MjQgMjc3LjY4MjQ5NSwyMzQuODMyMzA2IDMxNC44MzQ1NjQsMTk3Ljc1Njk1OCBDMzIwLjk1NjQyMSwxOTEuNjQ3Nzk3IDMyNy4yNjQ0MzUsMTg1LjcxNTI1NiAzMzMuNjczOTIwLDE3OS45MDgwODEgQzMzNy4zNzYwMzgsMTc2LjU1MzgzMyAzNDEuNzIxNDY2LDE3NC44NTMzMTcgMzQ3LjAwNTc5OCwxNzQuOTEyODcyIEMzNjYuNTAxNzA5LDE3NS4xMzI2MTQgMzg2LjAwMTYxNywxNzUuMDAwMzIwIDQwNiwxNzUuMDAwNDEyIFogTTUwMy4zNDQ2NjYsMjczLjg0MDE0OSBDNTA0LjEwMjcyMiwyNzYuMTY3NTcyIDUwNC45NDA5NDgsMjc4LjIxMTA5MCA1MDQuOTQzMjY4LDI4MC4yNTU1MjQgQzUwNS4wMTI4NDgsMzQxLjc0MjI0OSA1MDQuOTY5MTQ3LDQwMy4yMjkwNjUgNTA1LjAzMDc5Miw0NjQuNzE1NzkwIEM1MDUuMDQwODAyLDQ3NC42ODY0OTMgNDk2LjExNzQ2Miw0ODMuOTUzMTg2IDQ4NS43Nzc5MjQsNDgzLjk2NTI3MSBDNDI0LjYyNDQ1MSw0ODQuMDM2ODk2IDM2My40NzA5MTcsNDg0LjAwMzIzNSAzMDIuMzE3MzgzLDQ4My45OTY3MzUgQzI5NS41ODc3NjksNDgzLjk5NjAzMyAyOTMuMDAxMjUxLDQ4MS4zMDE2MDUgMjkzLjAwMDkxNiw0NzQuMzM4NTYyIEMyOTIuOTk3ODY0LDQxMy4zNTE2NTQgMjkzLjIwOTYyNSwzNTIuMzYzMzEyIDI5Mi43ODA3MDEsMjkxLjM3OTM5NSBDMjkyLjcxMzUzMSwyODEuODI4MDk0IDMwMy4yMTMwNDMsMjcwLjgyNDE1OCAzMTMuNDc4MjcxLDI3MC44OTQzMTggQzM1MS45NjgyMDEsMjcxLjE1NzQ0MCAzOTAuNDYwOTk5LDI3MC45OTk3ODYgNDI4Ljk1MjcyOCwyNzAuOTk5Nzg2IEM0NTEuMTE0NjI0LDI3MC45OTk3ODYgNDczLjI3NzI4MywyNzAuOTE3NDgwIDQ5NS40Mzc0NjksMjcxLjExMjE1MiBDNDk3Ljk3NzAyMCwyNzEuMTM0NDkxIDUwMC41MDI5MzAsMjcyLjcwNDM3NiA1MDMuMzQ0NjY2LDI3My44NDAxNDkgWiI+PC9wYXRoPjwvc3ZnPgo=&logoColor=white" alt="Website" /></a>
|
||
<a href="https://cal.com/obscura/quick-chat"><img src="https://img.shields.io/badge/Book_a_Demo-1a1a1a?style=for-the-badge&logo=googlecalendar&logoColor=white" alt="Book a demo" /></a>
|
||
<a href="https://github.com/h4ckf0r0day/obscura/releases"><img src="https://img.shields.io/badge/Releases-1a1a1a?style=for-the-badge&logo=github&logoColor=white" alt="Releases" /></a>
|
||
</p>
|
||
<p align="center">
|
||
<strong>The open-source headless browser for AI agents and web scraping.</strong><br>
|
||
Lightweight, stealthy, and built in Rust.
|
||
</p>
|
||
<h3 align="center">Native rendering is here. No Chromium required. 🎉 </h3>
|
||
<p align="center">
|
||
Capture screenshots, screencast live pages, and export PDFs directly with Obscura.
|
||
</p>
|
||
|
||
---
|
||
|
||
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
|
||
|
||
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 →](https://tally.so/r/gDWzdD)**
|
||
<br>
|
||
**[📅 Book a demo →](https://cal.com/obscura/quick-chat)**
|
||
|
||
## Sponsors
|
||
|
||
**Obscura** is supported by sponsors who help keep development independent.
|
||
|
||
Want to sponsor? Email [hello@obscura.sh](mailto:hello@obscura.sh).
|
||
|
||
<table>
|
||
<tr>
|
||
<td width="200" align="center" valign="middle">
|
||
<a href="https://go.nodemaven.com/obscura" target="_blank">
|
||
<img alt="NodeMaven" src="assets/sponsors/nodemaven.svg" width="180"/>
|
||
</a>
|
||
</td>
|
||
<td valign="middle">
|
||
<a href="https://go.nodemaven.com/obscuraread"><b>NodeMaven</b></a> — the most reliable proxy provider with the highest quality IPs on the market. Built for automation, web scraping, SEO research, and social media management.<br><br>
|
||
<b>99.9% uptime<br>
|
||
Sticky sessions up to 7 days<br>
|
||
IP filtering on every proxy<br>
|
||
No KYC required<br>
|
||
Cashback on traffic — earn up to 10% back<br><br></b>
|
||
🎁 Use code <b>OBSCURA35</b> for 35% off Mobile & Residential, or <b>OBSCURA40</b> for 40% off ISP (Static) proxies.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td width="200" align="center" valign="middle">
|
||
<a href="https://proxyempire.io/?ref=obscura&utm_source=obscuragithub" target="_blank">
|
||
<img alt="ProxyEmpire" src="assets/sponsors/proxyempire.png" width="180"/>
|
||
</a>
|
||
</td>
|
||
<td valign="middle">
|
||
🚀 <b>Obscura × ProxyEmpire</b><br>
|
||
Using Obscura for AI agents, browser automation, or web scraping? Power it with reliable residential and mobile proxies from <a href="https://proxyempire.io/?ref=obscura&utm_source=obscuragithub"><b>ProxyEmpire</b></a>.<br><br>
|
||
<b>🌍 30M+ residential IPs in 170+ countries<br>
|
||
📱 4G/5G mobile proxies<br>
|
||
🔄 Rotating & sticky sessions<br>
|
||
🎯 City, region & ISP targeting<br>
|
||
🔐 HTTP, HTTPS & SOCKS5 support<br><br>
|
||
🎁 Use code <b>OBSCURA35</b> for a <b>35% recurring discount</b>.<br><br></b>
|
||
Better proxies. Fewer blocks. More scalable automation.
|
||
</td>
|
||
</tr>
|
||
<td width="200" align="center" valign="middle">
|
||
<a href="https://9proxy.com/?utm_source=Github&utm_campaign=obscura" target="_blank">
|
||
<img alt="9Proxy" src="assets/sponsors/9proxy.png" width="180"/>
|
||
</a>
|
||
</td>
|
||
<td valign="middle">
|
||
<a href="https://9proxy.com/?utm_source=Github&utm_campaign=obscura"><b>9Proxy</b></a> provides residential proxies from
|
||
just $0.018/IP or $0.68/GB. 20M+ IPs across 90+ countries. Sticky or rotating sessions, managed from desktop or mobile app.
|
||
</td>
|
||
</tr>
|
||
<td width="200" align="center" valign="middle">
|
||
<a href="https://www.thordata.com/?ls=dob&lk=dob" target="_blank">
|
||
<img alt="Thordata" src="/assets/sponsors/thordatalogo.png" width="180"/>
|
||
</a>
|
||
</td>
|
||
<td valign="middle">
|
||
🚀 <b>Obscura × Thordata</b><br>
|
||
Need more stable proxies for automation, public web scraping, SEO, or ad verification? Power your workflow with <a href="https://www.thordata.com/?ls=dob&lk=dob"><b>Thordata</b></a>.<br><br>
|
||
<b>🌍 Residential Proxies: 100M+ real residential IPs in 190+ countries<br>
|
||
♾️ Unlimited Proxies: for heavy traffic and high concurrency<br>
|
||
✨ Recently upgraded residential IP pool<br>
|
||
✨ Unlimited Concurrent Sessions<br>
|
||
🔁 Rotating & Sticky Sessions<br>
|
||
📍 Flexible GEO targeting<br>
|
||
⚡ Stable HTTP(S) connections<br><br>
|
||
🎁 Use code <b>obscura</b> for <b>10% off</b>.<br><br></b>
|
||
Get started with a 3-day free trial and test Thordata with your own workflow.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
## Install
|
||
|
||
### Download
|
||
|
||
Grab the latest binary from [Releases](https://github.com/h4ckf0r0day/obscura/releases):
|
||
|
||
```bash
|
||
# 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
|
||
|
||
# Arch Linux (AUR)
|
||
yay -S obscura-browser
|
||
|
||
# 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
|
||
|
||
```bash
|
||
docker run -d --name obscura -p 127.0.0.1:9222:9222 h4ckf0r0day/obscura
|
||
```
|
||
|
||
Image on [Docker Hub](https://hub.docker.com/r/h4ckf0r0day/obscura). Multi-stage build on `distroless/cc`, no shell, no package manager, ~57 MB compressed.
|
||
|
||
### Build from source
|
||
|
||
```bash
|
||
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](https://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:
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
# 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
|
||
```
|
||
|
||
## 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](docs/Use-with-Puppeteer.md),
|
||
[Playwright](docs/Use-with-Playwright.md), and
|
||
[MCP](docs/Use-the-MCP-server.md) guides cover their capture APIs and limits.
|
||
|
||
### Start the CDP server
|
||
|
||
```bash
|
||
obscura serve --port 9222
|
||
|
||
# With stealth mode (anti-detection + tracker blocking)
|
||
obscura serve --port 9222 --stealth
|
||
```
|
||
|
||
### Scrape in parallel
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
npm install puppeteer-core
|
||
```
|
||
|
||
```javascript
|
||
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
|
||
|
||
```bash
|
||
npm install playwright-core
|
||
```
|
||
|
||
```javascript
|
||
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
|
||
|
||
```javascript
|
||
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:
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
OBSCURA_SCRIPT_DEADLINE_MS=60000 obscura serve --port 9222
|
||
```
|
||
|
||
### `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`, `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:
|
||
|
||
```bash
|
||
obscura mcp
|
||
```
|
||
|
||
**HTTP** — for clients that connect over the network:
|
||
|
||
```bash
|
||
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
|
||
|
||
```json
|
||
{
|
||
"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](https://github.com/SGavrl/hermes-plugin-obscura)**: run [Hermes](https://github.com/NousResearch/hermes-agent) 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
|
||
|
||
---
|