ultrabrowse
v0.1.4
Published
Ultra-fast browsing for Claude Code, Codex and any MCP client: hand off a goal, a Jev-driven Chrome does the clicking at ~300 ms per decision.
Maintainers
Readme
ultrabrowse
Ultra-fast browsing for Claude Code, Codex, Cursor and any MCP client.
Hand your agent a goal ("find the yearly price of the Pro plan", "search for X and open the first result") and a real Chrome on your machine does the clicking, driven by TypeSafe's Jev (a small action-selection model that returns one indexed choice per call, not text) at about 300 ms per decision. Your big model makes one tool call and gets the result. It never spends tokens or seconds on the intermediate pages.
Independent open-source project; not affiliated with TypeSafe (makers of Jev) or browser-use. The engine is the jev-ultrafast policy rebuilt in plain JavaScript over raw Chrome DevTools Protocol. No Playwright, no Python, no native modules.
| | per step | 10-step task | what your model sees |
| --- | --- | --- | --- |
| Model driving a browser tool click by click | seconds | 30–90 s | every page, every step |
| ultrabrowse browse | ~0.3 s | 3–10 s | one result |
Install
Needs Node 22+ and Google Chrome (Chromium, Brave or Edge also work). Two API keys:
TYPESAFE_API_KEYpicks every click. Get one at https://typesafe.aiTEXT_MODEL_API_KEYis an OpenAI-compatible key used whenever text has to be typed and forextract. Default provider is OpenRouter (https://openrouter.ai/keys); any/chat/completionsendpoint works viaTEXT_MODEL_BASE_URL.
Pass them like any other MCP server, in the env block. If you prefer a file, put them in
~/.ultrabrowse/.env (template: .env.example); the env block always takes precedence.
Claude Code
claude mcp add ultrabrowse -e TYPESAFE_API_KEY=… -e TEXT_MODEL_API_KEY=… -- npx -y ultrabrowse@latestOr install the plugin, which adds the server plus a skill that teaches Claude to delegate whole web
tasks instead of clicking step by step (keys then go in ~/.ultrabrowse/.env):
/plugin marketplace add narekgevorgyan/ultrabrowse
/plugin install ultrabrowse@ultrabrowseCodex CLI
codex mcp add ultrabrowse --env TYPESAFE_API_KEY=… --env TEXT_MODEL_API_KEY=… -- npx -y ultrabrowse@latestor in ~/.codex/config.toml (raise the tool timeout: Codex defaults to 60 s and a browse can take longer):
[mcp_servers.ultrabrowse]
command = "npx"
args = ["-y", "ultrabrowse@latest"]
tool_timeout_sec = 300
[mcp_servers.ultrabrowse.env]
TYPESAFE_API_KEY = "…"
TEXT_MODEL_API_KEY = "…"Add to AGENTS.md: "For any web task, call the ultrabrowse MCP browse tool with a goal instead of driving a browser click by click."
Cursor, Windsurf, Claude Desktop
{
"mcpServers": {
"ultrabrowse": {
"command": "npx",
"args": ["-y", "ultrabrowse@latest"],
"env": { "TYPESAFE_API_KEY": "…", "TEXT_MODEL_API_KEY": "…" }
}
}
}VS Code (.vscode/mcp.json)
{
"servers": {
"ultrabrowse": {
"command": "npx",
"args": ["-y", "ultrabrowse@latest"],
"env": { "TYPESAFE_API_KEY": "…", "TEXT_MODEL_API_KEY": "…" }
}
}
}From a clone
The bundle dist/cli.cjs is committed, so a clone needs no npm install:
git clone https://github.com/narekgevorgyan/ultrabrowse
claude mcp add ultrabrowse -- node "$PWD/ultrabrowse/dist/cli.cjs"
node ultrabrowse/dist/cli.cjs doctor # checks keys and Chrome (opens a Chrome window; add --no-launch to skip)Tools
| Tool | What it does |
| --- | --- |
| browse(url?, goal) | The one to use. Opens the URL (or continues in the current tab when url is omitted) and completes the goal end to end. Returns status (done / blocked / stuck / budget / timeout), the steps, and the final page: url, title, text, numbered elements. Consent walls (including ones inside cross-origin iframes) are dismissed before the first decision; JS alerts/confirms are accepted automatically and listed in notes; controls below the fold are indexed and scrolled to when chosen; a request that got redirected elsewhere before any action comes back blocked with reason: "redirected" and requested_url. When a run does not end done, it first tries once to clear overlays and retry, then returns with a screenshot attached, a reason when known (consent_overlay, redirected) and a hint on how to take over. |
| snapshot(url?, full?) | No-model read in ~0.5 s: on-screen text (plus same-origin iframe text) and numbered elements, one line each ([12] link "Title"). full: true returns the whole document's text (up to 40k chars). Reports a covering cross-origin iframe as overlay. Needs no keys. |
| extract(url?, goal?, schema) | Browse (optional), then return JSON shaped like schema from the page. Tolerates models that wrap JSON in prose or code fences, with one retry. |
| browse_many(tasks[], concurrency) | Goal-driven runs across many sites in parallel tabs. |
| click(index), type_text(index, text, submit), press_key(key), scroll, back | Manual control over the numbered elements, for taking over when a browse stops. |
| screenshot(), close(), close_all() | JPEG of the current tab; close this server's tab; close every page in ultrabrowse's Chrome (tabs left by other processes too). Tabs are also closed when the MCP client disconnects. |
Chrome
By default ultrabrowse launches a dedicated Chrome with its own profile under
~/.ultrabrowse/chrome-profile and reuses it across calls, restarts and clients: Claude Code and
Codex (or several sessions) running at once all share the one Chrome; whoever starts first launches it
and the others join it. The profile persists
(cookies and logins survive), so treat it like a browser profile; rm -rf ~/.ultrabrowse/chrome-profile
resets it. Set ULTRABROWSE_HEADLESS=1 to hide the window.
To browse as yourself (logged-in sessions, internal tools), start a Chrome with remote debugging and point ultrabrowse at it:
# macOS example; a separate profile dir so it doesn't fight your everyday Chrome
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/.ultrabrowse/my-chrome"ULTRABROWSE_CDP_URL=http://127.0.0.1:9222What leaves your machine
- api.typesafe.ai, on every step: the current page's URL, title, visible text, the labels and values of interactive elements, your goal, and the last 10 actions. No cookies, no screenshots, no password fields.
- openrouter.ai (or your
TEXT_MODEL_BASE_URL), only when text has to be typed or you callextract: the goal, the schema, and up to 14 000 characters of page text. - Nothing else. No telemetry, no update checks.
Safety
- Model output is only ever an index into elements the page snapshot observed. It cannot produce a selector, a URL, or code that runs.
- The snapshot skips
password,fileandhiddeninputs, so ultrabrowse cannot type a password. - Every click is hit-tested at execution time (visible, not covered, still the same element).
- Bot challenges (Cloudflare and friends) are reported as
challenge: true, never solved. - Runs are bounded by an action budget, wall time, and no-progress detection.
Develop
npm install
npm run build # regenerates the inlined snapshot and bundles to dist/cli.cjs
node scripts/smoke.js dist # live end-to-end test over stdio (needs keys + Chrome)
claude plugin validate . # checks the plugin manifestssrc/snapshot.js is the in-page atomic snapshot (from jev-ultrafast, plus React-clickable divs);
src/engine.js the bounded loop; src/browser.js the CDP tab; src/model.js the TypeSafe and
text-model client; src/server.js the tools.
MIT.
