mini-browser▌
runablehq/mini-browser · updated Apr 8, 2026
mb is a browser CLI where each command is a small Unix tool. It talks to Chrome over CDP (port 9222) via puppeteer-core.
mini-browser (mb) — Browser CLI for Agents
mb is a browser CLI where each command is a small Unix tool. It talks to Chrome over CDP (port 9222) via puppeteer-core.
Setup (only if not already available)
Setup is only needed when mb is not installed or Chrome is not reachable.
Run these checks first — if both pass, skip straight to the Command Reference.
Check if ready
# 1. Is mb installed?
which mb && echo "mb: ok" || echo "mb: MISSING"
# 2. Is Chrome listening on CDP?
curl -sf http://127.0.0.1:9222/json/version > /dev/null && echo "chrome: ok" || echo "chrome: NOT RUNNING"
If both print "ok", everything is ready — go use mb commands directly.
Install (only if mb is missing)
npm install -g @runablehq/mini-browser
Start Chrome (only if not running)
mb-start-chrome
This launches Chrome with --remote-debugging-port=9222, a fresh profile, and a
1024×768 window. It no-ops if Chrome is already running.
To kill and relaunch:
mb-restart-chrome
Verify
mb go "https://example.com" && mb text
Environment Variables
| Variable | Default | Description |
|---|---|---|
CHROME_PORT |
9222 |
CDP port |
CHROME_BIN |
auto-detected | Path to Chrome/Chromium binary |
CHROME_PID_FILE |
<scripts>/.chrome-pid |
PID file location |
CHROME_USER_DATA_DIR |
<scripts>/.chrome-profile |
Chrome profile directory |
Command Reference
Navigation
| Command | Description |
|---|---|
mb go <url> |
Navigate to URL (waits for networkidle) |
mb url |
Print current URL |
mb back |
Go back |
mb forward |
Go forward |
Observation
| Command | Description |
|---|---|
mb text [selector] |
Visible text content (default: body) |
mb shot [file] |
Screenshot to PNG (default: ./shot.png) |
mb snap |
List interactive elements with coordinates |
Interaction
| Command | Description |
|---|---|
mb click <x> <y> |
Click at coordinates |
mb type [x y] <text> |
Type text (with coords: selects first) |
mb fill <k=v...> |
Fill form fields by label/name/placeholder |
mb key <key...> |
Press keys (Enter, Tab, Meta+a) |
mb move <x> <y> |
Hover at coordinates |
mb drag <x1> <y1> <x2> <y2> |
Drag between points |
mb scroll [dir] [px] |
Scroll (default: down 500) |
Recording
| Command | Description |
|---|---|
mb record start <file> |
Start recording (.webm, .mp4, .gif) |
mb record stop |
Stop recording and save |
mb record status |
Check if recording is active |
Tabs
| Command | Description |
|---|---|
mb tab list |
List open tabs |
mb tab new [url] |
Open new tab, print index |
mb tab close [n] |
Close tab (default: last) |
Other
| Command | Description |
|---|---|
mb js <code> |
Run JavaScript in page context |
mb wait <target> |
Wait for ms / selector / networkidle / url:pattern |
mb audit |
Design audit (palette, typography, contrast, a11y, SEO) |
mb logs |
Stream console logs (Ctrl+C to stop) |
Flags
| Flag | Default | Description |
|---|---|---|
--timeout <ms> |
30000 | Command timeout |
--tab <n> |
0 | Target tab index |
--json |
false | Structured JSON output |
--right |
false | Right-click |
--double |
false | Double-click |
--fps <n> |
30 | Recording frame rate |
--scale <n> |
1 | Recording scale factor |
Usage Patterns
Observe → Act loop
The standard agent loop: snapshot the page, pick an element, act on it.
mb snap # list interactive elements with (x, y)
mb click 512 380 # click the button at those coordinates
mb wait networkidle # wait for the page to settle
mb snap # observe again
Fill and submit a form
mb go "https://example.com/login"
mb fill "Email=user@example.com" "Password=hunter2"
mb key Enter
mb wait url:/dashboard
Take a screenshot
mb shot page.png
Extract text
mb text "main" # text from <main>
mb text "#content" # text from #content
mb text # full body text
Run JavaScript
mb js 'document.title'
echo 'document.querySelectorAll("a").length' | mb js -
Record a screencast
mb record start demo.mp4 --fps 30 --scale 1
# ... interact with the page ...
mb record stop
Design audit
mb audit # human-readable report
mb audit --json # structured JSON output
Dismiss overlays
Cookie banners and modals block clicks. Remove them with JS:
mb js 'document.querySelector("[class*=cookie]")?.remove()'
Wait strategies
mb wait 2000 # sleep 2 seconds
mb wait ".modal" # wait for selector to appear
mb wait networkidle # wait for no network activity
mb wait url:/dashboard # wait for URL to contain string
Important Notes
- Viewport is 1024×768.
snaponly returns elements in the current viewport — scroll and snap again to find more. textuses querySelector — returns first match only. Usetext "main"overtext "p"for better results.gowaits for networkidle. For heavy SPAs, follow up withwait ".selector".typewith coordinates triple-clicks first to select existing text, then types the replacement.fillfield matching order: aria-label → placeholder → name attr → id → label text → CSS selector (use#/./[prefix).--jsonoutput:snap→[{role, name, x, y, state}],tab list→[{index, url, title}],logs→ JSON lines,audit→ full audit object.- Recording state is stored in
~/.mb-recorder.json. Only one recording at a time. tab closecannot close the last remaining tab.
Troubleshooting
| Problem | Fix |
|---|---|
| "Chrome not found" | Set CHROME_BIN=/path/to/chrome |
| Connection refused | Run mb-start-chrome first |
| Stale recording state | Delete ~/.mb-recorder.json |
| Chrome window wrong size | mb-restart-chrome (creates fresh profile) |
| Element not in snap output | mb scroll down 500 then mb snap again |