1 line
759 KiB
JSON
1 line
759 KiB
JSON
{"repo": "billy-enrizky/openbrowser-ai", "files": {"README.md": {"168d43e3aa9563609106f0bb96aa36b65f2fca5f": {"t": 1785746437.3634627, "n": 30712, "h": "d6f19d2cc1cf0874", "c": "<p align=\"center\">\n <img src=\"docs/logo/icon.svg\" alt=\"OpenBrowser\" width=\"120\" height=\"120\" />\n</p>\n\n<h1 align=\"center\">OpenBrowser</h1>\n\n<p align=\"center\"><strong>AI browser automation, powered by code.</strong></p>\n\n---\n\n**Cloud dashboard for saved cookies and scheduled tasks is available in the hosted version. Join the waitlist for early access: https://openbrowser.me** :\n\nhttps://github.com/user-attachments/assets/b17f97f3-f9f8-4707-8e39-abbbbe1a693b\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n**OpenBrowserAI Automatic Form Filling:**\n\nhttps://github.com/user-attachments/assets/16f7ef1a-beb1-45e2-a733-9592536e0ef7\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Research: Reinforcement Fine-Tuning for Browser Agents](#research-reinforcement-fine-tuning-for-browser-agents)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **15 LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure, Ollama, DeepSeek, Cerebras, OpenRouter, OCI, and more\n- **MCP Server** - Model Context Protocol for Claude Desktop, Claude Code, Codex, OpenCode, and other AI assistants, with reusable saved login sessions\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash, saved login state, and 10-minute auto-shutdown\n- **Workflow Recording** - Record, replay, and export browser sessions to Jupyter notebooks or API crawler code\n- **Video Recording** - Record browser sessions as video files with ffmpeg\n- **Cloud Platform** - Full-stack web UI with real-time VNC streaming, saved logins (KMS-encrypted), scheduled workflows (EventBridge + SQS), and email notifications (SES)\n- **Plugin System** - Claude Code plugin with 6 guided skills (web scraping, form filling, e2e testing, page analysis, accessibility audit, file download)\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\nBy default, MCP sessions reuse `~/.config/openbrowser/profiles/default` and save cookies plus origin storage to `~/.config/openbrowser/profiles/default/storage_state.json`, so logins survive MCP restarts. OpenBrowser also auto-cleans disposable Chromium caches in managed profiles, which keeps disk usage down without deleting cookies or login state.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `true` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_USER_DATA_DIR` | Chrome profile directory for persistent MCP sessions | `~/.config/openbrowser/profiles/default` |\n| `OPENBROWSER_STORAGE_STATE` | JSON file used to save and restore cookies plus localStorage | `~/.config/openbrowser/profiles/default/storage_state.json` |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\nThe CLI daemon stores its browser profile in `~/.config/openbrowser/profiles/daemon` and also writes `storage_state.json` there, so cookies and login sessions survive daemon restarts. One-shot `-p` runs use `~/.config/openbrowser/profiles/cli` with the same storage-state behavior. Managed profiles automatically clear disposable browser caches on startup and shutdown while keeping auth state.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Research: Reinforcement Fine-Tuning for Browser Agents\n\nBeyond the framework, we conducted two independent research studies on improving browser agents through reinforcement learning, both using the [FormFactory benchmark](https://arxiv.org/abs/2506.01520) (1,250 form-filling tasks across 8 domains) and OpenBrowser's browser execution environment.\n\n### Study 1: Browser-in-the-Loop (Autoregressive RL)\n\nWe investigated whether reinforcement learning can improve a language model's ability to fill web forms beyond what supervised learning achieves.\n\n- **Method**: Two-phase pipeline -- SFT on Qwen3-8B with QLoRA (992 demonstrations), then online GRPO with live browser execution rewards (composite: 40% submission success + 40% field accuracy + 20% execution completeness)\n- **Result**: GRPO achieves 9.1% higher average reward than SFT alone on held-out validation (p=0.007, Wilcoxon signed-rank test). Improvement comes specifically from better form submission, not field filling.\n- **Key finding**: SFT is a prerequisite -- without it, the base model generates unstructured text and earns zero reward across all attempts.\n- **Paper**: [Browser-in-the-Loop: Reinforcement Fine-Tuning LLM Agents for Web Form Filling](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [Qwen3-8B-FormFactory-SFT-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-SFT-LoRA), [Qwen3-8B-FormFactory-GRPO-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-GRPO-LoRA)\n\n### Study 2: Diffusion Language Models for Web Action Planning\n\nWe investigated whether diffusion language models -- which generate text by iteratively denoising an entire sequence in parallel rather than left-to-right -- can learn web action planning.\n\n- **Models tested**: ReFusion 8B (masked diffusion with causal LM backbone) and FS-DFM 1.3B (pure discrete flow matching)\n- **Result**: After SFT, diffusion models solve 60-69% of tasks vs. 100% for the AR baseline. Token-level RL is universally fragile (2/16 comparisons improve, both insignificant). Sequence-level RL succeeds: MDPO pushes ReFusion to 91.9% (+31.4pp) and ESPO pushes FS-DFM to 87.1% (+18.6pp).\n- **Key finding**: The appropriate RL formulation is architecture-dependent. ELBO-based optimization (ESPO) produces concentrated distributions across architectures, while per-step trajectory methods produce multimodal distributions.\n- **Paper**: [Concentrate or Collapse: When Reinforcement Learning Meets Diffusion Language Models for Web Planning](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [10 trained models on HuggingFace](https://huggingface.co/billyenrizky) including ReFusion-8B-MDPO, FS-DFM-1.3B-ESPO-mu8, and more\n\n### Reproducing RL Experiments\n\nAll training code is in `infra/training/`. Training runs on a single NVIDIA A10G GPU (24GB VRAM) via Anyscale.\n\n```bash\n# Study 1: Autoregressive RL (Qwen3-8B)\n# SFT phase -- QLoRA fine-tuning on 992 FormFactory demonstrations (2-4 hours)\npython infra/training/finetuning/sft_trainer.py\n\n# Online GRPO phase -- browser-in-the-loop reward (4-8 hours per epoch)\n# Requires headless Chromium + FormFactory forms server\npython infra/training/shared/formfactory_server.py & # Start form server\npython infra/training/finetuning/online_grpo_trainer.py\n\n# Evaluate SFT and GRPO checkpoints on val/test splits\npython infra/training/finetuning/eval_sft.py\n\n# Study 2: Diffusion LM RL (ReFusion 8B, FS-DFM 1.3B)\n# SFT phase\npython infra/training/flow_matching/fsdfm_sft_trainer.py # FS-DFM SFT\npython infra/training/flow_matching/flow_sft_trainer.py # ReFusion SFT\n\n# Sequence-level RL (best results)\npython infra/training/flow_matching/espo_fsdfm_trainer.py # ESPO on FS-DFM\npython infra/training/flow_matching/espo_refusion_trainer.py # ESPO on ReFusion\npython infra/training/flow_matching/mdpo_fsdfm_trainer.py # MDPO on FS-DFM\npython infra/training/flow_matching/mdpo_refusion_trainer.py # MDPO on ReFusion\n\n# Submit jobs to Anyscale cloud\npython infra/training/anyscale/submit_job.py --config infra/training/anyscale/online_grpo_job.yaml\n\n# Push trained checkpoints to HuggingFace\npython infra/training/anyscale/push_checkpoints_to_hf.py\n\n# Serve trained model locally via vLLM or Ollama\npython infra/training/serving/serve_vllm.py\npython infra/training/serving/export_gguf.py # Export to GGUF for Ollama\n```\n\nReward function (in `infra/training/shared/reward_functions.py`): composite score = 0.4 * task completion + 0.4 * field accuracy + 0.2 * execution completeness. Online reward (`online_reward.py`) launches headless Chromium, executes the model's action plan, and computes the score from live browser state.\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "8ed3a32651c14d28c6d37e54abcb7ce94eedea33": {"t": 1785764208.5051534, "n": 30712, "h": "d6f19d2cc1cf0874", "c": "<p align=\"center\">\n <img src=\"docs/logo/icon.svg\" alt=\"OpenBrowser\" width=\"120\" height=\"120\" />\n</p>\n\n<h1 align=\"center\">OpenBrowser</h1>\n\n<p align=\"center\"><strong>AI browser automation, powered by code.</strong></p>\n\n---\n\n**Cloud dashboard for saved cookies and scheduled tasks is available in the hosted version. Join the waitlist for early access: https://openbrowser.me** :\n\nhttps://github.com/user-attachments/assets/b17f97f3-f9f8-4707-8e39-abbbbe1a693b\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n**OpenBrowserAI Automatic Form Filling:**\n\nhttps://github.com/user-attachments/assets/16f7ef1a-beb1-45e2-a733-9592536e0ef7\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Research: Reinforcement Fine-Tuning for Browser Agents](#research-reinforcement-fine-tuning-for-browser-agents)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **15 LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure, Ollama, DeepSeek, Cerebras, OpenRouter, OCI, and more\n- **MCP Server** - Model Context Protocol for Claude Desktop, Claude Code, Codex, OpenCode, and other AI assistants, with reusable saved login sessions\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash, saved login state, and 10-minute auto-shutdown\n- **Workflow Recording** - Record, replay, and export browser sessions to Jupyter notebooks or API crawler code\n- **Video Recording** - Record browser sessions as video files with ffmpeg\n- **Cloud Platform** - Full-stack web UI with real-time VNC streaming, saved logins (KMS-encrypted), scheduled workflows (EventBridge + SQS), and email notifications (SES)\n- **Plugin System** - Claude Code plugin with 6 guided skills (web scraping, form filling, e2e testing, page analysis, accessibility audit, file download)\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\nBy default, MCP sessions reuse `~/.config/openbrowser/profiles/default` and save cookies plus origin storage to `~/.config/openbrowser/profiles/default/storage_state.json`, so logins survive MCP restarts. OpenBrowser also auto-cleans disposable Chromium caches in managed profiles, which keeps disk usage down without deleting cookies or login state.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `true` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_USER_DATA_DIR` | Chrome profile directory for persistent MCP sessions | `~/.config/openbrowser/profiles/default` |\n| `OPENBROWSER_STORAGE_STATE` | JSON file used to save and restore cookies plus localStorage | `~/.config/openbrowser/profiles/default/storage_state.json` |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\nThe CLI daemon stores its browser profile in `~/.config/openbrowser/profiles/daemon` and also writes `storage_state.json` there, so cookies and login sessions survive daemon restarts. One-shot `-p` runs use `~/.config/openbrowser/profiles/cli` with the same storage-state behavior. Managed profiles automatically clear disposable browser caches on startup and shutdown while keeping auth state.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Research: Reinforcement Fine-Tuning for Browser Agents\n\nBeyond the framework, we conducted two independent research studies on improving browser agents through reinforcement learning, both using the [FormFactory benchmark](https://arxiv.org/abs/2506.01520) (1,250 form-filling tasks across 8 domains) and OpenBrowser's browser execution environment.\n\n### Study 1: Browser-in-the-Loop (Autoregressive RL)\n\nWe investigated whether reinforcement learning can improve a language model's ability to fill web forms beyond what supervised learning achieves.\n\n- **Method**: Two-phase pipeline -- SFT on Qwen3-8B with QLoRA (992 demonstrations), then online GRPO with live browser execution rewards (composite: 40% submission success + 40% field accuracy + 20% execution completeness)\n- **Result**: GRPO achieves 9.1% higher average reward than SFT alone on held-out validation (p=0.007, Wilcoxon signed-rank test). Improvement comes specifically from better form submission, not field filling.\n- **Key finding**: SFT is a prerequisite -- without it, the base model generates unstructured text and earns zero reward across all attempts.\n- **Paper**: [Browser-in-the-Loop: Reinforcement Fine-Tuning LLM Agents for Web Form Filling](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [Qwen3-8B-FormFactory-SFT-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-SFT-LoRA), [Qwen3-8B-FormFactory-GRPO-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-GRPO-LoRA)\n\n### Study 2: Diffusion Language Models for Web Action Planning\n\nWe investigated whether diffusion language models -- which generate text by iteratively denoising an entire sequence in parallel rather than left-to-right -- can learn web action planning.\n\n- **Models tested**: ReFusion 8B (masked diffusion with causal LM backbone) and FS-DFM 1.3B (pure discrete flow matching)\n- **Result**: After SFT, diffusion models solve 60-69% of tasks vs. 100% for the AR baseline. Token-level RL is universally fragile (2/16 comparisons improve, both insignificant). Sequence-level RL succeeds: MDPO pushes ReFusion to 91.9% (+31.4pp) and ESPO pushes FS-DFM to 87.1% (+18.6pp).\n- **Key finding**: The appropriate RL formulation is architecture-dependent. ELBO-based optimization (ESPO) produces concentrated distributions across architectures, while per-step trajectory methods produce multimodal distributions.\n- **Paper**: [Concentrate or Collapse: When Reinforcement Learning Meets Diffusion Language Models for Web Planning](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [10 trained models on HuggingFace](https://huggingface.co/billyenrizky) including ReFusion-8B-MDPO, FS-DFM-1.3B-ESPO-mu8, and more\n\n### Reproducing RL Experiments\n\nAll training code is in `infra/training/`. Training runs on a single NVIDIA A10G GPU (24GB VRAM) via Anyscale.\n\n```bash\n# Study 1: Autoregressive RL (Qwen3-8B)\n# SFT phase -- QLoRA fine-tuning on 992 FormFactory demonstrations (2-4 hours)\npython infra/training/finetuning/sft_trainer.py\n\n# Online GRPO phase -- browser-in-the-loop reward (4-8 hours per epoch)\n# Requires headless Chromium + FormFactory forms server\npython infra/training/shared/formfactory_server.py & # Start form server\npython infra/training/finetuning/online_grpo_trainer.py\n\n# Evaluate SFT and GRPO checkpoints on val/test splits\npython infra/training/finetuning/eval_sft.py\n\n# Study 2: Diffusion LM RL (ReFusion 8B, FS-DFM 1.3B)\n# SFT phase\npython infra/training/flow_matching/fsdfm_sft_trainer.py # FS-DFM SFT\npython infra/training/flow_matching/flow_sft_trainer.py # ReFusion SFT\n\n# Sequence-level RL (best results)\npython infra/training/flow_matching/espo_fsdfm_trainer.py # ESPO on FS-DFM\npython infra/training/flow_matching/espo_refusion_trainer.py # ESPO on ReFusion\npython infra/training/flow_matching/mdpo_fsdfm_trainer.py # MDPO on FS-DFM\npython infra/training/flow_matching/mdpo_refusion_trainer.py # MDPO on ReFusion\n\n# Submit jobs to Anyscale cloud\npython infra/training/anyscale/submit_job.py --config infra/training/anyscale/online_grpo_job.yaml\n\n# Push trained checkpoints to HuggingFace\npython infra/training/anyscale/push_checkpoints_to_hf.py\n\n# Serve trained model locally via vLLM or Ollama\npython infra/training/serving/serve_vllm.py\npython infra/training/serving/export_gguf.py # Export to GGUF for Ollama\n```\n\nReward function (in `infra/training/shared/reward_functions.py`): composite score = 0.4 * task completion + 0.4 * field accuracy + 0.2 * execution completeness. Online reward (`online_reward.py`) launches headless Chromium, executes the model's action plan, and computes the score from live browser state.\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "6b7aa819e0cfffc54ef7b8d82cebc2e23d4b8645": {"t": 1785764210.0811021, "n": 29065, "h": "c8c36f81e9b462af", "c": "<p align=\"center\">\n <img src=\"docs/logo/icon.svg\" alt=\"OpenBrowser\" width=\"120\" height=\"120\" />\n</p>\n\n<h1 align=\"center\">OpenBrowser</h1>\n\n<p align=\"center\"><strong>AI browser automation, powered by code.</strong></p>\n\n---\n\n**Saved Cookies and Scheduled Tasks is available in the cloud-hosted version. Join the waitlist for early access: https://openbrowser.me** :\n\nhttps://github.com/user-attachments/assets/b17f97f3-f9f8-4707-8e39-abbbbe1a693b\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n**OpenBrowserAI Automatic Form Filling:**\n\nhttps://github.com/user-attachments/assets/16f7ef1a-beb1-45e2-a733-9592536e0ef7\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Research: Reinforcement Fine-Tuning for Browser Agents](#research-reinforcement-fine-tuning-for-browser-agents)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Research: Reinforcement Fine-Tuning for Browser Agents\n\nBeyond the framework, we conducted two independent research studies on improving browser agents through reinforcement learning, both using the [FormFactory benchmark](https://arxiv.org/abs/2506.01520) (1,250 form-filling tasks across 8 domains) and OpenBrowser's browser execution environment.\n\n### Study 1: Browser-in-the-Loop (Autoregressive RL)\n\nWe investigated whether reinforcement learning can improve a language model's ability to fill web forms beyond what supervised learning achieves.\n\n- **Method**: Two-phase pipeline -- SFT on Qwen3-8B with QLoRA (992 demonstrations), then online GRPO with live browser execution rewards (composite: 40% submission success + 40% field accuracy + 20% execution completeness)\n- **Result**: GRPO achieves 9.1% higher average reward than SFT alone on held-out validation (p=0.007, Wilcoxon signed-rank test). Improvement comes specifically from better form submission, not field filling.\n- **Key finding**: SFT is a prerequisite -- without it, the base model generates unstructured text and earns zero reward across all attempts.\n- **Paper**: [Browser-in-the-Loop: Reinforcement Fine-Tuning LLM Agents for Web Form Filling](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [Qwen3-8B-FormFactory-SFT-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-SFT-LoRA), [Qwen3-8B-FormFactory-GRPO-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-GRPO-LoRA)\n\n### Study 2: Diffusion Language Models for Web Action Planning\n\nWe investigated whether diffusion language models -- which generate text by iteratively denoising an entire sequence in parallel rather than left-to-right -- can learn web action planning.\n\n- **Models tested**: ReFusion 8B (masked diffusion with causal LM backbone) and FS-DFM 1.3B (pure discrete flow matching)\n- **Result**: After SFT, diffusion models solve 60-69% of tasks vs. 100% for the AR baseline. Token-level RL is universally fragile (2/16 comparisons improve, both insignificant). Sequence-level RL succeeds: MDPO pushes ReFusion to 91.9% (+31.4pp) and ESPO pushes FS-DFM to 87.1% (+18.6pp).\n- **Key finding**: The appropriate RL formulation is architecture-dependent. ELBO-based optimization (ESPO) produces concentrated distributions across architectures, while per-step trajectory methods produce multimodal distributions.\n- **Paper**: [Concentrate or Collapse: When Reinforcement Learning Meets Diffusion Language Models for Web Planning](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [10 trained models on HuggingFace](https://huggingface.co/billyenrizky) including ReFusion-8B-MDPO, FS-DFM-1.3B-ESPO-mu8, and more\n\n### Reproducing RL Experiments\n\nAll training code is in `infra/training/`. Training runs on a single NVIDIA A10G GPU (24GB VRAM) via Anyscale.\n\n```bash\n# Study 1: Autoregressive RL (Qwen3-8B)\n# SFT phase -- QLoRA fine-tuning on 992 FormFactory demonstrations (2-4 hours)\npython infra/training/finetuning/sft_trainer.py\n\n# Online GRPO phase -- browser-in-the-loop reward (4-8 hours per epoch)\n# Requires headless Chromium + FormFactory forms server\npython infra/training/shared/formfactory_server.py & # Start form server\npython infra/training/finetuning/online_grpo_trainer.py\n\n# Evaluate SFT and GRPO checkpoints on val/test splits\npython infra/training/finetuning/eval_sft.py\n\n# Study 2: Diffusion LM RL (ReFusion 8B, FS-DFM 1.3B)\n# SFT phase\npython infra/training/flow_matching/fsdfm_sft_trainer.py # FS-DFM SFT\npython infra/training/flow_matching/flow_sft_trainer.py # ReFusion SFT\n\n# Sequence-level RL (best results)\npython infra/training/flow_matching/espo_fsdfm_trainer.py # ESPO on FS-DFM\npython infra/training/flow_matching/espo_refusion_trainer.py # ESPO on ReFusion\npython infra/training/flow_matching/mdpo_fsdfm_trainer.py # MDPO on FS-DFM\npython infra/training/flow_matching/mdpo_refusion_trainer.py # MDPO on ReFusion\n\n# Submit jobs to Anyscale cloud\npython infra/training/anyscale/submit_job.py --config infra/training/anyscale/online_grpo_job.yaml\n\n# Push trained checkpoints to HuggingFace\npython infra/training/anyscale/push_checkpoints_to_hf.py\n\n# Serve trained model locally via vLLM or Ollama\npython infra/training/serving/serve_vllm.py\npython infra/training/serving/export_gguf.py # Export to GGUF for Ollama\n```\n\nReward function (in `infra/training/shared/reward_functions.py`): composite score = 0.4 * task completion + 0.4 * field accuracy + 0.2 * execution completeness. Online reward (`online_reward.py`) launches headless Chromium, executes the model's action plan, and computes the score from live browser state.\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "b3ef4632a16ad7accb49df418a4195003ca14e18": {"t": 1785764216.4802198, "n": 29060, "h": "acf193ba96e600bb", "c": "<p align=\"center\">\n <img src=\"docs/logo/icon.svg\" alt=\"OpenBrowser\" width=\"120\" height=\"120\" />\n</p>\n\n<h1 align=\"center\">OpenBrowser</h1>\n\n<p align=\"center\"><strong>AI browser automation, powered by code.</strong></p>\n\n**Saved Cookies and Scheduled Tasks is available in the cloud-hosted version. Join the waitlist for early access: https://openbrowser.me** :\n\nhttps://github.com/user-attachments/assets/b17f97f3-f9f8-4707-8e39-abbbbe1a693b\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n**OpenBrowserAI Automatic Form Filling:**\n\nhttps://github.com/user-attachments/assets/16f7ef1a-beb1-45e2-a733-9592536e0ef7\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Research: Reinforcement Fine-Tuning for Browser Agents](#research-reinforcement-fine-tuning-for-browser-agents)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Research: Reinforcement Fine-Tuning for Browser Agents\n\nBeyond the framework, we conducted two independent research studies on improving browser agents through reinforcement learning, both using the [FormFactory benchmark](https://arxiv.org/abs/2506.01520) (1,250 form-filling tasks across 8 domains) and OpenBrowser's browser execution environment.\n\n### Study 1: Browser-in-the-Loop (Autoregressive RL)\n\nWe investigated whether reinforcement learning can improve a language model's ability to fill web forms beyond what supervised learning achieves.\n\n- **Method**: Two-phase pipeline -- SFT on Qwen3-8B with QLoRA (992 demonstrations), then online GRPO with live browser execution rewards (composite: 40% submission success + 40% field accuracy + 20% execution completeness)\n- **Result**: GRPO achieves 9.1% higher average reward than SFT alone on held-out validation (p=0.007, Wilcoxon signed-rank test). Improvement comes specifically from better form submission, not field filling.\n- **Key finding**: SFT is a prerequisite -- without it, the base model generates unstructured text and earns zero reward across all attempts.\n- **Paper**: [Browser-in-the-Loop: Reinforcement Fine-Tuning LLM Agents for Web Form Filling](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [Qwen3-8B-FormFactory-SFT-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-SFT-LoRA), [Qwen3-8B-FormFactory-GRPO-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-GRPO-LoRA)\n\n### Study 2: Diffusion Language Models for Web Action Planning\n\nWe investigated whether diffusion language models -- which generate text by iteratively denoising an entire sequence in parallel rather than left-to-right -- can learn web action planning.\n\n- **Models tested**: ReFusion 8B (masked diffusion with causal LM backbone) and FS-DFM 1.3B (pure discrete flow matching)\n- **Result**: After SFT, diffusion models solve 60-69% of tasks vs. 100% for the AR baseline. Token-level RL is universally fragile (2/16 comparisons improve, both insignificant). Sequence-level RL succeeds: MDPO pushes ReFusion to 91.9% (+31.4pp) and ESPO pushes FS-DFM to 87.1% (+18.6pp).\n- **Key finding**: The appropriate RL formulation is architecture-dependent. ELBO-based optimization (ESPO) produces concentrated distributions across architectures, while per-step trajectory methods produce multimodal distributions.\n- **Paper**: [Concentrate or Collapse: When Reinforcement Learning Meets Diffusion Language Models for Web Planning](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [10 trained models on HuggingFace](https://huggingface.co/billyenrizky) including ReFusion-8B-MDPO, FS-DFM-1.3B-ESPO-mu8, and more\n\n### Reproducing RL Experiments\n\nAll training code is in `infra/training/`. Training runs on a single NVIDIA A10G GPU (24GB VRAM) via Anyscale.\n\n```bash\n# Study 1: Autoregressive RL (Qwen3-8B)\n# SFT phase -- QLoRA fine-tuning on 992 FormFactory demonstrations (2-4 hours)\npython infra/training/finetuning/sft_trainer.py\n\n# Online GRPO phase -- browser-in-the-loop reward (4-8 hours per epoch)\n# Requires headless Chromium + FormFactory forms server\npython infra/training/shared/formfactory_server.py & # Start form server\npython infra/training/finetuning/online_grpo_trainer.py\n\n# Evaluate SFT and GRPO checkpoints on val/test splits\npython infra/training/finetuning/eval_sft.py\n\n# Study 2: Diffusion LM RL (ReFusion 8B, FS-DFM 1.3B)\n# SFT phase\npython infra/training/flow_matching/fsdfm_sft_trainer.py # FS-DFM SFT\npython infra/training/flow_matching/flow_sft_trainer.py # ReFusion SFT\n\n# Sequence-level RL (best results)\npython infra/training/flow_matching/espo_fsdfm_trainer.py # ESPO on FS-DFM\npython infra/training/flow_matching/espo_refusion_trainer.py # ESPO on ReFusion\npython infra/training/flow_matching/mdpo_fsdfm_trainer.py # MDPO on FS-DFM\npython infra/training/flow_matching/mdpo_refusion_trainer.py # MDPO on ReFusion\n\n# Submit jobs to Anyscale cloud\npython infra/training/anyscale/submit_job.py --config infra/training/anyscale/online_grpo_job.yaml\n\n# Push trained checkpoints to HuggingFace\npython infra/training/anyscale/push_checkpoints_to_hf.py\n\n# Serve trained model locally via vLLM or Ollama\npython infra/training/serving/serve_vllm.py\npython infra/training/serving/export_gguf.py # Export to GGUF for Ollama\n```\n\nReward function (in `infra/training/shared/reward_functions.py`): composite score = 0.4 * task completion + 0.4 * field accuracy + 0.2 * execution completeness. Online reward (`online_reward.py`) launches headless Chromium, executes the model's action plan, and computes the score from live browser state.\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "241eed0db19af3aee01248a981ad21b553adcf0c": {"t": 1785764218.8000476, "n": 28855, "h": "603af887e977500e", "c": "# OpenBrowser\n\n**Saved Cookies and Scheduled Tasks is available in the cloud-hosted version. Join the waitlist for early access: https://openbrowser.me** :\n\nhttps://github.com/user-attachments/assets/b17f97f3-f9f8-4707-8e39-abbbbe1a693b\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n**OpenBrowserAI Automatic Form Filling:**\n\nhttps://github.com/user-attachments/assets/16f7ef1a-beb1-45e2-a733-9592536e0ef7\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Research: Reinforcement Fine-Tuning for Browser Agents](#research-reinforcement-fine-tuning-for-browser-agents)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Research: Reinforcement Fine-Tuning for Browser Agents\n\nBeyond the framework, we conducted two independent research studies on improving browser agents through reinforcement learning, both using the [FormFactory benchmark](https://arxiv.org/abs/2506.01520) (1,250 form-filling tasks across 8 domains) and OpenBrowser's browser execution environment.\n\n### Study 1: Browser-in-the-Loop (Autoregressive RL)\n\nWe investigated whether reinforcement learning can improve a language model's ability to fill web forms beyond what supervised learning achieves.\n\n- **Method**: Two-phase pipeline -- SFT on Qwen3-8B with QLoRA (992 demonstrations), then online GRPO with live browser execution rewards (composite: 40% submission success + 40% field accuracy + 20% execution completeness)\n- **Result**: GRPO achieves 9.1% higher average reward than SFT alone on held-out validation (p=0.007, Wilcoxon signed-rank test). Improvement comes specifically from better form submission, not field filling.\n- **Key finding**: SFT is a prerequisite -- without it, the base model generates unstructured text and earns zero reward across all attempts.\n- **Paper**: [Browser-in-the-Loop: Reinforcement Fine-Tuning LLM Agents for Web Form Filling](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [Qwen3-8B-FormFactory-SFT-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-SFT-LoRA), [Qwen3-8B-FormFactory-GRPO-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-GRPO-LoRA)\n\n### Study 2: Diffusion Language Models for Web Action Planning\n\nWe investigated whether diffusion language models -- which generate text by iteratively denoising an entire sequence in parallel rather than left-to-right -- can learn web action planning.\n\n- **Models tested**: ReFusion 8B (masked diffusion with causal LM backbone) and FS-DFM 1.3B (pure discrete flow matching)\n- **Result**: After SFT, diffusion models solve 60-69% of tasks vs. 100% for the AR baseline. Token-level RL is universally fragile (2/16 comparisons improve, both insignificant). Sequence-level RL succeeds: MDPO pushes ReFusion to 91.9% (+31.4pp) and ESPO pushes FS-DFM to 87.1% (+18.6pp).\n- **Key finding**: The appropriate RL formulation is architecture-dependent. ELBO-based optimization (ESPO) produces concentrated distributions across architectures, while per-step trajectory methods produce multimodal distributions.\n- **Paper**: [Concentrate or Collapse: When Reinforcement Learning Meets Diffusion Language Models for Web Planning](https://www.researchgate.net/profile/Muhammad-Enrizky-Brillian)\n- **Models**: [10 trained models on HuggingFace](https://huggingface.co/billyenrizky) including ReFusion-8B-MDPO, FS-DFM-1.3B-ESPO-mu8, and more\n\n### Reproducing RL Experiments\n\nAll training code is in `infra/training/`. Training runs on a single NVIDIA A10G GPU (24GB VRAM) via Anyscale.\n\n```bash\n# Study 1: Autoregressive RL (Qwen3-8B)\n# SFT phase -- QLoRA fine-tuning on 992 FormFactory demonstrations (2-4 hours)\npython infra/training/finetuning/sft_trainer.py\n\n# Online GRPO phase -- browser-in-the-loop reward (4-8 hours per epoch)\n# Requires headless Chromium + FormFactory forms server\npython infra/training/shared/formfactory_server.py & # Start form server\npython infra/training/finetuning/online_grpo_trainer.py\n\n# Evaluate SFT and GRPO checkpoints on val/test splits\npython infra/training/finetuning/eval_sft.py\n\n# Study 2: Diffusion LM RL (ReFusion 8B, FS-DFM 1.3B)\n# SFT phase\npython infra/training/flow_matching/fsdfm_sft_trainer.py # FS-DFM SFT\npython infra/training/flow_matching/flow_sft_trainer.py # ReFusion SFT\n\n# Sequence-level RL (best results)\npython infra/training/flow_matching/espo_fsdfm_trainer.py # ESPO on FS-DFM\npython infra/training/flow_matching/espo_refusion_trainer.py # ESPO on ReFusion\npython infra/training/flow_matching/mdpo_fsdfm_trainer.py # MDPO on FS-DFM\npython infra/training/flow_matching/mdpo_refusion_trainer.py # MDPO on ReFusion\n\n# Submit jobs to Anyscale cloud\npython infra/training/anyscale/submit_job.py --config infra/training/anyscale/online_grpo_job.yaml\n\n# Push trained checkpoints to HuggingFace\npython infra/training/anyscale/push_checkpoints_to_hf.py\n\n# Serve trained model locally via vLLM or Ollama\npython infra/training/serving/serve_vllm.py\npython infra/training/serving/export_gguf.py # Export to GGUF for Ollama\n```\n\nReward function (in `infra/training/shared/reward_functions.py`): composite score = 0.4 * task completion + 0.4 * field accuracy + 0.2 * execution completeness. Online reward (`online_reward.py`) launches headless Chromium, executes the model's action plan, and computes the score from live browser state.\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "7fe3725e508177b8a43c9dff313f3a92263f2bd5": {"t": 1785764221.281233, "n": 28728, "h": "baaf0a0556c38fae", "c": "# OpenBrowser\n\n**Saved Cookies and Scheduled Tasks is available in the cloud-hosted version. Join the waitlist for early access: https://openbrowser.me** :\n\nhttps://github.com/user-attachments/assets/b17f97f3-f9f8-4707-8e39-abbbbe1a693b\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n**OpenBrowserAI Automatic Form Filling:**\n\nhttps://github.com/user-attachments/assets/16f7ef1a-beb1-45e2-a733-9592536e0ef7\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Research: Reinforcement Fine-Tuning for Browser Agents](#research-reinforcement-fine-tuning-for-browser-agents)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Research: Reinforcement Fine-Tuning for Browser Agents\n\nBeyond the framework, we conducted two independent research studies on improving browser agents through reinforcement learning, both using the [FormFactory benchmark](https://arxiv.org/abs/2506.01520) (1,250 form-filling tasks across 8 domains) and OpenBrowser's browser execution environment.\n\n### Study 1: Browser-in-the-Loop (Autoregressive RL)\n\nWe investigated whether reinforcement learning can improve a language model's ability to fill web forms beyond what supervised learning achieves.\n\n- **Method**: Two-phase pipeline -- SFT on Qwen3-8B with QLoRA (992 demonstrations), then online GRPO with live browser execution rewards (composite: 40% submission success + 40% field accuracy + 20% execution completeness)\n- **Result**: GRPO achieves 9.1% higher average reward than SFT alone on held-out validation (p=0.007, Wilcoxon signed-rank test). Improvement comes specifically from better form submission, not field filling.\n- **Key finding**: SFT is a prerequisite -- without it, the base model generates unstructured text and earns zero reward across all attempts.\n- **Paper**: [ResearchGate DOI: 10.13140/RG.2.2.24922.71360](https://doi.org/10.13140/RG.2.2.24922.71360)\n- **Models**: [Qwen3-8B-FormFactory-SFT-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-SFT-LoRA), [Qwen3-8B-FormFactory-GRPO-LoRA](https://huggingface.co/billyenrizky/Qwen3-8B-FormFactory-GRPO-LoRA)\n\n### Study 2: Diffusion Language Models for Web Action Planning\n\nWe investigated whether diffusion language models -- which generate text by iteratively denoising an entire sequence in parallel rather than left-to-right -- can learn web action planning.\n\n- **Models tested**: ReFusion 8B (masked diffusion with causal LM backbone) and FS-DFM 1.3B (pure discrete flow matching)\n- **Result**: After SFT, diffusion models solve 60-69% of tasks vs. 100% for the AR baseline. Token-level RL is universally fragile (2/16 comparisons improve, both insignificant). Sequence-level RL succeeds: MDPO pushes ReFusion to 91.9% (+31.4pp) and ESPO pushes FS-DFM to 87.1% (+18.6pp).\n- **Key finding**: The appropriate RL formulation is architecture-dependent. ELBO-based optimization (ESPO) produces concentrated distributions across architectures, while per-step trajectory methods produce multimodal distributions.\n- **Paper**: [ResearchGate DOI: 10.13140/RG.2.2.11500.94088](https://doi.org/10.13140/RG.2.2.11500.94088)\n- **Models**: [10 trained models on HuggingFace](https://huggingface.co/billyenrizky) including ReFusion-8B-MDPO, FS-DFM-1.3B-ESPO-mu8, and more\n\n### Reproducing RL Experiments\n\nAll training code is in `infra/training/`. Training runs on a single NVIDIA A10G GPU (24GB VRAM) via Anyscale.\n\n```bash\n# Study 1: Autoregressive RL (Qwen3-8B)\n# SFT phase -- QLoRA fine-tuning on 992 FormFactory demonstrations (2-4 hours)\npython infra/training/finetuning/sft_trainer.py\n\n# Online GRPO phase -- browser-in-the-loop reward (4-8 hours per epoch)\n# Requires headless Chromium + FormFactory forms server\npython infra/training/shared/formfactory_server.py & # Start form server\npython infra/training/finetuning/online_grpo_trainer.py\n\n# Evaluate SFT and GRPO checkpoints on val/test splits\npython infra/training/finetuning/eval_sft.py\n\n# Study 2: Diffusion LM RL (ReFusion 8B, FS-DFM 1.3B)\n# SFT phase\npython infra/training/flow_matching/fsdfm_sft_trainer.py # FS-DFM SFT\npython infra/training/flow_matching/flow_sft_trainer.py # ReFusion SFT\n\n# Sequence-level RL (best results)\npython infra/training/flow_matching/espo_fsdfm_trainer.py # ESPO on FS-DFM\npython infra/training/flow_matching/espo_refusion_trainer.py # ESPO on ReFusion\npython infra/training/flow_matching/mdpo_fsdfm_trainer.py # MDPO on FS-DFM\npython infra/training/flow_matching/mdpo_refusion_trainer.py # MDPO on ReFusion\n\n# Submit jobs to Anyscale cloud\npython infra/training/anyscale/submit_job.py --config infra/training/anyscale/online_grpo_job.yaml\n\n# Push trained checkpoints to HuggingFace\npython infra/training/anyscale/push_checkpoints_to_hf.py\n\n# Serve trained model locally via vLLM or Ollama\npython infra/training/serving/serve_vllm.py\npython infra/training/serving/export_gguf.py # Export to GGUF for Ollama\n```\n\nReward function (in `infra/training/shared/reward_functions.py`): composite score = 0.4 * task completion + 0.4 * field accuracy + 0.2 * execution completeness. Online reward (`online_reward.py`) launches headless Chromium, executes the model's action plan, and computes the score from live browser state.\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "2acb2d14de4773d8bfb08f181143beb26921ca19": {"t": 1785764224.0985, "n": 23922, "h": "ded3906c424365c0", "c": "# OpenBrowser\n\n**Saved Cookies and Scheduled Tasks is available in the cloud-hosted version. Join the waitlist for early access: https://openbrowser.me** :\n\nhttps://github.com/user-attachments/assets/b17f97f3-f9f8-4707-8e39-abbbbe1a693b\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "5d48db3023d404f8a330a8b1bb0afa48ea80898a": {"t": 1785764225.4293425, "n": 23699, "h": "1d69cf7e828e1c6b", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n[](https://codecov.io/gh/billy-enrizky/openbrowser-ai)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "18a0a42ed29bdb59d7a4f3f2f369bdbf566a5a34": {"t": 1785764226.9947963, "n": 23553, "h": "7ee49bebfa8ff49e", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually (requires `uvx`): `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "fda5e2d26eb76c750dd19061c9ca90944b08236a": {"t": 1785764228.4487557, "n": 23536, "h": "b50b0477bdf61177", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found and `uvx` is available, Chromium is installed automatically on first run. To pre-install manually: `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "ff4fc8523eac76472e8e241fa8afe2705df86e66": {"t": 1785764229.9866636, "n": 23513, "h": "59a04aed063a55f2", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n> **No separate browser install needed.** OpenBrowser auto-detects any installed Chromium-based browser (Chrome, Edge, Brave, Chromium) and uses it directly. If none is found, Chromium is installed automatically on first run. To pre-install manually: `openbrowser-ai install`\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "c44ce611b49f39b268732bdafc308d0de1420e59": {"t": 1785764231.8283124, "n": 23364, "h": "2db3f25c7614e00a", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [Benchmark: Token Efficiency](#benchmark-token-efficiency)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\n# Windows (PowerShell)\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "716151b46b11876e5520c9c032667abea534632b": {"t": 1785764234.061954, "n": 23422, "h": "c5a12606849e3df5", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Benchmark: 4-Way Comparison](#cli-benchmark-4-way-comparison)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\n### Quick install (Windows PowerShell)\n\n```powershell\n# Windows (PowerShell)\nirm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 6 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "5c6282e4190e98dbd70c87fca62fac6445961bcc": {"t": 1785764235.935124, "n": 23344, "h": "4d58939e752f086d", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Benchmark: 4-Way Comparison](#cli-benchmark-4-way-comparison)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser-ai -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) supports OpenBrowser via the CLI daemon. Install OpenBrowser,\nthen use `openbrowser-ai -c` from the Bash tool:\n\n```bash\nopenbrowser-ai -c \"await navigate('https://example.com')\"\nopenbrowser-ai -c \"print(await evaluate('document.title'))\"\n```\n\nThe daemon starts automatically on first use and persists variables across calls.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/?q=openbrowser)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/?q=openbrowser) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "e34c96f0348ff789e89db1e5d3132122315b062e": {"t": 1785764237.390038, "n": 23827, "h": "387ea0658076c31e", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Benchmark: 4-Way Comparison](#cli-benchmark-4-way-comparison)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser-ai -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## Benchmark: Token Efficiency\n\n### CLI Benchmark: 4-Way Comparison (6 Tasks, N=3 runs)\n\nFour CLI tools compared with a single Bash tool each. Claude Sonnet 4.6 on Bedrock. Randomized order. All achieve 100% accuracy.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_scatter.png\" alt=\"CLI Benchmark: Token Usage vs Duration\" width=\"800\" />\n</p>\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nopenbrowser-ai uses **2.1-2.6x fewer tokens** than all competitors via Python code batching and compact DOM representation.\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_overview.png\" alt=\"CLI Benchmark: Overview\" width=\"800\" />\n</p>\n\n#### Per-Task Token Usage\n\n<p align=\"center\">\n <img src=\"benchmarks/cli_benchmark_per_task.png\" alt=\"CLI Benchmark: Per-Task Token Usage\" width=\"800\" />\n</p>\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens) where code batching avoids repeated page state dumps.\n\n#### Cost per Benchmark Run (6 Tasks)\n\n| Model | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|-------|---------------:|------------:|---------------:|--------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | **$0.12** | $0.24 | $0.29 | $0.27 |\n| Claude Opus 4.6 ($5/$25 per M) | **$0.24** | $0.45 | $0.56 | $0.51 |\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). [Full 4-way comparison with methodology](https://docs.openbrowser.me/cli-comparison).\n\n### E2E LLM Benchmark: MCP Server Comparison (6 Tasks, N=5 runs)\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\n[Full MCP comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "4eece2da9cc1d18ebac959d1f9711590f3a5784e": {"t": 1785764238.864457, "n": 26434, "h": "06a4a6cd1ecb4297", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Benchmark: 4-Way Comparison](#cli-benchmark-4-way-comparison)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser-ai -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Benchmark: 4-Way Comparison\n\n### E2E LLM Benchmark (6 Tasks, N=3 runs, Single Bash Tool)\n\nFour CLI browser automation tools compared head-to-head. Each tool gets a single generic Bash tool (identical overhead) with an optimized system prompt. Claude Sonnet 4.6 on AWS Bedrock drives all 4 approaches. Task and approach order randomized per run. Persistent browser daemon across all 6 tasks. 10,000-sample bootstrap CIs.\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nAll 4 tools achieve **100% accuracy** (18/18 task executions). openbrowser-ai uses **2.1x fewer tokens** than browser-use, **2.5x fewer** than agent-browser, and **2.6x fewer** than playwright-cli.\n\n### Per-Task Token Usage\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks on tokens. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n### Why the Difference\n\nEach tool uses the same single Bash tool. The key differences:\n\n- **openbrowser-ai**: Python code batching via `-c` flag. Multiple operations in one `openbrowser-ai -c '...'` call. DOM with `[i_N]` indices (~450 chars per page state). Variables persist across calls.\n- **browser-use**: Individual CLI commands (`open`, `click`, `input`). DOM with `[N]` indices (~880 chars). `input` combines click+type but no multi-operation batching.\n- **playwright-cli**: `run-code` enables JS batching, but snapshots save to `.yml` files requiring extra `cat` to read. Accessibility tree (~1,420 chars per snapshot).\n- **agent-browser**: Individual commands with `&&` chaining. `snapshot -i` flag for compact output (~590 chars). Accessibility tree with `@eN` refs.\n\n[Full 4-way comparison](https://docs.openbrowser.me/cli-comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nRaw results are in [`benchmarks/e2e_4way_cli_results.json`](benchmarks/e2e_4way_cli_results.json). See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "94df4881480ca3e2f24388d51d1556f9b0021d89": {"t": 1785764240.6177194, "n": 26387, "h": "f9112aeaee7da1e9", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Benchmark: 4-Way Comparison](#cli-benchmark-4-way-comparison)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser-ai -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Benchmark: 4-Way Comparison\n\n### E2E LLM Benchmark (6 Tasks, N=3 runs, Single Bash Tool)\n\nFour CLI browser automation tools compared head-to-head. Each tool gets a single generic Bash tool (identical overhead) with an optimized system prompt. Claude Sonnet 4.6 on AWS Bedrock drives all 4 approaches. Task and approach order randomized per run. Persistent browser daemon across all 6 tasks. 10,000-sample bootstrap CIs.\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nAll 4 tools achieve **100% accuracy** (18/18 task executions). openbrowser-ai uses **2.1x fewer tokens** than browser-use, **2.5x fewer** than agent-browser, and **2.6x fewer** than playwright-cli.\n\n### Per-Task Token Usage\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks on tokens. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n### Why the Difference\n\nEach tool uses the same single Bash tool. The key differences:\n\n- **openbrowser-ai**: Python code batching via `-c` flag. Multiple operations in one `openbrowser-ai -c '...'` call. DOM with `[i_N]` indices (~450 chars per page state). Variables persist across calls.\n- **browser-use**: Individual CLI commands (`open`, `click`, `input`). DOM with `[N]` indices (~880 chars). `input` combines click+type but no multi-operation batching.\n- **playwright-cli**: `run-code` enables JS batching, but snapshots save to `.yml` files requiring extra `cat` to read. Accessibility tree (~1,420 chars per snapshot).\n- **agent-browser**: Individual commands with `&&` chaining. `snapshot -i` flag for compact output (~590 chars). Accessibility tree with `@eN` refs.\n\n[Full 4-way comparison](https://docs.openbrowser.me/cli-comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket (localhost TCP on Windows). Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "178c5677c2e7d4ee62b2f672bd1f0eaee88153a0": {"t": 1785764242.5103805, "n": 26360, "h": "cb054eb0e536b055", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Benchmark: 4-Way Comparison](#cli-benchmark-4-way-comparison)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser-ai -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Benchmark: 4-Way Comparison\n\n### E2E LLM Benchmark (6 Tasks, N=3 runs, Single Bash Tool)\n\nFour CLI browser automation tools compared head-to-head. Each tool gets a single generic Bash tool (identical overhead) with an optimized system prompt. Claude Sonnet 4.6 on AWS Bedrock drives all 4 approaches. Task and approach order randomized per run. Persistent browser daemon across all 6 tasks. 10,000-sample bootstrap CIs.\n\n| CLI Tool | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens | Response Chars |\n|----------|------------------------:|-----------:|-------------------:|---------------:|\n| **openbrowser-ai** | **84.8 +/- 10.9s** | **15.3 +/- 2.3** | **36,010 +/- 6,063** | **9,452 +/- 472** |\n| browser-use | 106.0 +/- 9.5s | 20.7 +/- 6.4 | 77,123 +/- 33,354 | 36,241 +/- 12,940 |\n| agent-browser | 99.0 +/- 6.8s | 25.0 +/- 4.0 | 90,107 +/- 3,698 | 56,009 +/- 39,733 |\n| playwright-cli | 118.3 +/- 21.4s | 25.7 +/- 8.1 | 94,130 +/- 35,982 | 84,065 +/- 49,713 |\n\nAll 4 tools achieve **100% accuracy** (18/18 task executions). openbrowser-ai uses **2.1x fewer tokens** than browser-use, **2.5x fewer** than agent-browser, and **2.6x fewer** than playwright-cli.\n\n### Per-Task Token Usage\n\n| Task | openbrowser-ai | browser-use | playwright-cli | agent-browser |\n|------|---------------:|------------:|---------------:|--------------:|\n| fact_lookup | **2,504** | 4,710 | 16,857 | 9,676 |\n| form_fill | **7,887** | 15,811 | 31,757 | 19,226 |\n| multi_page_extract | **2,354** | 2,405 | 8,886 | 8,117 |\n| search_navigate | **16,539** | 47,936 | 27,779 | 44,367 |\n| deep_navigation | **2,178** | 3,747 | 4,705 | 5,534 |\n| content_analysis | 4,548 | **2,515** | 4,147 | 3,189 |\n\nopenbrowser-ai wins 5 of 6 tasks on tokens. The advantage is largest on complex pages (search_navigate: 2.9x fewer tokens than browser-use) where code batching avoids repeated page state dumps.\n\n### Why the Difference\n\nEach tool uses the same single Bash tool. The key differences:\n\n- **openbrowser-ai**: Python code batching via `-c` flag. Multiple operations in one `openbrowser-ai -c '...'` call. DOM with `[i_N]` indices (~450 chars per page state). Variables persist across calls.\n- **browser-use**: Individual CLI commands (`open`, `click`, `input`). DOM with `[N]` indices (~880 chars). `input` combines click+type but no multi-operation batching.\n- **playwright-cli**: `run-code` enables JS batching, but snapshots save to `.yml` files requiring extra `cat` to read. Accessibility tree (~1,420 chars per snapshot).\n- **agent-browser**: Individual commands with `&&` chaining. `snapshot -i` flag for compact output (~590 chars). Accessibility tree with `@eN` refs.\n\n[Full 4-way comparison](https://docs.openbrowser.me/cli-comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket. Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "aadef6f62059052a69c4ae9813afb6633316f0ce": {"t": 1785764244.4851556, "n": 23556, "h": "73521b5fc1afd31d", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser-ai -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket. Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "b1990866a3be356de66ce8af8b165f144050e7de": {"t": 1785764246.3211224, "n": 23553, "h": "b840cdea8ccd712c", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew tap billy-enrizky/openbrowser\nbrew install openbrowser-ai\n```\n\n### Quick install (macOS / Linux)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh\n```\n\nDetects `uv`, `pipx`, or `pip` and installs OpenBrowser + Chromium automatically.\n\nInstall to `~/.local/bin` without sudo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh -s -- --local\n```\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket. Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "3c72a940109568afd4dbf997063050fc7acac8de": {"t": 1785764247.7419462, "n": 23058, "h": "2874b2d61d3fb38a", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n### pip\n\n```bash\npip install openbrowser-ai\n```\n\n### uv (recommended)\n\n```bash\nuv pip install openbrowser-ai\n```\n\n### uvx (zero install)\n\nRun directly without installing -- `uvx` downloads and caches the package automatically:\n\n```bash\n# MCP server mode\nuvx openbrowser-ai --mcp\n\n# CLI daemon mode\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\n```\n\n### pipx\n\n```bash\npipx install openbrowser-ai\n```\n\n### From source\n\n```bash\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git\ncd openbrowser-ai\nuv pip install -e \".[agent]\"\n```\n\n### Optional Dependencies\n\n```bash\npip install openbrowser-ai[agent] # LLM agent support (langgraph, langchain, litellm)\npip install openbrowser-ai[all] # All LLM providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\npip install openbrowser-ai[video] # Video recording support\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket. Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "57290416f864c074587d153770fd0f824c8576bd": {"t": 1785764249.6032546, "n": 22608, "h": "f06cf3745b016a0e", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **CLI Daemon** - Persistent browser daemon with `-c` flag for direct code execution from Bash\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with LLM agent support (langgraph, langchain, litellm, etc.)\npip install openbrowser-ai[agent]\n\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 7 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n| `cli-execute` | Execute browser automation via `openbrowser -c` with persistent daemon |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n| `OPENBROWSER_COMPACT_DESCRIPTION` | Minimal tool description (~500 tokens) | `false` |\n| `OPENBROWSER_MAX_OUTPUT` | Max output characters per execution | `10000` |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task with an LLM agent\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Execute code directly via persistent daemon\nuvx openbrowser-ai -c \"await navigate('https://example.com')\"\nuvx openbrowser-ai -c \"print(await evaluate('document.title'))\"\n\n# Daemon management\nuvx openbrowser-ai daemon start # Start daemon (auto-starts on first -c call)\nuvx openbrowser-ai daemon stop # Stop daemon and browser\nuvx openbrowser-ai daemon status # Show daemon info\nuvx openbrowser-ai daemon restart # Restart daemon\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\nThe `-c` flag connects to a persistent browser daemon over a Unix socket. Variables persist across calls while the daemon is running. The daemon starts automatically on first use and shuts down after 10 minutes of inactivity.\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 7 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent + shared executor\n│ ├── daemon/ # Persistent browser daemon (Unix socket)\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "a93a6b0ca7b3465e1cd0f267d7efc417e5c73574": {"t": 1785764252.318356, "n": 21473, "h": "3a6414f2278b41b2", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n<!-- mcp-name: me.openbrowser/openbrowser-ai -->\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with LLM agent support (langgraph, langchain, litellm, etc.)\npip install openbrowser-ai[agent]\n\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "b5de632d9c86f9f6d40f45a107a1c4b731c0677e": {"t": 1785764254.3474305, "n": 21423, "h": "4a7bbe6e4ab78f9f", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with LLM agent support (langgraph, langchain, litellm, etc.)\npip install openbrowser-ai[agent]\n\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\n[](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai)\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. Listed on the [MCP Registry](https://registry.modelcontextprotocol.io/servers/me.openbrowser/openbrowser-ai) as `me.openbrowser/openbrowser-ai`. No external LLM API keys required -- the MCP client provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "ecebf6fcb74198d567393d3b3c068089d70deef4": {"t": 1785764256.1647542, "n": 21057, "h": "d076c8e52408c3d4", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://pepy.tech/projects/openbrowser-ai)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. No external LLM API keys required. The MCP client (Claude) provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai[mcp] --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai[mcp] --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "77b4b26c2cd7b49bcc760871cfd7530f6160e3a5": {"t": 1785764257.9160962, "n": 20918, "h": "d4fd5f8eb5562fcf", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 6 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n| `file-download` | Download files (PDFs, CSVs) using browser session |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. No external LLM API keys required. The MCP client (Claude) provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai[mcp] --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **Downloads** | `download_file(url, filename)`: download a file using browser cookies, `list_downloads()`: list downloaded files |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai[mcp] --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "e651536e2e20e2601c5dae8eb7965eb2ca4f04ae": {"t": 1785764259.744734, "n": 20713, "h": "1d40b1d9403e2a02", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/c517c739-9199-47b0-bac7-c2c642a21094\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 5 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. No external LLM API keys required. The MCP client (Claude) provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai[mcp] --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai[mcp] --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "fc8399efbfe7b3262fe7b5b0ab1aff892d0c2af3": {"t": 1785764261.6883245, "n": 20714, "h": "9879db18e67e8b5d", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/ae5d74ce-0ac6-46b0-b02b-ff5518b4b20d\n\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Backend and Frontend Deployment](#backend-and-frontend-deployment)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 5 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. No external LLM API keys required. The MCP client (Claude) provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai[mcp] --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai[mcp] --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Backend and Frontend Deployment\n\nThe project includes a FastAPI backend and a Next.js frontend, both containerized with Docker.\n\n### Prerequisites\n\n- Docker and Docker Compose\n- A `.env` file in the project root with `POSTGRES_PASSWORD` and any LLM API keys (see `backend/env.example`)\n\n### Local Development (Docker Compose)\n\n```bash\n# Start backend + PostgreSQL (frontend runs locally)\ndocker-compose -f docker-compose.dev.yml up --build\n\n# In a separate terminal, start the frontend\ncd frontend && npm install && npm run dev\n```\n\n| Service | URL | Description |\n|---------|-----|-------------|\n| Backend | http://localhost:8000 | FastAPI + WebSocket + VNC |\n| Frontend | http://localhost:3000 | Next.js dev server |\n| PostgreSQL | localhost:5432 | Chat persistence |\n| VNC | ws://localhost:6080 | Live browser view |\n\nThe dev compose mounts `backend/app/` and `src/` as volumes for hot-reload. API keys are loaded from `backend/.env` via `env_file`. The `POSTGRES_PASSWORD` is read from the root `.env` file.\n\n### Full Stack (Docker Compose)\n\n```bash\n# Start all services (backend + frontend + PostgreSQL)\ndocker-compose up --build\n```\n\nThis builds and runs both the backend and frontend containers together with PostgreSQL.\n\n### Backend\n\nThe backend is a FastAPI application in `backend/` with a Dockerfile at `backend/Dockerfile`. It includes:\n\n- REST API on port 8000\n- WebSocket endpoint at `/ws` for real-time agent communication\n- VNC support (Xvfb + x11vnc + websockify) for live browser viewing on ports 6080-6090\n- Kiosk security: Openbox window manager, Chromium enterprise policies, X11 key grabber daemon\n- Health check at `/health`\n\n```bash\n# Build the backend image\ndocker build -f backend/Dockerfile -t openbrowser-backend .\n\n# Run standalone\ndocker run -p 8000:8000 -p 6080:6080 \\\n --env-file backend/.env \\\n -e VNC_ENABLED=true \\\n -e AUTH_ENABLED=false \\\n --shm-size=2g \\\n openbrowser-backend\n```\n\n### Frontend\n\nThe frontend is a Next.js application in `frontend/` with a Dockerfile at `frontend/Dockerfile`.\n\n```bash\n# Build the frontend image\ncd frontend && docker build -t openbrowser-frontend .\n\n# Run standalone\ndocker run -p 3000:3000 \\\n -e NEXT_PUBLIC_API_URL=http://localhost:8000 \\\n -e NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws \\\n openbrowser-frontend\n```\n\n### Environment Variables\n\nKey environment variables for the backend (see `backend/env.example` for the full list):\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `GOOGLE_API_KEY` | Google/Gemini API key | (required) |\n| `DEFAULT_LLM_MODEL` | Default model for agents | `gemini-3-flash-preview` |\n| `AUTH_ENABLED` | Enable Cognito JWT auth | `false` |\n| `VNC_ENABLED` | Enable VNC browser viewing | `true` |\n| `DATABASE_URL` | PostgreSQL connection string | (optional) |\n| `POSTGRES_PASSWORD` | PostgreSQL password (root `.env`) | (required for compose) |\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "6dd4197ae108edf9ef15d38b8ca53ac5e10cbc8e": {"t": 1785764263.3919659, "n": 18105, "h": "63c46ee346a0ccde", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/ae5d74ce-0ac6-46b0-b02b-ff5518b4b20d\n\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-3-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-5.2\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-3-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-3-flash, gemini-3-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-5.2, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-r1 |\n| **Cerebras** | `ChatCerebras` | llama-4-scout, qwen-3-235b |\n| **Ollama** | `ChatOllama` | llama-4-scout, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 5 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. No external LLM API keys required. The MCP client (Claude) provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai[mcp] --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 62.7 +/- 4.8s | 9.4 +/- 0.9 | 158,787 |\n| **Chrome DevTools MCP** (Google) | 100% | 103.4 +/- 2.7s | 19.4 +/- 0.5 | 299,486 |\n| **OpenBrowser MCP** | 100% | 77.0 +/- 6.7s | 13.8 +/- 2.0 | **50,195** |\n\nOpenBrowser uses **3.2x fewer tokens** than Playwright and **6.0x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.50 | $0.92 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.83 | $1.53 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs. MCP response sizes: Playwright 1,132,173 chars, Chrome DevTools 1,147,244 chars, OpenBrowser 7,853 chars -- a **144x difference**.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 520,742 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai[mcp] --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Production deployment\n\nAWS production infrastructure (VPC, EC2 backend, API Gateway, Cognito, DynamoDB, ECR, S3 + CloudFront) is defined in Terraform. See **[infra/production/terraform/README.md](infra/production/terraform/README.md)** for architecture, prerequisites, and step-by-step deploy (ECR -> build/push image -> `terraform apply`).\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "7bce3bf67b2f1317a9039b556954647f5ee40895": {"t": 1785764265.0068078, "n": 17988, "h": "198ed7d1ea693bbf", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/ae5d74ce-0ac6-46b0-b02b-ff5518b4b20d\n\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-2.0-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-4o\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-2.0-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-2.5-flash, gemini-2.5-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-4.1, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **AWS Bedrock (Anthropic)** | `ChatAnthropicBedrock` | Claude models via Anthropic Bedrock SDK |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **OpenRouter** | `ChatOpenRouter` | Any model on openrouter.ai |\n| **DeepSeek** | `ChatDeepSeek` | deepseek-chat, deepseek-reasoner |\n| **Cerebras** | `ChatCerebras` | llama3.1-8b, qwen-3-coder-480b |\n| **Ollama** | `ChatOllama` | llama3.1, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 5 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. No external LLM API keys required. The MCP client (Claude) provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai[mcp] --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 92.2 +/- 11.4s | 11.0 +/- 1.4 | 150,248 |\n| **Chrome DevTools MCP** (Google) | 100% | 128.8 +/- 6.2s | 19.8 +/- 0.4 | 310,856 |\n| **OpenBrowser MCP** | 100% | 103.1 +/- 16.4s | 15.0 +/- 3.9 | **49,423** |\n\nOpenBrowser uses **3x fewer tokens** than Playwright and **6.3x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.47 | $0.96 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.78 | $1.59 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 478,793 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai[mcp] --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Production deployment\n\nAWS production infrastructure (VPC, EC2 backend, API Gateway, Cognito, DynamoDB, ECR, S3 + CloudFront) is defined in Terraform. See **[infra/production/terraform/README.md](infra/production/terraform/README.md)** for architecture, prerequisites, and step-by-step deploy (ECR -> build/push image -> `terraform apply`).\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}, "200e68ff581171dc9e49503715483eacbd25188c": {"t": 1785764266.59467, "n": 17686, "h": "90843809d4d2eda5", "c": "# OpenBrowser\n\n**Automating Walmart Product Scraping:**\n\nhttps://github.com/user-attachments/assets/ae5d74ce-0ac6-46b0-b02b-ff5518b4b20d\n\n\n**OpenBrowserAI Automatic Flight Booking:**\n\nhttps://github.com/user-attachments/assets/632128f6-3d09-497f-9e7d-e29b9cb65e0f\n\n\n[](https://pypi.org/project/openbrowser-ai/)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/billy-enrizky/openbrowser-ai/actions)\n\n**AI-powered browser automation using CodeAgent and CDP (Chrome DevTools Protocol)**\n\nOpenBrowser is a framework for intelligent browser automation. It combines direct CDP communication with a CodeAgent architecture, where the LLM writes Python code executed in a persistent namespace, to navigate, interact with, and extract information from web pages autonomously.\n\n## Table of Contents\n\n- [Documentation](#documentation)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Supported LLM Providers](#supported-llm-providers)\n- [Claude Code Plugin](#claude-code-plugin)\n- [Codex](#codex)\n- [OpenCode](#opencode)\n- [OpenClaw](#openclaw)\n- [MCP Server](#mcp-server)\n- [MCP Benchmark: Why OpenBrowser](#mcp-benchmark-why-openbrowser)\n- [CLI Usage](#cli-usage)\n- [Project Structure](#project-structure)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n- [Contact](#contact)\n\n## Documentation\n\n**Full documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n## Key Features\n\n- **CodeAgent Architecture** - LLM writes Python code in a persistent Jupyter-like namespace for browser automation\n- **Raw CDP Communication** - Direct Chrome DevTools Protocol for maximum control and speed\n- **Vision Support** - Screenshot analysis for visual understanding of pages\n- **12+ LLM Providers** - OpenAI, Anthropic, Google, Groq, AWS Bedrock, Azure OpenAI, Ollama, and more\n- **MCP Server** - Model Context Protocol support for Claude Desktop integration\n- **Video Recording** - Record browser sessions as video files\n\n## Installation\n\n```bash\npip install openbrowser-ai\n```\n\n### With Optional Dependencies\n\n```bash\n# Install with all LLM providers\npip install openbrowser-ai[all]\n\n# Install specific providers\npip install openbrowser-ai[anthropic] # Anthropic Claude\npip install openbrowser-ai[groq] # Groq\npip install openbrowser-ai[ollama] # Ollama (local models)\npip install openbrowser-ai[aws] # AWS Bedrock\npip install openbrowser-ai[azure] # Azure OpenAI\n\n# Install with video recording support\npip install openbrowser-ai[video]\n```\n\n### Install Browser\n\n```bash\nuvx openbrowser-ai install\n# or\nplaywright install chromium\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom openbrowser import CodeAgent, ChatGoogle\n\nasync def main():\n agent = CodeAgent(\n task=\"Go to google.com and search for 'Python tutorials'\",\n llm=ChatGoogle(model=\"gemini-2.0-flash\"),\n )\n\n result = await agent.run()\n print(f\"Result: {result}\")\n\nasyncio.run(main())\n```\n\n### With Different LLM Providers\n\n```python\nfrom openbrowser import CodeAgent, ChatOpenAI, ChatAnthropic, ChatGoogle\n\n# OpenAI\nagent = CodeAgent(task=\"...\", llm=ChatOpenAI(model=\"gpt-4o\"))\n\n# Anthropic\nagent = CodeAgent(task=\"...\", llm=ChatAnthropic(model=\"claude-sonnet-4-6\"))\n\n# Google Gemini\nagent = CodeAgent(task=\"...\", llm=ChatGoogle(model=\"gemini-2.0-flash\"))\n```\n\n### Using Browser Session Directly\n\n```python\nimport asyncio\nfrom openbrowser import BrowserSession, BrowserProfile\n\nasync def main():\n profile = BrowserProfile(\n headless=True,\n viewport_width=1920,\n viewport_height=1080,\n )\n \n session = BrowserSession(browser_profile=profile)\n await session.start()\n \n await session.navigate_to(\"https://example.com\")\n screenshot = await session.screenshot()\n \n await session.stop()\n\nasyncio.run(main())\n```\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# Google (recommended)\nexport GOOGLE_API_KEY=\"...\"\n\n# OpenAI\nexport OPENAI_API_KEY=\"sk-...\"\n\n# Anthropic\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Groq\nexport GROQ_API_KEY=\"gsk_...\"\n\n# AWS Bedrock\nexport AWS_ACCESS_KEY_ID=\"...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport AWS_DEFAULT_REGION=\"us-west-2\"\n\n# Azure OpenAI\nexport AZURE_OPENAI_API_KEY=\"...\"\nexport AZURE_OPENAI_ENDPOINT=\"https://your-resource.openai.azure.com/\"\n```\n\n### BrowserProfile Options\n\n```python\nfrom openbrowser import BrowserProfile\n\nprofile = BrowserProfile(\n headless=True,\n viewport_width=1280,\n viewport_height=720,\n disable_security=False,\n extra_chromium_args=[\"--disable-gpu\"],\n record_video_dir=\"./recordings\",\n proxy={\n \"server\": \"http://proxy.example.com:8080\",\n \"username\": \"user\",\n \"password\": \"pass\",\n },\n)\n```\n\n## Supported LLM Providers\n\n| Provider | Class | Models |\n|----------|-------|--------|\n| **Google** | `ChatGoogle` | gemini-2.5-flash, gemini-2.5-pro |\n| **OpenAI** | `ChatOpenAI` | gpt-4.1, o4-mini, o3 |\n| **Anthropic** | `ChatAnthropic` | claude-sonnet-4-6, claude-opus-4-6 |\n| **Groq** | `ChatGroq` | llama-4-scout, qwen3-32b |\n| **AWS Bedrock** | `ChatAWSBedrock` | anthropic.claude-sonnet-4-6, amazon.nova-pro |\n| **Azure OpenAI** | `ChatAzureOpenAI` | Any Azure-deployed model |\n| **Ollama** | `ChatOllama` | llama3.1, deepseek-r1 (local) |\n| **OCI** | `ChatOCIRaw` | Oracle Cloud GenAI models |\n| **Browser-Use** | `ChatBrowserUse` | External LLM service |\n\n## Claude Code Plugin\n\nInstall OpenBrowser as a Claude Code plugin:\n\n```bash\n# Add the marketplace (one-time)\nclaude plugin marketplace add billy-enrizky/openbrowser-ai\n\n# Install the plugin\nclaude plugin install openbrowser@openbrowser-ai\n```\n\nThis installs the MCP server and 5 built-in skills:\n\n| Skill | Description |\n|-------|-------------|\n| `web-scraping` | Extract structured data, handle pagination |\n| `form-filling` | Fill forms, login flows, multi-step wizards |\n| `e2e-testing` | Test web apps by simulating user interactions |\n| `page-analysis` | Analyze page content, structure, metadata |\n| `accessibility-audit` | Audit pages for WCAG compliance |\n\nSee [plugin/README.md](plugin/README.md) for detailed tool parameter documentation.\n\n## Codex\n\nOpenBrowser works with OpenAI Codex via native skill discovery.\n\n### Quick Install\n\nTell Codex:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.codex/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.codex/openbrowser\n\n# Symlink skills for native discovery\nmkdir -p ~/.agents/skills\nln -s ~/.codex/openbrowser/plugin/skills ~/.agents/skills/openbrowser\n\n# Restart Codex\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.codex/INSTALL.md](.codex/INSTALL.md)\n\n## OpenCode\n\nOpenBrowser works with [OpenCode.ai](https://opencode.ai) via plugin and skill symlinks.\n\n### Quick Install\n\nTell OpenCode:\n\n```\nFetch and follow instructions from https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/refs/heads/main/.opencode/INSTALL.md\n```\n\n### Manual Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/billy-enrizky/openbrowser-ai.git ~/.config/opencode/openbrowser\n\n# Create directories\nmkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills\n\n# Symlink plugin and skills\nln -s ~/.config/opencode/openbrowser/.opencode/plugins/openbrowser.js ~/.config/opencode/plugins/openbrowser.js\nln -s ~/.config/opencode/openbrowser/plugin/skills ~/.config/opencode/skills/openbrowser\n\n# Restart OpenCode\n```\n\nThen configure the MCP server in your project (see [MCP Server](#mcp-server) below).\n\nDetailed docs: [.opencode/INSTALL.md](.opencode/INSTALL.md)\n\n## OpenClaw\n\n[OpenClaw](https://openclaw.ai) does not natively support MCP servers, but the community\n[openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin\nbridges MCP servers to OpenClaw agents.\n\n1. Install the MCP adapter plugin (see its README for setup).\n\n2. Add OpenBrowser as an MCP server in `~/.openclaw/openclaw.json`:\n\n```json\n{\n \"plugins\": {\n \"entries\": {\n \"mcp-adapter\": {\n \"enabled\": true,\n \"config\": {\n \"servers\": [\n {\n \"name\": \"openbrowser\",\n \"transport\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n ]\n }\n }\n }\n }\n}\n```\n\nThe `execute_code` tool will be registered as a native OpenClaw agent tool.\n\nFor OpenClaw plugin documentation, see [docs.openclaw.ai/tools/plugin](https://docs.openclaw.ai/tools/plugin).\n\n## MCP Server\n\nOpenBrowser includes an MCP (Model Context Protocol) server that exposes browser automation as tools for AI assistants like Claude. No external LLM API keys required. The MCP client (Claude) provides the intelligence.\n\n### Quick Setup\n\n**Claude Code**: add to your project's `.mcp.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"]\n }\n }\n}\n```\n\n**Claude Desktop**: add to `~/Library/Application Support/Claude/claude_desktop_config.json`:\n\n```json\n{\n \"mcpServers\": {\n \"openbrowser\": {\n \"command\": \"uvx\",\n \"args\": [\"openbrowser-ai[mcp]\", \"--mcp\"],\n \"env\": {\n \"OPENBROWSER_HEADLESS\": \"true\"\n }\n }\n }\n}\n```\n\n**Run directly:**\n\n```bash\nuvx openbrowser-ai[mcp] --mcp\n```\n\n### Tool\n\nThe MCP server exposes a single `execute_code` tool that runs Python code in a persistent namespace with browser automation functions. The LLM writes Python code to navigate, interact, and extract data, returning only what was explicitly requested.\n\n**Available functions** (all async, use `await`):\n\n| Category | Functions |\n|----------|-----------|\n| **Navigation** | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)` |\n| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |\n| **Dropdowns** | `select_dropdown(index, text)`, `dropdown_options(index)` |\n| **Tabs** | `switch(tab_id)`, `close(tab_id)` |\n| **JavaScript** | `evaluate(code)`: run JS in page context, returns Python objects |\n| **State** | `browser.get_browser_state_summary()`: get page metadata and interactive elements |\n| **CSS** | `get_selector_from_index(index)`: get CSS selector for an element |\n| **Completion** | `done(text, success)`: signal task completion |\n\n**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`, `numpy`, `pandas`, `matplotlib`, `BeautifulSoup`\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `OPENBROWSER_HEADLESS` | Run browser without GUI | `false` |\n| `OPENBROWSER_ALLOWED_DOMAINS` | Comma-separated domain whitelist | (none) |\n\n## MCP Benchmark: Why OpenBrowser\n\n### E2E LLM Benchmark (6 Real-World Tasks, N=5 runs)\n\nSix real-world browser tasks run through Claude Sonnet 4.6 on AWS Bedrock (Converse API) with a server-agnostic system prompt. The LLM autonomously decides which tools to call and when the task is complete. 5 runs per server with 10,000-sample bootstrap CIs. All tasks run against live websites.\n\n| # | Task | Description | Target Site |\n|:-:|------|-------------|-------------|\n| 1 | **fact_lookup** | Navigate to a Wikipedia article and extract specific facts (creator and year) | en.wikipedia.org |\n| 2 | **form_fill** | Fill out a multi-field form (text input, radio button, checkbox) and submit | httpbin.org/forms/post |\n| 3 | **multi_page_extract** | Extract the titles of the top 5 stories from a dynamic page | news.ycombinator.com |\n| 4 | **search_navigate** | Search Wikipedia, click a result, and extract specific information | en.wikipedia.org |\n| 5 | **deep_navigation** | Navigate to a GitHub repo and find the latest release version number | github.com |\n| 6 | **content_analysis** | Analyze page structure: count headings, links, and paragraphs | example.com |\n\n<p align=\"center\">\n <img src=\"benchmarks/benchmark_comparison.png\" alt=\"E2E LLM Benchmark: MCP Server Comparison\" width=\"800\" />\n</p>\n\n| MCP Server | Pass Rate | Duration (mean +/- std) | Tool Calls | Bedrock API Tokens |\n|------------|:---------:|------------------------:|-----------:|-------------------:|\n| **Playwright MCP** (Microsoft) | 100% | 92.2 +/- 11.4s | 11.0 +/- 1.4 | 150,248 |\n| **Chrome DevTools MCP** (Google) | 100% | 128.8 +/- 6.2s | 19.8 +/- 0.4 | 310,856 |\n| **OpenBrowser MCP** | 100% | 103.1 +/- 16.4s | 15.0 +/- 3.9 | **49,423** |\n\nOpenBrowser uses **3x fewer tokens** than Playwright and **6.3x fewer** than Chrome DevTools, measured via Bedrock Converse API `usage` field (the actual billed tokens including system prompt, tool schemas, conversation history, and tool results).\n\n### Cost per Benchmark Run (6 Tasks)\n\nBased on Bedrock API token usage (input + output tokens at respective rates).\n\n| Model | Playwright MCP | Chrome DevTools MCP | OpenBrowser MCP |\n|-------|---------------:|--------------------:|----------------:|\n| Claude Sonnet 4.6 ($3/$15 per M) | $0.47 | $0.96 | **$0.18** |\n| Claude Opus 4.6 ($5/$25 per M) | $0.78 | $1.59 | **$0.30** |\n\n### Why the Difference\n\nPlaywright and Chrome DevTools return full page accessibility snapshots as tool output (~124K-135K tokens for Wikipedia). The LLM reads the entire snapshot to find what it needs.\n\nOpenBrowser uses a CodeAgent architecture (single `execute_code` tool). The LLM writes Python code that processes browser state server-side and returns only extracted results (~30-1,000 chars per call). The full page content never enters the LLM context window.\n\n```\nPlaywright: navigate to Wikipedia -> 478,793 chars (full a11y tree returned to LLM)\nOpenBrowser: navigate to Wikipedia -> 42 chars (page title only, state processed in code)\n evaluate JS for infobox -> 896 chars (just the extracted data)\n```\n\n[Full comparison with methodology](https://docs.openbrowser.me/comparison)\n\n## CLI Usage\n\n```bash\n# Run a browser automation task\nuvx openbrowser-ai -p \"Search for Python tutorials on Google\"\n\n# Install browser\nuvx openbrowser-ai install\n\n# Run MCP server\nuvx openbrowser-ai[mcp] --mcp\n```\n\n## Project Structure\n\n```\nopenbrowser-ai/\n├── .claude-plugin/ # Claude Code marketplace config\n├── .codex/ # Codex integration\n│ └── INSTALL.md\n├── .opencode/ # OpenCode integration\n│ ├── INSTALL.md\n│ └── plugins/openbrowser.js\n├── plugin/ # Plugin package (skills + MCP config)\n│ ├── .claude-plugin/\n│ ├── .mcp.json\n│ └── skills/ # 5 browser automation skills\n├── src/openbrowser/\n│ ├── __init__.py # Main exports\n│ ├── cli.py # CLI commands\n│ ├── config.py # Configuration\n│ ├── actor/ # Element interaction\n│ ├── agent/ # LangGraph agent\n│ ├── browser/ # CDP browser control\n│ ├── code_use/ # Code agent\n│ ├── dom/ # DOM extraction\n│ ├── llm/ # LLM providers\n│ ├── mcp/ # MCP server\n│ └── tools/ # Action registry\n├── benchmarks/ # MCP benchmarks and E2E tests\n│ ├── playwright_benchmark.py\n│ ├── cdp_benchmark.py\n│ ├── openbrowser_benchmark.py\n│ └── e2e_published_test.py\n└── tests/ # Test suite\n```\n\n## Testing\n\n```bash\n# Run unit tests\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# E2E test the MCP server against the published PyPI package\nuv run python benchmarks/e2e_published_test.py\n```\n\n### Benchmarks\n\nRun individual MCP server benchmarks (JSON-RPC stdio, 5-step Wikipedia workflow):\n\n```bash\nuv run python benchmarks/openbrowser_benchmark.py # OpenBrowser MCP\nuv run python benchmarks/playwright_benchmark.py # Playwright MCP\nuv run python benchmarks/cdp_benchmark.py # Chrome DevTools MCP\n```\n\nResults are written to `benchmarks/*_results.json`. See [full comparison](https://docs.openbrowser.me/comparison) for methodology.\n\n## Production deployment\n\nAWS production infrastructure (VPC, EC2 backend, API Gateway, Cognito, DynamoDB, ECR, S3 + CloudFront) is defined in Terraform. See **[infra/production/terraform/README.md](infra/production/terraform/README.md)** for architecture, prerequisites, and step-by-step deploy (ECR -> build/push image -> `terraform apply`).\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contact\n\n- **Email**: billy.suharno@gmail.com\n- **GitHub**: [@billy-enrizky](https://github.com/billy-enrizky)\n- **Repository**: [github.com/billy-enrizky/openbrowser-ai](https://github.com/billy-enrizky/openbrowser-ai)\n- **Documentation**: [https://docs.openbrowser.me](https://docs.openbrowser.me)\n\n---\n\n**Made with love for the AI automation community**\n"}}}} |