Obscura Headless Browser

repository·main·Indexed 12 days ago

https://github.com/h4ckf0r0day/obscura

A high-performance, Rust-based headless browser engine designed for AI agents and web scraping. It serves as a lightweight, stealthy alternative to Chromium, compatible with Puppeteer and Playwright via the Chrome DevTools Protocol (CDP). Features include a native Rust API (v0.1.0), built-in anti-fingerprinting stealth mode, and a Model Context Protocol (MCP) server for AI agent integration.

Tokens
84K
Snippets
310
Records
398
Agent score
94%

What's inside Obscura

  1. Overview of Obscura

    main

    Obscura is a lightweight, headless browser engine written in Rust, specifically designed for web scraping and AI agent automation. It executes real JavaScript via the V8 engine and supports the Chrome DevTools Protocol (CDP).

    Key features include:

    • Drop-in Replacement: Works with Puppeteer and Playwright.
    • Native Rendering: Can capture screenshots, screencast live pages, and export PDFs without requiring Chromium.
    • High Performance: Optimized for automation at scale with significantly lower memory usage and faster startup times compared to headless Chrome.
  2. What is Obscura?

    main
    Obscura is an open-source headless browser engine written in Rust. It uses the V8 engine to execute JavaScript and implements the Chrome DevTools Protocol (CDP). It is designed to be a high-performance, low-resource drop-in replacement for headless Chrome when using automation frameworks like Puppeteer or Playwright.
  3. Understand the Obscura workspace structure

    main

    Obscura is composed of nine specialized crates, each representing a specific layer of the browser stack. Developers should use these crates based on their required level of abstraction:

    • obscura: The primary embeddable Rust library API (provides Browser, Page, Element, and CookieStore).
    • obscura-browser: Handles page types, navigation, and lifecycle events.
    • obscura-cdp: A Chrome DevTools Protocol server providing WebSocket support and domain handlers.
    • obscura-js: The V8 runtime (via deno_core) including bootstrap.js and Rust ops.
    • obscura-dom: The DOM tree implementation.
    • obscura-net: HTTP client, stealth client, cookie jar, robots cache, and tracker blocklist.
    • obscura-render: Handles CSS cascade, layout (via Taffy), text shaping, and CPU paint.
    • obscura-mcp: Model Context Protocol server.
    • obscura-cli: The CLI entry point providing fetch, serve, scrape, and mcp commands.
    • obscura-browser & obscura-cdp: Work together to map screenshots and screencasts to CDP.
  4. Best practices for extending Obscura

    main

    When extending Obscura, follow these guidelines to ensure compatibility and performance:

    • Keep JS shims thin: The JavaScript shim should only handle input normalization and calling the underlying op. All side effects and heavy logic must reside in the Rust ops.
    • Handle Asynchrony: Use Promise.resolve in your JS shims to wrap results from synchronous Rust ops, allowing them to match the expected asynchronous shape of standard Web APIs.
    • Maintain Spec Fidelity: Ensure Web API names and parameter shapes match official specifications, as Puppeteer and Playwright wrappers rely on these exact signatures.
    • DOM Mutations: Do not create new ops for DOM changes; instead, use the existing op_dom.
    • Event Firing: For APIs that require firing events across handlers (like WebSocket or IntersectionObserver), use the _makeListenerBox helper available in bootstrap.js.
  5. Obscura Build Types: Standard vs Stealth

    main

    Obscura provides different build types depending on your requirements:

    • Release builds: Support core rendering and stealth features including screenshots, scroll-aware layout, activity-driven CDP screencasting, and raster PDF export.
    • Stealth builds: Retain all release build capabilities but add wreq/BoringSSL transport and enhanced browser-identity protections for bypassing anti-bot measures.
  6. Monitor requests and responses with passive callbacks

    main

    Use on_request(cb) and on_response(cb) to observe network activity without blocking it. These callbacks are non-blocking and scoped to the page that registered them. on_response is particularly useful for capturing JSON payloads from SPAs.

    Note: resource_type reports Fetch for both JS-initiated fetch() and XHR requests.

    use obscura::{Browser, ResourceType};
    use std::sync::Arc;
    
    let browser = Browser::new()?;
    let mut page = browser.new_page().await?;
    
    page.on_response(Arc::new(|info, resp| {
        if info.resource_type == ResourceType::Fetch {
            println!("{} -> {} bytes", info.url, resp.body.len());
        }
    }));
    
    page.goto("https://example.com").await?;
    page.settle(2000).await; // let in-page fetch() calls resolve
  7. When is session state written to disk?

    main

    Obscura writes state to the storage directory in the following scenarios:

    1. Clean process exit: When receiving SIGTERM or via Ctrl-C.
    2. Navigation completion: After every Page.navigate CDP command completes.
    3. Manual CDP commands: When using Network.setCookie or Network.deleteCookies via the Chrome DevTools Protocol.
  8. Markdown conversion details: what is included and stripped

    main

    When using --dump markdown, Obscura performs a structural conversion of the rendered DOM.

    Included elements:

    • Headings (<h1> through <h6>)
    • Paragraphs and line breaks
    • Text formatting (Bold, italic, code spans)
    • Links (preserving href)
    • Images (preserving src and alt)
    • Lists (ordered and unordered)
    • Block quotes
    • Code blocks (<pre>, <code>)
    • Tables

    Stripped elements:

    • <script>, <style>, and <noscript> tags
    • Inline styles
    • ARIA attributes
    • Tracking pixels and beacons
  9. Configure Browser Profiles, Timezone, and Geolocation

    main

    Obscura uses built-in browser profiles (Windows/macOS Chrome mixes) to ensure navigator.platform, userAgentData, and WebGL/GPU renderers are internally consistent.

    Profile Rotation

    By default, a single stable profile is used. To change this, use environment variables:

    • OBSCURA_PROFILE=<index>: Pin a specific profile by its index.
    • OBSCURA_ROTATE_PROFILE=<count>: Randomly select a profile per browser context.

    Timezone and Geolocation

    To avoid detection, ensure your timezone and geolocation match your proxy's region:

    • OBSCURA_TIMEZONE=<region>: Sets the process zone (e.g., America/New_York). This affects Date and Intl.DateTimeFormat.
    • OBSCURA_GEOLOCATION="lat,lon": Sets navigator.geolocation coordinates.

    Warning: Mismatched identities (e.g., a macOS profile with a Windows-based timezone or a mismatched proxy IP) can act as a fingerprinting signal.

    # Pin a specific profile
    OBSCURA_PROFILE=2 obscura serve
    
    # Randomize profile per context
    OBSCURA_ROTATE_PROFILE=1 obscura serve
    
    # Set timezone
    OBSCURA_TIMEZONE=America/New_York obscura serve
    
    # Set geolocation
    OBSCURA_GEOLOCATION="40.7128,-74.0060" obscura serve
  10. Handle multiple pages and V8 isolate limitations

    main

    You can create multiple pages within a single context. Note: All pages in a context share one V8 isolate. This means CPU-bound JavaScript execution on one page will block execution on all other pages in that context.

    const page1 = await context.newPage();
    const page2 = await context.newPage();
    
    await Promise.all([
      page1.goto('https://a.example.com'),
      page2.goto('https://b.example.com'),
    ]);
  11. Secure the Obscura CDP server

    main

    The Obscura CDP server has no built-in authentication. Anyone who can reach the port can control the browser.

    Security Recommendations:

    1. Bind to localhost: Bind to 127.0.0.1 (the default) and use SSH tunneling for remote access.
    2. Reverse Proxy: Place Obscura behind a reverse proxy (like Nginx or Caddy) that enforces authentication.
    3. Network Isolation: Use Docker networks to isolate the service.

    WARNING: Never bind to 0.0.0.0 on a public IP without implementing one of the above protections.

  12. Enable Stealth Mode for anti-detection

    main

    Stealth mode provides anti-fingerprinting and tracker blocking. It must be enabled at runtime using the --stealth flag (and requires a build with the stealth feature).

    Capabilities:

    • Anti-fingerprinting: Randomizes GPU, screen, canvas, audio, and battery fingerprints; provides realistic navigator.userAgentData; sets event.isTrusted = true; masks native functions; and sets navigator.webdriver = undefined.
    • Tracker Blocking: Blocks ~3,520 domains including analytics, ads, and telemetry scripts.

    Enabling stealth does not disable rendering, screenshots, PDF export, or CDP/MCP functionality.