BLOG
Browser Use Does: What It Does and How to Run It
Browser Use does browser automation for AI agents. Here is what it actually does, where it breaks, and how to run it on a hosted Chromium runtime.
# Browser Use Does: What It Does and How to Run It
Browser Use does one job: it lets an LLM drive a real browser to complete a task. You give it a goal in natural language, it looks at the page, decides what to click or type, and repeats until the task is done or it gives up. That is the whole product in one sentence. Everything else — the Python library, the cloud offering, the benchmark scores — is detail around that loop.
This post covers what Browser Use does mechanically, where the loop breaks in production, and how to run it against a hosted Chromium runtime instead of a browser on your laptop. If you already know the library and want the runtime layer, jump to Remote Browser for AI agents.
What Browser Use does, mechanically
The library wraps a browser automation driver — Playwright or CDP under the hood — and inserts an LLM between the page and the action. The loop looks like this:
- Observe. Extract the current page state. Browser Use serializes the DOM into a text representation, optionally with a screenshot, and trims it to fit the model's context window.
- Decide. Send the goal plus the page state to an LLM. The model returns a structured action: click element 14, type into the search box, scroll down, extract this text.
- Act. Translate that action into a Playwright call and execute it against the live page.
- Repeat. Re-observe, re-decide. Stop when the model emits a
doneaction or hits a step limit.
That is a ReAct-style agent loop with the browser as the tool. The interesting engineering is not the loop itself — it is everything around it: DOM serialization, element indexing, action validation, retry logic, and the browser session the loop runs inside.
What it is good at
- Multi-step tasks on unfamiliar sites. You do not write selectors. The model reads the page and figures out the path.
- Extraction with judgment. "Find the cheapest flight with a morning departure under a set budget" is a query, not a selector.
- Prototyping. You can go from idea to working agent in an afternoon.
What it is not
- Deterministic. Two runs on the same site can take different paths. That is fine for research, painful for anything with a compliance surface.
- Fast. Every step is a model round-trip. A 20-step task is 20 LLM calls plus 20 page loads.
- Self-healing. When a site changes layout, the agent adapts. When a site blocks the browser, the agent does not — it just fails, often after burning tokens on retries.
Where the loop breaks in production
The failure modes are consistent enough to enumerate.
Detection. Browser Use runs a stock Chromium. Stock Chromium on a datacenter IP gets flagged by Cloudflare, Akamai, and PerimeterX within a few requests. The agent then sees a challenge page, tries to click through it, and loops. This is the single most common reason a Browser Use agent works locally and fails in production.
Session state. Agents that need to log in, hold a cart, or resume a multi-day workflow need a persistent profile. A fresh browser per run means re-authenticating every time, which is both slow and a detection signal.
Resource contention. Each agent needs its own browser. Ten concurrent agents means ten Chromium processes, each eating 300–500 MB. On a single VM this becomes a scheduling problem fast.
Observability. When an agent fails at step 14, you need to see what it saw. Without a live view or a session recording, you are reading logs and guessing.
Cost opacity. Model tokens are easy to track. Browser time is not, unless you meter it. A stuck agent can burn browser-hours doing nothing.
Local browser vs hosted runtime
The decision is not "Browser Use or something else." It is "which browser does Browser Use drive." That is the runtime layer, and it is where most production pain lives.
| Concern | Local / self-managed Chromium | Hosted Chromium runtime |
|---|---|---|
| Setup | Install Chromium, manage versions, patch | Connect over CDP with a URL |
| Concurrency | One VM per N browsers, manual scaling | Sessions provisioned per request |
| Detection surface | Datacenter IP, stock fingerprint | Configurable browser settings, proxy options |
| Session persistence | Manual profile directories | Persistent profiles via API |
| Debugging | Screenshots and logs | Live viewer, session replay |
| Cost model | Fixed VM cost, idle or not | Metered per browser-hour |
| Failure recovery | Restart the process | Reconnect to a new session |
The trade-off is control versus operational load. Self-hosting gives you full control over the Chromium build and network path. A hosted runtime gives you a connection URL and removes the ops work. For most teams running agents rather than building a browser platform, the second is the better default.
If you want the longer version of that argument, see Remote Browser online.
Connecting Browser Use to a hosted runtime
Browser Use accepts a CDP WebSocket endpoint. That is the integration point. You do not need a Browser Use-specific SDK — you need a ws:// URL that speaks the Chrome DevTools Protocol.
Here is the pattern with Playwright, which is what Browser Use uses underneath:
import { chromium, Browser, Page } from 'playwright';
interface SessionConfig {
goal: string;
profileId?: string;
proxyCountry?: string;
}
async function runAgentTask(config: SessionConfig): Promise<string> {
// The runtime returns a CDP endpoint for a provisioned Chromium session.
const cdpUrl = await provisionSession({
profile: config.profileId,
proxy: config.proxyCountry,
});
const browser: Browser = await chromium.connectOverCDP(cdpUrl);
// Reuse the existing context so persistent profile state carries over.
const context = browser.contexts()[0] ?? (await browser.newContext());
const page: Page = context.pages()[0] ?? (await context.newPage());
try {
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
// Hand the live page to the agent loop. Browser Use drives from here.
const result = await runBrowserUseLoop(page, config.goal);
return result;
} finally {
// Disconnect without killing the session if you want to resume later.
await browser.close();
}
}
async function provisionSession(opts: {
profile?: string;
proxy?: string;
}): Promise<string> {
// Replace with your runtime's session API.
const res = await fetch('https://api.remote-browser.dev/sessions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
profile_id: opts.profile,
proxy_country: opts.proxy,
}),
});
const data = await res.json();
return data.cdp_url;
}Three things matter in that snippet:
- `connectOverCDP` is the whole integration. No local Chromium binary, no version pinning. The runtime owns the browser.
- `browser.contexts()[0]` — a hosted session usually arrives with a context already open. Creating a new one discards profile state.
- `browser.close()` disconnects, it does not necessarily terminate. Whether the session survives depends on your runtime's session lifecycle. Check the docs for your provider.
The CDP contract is documented by the Chrome DevTools Protocol project and by Playwright's `connectOverCDP` reference. Read both before you build retry logic — the disconnect semantics are not obvious.
Production criteria for a Browser Use runtime
If you are evaluating where to run Browser Use, these are the questions that actually matter.
Does it speak CDP? Anything else means a custom adapter and a maintenance burden. CDP is the lowest common denominator across Playwright, Puppeteer, and Selenium.
Can sessions persist? Persistent profiles mean the agent stays logged in across runs. Without them, every task starts with an auth flow, which is slow and detectable.
What does the network look like? Datacenter IPs get blocked. Residential or mobile proxies in the right geography change the success rate more than any prompt engineering. This is the "browser use stealth" question, and it is mostly a network question, not a JavaScript question.
Can you watch a session live? Debugging an agent without a live view is guesswork. A viewer that shows the actual rendered page — not a screenshot stream — is worth more than a verbose log.
How is it metered? Per-browser-hour is the honest unit. It maps to the actual cost (a Chromium process holding a slot) and it does not punish you for long-running tasks the way per-request pricing does. See /pricing for current rates.
What happens on failure? A runtime that returns a fresh session on reconnect is more useful than one that returns a dead endpoint. Retry logic belongs in your agent, but the runtime has to make retries cheap.
What "browser use stealth" actually means
The phrase gets used loosely. In practice, surviving detection comes down to four things, in rough order of impact:
- IP reputation. Residential or mobile IPs in the target geography. This is the biggest lever and the one most teams under-invest in.
- Browser consistency. A Chromium build whose headers, TLS fingerprint, and JS surface agree with each other. Mismatches are trivially detectable.
- Behavioral signals. Mouse movement, timing, navigation patterns. Agents that click instantly on page load look like agents.
- Configurable browser settings. User agent, viewport, locale, timezone, and similar properties set consistently per session.
Remote Browser exposes configurable browser settings and proxy options so you can align these. It does not claim to defeat every detection system — nobody credibly does — but it removes the stock-Chromium-on-a-datacenter-IP problem, which is the one that kills most agents.
When to use Browser Use, and when not to
Use Browser Use when:
- The task is exploratory or the target site changes often.
- You can tolerate non-determinism and a step limit.
- You are prototyping and want to skip selector maintenance.
Do not use Browser Use when:
- The workflow is fixed and repeatable. Write a Playwright script. It is faster, cheaper, and deterministic.
- You need sub-second latency. Every step is a model call.
- The task has a hard compliance boundary and you cannot audit the path taken.
The honest framing: Browser Use is a good agent loop and a bad browser runtime. Pair it with a runtime that handles sessions, proxies, and observability, and it holds up in production. Run it against local Chromium and you will spend your time on infrastructure instead of tasks.
Getting started
The integration is short. Provision a session, get a CDP URL, pass it to connectOverCDP, and let Browser Use drive. The runtime handles the browser; your agent handles the task.
- Read the documentation for session provisioning, profiles, and CDP endpoints.
- Check /pricing for the current per-browser-hour rate and what is included.
- For the broader architecture, see Remote Browser for AI agents and Remote web browser.
If you are moving an existing Browser Use project off local Chromium, the migration is usually a few lines: swap the browser launch for a CDP connect, point profile storage at the runtime, and add a retry wrapper around session provisioning. Everything above that layer stays the same.