TL;DR:

  • browser-use is a Python library that connects LLMs to a real browser via structured DOM representations, enabling reliable multi-step web tasks that screenshot-based agents fail at
  • It’s distinct from Playwright (a test framework) and Stagehand (a JS wrapper) — browser-use is specifically designed for LLM-driven agent loops that plan and execute web interactions
  • Best for tasks that require navigating complex authentication flows, multi-step form submissions, scraping dynamic content, or web research that doesn’t have an API alternative

Web automation has two failure modes. The first is brittle scripts — CSS selector changes break everything, dynamic content loads out of sequence, and auth flows change without notice. The second is screenshot-based AI agents — they see what a human sees, but they lose precise element boundaries, can’t distinguish clickable from non-clickable regions reliably, and hallucinate interactions that the underlying DOM doesn’t support.

browser-use is built around a third approach: give the LLM a structured, semantically-cleaned representation of the current DOM state, let it decide what action to take, execute the action in a real browser, and repeat. The browser is real (Chromium via Playwright), the DOM parsing is structured, and the agent loop is designed for multi-step task completion rather than one-shot query answering.

How It Works

The core loop in browser-use:

  1. The LLM agent receives a task (e.g., “find the cheapest return flight from Manchester to Barcelona in the next two weeks and return the price and flight number”)
  2. browser-use opens a real Chromium browser and navigates to the starting URL
  3. The current page DOM is parsed and converted to a simplified interactive element tree — inputs, buttons, links, form fields — with their positions and labels, stripped of layout noise
  4. This element tree is passed to the LLM with the task context
  5. The LLM chooses an action: click element X, fill input Y with value Z, scroll, navigate to URL, extract data
  6. browser-use executes the action in the browser
  7. The updated DOM is parsed and the loop repeats until the task is complete or the agent determines it cannot proceed

The structured element tree is the key difference from screenshot-based agents. Instead of pixel coordinates on an image, the LLM sees something like:

[Interactive elements]
Button: "Search flights" (id: search-btn)
Input: "Origin" (placeholder: "City or airport", value: "Manchester")
Input: "Destination" (placeholder: "City or airport", value: "")
Dropdown: "Trip type" (selected: "Return")
DatePicker: "Departure date"
DatePicker: "Return date"

This representation is accurate, compact, and doesn’t require the LLM to infer clickability from visual cues.

Installation and Basic Usage

pip install browser-use playwright
playwright install chromium
from browser_use import Agent
from langchain_anthropic import ChatAnthropic
import asyncio

async def main():
    agent = Agent(
        task="Go to hacker news and return the top 5 story titles",
        llm=ChatAnthropic(model="claude-sonnet-4-5"),
    )
    result = await agent.run()
    print(result)

asyncio.run(main())

browser-use supports Claude, GPT-4o, Gemini, and any LangChain-compatible LLM. The agent handles the full browser lifecycle — opening, navigating, and closing — unless you pass a persistent browser instance.

Where It Outperforms Alternatives

vs. Playwright scripts: Playwright scripts are excellent for known, stable workflows. browser-use is better when the task structure is variable — different sites, different form layouts, content that needs interpretation to decide the next action. Use Playwright for “fill this specific login form”; use browser-use for “log into my account on any of these 20 different supplier portals.”

vs. Screenshot agents (Claude computer use, GPT-4o vision): Screenshot-based agents see images. They’re good at reading text from screenshots but imprecise at targeting small interactive elements, can’t distinguish input state reliably, and hallucinate actions that the DOM doesn’t support. browser-use sees the actual DOM — it knows exactly which elements exist and whether they’re interactive.

vs. web scraping libraries (BeautifulSoup, Scrapy): Traditional scrapers are fast and efficient for static content but can’t handle JavaScript-rendered pages, authentication, or multi-step navigation with session state. browser-use runs a real browser that handles all of this.

Practical Use Cases

Research and data collection: “For each company on this list, find their current pricing page and return the cheapest plan that includes API access.” This requires navigating different site structures per company — not something a fixed script handles, but browser-use can plan each navigation from the DOM state it observes.

Form automation with conditional logic: Complex multi-step forms where later fields depend on earlier answers. The LLM can read field labels and instructions to fill correctly, rather than relying on hardcoded values that break when form logic changes.

Authenticated workflows: “Log into our supplier portal, find all pending orders from the past 30 days, and return them as JSON.” The agent handles the login flow, navigation through authenticated pages, and structured data extraction.

Competitive monitoring: Tracking competitor pricing, product availability, or content changes across sites without APIs. browser-use handles the full cycle: navigate, authenticate if needed, locate the data, extract it.

Limitations

Speed: Each step involves an LLM API call. A 15-step task at 1–2 seconds per LLM call takes 15–30 seconds minimum. This is fine for periodic batch tasks; it’s not a substitute for a fast scraper on high-volume pipelines.

Cost: LLM API costs per task can be significant for large-scale operations. browser-use is best for tasks where the alternative is manual human effort, not tasks that a well-written script could handle reliably.

Reliability on adversarial sites: Sites with aggressive anti-bot measures (CAPTCHA, fingerprinting, JavaScript obfuscation) will cause failures. browser-use uses a real Chromium instance which passes most bot detection, but not all.

Hallucination on complex pages: Highly dynamic pages, single-page apps with complex state, or pages with ambiguous UI (multiple similarly-labelled buttons) can cause the LLM to choose incorrectly. Adding human-in-the-loop checkpoints for high-stakes actions mitigates this.

When to Use It in Your Agent Workflow

browser-use fits in the agent workflow where:

  • The task requires web access and no API exists
  • The workflow is complex enough to break fixed scripts but tractable enough to complete reliably with LLM planning
  • You’re comfortable with LLM API costs proportional to task complexity
  • The task runs periodically rather than in high-frequency loops

For simple, stable workflows with known structure, prefer a conventional Playwright script. For visual tasks that don’t require DOM precision, screenshot-based agents are cheaper. browser-use sits in the middle: structured, flexible, and capable of navigating the messy reality of live web interfaces that scripts break on and vision models squint at.

Persistent Sessions and Context

browser-use supports persistent browser contexts — you can authenticate once and reuse the session across multiple agent runs. This is important for authenticated workflows where logging in on every task run is slow or triggers security flags.

from browser_use import Agent, BrowserConfig
from playwright.async_api import async_playwright

async def main():
    # Use an existing browser context (e.g., with saved cookies)
    config = BrowserConfig(
        headless=False,
        user_data_dir="./browser_profile"
    )
    agent = Agent(
        task="Check my inbox for unread emails from suppliers",
        llm=llm,
        browser_config=config
    )
    result = await agent.run()

For production agent workflows, storing authenticated sessions avoids repeated login flows and works more reliably with sites that rate-limit authentication attempts.