BLOG
Agent Browser vs Browser Use: What Actually Differs
Agent browser vs browser use explained: CLI vs Python library, CDP connections, Playwright launch options, and how to pick a runtime for production.
# Agent Browser vs Browser Use: What Actually Differs
"Agent browser vs browser use" gets searched a lot, and most answers treat them as competing products. They aren't. An agent browser is the browser layer an agent drives — a Chromium instance, a CDP endpoint, a session. Browser use is the practice of an agent using that browser to complete a task, and it's also the name of a specific Python library. The confusion is real because the two terms overlap in search results, GitHub repos, and npm packages, but they describe different layers of the same stack.
This post separates the layers, compares the two common implementations (the agent-browser CLI and the browser-use library), and shows where a hosted runtime like Remote Browser fits when you move past local scripts.
The short answer
- Agent browser = the browser runtime. A Chromium process, a CDP endpoint, a session with a profile and proxy. Something has to own this.
- Browser use = the agent logic that calls into that runtime. Navigation, clicking, extraction, verification.
If you're choosing between them, you're asking the wrong question. You need both. The real decision is *where the browser runs* and *how your agent connects to it*.
Where the terms come from
Two projects dominate the search results:
`agent-browser` (vercel-labs) is a browser automation CLI for AI agents. It's a command-line tool — you invoke it, it drives a browser, it returns structured output. It's designed to be called by an agent that shells out rather than one that imports a Python module.
`browser-use` is a Python library that connects an LLM to a browser. You write Python, define a task, and the library handles the perception-action loop. It typically drives Playwright or a CDP-connected Chromium under the hood.
Both need a browser. Neither ships one that's production-grade on its own. That's the gap a hosted runtime fills.
Comparison table
| Dimension | Agent browser (CLI) | Browser use (library) |
|---|---|---|
| Interface | Shell commands, JSON output | Python API, async tasks |
| Best for | Agents that shell out, CI steps, quick scripts | Agents that reason in Python, custom loops |
| Browser ownership | You provide it (local or remote) | You provide it (local or remote) |
| Connection method | Usually launches Chromium locally | Playwright launch or connect_over_cdp |
| State persistence | Manual — you manage profiles | Manual — you manage profiles |
| Scaling | One process per invocation | One process per task, unless you pool |
| Debugging | Logs and screenshots | Logs, screenshots, live viewer if hosted |
| Production gap | No session isolation, no per-session proxy support | No session isolation, no per-session proxy support |
The last row is the point. Both tools are excellent at the *agent* layer. Neither is a runtime.
The browser layer is the hard part
When you run either tool locally, you inherit a set of problems that don't show up in a demo:
- Chromium version drift. Your local Chrome updates, your Playwright version pins a different build, and
connect_over_cdpstarts failing with protocol mismatches. - Profile state. Cookies, localStorage, and auth tokens live in a user data directory. Two concurrent agents sharing one directory corrupt each other.
- Proxy and network config. Per-session proxies mean per-session browser launches, which means process management.
- Resource contention. Headless Chromium is not free. Ten concurrent sessions on a laptop is a different workload than ten on a server.
- Observability. When an agent fails at step 7, you need the DOM, the network log, and a screenshot from that moment — not a stack trace.
A hosted runtime addresses these by making the browser a service. You get a CDP endpoint, you connect, you disconnect, the session is cleaned up. That's the model Remote Browser uses, and it's the same model the remote browser for AI agents post covers in more depth.
Connecting an agent to a browser: the actual mechanics
Whether you use a CLI or a library, the connection is CDP. Playwright exposes two paths:
- `chromium.launch()` — Playwright starts a browser process. Fine locally, awkward in containers.
- `chromium.connectOverCDP(endpointURL)` — Playwright attaches to an already-running browser. This is the production path.
Here's what connecting to a hosted session looks like in TypeScript:
import { chromium, Browser, BrowserContext, Page } from 'playwright';
const CDP_ENDPOINT = process.env.REMOTE_BROWSER_CDP_URL!;
async function runAgentTask(task: string): Promise<string> {
const browser: Browser = await chromium.connectOverCDP(CDP_ENDPOINT, {
timeout: 30_000,
});
// A hosted session usually exposes one default context.
const context: BrowserContext = browser.contexts()[0];
const page: Page = context.pages()[0] ?? (await context.newPage());
try {
await page.goto('https://example.com/login', {
waitUntil: 'domcontentloaded',
});
await page.fill('#username', process.env.APP_USER!);
await page.fill('#password', process.env.APP_PASS!);
await page.click('button[type="submit"]');
// Wait for a real signal, not a fixed sleep.
await page.waitForResponse(
(res) => res.url().includes('/api/session') && res.status() === 200,
{ timeout: 15_000 }
);
return await page.title();
} finally {
// Do NOT call browser.close() on a hosted session unless you want
// the session torn down. Disconnect instead.
await browser.close();
}
}Two details matter here and they trip people up constantly:
- `browser.close()` on a CDP connection terminates the remote browser. If you want to keep the session alive for the next step, use
browser.close()only when you're done, or manage lifecycle through the runtime's API. - `connectOverCDP` is Chromium-only. Playwright's docs are explicit about this. If you need Firefox or WebKit, you're using
launch/launchServer, not CDP. See the Playwright CDP documentation for the authoritative behavior.
If you're coming from a local setup, the remote browser online guide walks through the same connection with less local tooling.
Playwright launch options you'll actually tune
When you *do* launch a browser — locally or inside a container you manage — these launchOptions matter in production:
const browser = await chromium.launch({
headless: true,
args: [
'--no-sandbox', // required in most containers
'--disable-dev-shm-usage', // avoids /dev/shm exhaustion
'--disable-gpu',
'--window-size=1920,1080',
],
proxy: {
server: 'http://proxy.internal:8080',
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS,
},
timeout: 60_000,
});--disable-dev-shm-usage is the single most common fix for "Chromium crashes randomly in Docker." --no-sandbox is required when running as root in a container, but it reduces isolation — don't run untrusted content that way. On a hosted runtime, these flags are the runtime's problem, not yours.
When to use which
Use the `agent-browser` CLI when:
- Your agent already shells out to tools and parses JSON.
- You want a thin, scriptable interface with no Python dependency.
- You're wiring browser steps into a CI pipeline or a shell-based orchestrator.
Use the `browser-use` library when:
- Your agent logic lives in Python and needs to reason over page state.
- You want to customize the perception-action loop.
- You're prototyping and want fast iteration on prompts and tools.
Use a hosted runtime when:
- You need more than a handful of concurrent sessions.
- Sessions must persist across worker restarts.
- You need per-session proxies, isolated profiles, or a live viewer for debugging.
- You don't want to own Chromium version management.
These aren't mutually exclusive. A common production pattern: browser-use for the reasoning loop, a hosted CDP endpoint for the browser, and the CLI for one-off operational tasks like taking a screenshot of a stuck session.
What "production" actually requires
If you're evaluating a runtime — hosted or self-managed — check these before committing:
- Session isolation. Each agent task gets its own browser context. Shared contexts leak cookies and break auth flows.
- Persistent profiles. Some tasks need to stay logged in across sessions. Others need a clean slate every time. You need both modes.
- CDP compatibility. Confirm the endpoint works with
connectOverCDP, not just a custom protocol. This keeps you portable across Playwright, Puppeteer, and Selenium. - Live debugging. A viewer or VNC-style stream saves hours when an agent fails silently.
- Proxy configuration. Per-session, not global. And configurable browser settings rather than hardcoded defaults.
- Usage controls. You need to see browser-hours and set limits before a runaway loop burns your budget. Current rates are on the pricing page.
The remote web browser post covers the operational side of these in more detail.
A note on extensions
People search for "playwright chrome extension" and "playwright mcp chrome extension" expecting Playwright to ship a browser extension. It doesn't. Playwright drives browsers via CDP or its own protocol bindings — there is no official Chrome extension you install to make Playwright work. What exists is:
- MCP servers that wrap Playwright and expose browser control to MCP-compatible clients. These are third-party integrations, not Playwright extensions.
- Browser extensions that expose CDP-like control surfaces, which you then connect to with
connectOverCDP.
If you're trying to connect Playwright to a browser you already have open, the mechanism is connectOverCDP against that browser's debugging port — not an extension. The remote control browser post covers the attach-to-existing-browser pattern.
Practical recommendation
Stop framing it as agent browser *vs* browser use. Frame it as:
- Agent layer: CLI or library — pick based on your orchestrator's language and your need to customize the loop.
- Browser layer: local for development, hosted for anything that runs unattended.
The migration path is short. Write your agent against connectOverCDP from day one, even if you're pointing at localhost:9222. When you move to a hosted endpoint, you change one environment variable. If you hardcode chromium.launch() everywhere, you'll rewrite your connection code later.
Start with the documentation to see the connection model, then decide whether your workload justifies a hosted runtime. For most agents that run more than a few times a day, it does.