Script-first browser automation for AI agents. Snapshot → Refs → Actions.
OpenDevBrowser is an OpenCode plugin that gives AI agents direct browser control via Chrome DevTools Protocol. Launch browsers, capture page snapshots, and interact with elements using stable refs.
| Feature | Benefit |
|---|---|
| Script-first UX | Snapshot → Refs → Actions workflow optimized for AI agents |
| Accessibility-tree snapshots | Token-efficient page representation (not raw DOM) |
| Stable refs | Elements identified by backendNodeId, not fragile selectors |
| Security by default | CDP localhost-only, timing-safe auth, HTML sanitization |
| 3 browser modes | Managed, CDP connect, or extension relay for logged-in sessions |
| Relay Hub (FIFO leases) | Single-owner CDP binding with a FIFO queue for multi-client safety |
| Flat-session routing | Extension relay uses DebuggerSession sessionId routing (Chrome 125+) |
| 5 bundled skill packs | Best practices for login, forms, data extraction |
| 30 tools | Complete browser automation coverage |
| 95% test coverage | Production-ready with strict TypeScript |
# Interactive installer (recommended)
npx opendevbrowser
# Or specify location
npx opendevbrowser --global # ~/.config/opencode/opencode.json
npx opendevbrowser --local # ./opencode.json
# Full install (config + extension assets)
npx opendevbrowser --fullRestart OpenCode after installation.
OpenCode discovers skills in .opencode/skill (project) and ~/.config/opencode/skill (global) first; .claude/skills is compatibility-only. The CLI installs bundled skills into the OpenCode-native locations by default.
Recommended (CLI, installs plugin + config + bundled skills + extension assets):
npx opendevbrowser --full --global --no-promptExplicit flags (config + skills, no prompt):
npx opendevbrowser --global --with-config --skills-global --no-promptManual fallback (edit OpenCode config):
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opendevbrowser"]
}Config location: ~/.config/opencode/opencode.json
Restart OpenCode, then run opendevbrowser_status to verify the plugin is loaded (daemon status when hub is enabled).
1. Launch a browser session
2. Navigate to a URL
3. Take a snapshot to get element refs
4. Interact using refs (click, type, select)
5. Re-snapshot after navigation
| Step | Tool | Purpose |
|---|---|---|
| 1 | opendevbrowser_launch |
Launch a session (extension relay first; managed fallback is explicit) |
| 2 | opendevbrowser_goto |
Navigate to URL |
| 3 | opendevbrowser_snapshot |
Get page structure with refs |
| 4 | opendevbrowser_click / opendevbrowser_type |
Interact with elements |
| 5 | opendevbrowser_disconnect |
Clean up session |
Run a local daemon for persistent sessions, then drive automation via CLI commands:
# Start daemon
npx opendevbrowser serve
# Launch a session
npx opendevbrowser launch --start-url https://example.com
# Capture a snapshot
npx opendevbrowser snapshot --session-id <session-id>
# Interact by ref
npx opendevbrowser click --session-id <session-id> --ref r12For single-shot scripts:
npx opendevbrowser run --script ./script.json --output-format jsonUse --output-format json|stream-json for automation-friendly output.
- Launch & Connect - Start managed Chrome or connect to existing browsers
- Multi-Tab Support - Create, switch, and manage browser tabs
- Profile Persistence - Maintain login sessions across runs
- Headless Mode - Run without visible browser window
- Snapshot - Accessibility-tree based page capture (token-efficient)
- Click - Click elements by ref
- Type - Enter text into inputs
- Select - Choose dropdown options
- Scroll - Scroll page or elements
- Wait - Wait for selectors or navigation
- Console Capture - Monitor console.log, errors, warnings
- Network Tracking - Request/response metadata (method, url, status)
- Screenshot - Viewport PNG screenshot (file or base64)
- Performance - Page load metrics
- DOM Capture - Extract sanitized HTML with inline styles
- React Emitter - Generate React component code from pages
- CSS Extraction - Pull computed styles
OpenDevBrowser provides 30 tools organized by category:
| Tool | Description |
|---|---|
opendevbrowser_launch |
Launch a session (extension relay first; managed is explicit) |
opendevbrowser_connect |
Connect to existing Chrome CDP endpoint (or relay /cdp) |
opendevbrowser_disconnect |
Disconnect browser session |
opendevbrowser_status |
Get session status and connection info (daemon status in hub mode) |
| Tool | Description |
|---|---|
opendevbrowser_targets_list |
List all browser tabs/targets |
opendevbrowser_target_use |
Switch to a specific tab by targetId |
opendevbrowser_target_new |
Open new tab (optionally with URL) |
opendevbrowser_target_close |
Close a tab by targetId |
| Tool | Description |
|---|---|
opendevbrowser_page |
Open or focus a named page (logical tab alias) |
opendevbrowser_list |
List all named pages in session |
opendevbrowser_close |
Close a named page |
| Tool | Description |
|---|---|
opendevbrowser_goto |
Navigate to URL |
opendevbrowser_wait |
Wait for load state or element |
opendevbrowser_snapshot |
Capture page accessibility tree with refs |
opendevbrowser_click |
Click element by ref |
opendevbrowser_type |
Type text into input by ref |
opendevbrowser_select |
Select dropdown option by ref |
opendevbrowser_scroll |
Scroll page or element |
opendevbrowser_run |
Execute multiple actions in sequence |
| Tool | Description |
|---|---|
opendevbrowser_dom_get_html |
Get outerHTML of element by ref |
opendevbrowser_dom_get_text |
Get innerText of element by ref |
| Tool | Description |
|---|---|
opendevbrowser_console_poll |
Poll console logs since sequence |
opendevbrowser_network_poll |
Poll network requests since sequence |
opendevbrowser_screenshot |
Capture page screenshot |
opendevbrowser_perf |
Get page performance metrics |
opendevbrowser_prompting_guide |
Get best-practice prompting guidance |
| Tool | Description |
|---|---|
opendevbrowser_clone_page |
Export page as React component + CSS |
opendevbrowser_clone_component |
Export element subtree as React component |
| Tool | Description |
|---|---|
opendevbrowser_skill_list |
List available skills |
opendevbrowser_skill_load |
Load a skill by name (with optional topic filter) |
OpenDevBrowser includes 5 task-specific skill packs:
| Skill | Purpose |
|---|---|
opendevbrowser-best-practices |
Core prompting patterns and workflow guidance |
opendevbrowser-continuity-ledger |
Long-running task state management |
login-automation |
Authentication flow patterns |
form-testing |
Form validation and submission workflows |
data-extraction |
Structured data scraping patterns |
Skills are discovered from (priority order):
.opencode/skill/(project)~/.config/opencode/skill/(global).claude/skills/(compatibility)~/.claude/skills/(compatibility)- Custom paths via
skillPathsconfig
Load a skill: opendevbrowser_skill_load with name and optional topic filter.
| Mode | Tool | Use Case |
|---|---|---|
| Managed | opendevbrowser_launch |
Fresh browser, full control, automatic cleanup |
| CDP Connect | opendevbrowser_connect |
Attach to existing Chrome with --remote-debugging-port |
| Extension Relay | Chrome Extension | Attach to logged-in tabs via relay server |
Default behavior: opendevbrowser_launch prefers Extension Relay when available. Use --no-extension (and --headless if desired) for managed sessions.
Extension relay relies on flat CDP sessions (Chrome 125+) and uses DebuggerSession sessionId routing for multi-tab and child-target support. When hub mode is enabled, the hub daemon is the sole relay owner and there is no local relay fallback.
Relay CDP endpoint: ws://127.0.0.1:<relayPort>/cdp.
The connect command also accepts base relay WS URLs (ws://127.0.0.1:<relayPort> or ws://localhost:<relayPort>) and normalizes them to /cdp.
When pairing is enabled, /cdp requires a relay token (?token=<relayToken>). Tools and the CLI auto-fetch relay config and tokens.
opendevbrowser_launchnow prefers the extension relay by default. Use--no-extension(and--headlessif desired) for managed sessions.- Relay
/cdprequires a token when pairing is enabled; tools/CLI handle this automatically.
The extension enables Extension Relay mode - attach to existing logged-in browser tabs without launching a new browser.
Requirements: Chrome 125+ (flat CDP sessions). Older versions will fail fast with a clear error.
The plugin and extension can automatically pair:
- Plugin side: Starts a local relay server and config discovery endpoint
- Extension side: Enable "Auto-Pair" toggle and click Connect
- Extension fetches relay port from discovery, then fetches token from the relay server
- Connection established with color indicator (green = connected)
Auto-connect and Auto-pair are enabled by default for a seamless setup. The extension badge shows status (ON/OFF).
| Setting | Default |
|---|---|
| Relay port | 8787 |
| Auto-connect | true |
| Auto-pair | true |
| Require pairing token | true |
| Pairing token | null (fetched on connect) |
- Extension checks the discovery endpoint at
http://127.0.0.1:8787/config. - It learns the relay port and whether pairing is required.
- If pairing is required and Auto-pair is on, it fetches the token from
http://127.0.0.1:<relayPort>/pair. - It connects to
ws://127.0.0.1:<relayPort>/extensionusing the extension origin.
/config and /pair are extension-origin only for CSWSH protection.
- Ensure the active tab is a normal
http(s)page (notchrome://or extension pages). - Confirm
relayPortandrelayTokenin~/.config/opencode/opendevbrowser.jsoncmatch the popup (Auto-pair should fetch the token). - If pairing is disabled (
relayToken: false) orrelayPortis0, the relay is off. - Clear extension local data and retry if the token/port seem stuck.
- If another process owns the port, change
relayPortor stop it;opencodelistening is expected.
- Start OpenCode once so the plugin can extract the extension assets.
- Load unpacked from
~/.config/opencode/opendevbrowser/extension(fallback:~/.cache/opencode/node_modules/opendevbrowser/extension). - Open extension popup
- Enter the same relay port and token as the plugin config
(if
relayTokenis missing, either add one toopendevbrowser.jsoncor use Auto-Pair). - Click Connect
Extension assets are bundled inside the NPM package and extracted on install/startup:
- Primary:
~/.config/opencode/opendevbrowser/extension - Fallback:
~/.cache/opencode/node_modules/opendevbrowser/extension
Extraction is handled by extractExtension() (see src/extension-extractor.ts).
Optional config file: ~/.config/opencode/opendevbrowser.jsonc
All fields optional. Plugin works with sensible defaults.
| Command | Description |
|---|---|
npx opendevbrowser |
Interactive install |
npx opendevbrowser --global |
Install to global config |
npx opendevbrowser --local |
Install to project config |
npx opendevbrowser --with-config |
Also create opendevbrowser.jsonc |
npx opendevbrowser --full |
Full install (config + extension assets) |
npx opendevbrowser --update |
Clear cache, trigger reinstall |
npx opendevbrowser --uninstall |
Remove from config |
npx opendevbrowser --version |
Show version |
Start the daemon with npx opendevbrowser serve, then use:
| Command | Description |
|---|---|
npx opendevbrowser launch |
Launch managed session |
npx opendevbrowser connect |
Connect to existing CDP endpoint |
npx opendevbrowser disconnect |
Disconnect session |
npx opendevbrowser status |
Show session status |
npx opendevbrowser goto |
Navigate to URL |
npx opendevbrowser wait |
Wait for load or element |
npx opendevbrowser snapshot |
Capture snapshot with refs |
npx opendevbrowser click |
Click element by ref |
npx opendevbrowser type |
Type into element by ref |
npx opendevbrowser select |
Select dropdown option by ref |
npx opendevbrowser scroll |
Scroll page or element |
npx opendevbrowser run |
Run a JSON script |
OpenDevBrowser is secure by default with defense-in-depth protections:
| Protection | Details |
|---|---|
| CDP Localhost-Only | Remote endpoints blocked; hostname normalized to prevent bypass |
| Timing-Safe Auth | crypto.timingSafeEqual() for token comparison |
| Origin Validation | Only chrome-extension:// origins can connect to relay |
| Rate Limiting | 5 handshake attempts/minute per IP |
| Data Redaction | Tokens, API keys, sensitive paths auto-redacted |
| Export Sanitization | Scripts, event handlers, dangerous CSS stripped |
| Atomic Writes | Config writes are atomic to prevent corruption |
| Secure Defaults | allowRawCDP, allowNonLocalCdp, allowUnsafeExport all false |
# Option 1: Clear cache (recommended)
rm -rf ~/.cache/opencode/node_modules/opendevbrowser
# Then restart OpenCode
# Option 2: Use CLI
npx opendevbrowser --updateArchitecture overview: docs/ARCHITECTURE.md Release checklist: docs/DISTRIBUTION_PLAN.md
src/
├── browser/ # BrowserManager, TargetManager, CDP lifecycle
├── cli/ # CLI commands and installers
├── core/ # Bootstrap, runtime wiring
├── devtools/ # Console/network trackers with redaction
├── export/ # DOM capture, React emitter, CSS extraction
├── relay/ # Extension relay server, protocol types
├── skills/ # SkillLoader for skill pack discovery
├── snapshot/ # AX-tree snapshots, ref management
├── tools/ # 30 opendevbrowser_* tool definitions
└── utils/ # Shared utilities
Extension relay uses flat CDP sessions (Chrome 125+) with DebuggerSession sessionId routing for multi-tab support.
When hub mode is enabled, the hub daemon is the sole relay owner and enforces a FIFO lease queue for multi-client safety.
See docs/ARCHITECTURE.md for detailed component diagrams.
npm install
npm run build # Compile to dist/
npm run test # Run tests with coverage (95% threshold)
npm run lint # ESLint checks (strict TypeScript)
npm run extension:build # Compile extension
npm run version:check # Verify package/extension version alignment
npm run extension:pack # Build extension zip for releasesUniform versioning is required (source of truth: package.json):
- Bump
package.jsonversion. - Run:
npm run extension:sync - Run:
npm run version:check - Run:
npm run build - Run:
npm run extension:build - Run:
npm run extension:pack(outputs./opendevbrowser-extension.zip) - Publish to NPM and attach the zip to the GitHub release tag (
vX.Y.Z).
Release checklist: docs/DISTRIBUTION_PLAN.md
See Privacy Policy for data handling details.
MIT
{ // Browser settings "headless": false, "profile": "default", "persistProfile": true, "chromePath": "/path/to/chrome", // Custom Chrome executable "flags": ["--disable-extensions"], // Additional Chrome flags // Snapshot limits "snapshot": { "maxChars": 16000, "maxNodes": 1000 }, // Export limits "export": { "maxNodes": 1000, "inlineStyles": true }, // DevTools output "devtools": { "showFullUrls": false, "showFullConsole": false }, // Security (all default false for safety) "security": { "allowRawCDP": false, "allowNonLocalCdp": false, "allowUnsafeExport": false }, // Skills configuration "skills": { "nudge": { "enabled": true, "keywords": ["form", "login", "extract", "scrape"], "maxAgeMs": 60000 } }, "skillPaths": ["./custom-skills"], // Additional skill directories // Continuity ledger "continuity": { "enabled": true, "filePath": "opendevbrowser_continuity.md", "nudge": { "enabled": true, "keywords": ["plan", "multi-step", "refactor", "migration"], "maxAgeMs": 60000 } }, // Extension relay "relayPort": 8787, "relayToken": "auto-generated-on-first-run", // Hub daemon (relay ownership + FIFO queue) "daemonPort": 8788, "daemonToken": "auto-generated-on-first-run", // Updates "checkForUpdates": false }