from browser_use import Tools, Agent, ActionResulttools = Tools()@tools.action(description='Ask human for help with a question')async def ask_human(question: str) -> ActionResult: answer = input(f'{question} > ') return ActionResult(extracted_content=f'The human responded with: {answer}')
agent = Agent(task='...', llm=llm, tools=tools)
description(required) - What the tool does, the LLM uses this to decide when to call it.
allowed_domains - List of domains where tool can run (e.g. ['*.example.com']), defaults to all domains
The Agent fills your function parameters based on their names, type hints, & defaults.
Common Pitfall: Parameter names must match exactly! Use browser_session: BrowserSession (not browser: Browser).
The agent injects special parameters by name matching, so using incorrect names will cause your tool to fail silently.
See Available Objects below for the correct parameter names.
The Python library can also import tools from an external MCP server.
This extends a Browser Use agent; it is different from running Browser Use as an MCP server.Install uv and Browser Use, and set BROWSER_USE_API_KEY for the agent’s model.
Warm the reference time server’s package cache before connecting:
tool_filter uses the server’s original names. prefix changes the names the agent sees and avoids collisions with built-in actions, which remain available.
Keep the connection open until the agent finishes, then disconnect it. Create a fresh client for a new run.The current client launches local stdio servers, has a roughly 10-second connection budget, and reads one tools/list response. It does not yet discover tools on later catalog pages or connect directly to HTTP/SSE endpoints.
Only run trusted servers: their subprocesses execute on your machine, and their tools may have side effects.
The time lookup itself needs no model key; running the agent above uses your configured model and may incur model charges.
You can use browser_session to directly interact with page elements using CSS selectors:
from browser_use import Tools, Agent, ActionResult, BrowserSessiontools = Tools()@tools.action(description='Click the submit button using CSS selector')async def click_submit_button(browser_session: BrowserSession): # Get the current page page = await browser_session.must_get_current_page() # Get element(s) by CSS selector elements = await page.get_elements_by_css_selector('button[type="submit"]') if not elements: return ActionResult(extracted_content='No submit button found') # Click the first matching element await elements[0].click() return ActionResult(extracted_content='Submit button clicked!')
Available methods on Page:
get_elements_by_css_selector(selector: str) - Returns list of matching elements
get_element_by_prompt(prompt: str, llm) - Returns element or None using LLM
must_get_element_by_prompt(prompt: str, llm) - Returns element or raises error
import jsonfrom pydantic import BaseModel, Fieldfrom browser_use import Toolstools = Tools()class Cars(BaseModel): name: str = Field(description='The name of the car, e.g. "Toyota Camry"') price: int = Field(description='The price of the car as int in USD, e.g. 25000')@tools.action(description='Save cars to file')def save_cars(cars: list[Cars]) -> str: with open('cars.json', 'w') as f: json.dump(cars, f) return f'Saved {len(cars)} cars to file'task = "find cars and save them to file"
@tools.action( description='Fill out banking forms', allowed_domains=['https://mybank.com'])def fill_bank_form(account_number: str) -> str: # Only works on mybank.com return f'Filled form for account {account_number}'
For a comprehensive example of custom tools with Playwright integration, see:
Playwright Integration ExampleThis shows how to create custom actions that use Playwright’s precise browser automation alongside Browser-Use.
from browser_use import Tools, ActionResult, Browser@tools.action('My action')def my_action(browser: Browser) -> ActionResult: # WRONG! # This will NOT receive the browser session pass
from browser_use import Tools, ActionResult, BrowserSession@tools.action('My action')async def my_action(browser_session: BrowserSession) -> ActionResult: # CORRECT! page = await browser_session.must_get_current_page() # Now you have access to the browser return ActionResult(extracted_content='Done')