Skip to main content

Control your browser from the command line via a Chrome extension + WebSocket bridge

Project description

English | 中文

browser-ctl

Browser automation built for AI agents.
Give your LLM a real Chrome browser — with your sessions, cookies, and extensions — through simple CLI commands.

PyPI Python License


pip install browser-ctl

bctl go https://github.com
bctl click "a.search-button"
bctl type "input[name=q]" "browser-ctl"
bctl press Enter
bctl screenshot results.png

The Problem with Existing Browser Automation

Tools like browser-use, Playwright MCP, and Puppeteer are powerful, but they share a set of pain points when used with AI agents:

Pain point Typical tools browser-ctl
Heavy browser binaries — must download and manage a bundled Chromium (~400 MB) Playwright, Puppeteer Uses your existing Chrome — zero browser downloads
No access to real sessions — launches a fresh, empty browser with no cookies, logins, or extensions browser-use, Playwright MCP Controls your real Chrome — all sessions, cookies, and extensions intact
Anti-bot detection — headless browsers are flagged and blocked by many websites Puppeteer, Playwright Uses your real browser profile — indistinguishable from normal browsing
Complex SDK integration — requires importing libraries and writing async code browser-use, Stagehand Pure CLI with JSON output — any LLM can call bctl click "button"
Heavy dependencies — Playwright alone pulls ~50 MB of packages + browser binary Playwright, Puppeteer CLI is stdlib-only; server needs only aiohttp
Token-inefficient for LLMs — verbose API calls waste context window tokens SDK-based tools Concise commands: bctl text h1 vs pages of boilerplate

Designed for LLM Agents

browser-ctl is purpose-built for AI agent workflows:

  • Tool-calling ready — every command is a single shell call returning structured JSON, perfect for function-calling / tool-use patterns
  • Built-in AI skill — ships with SKILL.md that teaches AI agents (Cursor, OpenCode, etc.) the full command set and best practices
  • Real browser = real access — your LLM can operate on authenticated pages (Gmail, Jira, internal tools) without credential management
  • Deterministic output — JSON responses with CSS-selector-based queries, no vision model needed for most tasks
  • Minimal token costbctl select "a.link" -l 5 returns structured data in one call vs multi-step screenshot → vision → parse loops
# Install the AI skill for Cursor IDE in one command
bctl setup cursor

How It Works

AI Agent / Terminal  ──HTTP──▶  Bridge Server  ◀──WebSocket──  Chrome Extension
     (bctl CLI)                  (:19876)                      (your browser)
  1. CLI (bctl) sends commands via HTTP to a local bridge server
  2. Bridge server relays them over WebSocket to the Chrome extension
  3. Extension executes commands using Chrome APIs & content scripts in your real browser
  4. Results flow back the same path as JSON

The bridge server auto-starts on first command — no manual setup needed.


Installation

Step 1 — Install the Python package:

pip install browser-ctl

Step 2 — Load the Chrome extension:

bctl setup

Then in Chrome: chrome://extensions → Enable Developer modeLoad unpacked → select ~/.browser-ctl/extension/

Step 3 — Verify:

bctl ping
# {"success": true, "data": {"server": true, "extension": true}}

Command Reference

Navigation

Command Description
bctl navigate <url> Navigate to URL   (aliases: nav, go; auto-prepends https://)
bctl back Go back in history
bctl forward Go forward   (alias: fwd)
bctl reload Reload current page

Interaction

Command Description
bctl click <sel> [-i N] Click element (CSS selector, optional Nth match)
bctl hover <sel> [-i N] Hover over element
bctl type <sel> <text> Type text into input/textarea
bctl press <key> Press key — Enter submits forms, Escape closes dialogs
bctl scroll <dir|sel> [px] Scroll: up / down / top / bottom or element into view
bctl select-option <sel> <val> Select dropdown option   (alias: sopt) [--text]
bctl drag <src> [target] Drag to element or offset [--dx N --dy N]

DOM Query

Command Description
bctl text [sel] Get text content (default: body)
bctl html [sel] Get innerHTML
bctl attr <sel> [name] [-i N] Get attribute(s) of element
bctl select <sel> [-l N] List matching elements   (alias: sel)
bctl count <sel> Count matching elements
bctl status Current page URL and title

JavaScript

Command Description
bctl eval <code> Execute JS in page context (auto-bypasses CSP)

Tabs

Command Description
bctl tabs List all tabs
bctl tab <id> Switch to tab by ID
bctl new-tab [url] Open new tab
bctl close-tab [id] Close tab (default: active)

Screenshot & Files

Command Description
bctl screenshot [path] Capture screenshot   (alias: ss)
bctl download <target> [-o path] [-i N] Download file/image   (alias: dl; -o supports absolute paths)
bctl upload <sel> <files...> Upload file(s) to <input type="file">

Wait & Dialog

Command Description
bctl wait <sel|seconds> [timeout] Wait for element or sleep
bctl dialog [accept|dismiss] [--text val] Handle next alert / confirm / prompt

Server

Command Description
bctl ping Check server & extension status
bctl serve Start server in foreground
bctl stop Stop server

Examples

Search and extract
bctl go "https://news.ycombinator.com"
bctl select "a.titlelink" -l 5       # Top 5 links with text, href, etc.
Fill a form
bctl type "input[name=email]" "user@example.com"
bctl type "input[name=password]" "hunter2"
bctl select-option "select#country" "US"
bctl upload "input[type=file]" ./resume.pdf
bctl click "button[type=submit]"
Scroll and screenshot
bctl go "https://en.wikipedia.org/wiki/Web_browser"
bctl scroll down 1000
bctl ss page.png
Handle dialogs
bctl dialog accept              # Set up handler BEFORE triggering
bctl click "#delete-button"     # This triggers a confirm() dialog
Drag and drop
bctl drag ".task-card" ".done-column"
bctl drag ".range-slider" --dx 50 --dy 0
Shell scripting
# Extract all image URLs from a page
bctl go "https://example.com"
bctl eval "JSON.stringify(Array.from(document.images).map(i=>i.src))"

# Wait for SPA content to load
bctl go "https://app.example.com/dashboard"
bctl wait ".dashboard-loaded" 15
bctl text ".metric-value"

Output Format

All commands return JSON to stdout:

// Success
{"success": true, "data": {"url": "https://example.com", "title": "Example"}}

// Error
{"success": false, "error": "Element not found: .missing"}

Non-zero exit code on errors — works naturally with set -e and && chains.


Architecture

┌─────────────────────────────────────────────────────┐
│  AI Agent / Terminal                                │
│  $ bctl click "button.submit"                       │
│       │                                             │
│       ▼  HTTP POST localhost:19876/command           │
│  ┌──────────────────────┐                           │
│  │   Bridge Server      │  (Python, aiohttp)        │
│  │   :19876             │                           │
│  └──────────┬───────────┘                           │
│             │  WebSocket                            │
│             ▼                                       │
│  ┌──────────────────────┐                           │
│  │  Chrome Extension    │  (Manifest V3)            │
│  │  Service Worker      │                           │
│  └──────────┬───────────┘                           │
│             │  chrome.scripting / chrome.debugger    │
│             ▼                                       │
│  ┌──────────────────────┐                           │
│  │  Your Real Browser   │  (sessions, cookies, etc) │
│  └──────────────────────┘                           │
└─────────────────────────────────────────────────────┘
Component Details
CLI Stdlib only, communicates via HTTP
Bridge Server Async relay (aiohttp), auto-daemonizes
Extension MV3 service worker, auto-reconnects via chrome.alarms
Eval Dual strategy: MAIN-world injection (fast) + CDP fallback (CSP-safe)

Requirements

  • Python >= 3.11
  • Chrome / Chromium with the extension loaded
  • macOS, Linux, or Windows

Privacy

All communication is local (127.0.0.1). No analytics, no telemetry, no external servers. See PRIVACY.md.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

browser_ctl-0.1.1.tar.gz (19.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

browser_ctl-0.1.1-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

File details

Details for the file browser_ctl-0.1.1.tar.gz.

File metadata

  • Download URL: browser_ctl-0.1.1.tar.gz
  • Upload date:
  • Size: 19.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for browser_ctl-0.1.1.tar.gz
Algorithm Hash digest
SHA256 904c1aad588aa14dd783a65eecb52c27cdbb439232a2a664a620f456c1285dc6
MD5 19ac60dca048684211208189f328fe56
BLAKE2b-256 cc0a1825405213a5389cc1194ea666440a4067b6bd7d744127c42908cd972865

See more details on using hashes here.

Provenance

The following attestation bundles were made for browser_ctl-0.1.1.tar.gz:

Publisher: publish.yml on mikuh/browser-ctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file browser_ctl-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: browser_ctl-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 18.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for browser_ctl-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 145092f14da90633f8120c16fcb64c48f79314dd33c28f3b93f53970b782008d
MD5 8e0c1496857f97f9572f2b708c53cf86
BLAKE2b-256 8ad1a076595246af4cc2ba9c07627d8df018e0acc3eabd62c5bfb445da519fc7

See more details on using hashes here.

Provenance

The following attestation bundles were made for browser_ctl-0.1.1-py3-none-any.whl:

Publisher: publish.yml on mikuh/browser-ctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page