> SpecStream is the live web data engine for teams and agents. This is the Markdown copy of https://specstream.ai/docs/integrations/browser-use. Every page, with what SpecStream does and costs: https://specstream.ai/llms.txt

# Browser Use

Give a browser-use agent a SpecStream search tool with `@tools.action`. The agent searches the live web in one call from your own process, gets an answer with the page it was read from, and opens only the pages it needs in the browser.

[SpecStream for Browser UseAgent frameworks & builders](https://specstream.ai/integrations/browser-use.md)

## What you need

-   Python 3.11 or newer and browser-use 1.0, with a model it can run: your Browser Use key or your own model's key.
-   A SpecStream account. New accounts start with $10 of credit, no card. [Create one](https://specstream.ai/signup?utm_source=browser-use).

1.  1

    ## 1. Install browser-use and httpx

    browser-use changes quickly, so its quickstart pins the exact version. httpx makes the calls to SpecStream.

    Terminal

    ```bash
    pip install 'browser-use==1.0.2' httpx
    ```

2.  2

    ## 2. Create a SpecStream key

    Open the [Search API screen](https://specstream.ai/workspace/search?utm_source=browser-use&utm_medium=howto) of your SpecStream workspace and create a key. A key that searches needs the `finds:spend` scope and a spending limit above 0. Keep it in an environment variable where the agent runs:

    Terminal

    ```bash
    export SPECSTREAM_API_KEY="YOUR_SPECSTREAM_API_KEY"
    ```

3.  3

    ## 3. Register the search tool

    `@tools.action` turns a function into a tool the model can call next to its Python REPL. The parameter `q` becomes the tool's argument, and the description tells the model when to use it. Pass the `Tools()` object to the `Agent` as `tools`:

    agent.py

    ```python
    import os
    
    import httpx
    from browser_use import Agent, Tools
    
    tools = Tools()
    SPECSTREAM = "https://api.specstream.ai/v1"
    HEADERS = {"Authorization": f"Bearer {os.environ['SPECSTREAM_API_KEY']}"}
    
    
    @tools.action("Search the live web. Returns the answer when the pages print one, and the top 10 results with title, URL, snippet and date.")
    async def specstream_search(q: str) -> dict:
        async with httpx.AsyncClient(timeout=60) as client:
            r = await client.get(f"{SPECSTREAM}/web-search", params={"q": q, "num": 10}, headers=HEADERS)
            r.raise_for_status()
        data = r.json()["data"]
        return {
            "answer": data.get("answer"),
            "results": [
                {"title": s.get("title"), "url": s["url"], "snippet": s.get("snippet"), "published": s.get("published")}
                for s in data["sources"]
            ],
        }
    
    
    agent = Agent(
        "Find the latest stable PostgreSQL release and the date it came out. Use specstream_search first, then open the release notes.",
        tools=tools,
    )
    print(agent.run_sync().final_result())
    ```

4.  4

    ## 4. Run the agent

    Run `python agent.py`. When the task needs a fact or a page the agent does not know yet, it calls `specstream_search` and opens the results it chooses in the browser.

    If a call fails, `raise_for_status` raises and the model gets the error. A tool that raises does not end the run, so the model can try again with other words.

    Terminal

    ```bash
    python agent.py
    ```

## What the agent gets back

`answer` is filled when the pages print a value that answers the question: the value as the page prints it, the `page` it was read from, the other pages that print it in `sources`, and the read time in `seen_at`. It is `null` when no page prints one.

`results` are the search results in rank order, each with its `title`, `url` and `snippet`, and `published` when the page states the day it was published. The tool sends the model these fields only, so each search adds a short reply to the conversation.

Search operators in `q` hold on every result: `site:`, `-site:`, `"phrase"`, `filetype:`, and `after:` or `before:` with a date. The model can write them into its query.

## Read pages without the browser

Add a second tool to `agent.py`, above the `Agent`, and the agent reads up to 20 pages in one call as Markdown, PDFs and Word files included. A page that refuses a plain read is tried as a browser would ask for it, then in a real browser, then from the site's own feed, then from its newest public archive capture. Each result's `status` is `ok`, `blocked`, `not_found`, `empty`, `unsupported`, `invalid_url` or `failed`.

## SpecStream search or Agent(web\_search=True)

browser-use 1.0 has its own search helper, off by default. `Agent(web_search=True)` gives the agent `search(query, num_results=None, category=None)`, billed per search to your Browser Use key. Each hit is one text entry with its title, URL and matching excerpts, `num_results` is 8 by default and 20 at most, and the agent opens pages in the browser for their full content.

The helper can't be combined with `Browser(allowed_domains=...)`: `run()` raises a `ValueError` before any browser starts. browser-use raises that error for `web_search` only. A function registered with `@tools.action` runs in your own process with only the arguments the model passes, so the browser keeps its `allowed_domains`.

The SpecStream tool returns an answer with the page it was read from when the pages print one, a `published` date where the page states it, and search operators that hold on every result. The Extract API reads the pages, so the agent needs no browser steps to read a page's text. SpecStream's is the most accurate web search API on SimpleQA Verified and WideSearch: [scores and method](https://specstream.ai/benchmarks.md).

Leave `web_search` off when you register the SpecStream tool, so the agent has one search tool and one bill for it.

## Cost

Each `specstream_search` call asks for 10 results and costs $5 per 1,000 searches. A call that returns no results costs nothing, and the reply's `price_usd` is what the call cost. Each page the Extract API reads costs $0.80 per 1,000 pages, and a page with no text is not charged. Both come out of your SpecStream balance with no quote and no approval, and a call past the key's spending limit is refused with `403`. Your model and browser are billed as before. See [pricing](https://specstream.ai/pricing.md).

## For a list of many records

When the task is a list, every match with the same facts on each, [Deep Search](https://specstream.ai/deep-search.md) returns it as structured rows with the source URL and read time on every value. [Agent frameworks](https://specstream.ai/docs/frameworks.md) shows how to call it from your own code.

## Remove

Delete the `@tools.action` functions, or create the `Agent` without `tools`. To stop the key working everywhere, revoke it in **Agents & API** in your workspace. Questions go to [support@specstream.ai](mailto:support@specstream.ai).

## More

[SpecStream for Browser Use](https://specstream.ai/integrations/browser-use.md) covers what it does in Browser Use on one page. Every other tool has its guide in [Connect your tools](https://specstream.ai/docs/integrations.md). You see the most a request can cost before it starts, and the matches are paid from your balance. [Billing](https://specstream.ai/docs/billing.md) has the details. For help, email [support@specstream.ai](mailto:support@specstream.ai).
