browsing 0.1.7

Browser automation: navigate, click, extract, screenshot. Standalone browser control via CDP.
Documentation

Browsing

Rust-native browser automation β€” 20+ CDP managers, MCP server, zero AI deps

Data Point
Binary size ~2–5 MB release (LTO + strip + opt-level = "z")
Test coverage 360+ tests, all passing
CDP domains covered Page, Network, Fetch, Emulation, Tracing, Profiler, CSS, DOM, Runtime, Target, ServiceWorker, Input, Browser, Console
Zero LLM dependencies, Box::leak, recursive async retry

πŸ—ΊοΈ Where Does Browsing Fit?

Tool Language Best For Footprint CDP Access
Selenium Java/Python Legacy testing Heavy WebDriver Indirect
Puppeteer JavaScript Chrome scripts ~50 MB Node Thin wrapper
Playwright JS/Python Cross-browser tests ~200 MB Batteries-included, opinionated
browser-use Python LLM agents Python + AI deps Hidden behind agent loop
Browsing Rust Fast, embeddable automation ~2–5 MB Raw + 20 typed managers

Browsing gives you Playwright's feature coverage (dialogs, file choosers, device presets, permissions, HAR, tracing, touch, workers, service workers) in a Rust-native, zero-bloat package with an MCP server for LLM integration.

🎯 Key Features

πŸ—οΈ Architecture

  • Trait-based β€” BrowserClient, DOMProcessor, ActionHandler for mocking and backends
  • 20+ typed managers β€” Each wraps a CDP domain: Dialog, FileChooser, Permissions, HAR, Interceptor, Performance, Coverage, Tracing, Touch, Worker, ServiceWorker, Viewport (with device presets, color scheme, vision deficiency, locale), Auth, Console, Cookies, PDF
  • Headless by default β€” 17+ lightweight Chrome flags; BrowserProfile::default() runs --headless=new
  • Raw CDP access β€” Browser::raw_cdp_command() for anything the managers don't cover
  • Zero AI dependencies β€” Pure Rust, no LLM lock-in

πŸ“¦ Installation

As a Library

[dependencies]
browsing = "0.1"
tokio = { version = "1.40", features = ["full"] }

As a CLI Tool

cargo install --path . --bin browsing

As an MCP Server

cargo build --release --bin browsing-mcp

πŸš€ Quick Start

1️⃣ CLI Usage

# Run a browser automation task (headless by default)
browsing run "Navigate to example.com and extract content" --url https://news.ycombinator.com

# Run with visible browser
browsing run "Navigate to example.com and extract content" --url https://news.ycombinator.com --no-headless

# Launch a headless browser and get CDP URL (headless by default)
browsing launch

# Launch with visible browser
browsing launch --no-headless

# Connect to existing browser
browsing connect ws://localhost:9222/devtools/browser/abc123

πŸ“– Full CLI Documentation

2️⃣ MCP Server Usage

Configure in Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "browsing": {
      "command": "/path/to/browsing/target/release/browsing-mcp",
      "env": {
        "BROWSER_USE_HEADLESS": "true"
      }
    }
  }
}

Then ask Claude:

"Navigate to rust-lang.org, get the links, follow the second link, and screenshot the main content area"

πŸ“– Full MCP Documentation

3️⃣ Library Usage

use anyhow::Result;
use browsing::Browser;
use browsing::browser::BrowserProfile;

#[tokio::main]
async fn main() -> Result<()> {
    browsing::init();

    let mut browser = Browser::new(BrowserProfile::default());
    browser.start().await?;

    browser.navigate("https://example.com").await?;

    let title = browser.get_current_page_title().await?;
    println!("Title: {}", title);

    let _ = browser.stop().await;
    Ok(())
}

πŸ“– Full Library Documentation

Browser Launch Options

use browsing::{Browser, BrowserProfile};

// Option 1: Auto-launch headless browser (default)
let profile = BrowserProfile::default(); // headless = true by default
let browser = Browser::new(profile);

// Option 2: Launch with visible browser
let profile = BrowserProfile::default().with_headless(false);
let browser = Browser::new(profile);

// Option 3: Connect to existing browser
let browser = Browser::new(BrowserProfile::default())
    .with_cdp_url("http://localhost:9222".to_string());

// Option 4: Custom browser executable
use browsing::browser::launcher::BrowserLauncher;
let launcher = BrowserLauncher::new(profile)
    .with_executable_path(std::path::PathBuf::from("/path/to/chrome"));

πŸ“š Quick Example

use browsing::browser::{Browser, BrowserProfile};

#[tokio::main]
async fn main() -> browsing::Result<()> {
    let mut browser = Browser::new(BrowserProfile::default());
    browser.start().await?;

    browser.navigate("https://example.com").await?;

    // Use any manager
    let viewport = browser.viewport_manager()?;
    viewport.preset_device(&browsing::DevicePreset::iphone_15()).await?;

    // Or send raw CDP
    let result = browser
        .raw_cdp_command("Runtime.evaluate", json!({"expression": "1+1"}))
        .await?;

    Ok(())
}

More examples: See examples/ β€” device emulation, dialog handling, HAR capture, permissions, touch gestures, raw CDP access.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Browser  β”‚ DOMProcessor β”‚        Tools           β”‚
β”‚ (trait)  β”‚   (trait)    β”‚                        β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚            β”‚                       β”‚
β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”  β”Œβ”€β”€β”€β–Όβ”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
β”‚ Browser β”‚  β”‚ DomSvc β”‚       β”‚   Handlers     β”‚
β”‚ Session β”‚  β”‚        β”‚       β”‚ (nav, click,   β”‚
β”‚ + 20+   β”‚  β”‚ CDP    β”‚       β”‚  tabs, content)β”‚
β”‚ managersβ”‚  β”‚ HTML   β”‚       β”‚                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

See docs/ARCHITECTURE.md for full design.

πŸ“ Project Structure

browsing/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ agent/              # Agent view types (used by tools layer)
β”‚   β”‚   β”œβ”€β”€ views.rs        # Data types
β”‚   β”‚   └── memory.rs       # Session memory types
β”‚   β”œβ”€β”€ browser/            # Browser management
β”‚   β”‚   β”œβ”€β”€ session.rs      # Browser session (BrowserClient impl)
β”‚   β”‚   β”œβ”€β”€ tab_manager.rs  # Tab operations
β”‚   β”‚   β”œβ”€β”€ navigation.rs   # Navigation operations
β”‚   β”‚   β”œβ”€β”€ screenshot.rs   # Screenshot operations
β”‚   β”‚   β”œβ”€β”€ cdp.rs          # CDP WebSocket client
β”‚   β”‚   β”œβ”€β”€ launcher.rs     # Browser launcher
β”‚   β”‚   β”œβ”€β”€ profile.rs      # Browser configuration
β”‚   β”‚   β”œβ”€β”€ auth.rs         # HTTP auth / proxy / extra headers
β”‚   β”‚   β”œβ”€β”€ console.rs      # Console log capture
β”‚   β”‚   β”œβ”€β”€ cookies.rs      # Cookie management
β”‚   β”‚   β”œβ”€β”€ coverage.rs     # JS/CSS coverage tracking
β”‚   β”‚   β”œβ”€β”€ dialog.rs       # Dialog handling (alert/confirm/prompt)
β”‚   β”‚   β”œβ”€β”€ download.rs     # Download monitoring
β”‚   β”‚   β”œβ”€β”€ filechooser.rs  # File chooser interception
β”‚   β”‚   β”œβ”€β”€ har.rs          # Network traffic HAR capture
β”‚   β”‚   β”œβ”€β”€ interceptor.rs  # Network request interception
β”‚   β”‚   β”œβ”€β”€ pdf.rs          # PDF export
β”‚   β”‚   β”œβ”€β”€ performance.rs  # Performance metrics
β”‚   β”‚   β”œβ”€β”€ permissions.rs  # Browser permissions API
β”‚   β”‚   β”œβ”€β”€ serviceworker.rs # Service worker management
β”‚   β”‚   β”œβ”€β”€ touch.rs        # Touch gesture emulation
β”‚   β”‚   β”œβ”€β”€ tracing.rs      # Chrome tracing / CPU profiling
β”‚   β”‚   β”œβ”€β”€ viewport.rs     # Viewport / device emulation
β”‚   β”‚   β”œβ”€β”€ worker.rs       # Web worker management
β”‚   β”‚   └── views.rs        # Data types
β”‚   β”œβ”€β”€ dom/                # DOM processing
β”‚   β”‚   β”œβ”€β”€ processor.rs    # DOMProcessor trait impl
β”‚   β”‚   β”œβ”€β”€ serializer.rs   # Text serialization
β”‚   β”‚   β”œβ”€β”€ tree_builder.rs # DOM tree construction
β”‚   β”‚   β”œβ”€β”€ cdp_client.rs   # CDP wrapper for DOM
β”‚   β”‚   └── html_converter.rs # HTML to markdown
β”‚   β”œβ”€β”€ tools/              # Action system
β”‚   β”‚   β”œβ”€β”€ service.rs      # Tools registry
β”‚   β”‚   β”œβ”€β”€ handlers/       # Action handlers
β”‚   β”‚   β”‚   β”œβ”€β”€ navigation.rs
β”‚   β”‚   β”‚   β”œβ”€β”€ interaction.rs
β”‚   β”‚   β”‚   β”œβ”€β”€ tabs.rs
β”‚   β”‚   β”‚   β”œβ”€β”€ content.rs
β”‚   β”‚   β”‚   └── advanced.rs
β”‚   β”‚   └── params.rs       # Parameter extraction
β”‚   β”œβ”€β”€ traits/             # Core trait abstractions
β”‚   β”‚   β”œβ”€β”€ browser_client.rs  # BrowserClient trait
β”‚   β”‚   └── dom_processor.rs   # DOMProcessor trait
β”‚   β”œβ”€β”€ actor/              # Low-level interactions
β”‚   β”‚   β”œβ”€β”€ page.rs         # Page operations
β”‚   β”‚   β”œβ”€β”€ element.rs      # Element operations
β”‚   β”‚   β”œβ”€β”€ mouse.rs        # Mouse interactions
β”‚   β”‚   └── keyboard.rs     # Keyboard input
β”‚   β”œβ”€β”€ config.rs           # Configuration
β”‚   β”œβ”€β”€ error.rs            # Error types
β”‚   β”œβ”€β”€ logging.rs          # Logging setup
β”‚   β”œβ”€β”€ metrics.rs          # Metrics collection
β”‚   β”œβ”€β”€ utils.rs            # Utilities
β”‚   └── views.rs            # Shared data types
└── Cargo.toml

πŸ§ͺ Testing

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_browser_navigation

# Run integration tests only
cargo test --test integration

Test Coverage

360+ tests, all passing, 0 ignored. Every manager has unit tests. Mock implementations for deterministic testing without real browsers.

Module Tests Focus
Actor 29 Page, Element, Mouse, Keyboard
Browser 154 All 20+ managers + lifecycle
Tools 67 Action handlers + registry
Traits 27 BrowserClient, DOMProcessor mocks
Utils 52 URL extraction, signals
Integration 115+ End-to-end workflows

⚠️ Data Retention

Browser data is never deleted to prevent accidental loss of real profiles. Temp directories in /tmp/browser-use-* are left for inspection; clean them manually.

rm -rf /tmp/browser-use-*

πŸ”§ Configuration

use browsing::BrowserProfile;

let profile = BrowserProfile::default();          // headless, lightweight flags
let profile = BrowserProfile::default().with_headless(false); // visible
let profile = BrowserProfile {
    user_data_dir: Some("/path/to/profile".into()),
    ..Default::default()
};

πŸ“– API Documentation

Generate and view API docs:

cargo doc --open