Skip to main content

browsectl

Browser-agnostic automation for AI agents.

A lightweight CLI that lets AI agents (or humans) drive a real browser session: navigate, screenshot, click, type, extract DOM, and evaluate JavaScript. Designed so that agents can see client-side-rendered pages (like LinkedIn) that aren't curl-friendly.

How it works

You launch your browser with remote debugging enabled. browsectl connects to it and sends commands over the browser's native automation protocol. The agent takes screenshots to "see" the page and decides what to do next. When it hits a CAPTCHA or 2FA wall, it tells you and waits.

The core is browser-agnostic. Concrete browser support is provided by swappable backends (currently: CDP for Chrome/Chromium).

Requirements

  • Python 3.14+
  • Chrome or Chromium (for the CDP backend)

Installation

git clone <repo-url>
cd browsectl
python -m venv .venv
.venv/bin/pip install poetry
.venv/bin/poetry install

Quick start

1. Launch and connect (one step)

browsectl -s <session> launch

This auto-assigns a free port, starts Chrome with its own profile at ~/.browsectl/profiles/<session>/, waits for CDP readiness, connects, and saves the session. The port is stored in the session file so all subsequent commands find it automatically. Logins persist across runs. Your existing Chrome windows are unaffected.

You can also specify a port explicitly if needed:

browsectl -s <session> launch <port>

If the explicit port is already in use, launch fails immediately with a clear error.

For slow-starting environments, override the CDP readiness timeout (default 15s):

browsectl -s <session> launch --timeout 30

2. Use it

Every command requires -s <session>:

browsectl -s <session> goto "https://example.com"
browsectl -s <session> screenshot                    # saves screenshot.png
browsectl -s <session> screenshot /tmp/page.png      # custom path
browsectl -s <session> info                          # current URL and title
browsectl -s <session> html "h1"                     # extract innerHTML
browsectl -s <session> eval "document.title"         # run JavaScript
browsectl -s <session> click "#login-button"         # click by CSS selector
browsectl -s <session> type "#email" "me@example.com"
browsectl -s <session> scroll 500                    # scroll down 500px
browsectl -s <session> scroll -300                   # scroll up 300px
browsectl -s <session> wait ".results" 10            # wait for element (10s timeout)
browsectl -s <session> tabs                          # list open tabs
browsectl -s <session> newtab "https://github.com"   # open new tab
browsectl -s <session> switchtab <tab-id>            # switch to tab (ID from 'tabs')
browsectl -s <session> clear-cookies                 # clear all browser cookies

3. Manage sessions

browsectl sessions                    # list all sessions and their status
browsectl -s <session> stop           # kill Chrome and remove the session
browsectl stop-all                    # stop all sessions at once
browsectl profiles                    # list profile directories
browsectl profiles --prune            # remove orphaned profile directories

sessions shows each session's name, host:port, PID, and whether the process is running, dead, or external (connected manually, no PID tracked).

Connecting to an existing browser

If Chrome is already running with --remote-debugging-port, use connect instead of launch:

browsectl -s <session> connect <host> <port>

Both host and port are required.

Multiple sessions

Run multiple independent browser sessions simultaneously. Each gets its own auto-assigned port:

browsectl -s <session-a> launch
browsectl -s <session-b> launch
browsectl -s <session-a> goto "https://example.com"
browsectl -s <session-b> goto "https://github.com"

Each session gets its own Chrome process, profile directory, cookies, and localStorage. Ports are auto-assigned so agents never clash. Use browsectl sessions to see all active sessions, and browsectl -s <session> stop to shut one down. See docs/multi-session.md for details.

Backend selection

browsectl -s <session> -b cdp goto "https://example.com"   # explicit (default)

Available backends: cdp. The architecture supports adding others (WebDriver, Marionette, etc.) without changing the core.

Architecture

Hexagonal / ports-and-adapters. The core never imports a concrete browser adapter.

browsectl/
  models.py       # domain types (PageInfo, Screenshot, Tab, etc.)
  ports.py         # function signature contracts, generic over Session
  gateway.py       # BrowserGateway[S] -- frozen bundle of port functions
  core.py          # command dispatch, browser-agnostic
  main.py          # CLI entry point, wiring
  adapters/
    cdp.py         # Chrome DevTools Protocol implementation

Per-site guides

docs/sites/ contains navigation guides for specific websites. Each guide documents working selectors, SPA quirks, authentication patterns, and step-by-step browsectl workflows for that site. Selectors are timestamped since sites change their DOM frequently.

Use docs/sites/_template.md as a starting point for new guides.

Development

.venv/bin/pytest tests/ -v       # run tests
.venv/bin/mypy browsectl/        # type check (strict)
.venv/bin/ruff check browsectl/  # lint

License

MIT. See LICENSE.

Download files

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

Source Distribution

browsectl-0.2.2.tar.gz (16.9 kB view details)

Uploaded Source

Built Distribution

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

browsectl-0.2.2-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file browsectl-0.2.2.tar.gz.

File metadata

  • Download URL: browsectl-0.2.2.tar.gz
  • Upload date:
  • Size: 16.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.14.6 Linux/6.17.0-1020-azure

File hashes

Hashes for browsectl-0.2.2.tar.gz
Algorithm Hash digest
SHA256 bfa8f674e39db190a2d44720dce84d2be6ffc7396649e49418f11d79a376338a
MD5 4a693eb1dce72d5c94851eb217097435
BLAKE2b-256 a901d67b96ec3b1317e0949e047385af546a654f15905e91b32d1d12351cf5ec

See more details on using hashes here.

File details

Details for the file browsectl-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: browsectl-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 18.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.14.6 Linux/6.17.0-1020-azure

File hashes

Hashes for browsectl-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3c7873cac38d3bc382e82f15abc09324a12f2cf54d771f85a03ebc81722984e1
MD5 883f256fdaddc69e6271246d9255d15d
BLAKE2b-256 2bbf890c09f2862dac2e3effbde4038c911cab546b7556d428f097941ab5c9f0

See more details on using hashes here.

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