@ulpi/browse

121 commands. 12 categories.

Everything an AI agent needs to browse the web, organized by what you want to do.

goto

Navigate to URL

$ browse goto https://example.com
back

Go back in browser history

$ browse back
forward

Go forward in browser history

$ browse forward
reload

Reload the current page

$ browse reload
url

Print the current page URL

$ browse url

The @ref workflow

Browse assigns numbered refs to page elements. No CSS selectors, no XPath — just @e1, @e2, @e3.

$ browse snapshot -i
@e1 [button] "Submit"
@e2 [link] "Home"
@e3 [textbox] "Email"

$ browse fill @e3 "user@example.com"
Filled @e3

$ browse click @e1
Clicked @e1 "Submit"

Session multiplexing

Run 10+ AI agents in parallel sharing one Chromium instance. ~5MB per session.

# Agent 1
browse --session agent-1 goto https://app.com
browse --session agent-1 snapshot -i

# Agent 2 (parallel, same Chromium)
browse --session agent-2 goto https://docs.app.com
browse --session agent-2 text

Handoff protocol

Seamlessly swap to a visible browser for MFA, CAPTCHA, or OAuth. Then resume headless.

$ browse goto https://app.com/login
$ browse fill @e2 "user@example.com"
$ browse click @e4
# CAPTCHA detected!

$ browse handoff "Please solve the CAPTCHA"
# Browser opens visually for user...

$ browse resume
# Back to headless with fresh snapshot

React DevTools integration

Inspect component trees, props/state, Suspense boundaries, hydration timing — from the command line.

$ browse react-devtools enable
React DevTools enabled. Page reloaded.

$ browse react-devtools tree
<App>
  <Layout>
    <Header />
    <Suspense fallback={<Spinner />}>
      <Dashboard data={...} />
    </Suspense>
  </Layout>
</App>

$ browse react-devtools hydration
Component          | Server | Client | Delta
App                | 12ms   | 45ms   | +33ms
Dashboard          | 8ms    | 120ms  | +112ms

Command chaining

Pipe a JSON array of commands into browse chain to execute an entire workflow in a single call. One round-trip, no shell loops — login, navigate, and extract in one shot.

$ echo '[
  ["goto", "https://app.com/login"],
  ["fill", "@e3", "user@example.com"],
  ["fill", "@e5", "s3cure-p4ss"],
  ["click", "@e7"],
  ["wait", "networkidle"],
  ["snapshot", "-i"]
]' | browse chain

Navigated to https://app.com/login
Filled @e3
Filled @e5
Clicked @e7 "Sign in"
Waited for networkidle
@e1 [heading] "Dashboard"
@e2 [link] "Settings"
@e3 [link] "Projects"

MCP server mode

Run browse as a Model Context Protocol server. Native integration with Cursor, Claude Desktop, and Windsurf — no shell commands needed.

# .cursor/mcp.json
{
  "mcpServers": {
    "browse": {
      "command": "browse",
      "args": ["--mcp"]
    }
  }
}

# Works with Cursor, Claude Desktop, Windsurf
# All 121 commands available as MCP tools
# Same persistent daemon — ~100ms per command

Multiple browser engines

Switch between Playwright (default), Rebrowser (stealth — evades bot detection), and LightPanda (lightweight Zig engine). Connect to cloud browsers via Browserbase or Browserless.

# Default: Playwright (full compatibility)
browse goto https://example.com

# Stealth: evade bot detection
browse --runtime rebrowser goto https://protected-site.com

# Lightweight: 10x faster for static pages
browse --runtime lightpanda goto https://docs.example.com

# Cloud: no local Chromium needed
browse provider save browserbase <api-key>
browse --provider browserbase goto https://example.com