TabbitBlog

Browser Use Python Tutorial for a Read-Only Agent

Connect a model and browser, then verify a typed result against a test page.

In this article
  1. Key takeaways
  2. Choose where the browser and model run
  3. Make a test page with a known answer
  4. Run the agent and check the two fields
  5. Check the page visit, output, and side effects separately
  6. Diagnose the first failing stage
  7. When to keep this in Python

To build a Browser Use agent in Python, give Agent a model, a fresh Browser, and a task with an answer you can check. This example asks the agent to read a heading and a reference code from a local HTML page. Pydantic checks the shape of the answer. Your program checks the two values against the page you wrote.

A GitHub issue about action validation shows how an older Browser Use run could fail before producing a useful answer. A model has to express a browser action in the format the library expects before it can return your two fields. The example below follows the current Python quickstart and output format guide. It has been reviewed against those docs and is untested end to end.

Key takeaways

  • Use the Browser Use Python library when your application needs to own the browser session, the task, and the checks on the result.

  • Start with a local HTML file and a browser session that has no signed-in accounts.

  • A local browser and a local model are separate choices. ChatBrowserUse calls a hosted model even when Chromium runs on your machine.

  • Compare the values to independent evidence. history.is_successful() reports the agent's own assessment.

  • Keep the first task free of side effects. Use a fixture with no form, upload, or account.

Choose where the browser and model run

The model decides which actions to request. The browser opens the page and runs those actions. Your Python program connects the two. This separation is useful when comparing a browser agent with fixed Playwright steps or deciding whether web search is enough.

SetupWhere the browser runsWhen to choose it
Python library + local browserOn the machine running your scriptYou want to read a loopback fixture and own the checks in Python
Python library + remote browserIn a remote session your script can reachYou need remote browser infrastructure and can make the target reachable from it
Browser Use Cloud hosted agentIn managed infrastructureYou want the hosted agent API and can give it a reachable target

This walkthrough takes the first route. The model adapter still needs a key from Browser Use. Put BROWSER_USE_API_KEY in your environment or a local .env file as shown in the quickstart. Keep the key out of source control. Run these commands in a new project directory with uv installed.

uv init --python 3.12
uv add browser-use
uvx browser-use install

The quickstart installs Chromium for the browser session. Keep the lockfile if you plan to reproduce the setup later. The supported models guide documents other adapters, including ChatOllama. If you switch providers, rerun the same fixture and keep its expected values fixed. The adapter must support the action format as well as the final output. The Cloud quickstart has separate authentication and session setup.

A QA engineer's Reddit post asks for a self-hosted model to keep client data within their infrastructure. That constraint would rule out the hosted model used here. For this exercise, send only the synthetic fixture to the model.

Make a test page with a known answer

Save the following file as fixture/index.html. The reference code is synthetic. The page has no forms or credentials, and the HTTP server exposes only the fixture directory. Keep the server running in a separate terminal.

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Inventory fixture</title>
<main>
  <h1>Inventory Check</h1>
  <p>Reference code: BU-741</p>
</main>
</html>
uv run python -m http.server 8765 --bind 127.0.0.1 --directory fixture

The address is relative to the browser's machine. A remote Chromium session opening 127.0.0.1 will look at its own loopback address. For this walkthrough, keep the browser local and open the URL manually first if you need to confirm the server is listening.

Run the agent and check the two fields

Save the code as check_page.py at the project root. The browser parameters describe the navigation allowlist, and the Agent parameters describe the schema option. The URL goes in the task, while the expected strings stay in the verifier. That keeps the expected answer out of the instruction the model receives.

import asyncio
from tempfile import TemporaryDirectory

from browser_use import Agent, Browser, ChatBrowserUse
from pydantic import BaseModel

URL = "http://127.0.0.1:8765/"


class PageCheck(BaseModel):
    heading: str
    reference: str


async def main():
    with TemporaryDirectory(prefix="browser-use-fixture-") as profile:
        browser = Browser(
            headless=True,
            user_data_dir=profile,
            allowed_domains=["127.0.0.1"],
            accept_downloads=False,
        )
        try:
            agent = Agent(
                task=(
                    f"Open {URL} and read its visible heading and reference code. "
                    "Return only those two values. Do not interact with any form."
                ),
                browser=browser,
                llm=ChatBrowserUse(),
                output_model_schema=PageCheck,
            )
            history = await agent.run(max_steps=5)
            result = history.structured_output
            expected = PageCheck(heading="Inventory Check", reference="BU-741")
            if result != expected:
                raise RuntimeError("The output does not match the fixture.")
            print(result.model_dump_json())
        finally:
            await browser.stop()


if __name__ == "__main__":
    asyncio.run(main())
uv run python check_page.py

A successful print would contain the heading Inventory Check and reference BU-741. Those are the fixture's expected values. If the script raises the mismatch error, inspect the history before raising the step limit. A longer run can simply repeat a failed action.

Check the page visit, output, and side effects separately

Diagram showing a fixture request, a parsed PageCheck object, and an independent value comparison
The request log, output schema, and value comparison each establish a different part of the result.

Start with the fixture server log. Look for a request for / during the agent run. Then check history.urls() and history.errors() alongside the terminal output. A recorded URL and a valid object answer different questions. The output format guide distinguishes completion and agent-reported success from a verified result.

Keep the test browser separate from your daily profile. Connecting to an existing browser changes which sessions and cookies the agent can reach. Treat a domain allowlist as a navigation rule. If the task moves to a real system, use a test account with read permissions and enforce restrictions on the server. See the browser agent security guide for the risks that come with page instructions and write access.

Diagnose the first failing stage

What you observeWhere to look firstNext check
Browser starts but the fixture gets no requestBrowser location, loopback address, port, navigation rulesOpen the fixture from the same environment that runs Chromium
The provider rejects the requestKey, endpoint, adapter, model accessCheck the provider error before changing browser settings
History records action validation errorsModel adapter and Browser Use versionRun the same task with a documented adapter
Output parses but a value differsWhat the browser saw and what the model copiedCompare each field to the HTML and request log

A remote CDP issue describes a session hanging on browser protocol calls. That report concerns a different failure stage from action parsing, and both reports describe particular versions. Use the error from your own run to decide where to start.

When a task can create records or send messages, treat a timeout as an unknown outcome. Check the destination before retrying. For a read-only fixture, you can repeat the request and inspect the log without changing account data.

When to keep this in Python

Keep Browser Use in Python when a job needs typed fields that your program can check and consume. A fixed browser script fits better when the URL and selectors are already stable and the task has an exact sequence. For a one-off inspection of the fixture, opening the tab and comparing the visible text is enough. The Tabbit and Browser Use comparison and the guide to agentic browsers explain the difference between a browser interface and a Python integration.

For a first run, stop when the fixture is reachable and both fields match. If you change the browser, provider, or target later, change one at a time and run the same checks again.

FAQ

Do I need a Browser Use API key to use the Python library?

The ChatBrowserUse adapter in this example needs a Browser Use API key. Other documented adapters have their own configuration, and a local Ollama server can run without that key.

Can Browser Use run with a local Ollama model?

Yes. The supported models guide documents ChatOllama, but check that your specific model can produce both browser actions and the requested final schema.

How do I make the first task read-only?

Serve a local fixture with no write endpoints or account access. Keep the browser profile separate and enforce permissions on the server if you later use a real application.

Why does the remote browser fail to reach localhost?

The loopback address points to the remote browser host. Run the fixture and browser on the same machine for this tutorial, or provide a separately reachable test endpoint.

What does history.is_successful() tell me?

It reports the agent's assessment of its run. Check the destination and returned values independently before treating the task as complete.

What should I check if structured_output is empty?

Read the agent history for navigation, provider, and action errors. Confirm that the run reached completion with output_model_schema set before changing the schema or step limit.

Take the next step

Let Tabbit work alongside you.

Research across tabs, automate repetitive browser work, and keep every piece of context within reach.