← Blog

BLOG

Read Browser-Use: What the Project Does and How to Run It

Read browser-use as a production runtime: what the library does, where it breaks, and how to run browser-use agents on hosted Chromium via CDP.

October 13, 20267 min readRemote Browser

# Read Browser-Use: What the Project Does and How to Run It

If you want to read browser-use before committing to it, the short version is this: browser-use is an open-source Python library that lets an LLM drive a real browser to complete tasks. It wraps Playwright, exposes the page as a structured element tree, and lets a model pick actions in a loop. That design is genuinely useful for prototyping. It is also where most teams discover that the hard part of browser-use is not the agent loop — it is the browser underneath it. This guide covers what browser-use actually does, where local execution stops scaling, and how to run browser-use agents against a hosted Chromium runtime over CDP.

What browser-use actually is

Browser-use is an agent framework, not a browser. It sits on top of Playwright and does three things:

  1. Perception. It extracts an indexed, LLM-readable representation of the DOM — clickable elements, inputs, text — rather than raw HTML.
  2. Reasoning. It sends that representation plus the task to a model, which returns a structured action (click index 14, type into index 7, scroll, extract).
  3. Execution. It translates the action into Playwright calls against a live Chromium instance.

The loop repeats until the model reports the task done or hits a step limit. Everything else — retries, memory, multi-tab handling — is built on that core.

The important architectural detail: browser-use assumes it owns a browser process it launched. Browser() starts Chromium locally, BrowserSession manages the lifecycle, and the agent talks to it through Playwright. That assumption is fine on a laptop and becomes the first thing you have to change in production.

Where local browser-use breaks

The failure modes are predictable and they are not about model quality.

Session state dies with the process. A local Chromium launched by browser-use has no persistence unless you configure a user data directory. Restart the worker, lose the login. Run two workers, get two unrelated sessions.

Concurrency is bounded by the machine. Each Chromium instance costs memory. Ten parallel agents on one box is already uncomfortable; a hundred is not a configuration problem, it is a hardware problem.

Detection is a browser-level concern. Browser-use can set a user agent and some launch flags, but the signals that get agents blocked — TLS fingerprint, headless markers, IP reputation, missing browser APIs — live below the agent layer. No amount of prompt engineering fixes a datacenter IP hitting a protected endpoint.

Debugging is opaque. When an agent fails at step 23, you need the screenshot, the DOM at that moment, and the network log. A local run that already exited gives you a stack trace and nothing else.

Infrastructure becomes your job. Browser versions, system dependencies, fonts, sandbox flags, zombie processes, disk cleanup. This is the work that has nothing to do with your product.

The production criteria that matter

Before choosing how to run browser-use, decide what you actually need. The criteria that separate a demo from a deployment:

CriterionLocal browser-useHosted Chromium runtime
Session persistenceManual user-data dirPersistent profiles managed by the runtime
ConcurrencyBounded by host RAM/CPUScales independently of your workers
Browser version pinningYou manage itRuntime-managed
IP / network controlsWhatever your host hasConfigurable proxies and browser settings
Live debuggingScreenshots you remembered to saveLive viewer plus session replay
Isolation between tasksProcess-level, if you build itSession-level by default
Cost modelFixed VM cost, idle or notMetered per browser-hour
Failure recoveryRestart the scriptReconnect to the session

The last row is the one teams underestimate. If your agent crashes mid-task, a hosted session can survive the crash. A local Chromium cannot.

Running browser-use against a remote browser

Browser-use supports connecting to an existing browser over CDP. That is the seam you use. Instead of letting browser-use launch Chromium, you point it at a WebSocket endpoint from a hosted runtime.

The pattern in Python looks like this:

from browser_use import Agent, Browser, BrowserConfig
from langchain_openai import ChatOpenAI

browser = Browser(
    config=BrowserConfig(
        cdp_url="wss://<your-session-endpoint>",
        # browser-use will attach instead of launching
    )
)

agent = Agent(
    task="Log in and export the latest invoice as PDF",
    llm=ChatOpenAI(model="gpt-4o"),
    browser=browser,
)

await agent.run()

If you are driving the same session from TypeScript — for a test harness, a CLI, or a service that is not Python — connect with Playwright directly. The CDP endpoint is the same:

import { chromium, Browser, Page } from 'playwright';

async function attach(endpoint: string): Promise<{ browser: Browser; page: Page }> {
  // connectOverCDP attaches to an already-running Chromium.
  // No local browser binary is downloaded or launched.
  const browser = await chromium.connectOverCDP(endpoint, {
    timeout: 30_000,
  });

  // A hosted session usually has one default context already open.
  const context = browser.contexts()[0] ?? (await browser.newContext());
  const page = context.pages()[0] ?? (await context.newPage());

  page.setDefaultTimeout(20_000);
  return { browser, page };
}

const { browser, page } = await attach(process.env.CDP_URL!);
await page.goto('https://example.com/dashboard');
await page.getByRole('button', { name: 'Export' }).click();
// Do NOT call browser.close() — that tears down the remote session.
await browser.close();

Two things to note. First, connectOverCDP is Chromium-only in Playwright; if you need Firefox or WebKit you are not using CDP, you are using a different transport. Second, closing the browser object disconnects the client but the semantics of session teardown depend on the runtime — check whether your endpoint treats disconnect as session end or as a pause. The Playwright CDP documentation is the authoritative reference for the client side.

What "browser use does" at the runtime layer

Once browser-use is pointed at a remote endpoint, the runtime takes over responsibilities the library was never designed to handle:

  • Session lifecycle. Create, attach, pause, resume, destroy. Sessions outlive the client process.
  • Profiles. Persistent cookies, localStorage, and auth state that survive across runs, so your agent does not re-authenticate every time.
  • Network controls. Proxy configuration and configurable browser settings for sites that treat automation traffic differently. This is the layer where "browser use stealth" discussions actually belong — not in the agent prompt.
  • Observability. A live viewer to watch the session in real time, plus recorded sessions for post-mortem. When step 23 fails, you have the artifact.
  • Isolation. Each session gets its own browser context. One agent's cookies do not leak into another's.

If you are evaluating this layer, the remote browser for AI agents writeup covers the architecture in more depth.

Cost and metering

Local browser-use has no marginal cost per run, which is why it feels free. It is not — you are paying for a VM that idles between tasks, and you are paying engineer time for the infrastructure work above.

Hosted runtimes typically meter per browser-hour: you pay for wall-clock time a session exists, not for the VM it runs on. That model rewards short, well-scoped tasks and punishes agents that sit idle waiting on a human. If your agent loop has long think times between actions, measure them — a browser-hour commitment is only cheap if the browser is actually doing work. Current rates and any free tier are on the pricing page; do not plan a budget from a blog post.

Practical guidance

Start local, move when you hit a wall. Browser-use on your laptop is the fastest way to learn the API. Move to a hosted runtime when you need concurrency, persistence, or a debugging story.

Keep the agent loop and the browser separate. The agent decides what to do; the runtime decides where it happens. Mixing them is what makes browser-use code hard to test.

Pin your browser version. Agent behavior changes when the DOM representation changes. A runtime that lets you pin Chromium removes a class of "it worked yesterday" bugs.

Log the element tree, not just the action. When an agent clicks the wrong thing, the indexed tree at that step is the only useful evidence.

Treat stealth as a browser concern. Configurable browser settings and proxy choice affect detection far more than prompt wording. See stealth browser runtime for what actually moves the needle.

Reconnect, don't restart. Design your worker so a crashed agent can reattach to a live session rather than replaying the task from step one.

Where this fits

Browser-use is a good agent framework with a real limitation: it assumes it owns a local browser. Production workloads need sessions that persist, scale independently of your workers, and can be watched and debugged after the fact. Connecting browser-use to a hosted Chromium endpoint over CDP is a small code change that moves the browser out of your process and into infrastructure you do not have to operate.

If you want to try the connection path, the documentation covers session creation, CDP endpoints, and profile handling. If you are still deciding between local and hosted execution, remote browser online walks through the trade-offs without the marketing.