Skip to content

Lulzx/ubrowser

Repository files navigation

ΞΌBrowser

The fastest, cheapest browser automation for Claude.

ΞΌBrowser      β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 51s  $0.18
Dev Browser   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 3m 53s  $0.88
Playwright    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ 4m 31s  $1.45

Benchmarks

Tested on dev-browser-eval game-tracker task with Claude Opus 4.5 (benchmark setup cloned from SawyerHood, eval tasks created independently):

Method Time Cost Turns
ΞΌBrowser 51s $0.18 7
Dev Browser 3m 53s $0.88 29
Playwright MCP 4m 31s $1.45 51

Results:

  • 5Γ— faster than Dev Browser
  • 5Γ— cheaper than Dev Browser
  • 8Γ— cheaper than Playwright MCP

Latest local run (dev-browser-eval simulation, HN proxy):

Method Time Cost Turns Tokens
Traditional (6 calls) 17.36s $0.1439 6 2177
ΞΌBrowser (batch) 6.87s $0.0052 1 204

How It Works

1. Batch Execution

Combine 25+ browser actions into a single API call:

{"steps": [
  {"tool": "navigate", "args": {"url": "/login"}},
  {"tool": "type", "args": {"selector": "#email", "text": "user@test.com"}},
  {"tool": "type", "args": {"selector": "#pass", "text": "secret"}},
  {"tool": "click", "args": {"selector": "button[type=submit]"}}
], "snapshot": {"when": "final", "maxElements": 40}}

Others make 4 separate calls. We make 1. 75% fewer API calls.

2. Ultra-Compact Snapshot Format

Standard HTML (~180 tokens):

<button id="e1" role="button">Submit</button>
<input id="e2" type="email" placeholder="Email" required>
<input id="e3" type="password" placeholder="Password">

ΞΌBrowser (~50 tokens):

btn#e1"Submit"
inp#e2@e~"Email"!r
inp#e3@p~"Password"

70% smaller snapshots. Output tokens cost 5Γ— more than input.

3. Minimal Responses

{"ok":true}
{"ok":true,"snap":"btn#e1\"Submit\"\ninp#e2@e~\"Email\""}

Only return DOM when explicitly requested.

Speed + Cost Tuning

Environment variables:

  • UBROWSER_BLOCK_STYLESHEETS=1 blocks CSS for faster loads (may affect layout-dependent pages).
  • UBROWSER_MAX_ELEMENTS=40 caps snapshots by default when maxElements is not provided.
  • UBROWSER_PROFILE_DIR=~/.ubrowser/profile browser profile directory for session persistence.
  • UBROWSER_CONSOLE_LIMIT=100 max console messages to retain in buffer.
  • UBROWSER_NETWORK_LIMIT=100 max network requests to retain in buffer.

Snapshot options (per-call overrides):

  • snapshot.maxElements limits returned elements for browser_snapshot, per-tool snapshots, and browser_batch.

Session Persistence

Browser state (cookies, localStorage, IndexedDB) persists to disk between MCP server restarts. This enables:

  • Staying logged in across sessions
  • Preserving form data and preferences
  • Maintaining shopping carts and app state

Profile stored at ~/.ubrowser/profile by default (customize with UBROWSER_PROFILE_DIR).

Implementation Details

Pre-injected extraction script β€” Script is injected once and JIT-cached in browser, eliminating recompilation overhead. Subsequent snapshots complete in <1ms.

Batched visibility checks β€” All getBoundingClientRect() calls happen in a single pass, avoiding layout thrashing that occurs with per-element checks.

MutationObserver caching β€” DOM changes are tracked via MutationObserver. If nothing changed, cached snapshot returns instantly (0.5ms vs 50ms).

CDP fast operations β€” Click and type use Chrome DevTools Protocol directly when element positions are known, bypassing Playwright's actionability checks.

Resource blocking β€” Images, fonts, media blocked at network level via Playwright route interception. Stylesheets preserved for layout accuracy.

Parallel snapshot β€” Promise.all fetches URL, title, and DOM elements concurrently during batch finalization.

Single-op type β€” Uses fill() for instant text input when no delay/enter needed, bypassing character-by-character simulation.

Install

Claude Code Plugin (Recommended)

/plugin marketplace add lulzx/claude-code
/plugin install ubrowser@claude-code

Restart Claude Code and the ubrowser MCP tools are ready.

Manual Installation

git clone https://github.com/lulzx/ubrowser && cd ubrowser
npm install && npx playwright install chromium && npm run build
claude mcp add ubrowser -- node "$PWD/build/index.js"

Tools

Tool Purpose
browser_batch Execute multiple actions in one call
browser_navigate Go to URL
browser_click Click element by ref or selector
browser_type Type into input field
browser_select Select dropdown option
browser_scroll Scroll page or element
browser_snapshot Get interactive elements
browser_pages Manage multiple tabs
browser_inspect Deep inspect specific element
browser_console Access browser console logs
browser_network Inspect network requests

Format Reference

tag#ref@type~"placeholder"/href"content"!flags

btn#e1"Submit"           β†’ <button>Submit</button>
inp#e2@e~"Email"!r       β†’ <input type="email" placeholder="Email" required>
a#e3/login"Sign in"      β†’ <a href="/login">Sign in</a>
sel#e4"Country"          β†’ <select>Country</select>

Types: @e=email @p=password @t=text @n=number @c=checkbox @r=radio

Flags: !d=disabled !c=checked !r=required

Feature Comparison

Playwright MCP Dev Browser ΞΌBrowser
Navigate, click, type βœ“ βœ“ βœ“
Element refs β€” βœ“ βœ“
Multi-tab support β€” βœ“ βœ“
Session persistence β€” βœ“ βœ“
Console/network inspect β€” β€” βœ“
Batch execution β€” β€” βœ“
Compact snapshot format β€” β€” βœ“
Scoped snapshots β€” partial βœ“
Diff snapshots β€” β€” βœ“
Configurable responses β€” β€” βœ“
Pre-injected scripts β€” β€” βœ“
MutationObserver cache β€” β€” βœ“
CDP fast operations β€” β€” βœ“

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         Claude                               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚ 1 batch call (25+ steps)
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        ΞΌBrowser                              β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              Batch Executor (sequential)              β”‚   β”‚
β”‚  β”‚  navigate β†’ type β†’ type β†’ click β†’ navigate β†’ ...     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                             β”‚                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚            Snapshot Engine (optimized)                β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚   β”‚
β”‚  β”‚  β”‚ Pre-injected script (JIT cached)                β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ MutationObserver (change detection)             β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ Batched getBoundingClientRect (no thrashing)    β”‚ β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚   β”‚
β”‚  β”‚                    β–Ό                                  β”‚   β”‚
β”‚  β”‚           Ultra-compact formatter                     β”‚   β”‚
β”‚  β”‚           btn#e1"Submit"\ninp#e2@e~"Email"           β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚ 1 response (~50 tokens)
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         Claude                               β”‚
β”‚              (continues with minimal context)                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Performance

MCP server-side benchmarks (not including LLM response time):

Operation Time
First snapshot (cold) 4ms
Cached snapshot 0.5ms
4-step batch 34ms
Type operation 12-16ms

DOM-heavy snapshot cap (data page with 500+ interactive elements):

Mode Elements Snapshot Size (body)
baseline 100 1881 chars
maxElements=40 40 740 chars

Run locally:

node bench-game-tracker.cjs
node bench-dom-heavy.cjs

License

MIT

About

The fastest, cheapest browser automation for Claude Code.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors