Skip to content

Repository files navigation

BetterWright

BetterWright

The token-efficient browser for AI agents.

npm CI node license

One persistent, policy-guarded browser your agent returns to turn after turn. Drive it from your own agent (skill, MCP, or JS API) — or hand whole tasks to its built-in browser agent and just read the answer.

npm install -g betterwright && betterwright setup

betterwright run -c "await page.goto('https://example.com'); return page.title()"
# {"ok": true, "result": "Example Domain", ...}

30–75% fewer observation tokens than a standard accessibility dump · read-only tasks finish in one model turn · persistent sessions so you don't re-pay login and navigation cost every step.


Two ways to use it

You want… You get…
Integrated your agent (Claude Code, Codex, Pi, any MCP client, your own code) to browse as one part of a bigger job a skill, MCP server, or JS API through which your agent mans the browser step by step
Standalone agent to hand over a whole browser task and read back one answer betterwright exec "<task>" — BetterWright's own browser-tuned agent loop does the driving; you (or your agent) get one JSON result

They share everything — the same persistent sessions, vault, network policy, and snapshots — so you can start with one and mix in the other later.

1. Integrated — your agent drives the browser

Any agent that can run a shell command can drive the browser. betterwright skill prints the instructions that teach it how — CLI usage plus operator guidance. No server, no SDK, no glue code.

# Claude Code — install as a skill (writes ~/.claude/skills/browser/SKILL.md)
betterwright skill --install

# Codex — append to AGENTS.md
betterwright skill >> ~/.codex/AGENTS.md

# Any custom agent — the same instructions ship as SKILL.md in this repo
# and the npm package (node_modules/betterwright/SKILL.md); copy it wherever
# your agent reads skills, or print it with `betterwright skill`.

# MCP (stdio server: browser, browser_login, browser_download, browser_handoff, browser_doctor)
npm install -g betterwright @modelcontextprotocol/sdk
claude mcp add betterwright -- npx betterwright mcp

# Pi Coding Agent (native persistent tools, trusted login, approval-gated downloads)
pi install npm:betterwright

Or drive it from your own code:

import { BetterWright } from "betterwright";

const bw = new BetterWright();
await bw.run("await page.goto('http://localhost:5173')", { session: "dev" });
const title = await bw.run("return page.title()", { session: "dev" });
console.log(title.result);
await bw.close();

run() takes a string of async Playwright JavaScript with sandboxed globals — page, snapshot, screenshot, human, credentials, and friends — and returns one result envelope. Full API: docs/javascript.md · docs/browser-api.md.

SETUP.md is the full integration guide, written to be followed by an AI agent — point your coding agent at it and it wires any host end to end.

2. Standalone — BetterWright is the browser agent

BetterWright ships its own browser-tuned agent loop. Plug in a model, hand it a task in plain language:

betterwright auth --login codex     # OAuth sign-in, no API key to paste
betterwright exec "find the top Hacker News story and give me its title and points" --model gpt-5.6-sol

The loop observes with compressed snapshots, acts, verifies, captures a proof screenshot, and prints one JSON object — answer, steps, token usage, proof path.

Models are selected by real id, not by adapter nickname. Pass the model id you want (gpt-5.6-sol, claude-opus-4-8, qwen3:8b, …). BetterWright probes running local servers (Ollama, vLLM), OpenRouter when keyed, and native Claude / Codex / Grok routes; if exactly one source exposes that id, it uses it. Prefix the source only to pin a collision (ollama/qwen3:8b). The words claude, codex, and grok alone are not model shortcuts.

You have… Typical start
ChatGPT / Codex subscription betterwright auth --login codex--model gpt-5.6-sol
Anthropic API key ANTHROPIC_API_KEY=…--model claude-opus-4-8
xAI (OAuth or API key) betterwright auth --login grok or XAI_API_KEY--model grok-4.3
Local Ollama pull a tool-calling model → --model qwen3:8b or ollama/…
Local vLLM serve with tool-calling enabled → --model <id> or vllm/<id>
OpenRouter OPENROUTER_API_KEY=…--model <author/model>
Any OpenAI-compatible /v1 --base-url https://host/v1 --model <id>
# Discover what is available (native defaults + reachable endpoints)
betterwright models
betterwright models ollama

# Local Ollama — no API key; default base http://127.0.0.1:11434/v1
betterwright exec "check example.com" --model ollama/qwen3:8b

# OpenRouter — bare author/model id when unambiguous
OPENROUTER_API_KEY=… betterwright exec "check example.com" \
  --model anthropic/claude-sonnet-4

# Custom OpenAI-compatible endpoint
BETTERWRIGHT_MODEL_API_KEY=… betterwright exec "check example.com" \
  --base-url https://models.example/v1 --model <model-id>

The model must support function / tool calling well enough to drive the browser tools — text-only chat models are not enough. Full flags, env vars, and troubleshooting: docs/agent.md.

Run bare betterwright for the interactive console: one browser session across tasks, steps streaming as they happen, /model, /endpoint, and /models, plus an ask tool so the agent can check with you before consequential choices.

Use it as a sub-agent. Because exec is one shell command in and one JSON object out, a coding agent can delegate entire browser tasks to it:

betterwright exec "log in to staging and download this month's invoice" --model gpt-5.6-sol

The whole browsing transcript — every snapshot, every retry — stays inside the sub-agent. A 30-turn checkout costs your main agent one tool call, not 30 pages of context. Programmatic equivalent: runAgentTask() from betterwright/agent.

Tokens are the bottleneck

An agent's browser loop is observe → decide → act, and the observe step is where context windows go to die. Raw HTML dumps, full accessibility trees, and screenshot-only loops burn thousands of tokens per turn — so tasks hit context limits, costs climb, and the model drowns in markup it never needed.

BetterWright's whole observation stack is built around that problem:

Mechanism Token effect
Compressed agent snapshots A distilled accessibility tree — not raw HTML — measuring 30–75% fewer tokens than standard tree output, with [ref=eN] markers the model acts on directly instead of re-deriving selectors
Diff mode After an action, return only what changed — not the page again
Interactive-only filter Drop static text nodes; keep what the agent can click, fill, or read
Scoped truncation Hints about where to look next instead of a silently clipped wall
Single-call finish Read-only tasks complete in one model turn — the code returns {finalAnswer} and the loop ends, no confirmation round-trip
Persistent session One long-lived browser: no re-login, no re-navigation, no re-paying the token cost of getting back to where you were
Sub-agent delegation betterwright exec keeps the entire browsing transcript out of your main agent's context — a whole task costs it one tool call

Watch it, coach it, take the wheel

Every run can carry a self-hosted live view: a web page showing the browser in real time, with chat to guide the agent between turns and a handoff flow for the moments automation shouldn't finish alone — MFA, a resistant CAPTCHA, a consequential click. The agent pauses, you take the controls, hit Done, and it resumes with your note.

betterwright exec "" --live-view          # watch the whole run
betterwright view --expose tailscale       # drive a headless VPS browser from your laptop
betterwright view --set-password           # lock every viewer behind a password

Hosting is one word (lan, local, tailscale), auth is a capability token plus an optional config-stored password, and nothing live-view-related is reachable from model code.

Why not just Playwright?

Playwright is built for tests: trusted scripts, known selectors, teardown at the end. An agent is the opposite — untrusted model output deciding its next step from what it sees, in a browser that must still be there next turn:

Playwright BetterWright
Observations Raw accessibility tree or DIY HTML Compressed, diffable, redacted snapshots priced for a context window
Session Browser per script One persistent managed browser — logins survive turns, days, restarts
Trust Full API access Model code runs sandboxed: no file, process, or network-routing APIs
Network Any URL Every request policy-checked (DNS-rebinding-proof); cloud metadata endpoints always blocked
Secrets Passwords in the script AES-256-GCM vault; forms are detected and filled without the secret ever entering the conversation
Evidence Assertions screenshot({kind: 'proof'}) — tagged artifacts the agent cites as proof of work
CAPTCHAs Out of scope Local captcha.solve() — checkbox, Turnstile, slider; vision handoff for image grids
Human in the loop Out of scope Token-gated live view: watch, chat, answer ask, or take over on handoff

What's in the box

Piece What it gives you
Agent snapshots The token-efficiency core: compressed tree, [ref=eN] actions, diff and interactive-only modes, password redaction
Built-in agent loop betterwright exec / the interactive console / runAgentTask() — model-first selection across Claude, Codex, Grok, OpenRouter, Ollama, vLLM, and any OpenAI-compatible endpoint
Credential vault AES-256-GCM outside the profile; PSL site matching, selector-free login detection, metadata-only account choice
Live view & handoff Watch and coach the agent live; token + optional password gated; handoff pauses for human hands and resumes on Done
Network policy Every navigation, subresource, WebSocket, and raw TCP connection checked; metadata endpoints always blocked
CAPTCHA helpers Local solving for checkbox/Turnstile/slider; image grids hand off to the agent's own vision with tile crops
Human-shaped input Curved pointer movement, paced typing, eased wheel — no extra dependency
Cloaking V2 Coherent native fingerprint: build-specific viewport, locale, timezone, optional geo-matched egress. No page-world shims; live reCAPTCHA v3 returns 0.9 headed and headless
Native Chromium fork Optional BetterWright-built Chromium: per-profile-stable canvas/audio farbling, platform masking, macOS-metric fonts. Auto-detected at ~/.betterwright/chromium/; platforms without an artifact (Windows) stay on managed CloakBrowser
Skill packs Per-site and per-password-manager guidance the host agent reads on demand — surfaced automatically when an open page matches
Download approval Denied by default; a trusted host approves one download run at a time
Operator guidance betterwright skill / agentSystemPrompt() — decisive action on authorized tasks, with optional confirmation/spending guardrails

Install

Requires Node.js 22+. Setup downloads the browser (~200 MB, once) — the Chromium fork on macOS arm64 / Linux x64, CloakBrowser elsewhere — never as an npm lifecycle side effect, so installs stay predictable with --ignore-scripts.

npm install -g betterwright
betterwright setup     # fork (mac/linux) + Cloak fallback
betterwright update    # refresh / switch to the Chromium fork
betterwright doctor    # confirm everything resolves

How it works

The CLI (or your JS host) owns one long-lived Node worker. The worker holds the persistent browser context and exposes sandboxed globals to model code; it calls back to the host to authorize requests and resolve credentials without putting secrets in results. CDP and raw browser handles stay worker-internal. The security model — what the sandbox removes, why the metadata floor cannot be lifted, and where it does not claim to be a boundary — is in docs/architecture.md.

Docs

Start here Capabilities Under the hood
Getting started Credential vault Architecture & security model
Integration guide (SETUP.md) Live view & handoff Cloaking V2
The built-in agent CAPTCHA helpers Chromium fork
JavaScript API Network policy Headed / headless
Browser API (snippet globals) Skill packs Operator guidance
Recipes

Scope and responsible use

BetterWright automates a browser under your direction, including signing in and interacting with simple CAPTCHAs on sites you are authorized to use. It is not built for bulk account creation, credential stuffing, or scraping behind anti-bot walls at scale; its helpers exist to unblock a task you legitimately own, not to repeatedly defeat a site that is telling automation to stop. No browser configuration can guarantee undetectability or challenge acceptance. See the security model for the boundaries the code does and does not enforce.

License

MIT — see LICENSE.

About

A persistent, policy-guarded Playwright browser for AI agents — network policy, encrypted credential vault, proof screenshots, and CAPTCHA solving. inspired by https://aside.com

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages