# Browser Use Open Source β Full Documentation
# Browser Use Open Source
Source: https://docs.browser-use.com/open-source/introduction
[Human Quickstart](https://docs.browser-use.com/open-source/quickstart)
Install and run your first agent.
[Prompts for Vibecoders](https://docs.browser-use.com/open-source/vibecoding)
Full SDK reference in a single page.
Try [Browser Use Cloud](https://docs.browser-use.com/cloud/introduction) for our SOTA model, stealth browsers, CAPTCHA solving, and managed infrastructure.
# Human Quickstart
Source: https://docs.browser-use.com/open-source/quickstart
To get started with Browser Use you need to install the package and create an `.env` file with your API key.
`ChatBrowserUse` offers the [fastest and most cost-effective models](https://browser-use.com/posts/speed-matters/), completing tasks 3-5x faster. New users get 5 free tasks. Get your API key [here](https://cloud.browser-use.com/new-api-key).
## 1. Installing Browser-Use
```bash create environment
pip install uv
uv venv --python 3.12
```
```bash activate environment
source .venv/bin/activate
# On Windows use `.venv\Scripts\activate`
```
```bash install browser-use & chromium
uv pip install browser-use
uvx browser-use install
```
## 2. Choose your favorite LLM
Create a `.env` file and add your API key.
We recommend using ChatBrowserUse which is optimized for browser automation tasks (highest accuracy + fastest speed + lowest token cost). Get your API key [here](https://cloud.browser-use.com/new-api-key) β new users get 5 free tasks.
```bash .env
touch .env
```
Then add your API key to the file.
```bash Browser Use
# add your key to .env file
BROWSER_USE_API_KEY=
# Get your API key at https://cloud.browser-use.com/new-api-key - new users get 5 free tasks
```
```bash Google
# add your key to .env file
GOOGLE_API_KEY=
# Get your free Gemini API key from https://aistudio.google.com/app/u/1/apikey?pli=1.
```
```bash OpenAI
# add your key to .env file
OPENAI_API_KEY=
```
```bash Anthropic
# add your key to .env file
ANTHROPIC_API_KEY=
```
See [Supported Models](/open-source/supported-models) for more.
## 3. Run your first agent
```python Browser Use
from browser_use import Agent, ChatBrowserUse
from dotenv import load_dotenv
import asyncio
load_dotenv()
async def main():
llm = ChatBrowserUse()
task = "Find the number 1 post on Show HN"
agent = Agent(task=task, llm=llm)
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
```
```python Google
from browser_use import Agent, ChatGoogle
from dotenv import load_dotenv
import asyncio
load_dotenv()
async def main():
llm = ChatGoogle(model="gemini-flash-latest")
task = "Find the number 1 post on Show HN"
agent = Agent(task=task, llm=llm)
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
```
```python OpenAI
from browser_use import Agent, ChatOpenAI
from dotenv import load_dotenv
import asyncio
load_dotenv()
async def main():
llm = ChatOpenAI(model="gpt-4.1-mini")
task = "Find the number 1 post on Show HN"
agent = Agent(task=task, llm=llm)
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
```
```python Anthropic
from browser_use import Agent, ChatAnthropic
from dotenv import load_dotenv
import asyncio
load_dotenv()
async def main():
llm = ChatAnthropic(model='claude-sonnet-4-0', temperature=0.0)
task = "Find the number 1 post on Show HN"
agent = Agent(task=task, llm=llm)
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
```
## 4. Going to Production
Sandboxes are the **easiest way to run Browser-Use in production**. We handle agents, browsers, persistence, auth, cookies, and LLMs. It is also the **fastest way to deploy** - the agent runs right next to the browser, so latency is minimal.
To run in production with authentication, add `@sandbox` to your function:
```python
import asyncio
from browser_use import Browser, sandbox, ChatBrowserUse
from browser_use.agent.service import Agent
@sandbox(cloud_profile_id='your-profile-id')
async def production_task(browser: Browser):
agent = Agent(
task="Your authenticated task",
browser=browser,
llm=ChatBrowserUse(),
)
await agent.run()
if __name__ == "__main__":
asyncio.run(production_task())
```
See [Browser Use Cloud](https://docs.browser-use.com/cloud/quickstart) for how to sync your cookies to the cloud.
# Prompts for Vibecoders
Source: https://docs.browser-use.com/open-source/vibecoding
1. Copy all content [π from here](https://github.com/browser-use/browser-use/blob/main/AGENTS.md) (~9k tokens)
2. Paste it into your project
3. Prompt your coding agent (Cursor, Claude, etc.) "Help me get started with Browser Use"
# Supported Models
Source: https://docs.browser-use.com/open-source/supported-models
Browser Use natively supports 15+ LLM providers. Most providers accept any model string. Check each provider's docs to see which models are available.
> **Which model should I use?** See our [benchmark results and recommendations](https://browser-use.com/posts/what-model-to-use) for detailed comparisons across real-world browser tasks.
### Browser Use [example](https://github.com/browser-use/browser-use/blob/main/examples/models/browser_use_llm.py)
`ChatBrowserUse()` is our optimized in-house model, matching the accuracy of top models while completing tasks **3-5x** faster. [See our blog postβ](https://browser-use.com/posts/speed-matters)
Read the [bu-2-0 model card](/open-source/bu-2-0-model-card) for details on intended use, inputs and outputs, tools, benchmarks, judge setup, and limitations.
```python
from browser_use import Agent, ChatBrowserUse
# Initialize the model - defaults to bu-latest (bu-2-0)
llm = ChatBrowserUse()
# Create agent with the model
agent = Agent(
task="...", # Your task here
llm=llm
)
```
Required environment variables:
```bash .env
BROWSER_USE_API_KEY=
```
Get your API key from the [Browser Use Cloud](https://cloud.browser-use.com/new-api-key). New users get 5 free tasks.
#### Pricing
ChatBrowserUse offers competitive pricing per 1 million tokens:
**bu-2-0 / bu-latest (Default)**
| Token Type | Price per 1M tokens |
|------------|---------------------|
| Input tokens | $0.60 |
| Cached tokens | $0.06 |
| Output tokens | $3.50 |
**bu-1-0**
Since May 20, 2026, `bu-1-0` is priced the same as `bu-2-0`:
| Token Type | Price per 1M tokens |
|------------|---------------------|
| Input tokens | $0.60 |
| Cached tokens | $0.06 |
| Output tokens | $3.50 |
### Google Gemini [example](https://github.com/browser-use/browser-use/blob/main/examples/models/gemini.py) {#google-gemini}
[Available models](https://ai.google.dev/api/models). Also supports Gemma models and Vertex AI via `ChatGoogle(model="...", vertexai=True)`.
`GEMINI_API_KEY` is deprecated and should be named `GOOGLE_API_KEY` as of 2025-05.
```python
from browser_use import Agent, ChatGoogle
from dotenv import load_dotenv
# Read GOOGLE_API_KEY into env
load_dotenv()
# Initialize the model
llm = ChatGoogle(model='gemini-2.5-flash')
# Create agent with the model
agent = Agent(
task="Your task here",
llm=llm
)
```
Required environment variables:
```bash .env
GOOGLE_API_KEY=
```
### OpenAI [example](https://github.com/browser-use/browser-use/blob/main/examples/models/gpt-5-mini.py)
[Available models](https://platform.openai.com/docs/models)
```python
from browser_use import Agent, ChatOpenAI
# Initialize the model
llm = ChatOpenAI(
model="gpt-5",
)
# Create agent with the model
agent = Agent(
task="...", # Your task here
llm=llm
)
```
Required environment variables:
```bash .env
OPENAI_API_KEY=
```
You can use any OpenAI compatible model by passing the model name to the
`ChatOpenAI` class using a custom URL (or any other parameter that would go
into the normal OpenAI API call).
### Anthropic [example](https://github.com/browser-use/browser-use/blob/main/examples/models/claude-4-sonnet.py)
[Available models](https://docs.anthropic.com/en/docs/about-claude/models). Coordinate clicking is automatically enabled for `claude-sonnet-4-*` and `claude-opus-4-*` models.
```python
from browser_use import Agent, ChatAnthropic
# Initialize the model
llm = ChatAnthropic(
model="claude-sonnet-4-6",
)
# Create agent with the model
agent = Agent(
task="...", # Your task here
llm=llm
)
```
And add the variable:
```bash .env
ANTHROPIC_API_KEY=
```
### Azure OpenAI [example](https://github.com/browser-use/browser-use/blob/main/examples/models/azure_openai.py) {#azure-openai}
[Available models](https://learn.microsoft.com/en-us/azure/foundry/foundry-models/concepts/models-sold-directly-by-azure)
```python
from browser_use import Agent, ChatAzureOpenAI
from pydantic import SecretStr
import os
# Initialize the model
llm = ChatAzureOpenAI(
model="o4-mini",
)
# Create agent with the model
agent = Agent(
task="...", # Your task here
llm=llm
)
```
Required environment variables:
```bash .env
AZURE_OPENAI_ENDPOINT=https://your-endpoint.openai.azure.com/
AZURE_OPENAI_API_KEY=
```
#### Using the Responses API (for GPT-5.1 Codex models)
Azure OpenAI now requires `api_version >= 2025-03-01-preview` for certain models like `gpt-5.1-codex-mini`.
These models only support the [Responses API](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/responses) instead of the Chat Completions API.
Browser Use automatically detects and uses the Responses API for these models:
- `gpt-5.1-codex`, `gpt-5.1-codex-mini`, `gpt-5.1-codex-max`
- `gpt-5-codex`, `codex-mini-latest`
- `computer-use-preview`
```python
from browser_use import Agent, ChatAzureOpenAI
# Auto-detection (recommended) - uses Responses API for gpt-5.1-codex-mini
llm = ChatAzureOpenAI(
model="gpt-5.1-codex-mini",
api_version="2025-03-01-preview", # Required for Responses API
)
# Or explicitly enable/disable Responses API for any model
llm = ChatAzureOpenAI(
model="gpt-4o",
api_version="2025-03-01-preview",
use_responses_api=True, # Force Responses API (True/False/'auto')
)
agent = Agent(
task="...",
llm=llm
)
```
The `use_responses_api` parameter accepts:
- `'auto'` (default): Automatically uses Responses API for models that require it
- `True`: Force use of the Responses API
- `False`: Force use of the Chat Completions API
### AWS Bedrock [example](https://github.com/browser-use/browser-use/blob/main/examples/models/aws.py) {#aws-bedrock}
[Available models](https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html). AWS Bedrock provides access to multiple model providers through a single API. We support both a general AWS Bedrock client and provider-specific convenience classes. Install with `pip install "browser-use[aws]"`.
#### General AWS Bedrock (supports all providers)
```python
from browser_use import Agent
from browser_use.llm import ChatAWSBedrock
# Works with any Bedrock model (Anthropic, Meta, AI21, etc.)
llm = ChatAWSBedrock(
model="anthropic.claude-3-5-sonnet-20240620-v1:0", # or any Bedrock model
aws_region="us-east-1",
)
# Create agent with the model
agent = Agent(
task="Your task here",
llm=llm
)
```
#### Anthropic Claude via AWS Bedrock (convenience class)
```python
from browser_use import Agent
from browser_use.llm import ChatAnthropicBedrock
# Anthropic-specific class with Claude defaults
llm = ChatAnthropicBedrock(
model="anthropic.claude-3-5-sonnet-20240620-v1:0",
aws_region="us-east-1",
)
# Create agent with the model
agent = Agent(
task="Your task here",
llm=llm
)
```
#### AWS Authentication
Required environment variables:
```bash .env
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
```
You can also use AWS profiles or IAM roles instead of environment variables. The implementation supports:
- Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION`)
- AWS profiles and credential files
- IAM roles (when running on EC2)
- Session tokens for temporary credentials
- AWS SSO authentication (`aws_sso_auth=True`)
## Groq [example](https://github.com/browser-use/browser-use/blob/main/examples/models/llama4-groq.py) {#groq}
[Available models](https://console.groq.com/docs/models)
```python
from browser_use import Agent, ChatGroq
llm = ChatGroq(model="meta-llama/llama-4-maverick-17b-128e-instruct")
agent = Agent(
task="Your task here",
llm=llm
)
```
Required environment variables:
```bash .env
GROQ_API_KEY=
```
## Oracle Cloud Infrastructure (OCI) [example](https://github.com/browser-use/browser-use/blob/main/examples/models/oci_models.py) {#oci}
[Available models](https://docs.oracle.com/en-us/iaas/Content/generative-ai/imported-models.htm). OCI provides access to various generative AI models including Meta Llama, Cohere, and other providers through their Generative AI service. Install with `pip install "browser-use[oci]"`.
```python
from browser_use import Agent, ChatOCIRaw
# Initialize the OCI model
llm = ChatOCIRaw(
model_id="ocid1.generativeaimodel.oc1.us-chicago-1.amaaaaaask7dceya...",
service_endpoint="https://inference.generativeai.us-chicago-1.oci.oraclecloud.com",
compartment_id="ocid1.tenancy.oc1..aaaaaaaayeiis5uk2nuubznrekd...",
provider="meta", # or "cohere"
temperature=0.7,
max_tokens=800,
top_p=0.9,
auth_type="API_KEY",
auth_profile="DEFAULT"
)
# Create agent with the model
agent = Agent(
task="Your task here",
llm=llm
)
```
Required setup:
1. Set up OCI configuration file at `~/.oci/config`
2. Have access to OCI Generative AI models in your tenancy
3. Install the OCI Python SDK: `uv add oci` or `pip install oci`
Authentication methods supported:
- `API_KEY`: Uses API key authentication (default)
- `INSTANCE_PRINCIPAL`: Uses instance principal authentication
- `RESOURCE_PRINCIPAL`: Uses resource principal authentication
## Ollama
[Available models](https://ollama.com/library).
1. Install Ollama: https://github.com/ollama/ollama
2. Run `ollama serve` to start the server
3. In a new terminal, install the model you want to use: `ollama pull llama3.1:8b` (this has 4.9GB)
```python
from browser_use import Agent, ChatOllama
llm = ChatOllama(model="llama3.1:8b")
```
## Langchain
[Example](https://github.com/browser-use/browser-use/blob/main/examples/models/langchain) on how to use Langchain with Browser Use.
## Qwen [example](https://github.com/browser-use/browser-use/blob/main/examples/models/qwen.py)
Currently, only `qwen-vl-max` is recommended for Browser Use. Other Qwen models, including `qwen-max`, have issues with the action schema format.
Smaller Qwen models may return incorrect action schema formats (e.g., `actions: [{"navigate": "google.com"}]` instead of `[{"navigate": {"url": "google.com"}}]`). If you want to use other models, add concrete examples of the correct action format to your prompt.
```python
from browser_use import Agent, ChatOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
# Get API key from https://modelstudio.console.alibabacloud.com/?tab=playground#/api-key
api_key = os.getenv('ALIBABA_CLOUD')
base_url = 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
llm = ChatOpenAI(model='qwen-vl-max', api_key=api_key, base_url=base_url)
agent = Agent(
task="Your task here",
llm=llm,
use_vision=True
)
```
Required environment variables:
```bash .env
ALIBABA_CLOUD=
```
## ModelScope [example](https://github.com/browser-use/browser-use/blob/main/examples/models/modelscope_example.py)
```python
from browser_use import Agent, ChatOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
# Get API key from https://www.modelscope.cn/docs/model-service/API-Inference/intro
api_key = os.getenv('MODELSCOPE_API_KEY')
base_url = 'https://api-inference.modelscope.cn/v1/'
llm = ChatOpenAI(model='Qwen/Qwen2.5-VL-72B-Instruct', api_key=api_key, base_url=base_url)
agent = Agent(
task="Your task here",
llm=llm,
use_vision=True
)
```
Required environment variables:
```bash .env
MODELSCOPE_API_KEY=
```
### Vercel AI Gateway [example](https://github.com/browser-use/browser-use/blob/main/examples/models/vercel_ai_gateway.py) {#vercel}
[Available models](https://vercel.com/ai-gateway/models). Vercel AI Gateway provides an OpenAI-compatible API endpoint that acts as a proxy to various AI providers, with features like rate limiting, caching, and monitoring.
```python
from browser_use import Agent, ChatVercel
from dotenv import load_dotenv
import os
load_dotenv()
# Get API key (https://vercel.com/ai-gateway)
api_key = os.getenv('VERCEL_API_KEY')
if not api_key:
raise ValueError('VERCEL_API_KEY is not set')
# Basic usage
llm = ChatVercel(
model='openai/gpt-4o',
api_key=api_key,
)
# With provider options - control which providers are used and in what order
# This will try Vertex AI first, then fall back to Anthropic if Vertex fails
llm_with_provider_options = ChatVercel(
model='anthropic/claude-sonnet-4',
api_key=api_key,
provider_options={
'gateway': {
'order': ['vertex', 'anthropic'] # Try Vertex AI first, then Anthropic
}
},
)
agent = Agent(
task="Your task here",
llm=llm
)
```
Required environment variables:
```bash .env
VERCEL_API_KEY=
```
## DeepSeek [example](https://github.com/browser-use/browser-use/blob/main/examples/models/deepseek-chat.py) {#deepseek}
[Available models](https://api-docs.deepseek.com/quick_start/pricing)
```python
from browser_use import Agent, ChatDeepSeek
llm = ChatDeepSeek(model="deepseek-chat")
agent = Agent(
task="Your task here",
llm=llm
)
```
Required environment variables:
```bash .env
DEEPSEEK_API_KEY=
```
## Mistral [example](https://github.com/browser-use/browser-use/blob/main/examples/models/mistral.py) {#mistral}
[Available models](https://docs.mistral.ai/getting-started/models/models_overview/)
```python
from browser_use import Agent, ChatMistral
llm = ChatMistral(model="mistral-large-latest")
agent = Agent(
task="Your task here",
llm=llm
)
```
Required environment variables:
```bash .env
MISTRAL_API_KEY=
```
## Cerebras [example](https://github.com/browser-use/browser-use/blob/main/examples/models/cerebras_example.py) {#cerebras}
[Available models](https://inference-docs.cerebras.ai/models/overview)
```python
from browser_use import Agent, ChatCerebras
llm = ChatCerebras(model="llama3.3-70b")
agent = Agent(
task="Your task here",
llm=llm
)
```
Required environment variables:
```bash .env
CEREBRAS_API_KEY=
```
## OpenRouter [example](https://github.com/browser-use/browser-use/blob/main/examples/models/openrouter.py) {#openrouter}
[Available models](https://openrouter.ai/models). Access 300+ models from any provider through a single API.
```python
from browser_use import Agent, ChatOpenRouter
llm = ChatOpenRouter(model="anthropic/claude-sonnet-4-6")
agent = Agent(
task="Your task here",
llm=llm
)
```
Required environment variables:
```bash .env
OPENROUTER_API_KEY=
```
## LiteLLM {#litellm}
Requires separate install (`pip install litellm`). Supports any [LiteLLM model string](https://docs.litellm.ai/docs/providers) β useful when you need a provider not covered by the native integrations above.
```python
from browser_use import Agent
from browser_use.llm.litellm import ChatLiteLLM
llm = ChatLiteLLM(model="openai/gpt-5")
agent = Agent(
task="Your task here",
llm=llm
)
```
## Other OpenAI-Compatible Providers
Any provider with an OpenAI-compatible endpoint works via `ChatOpenAI` with a custom `base_url`:
**Examples available:**
- [Novita](https://github.com/browser-use/browser-use/blob/main/examples/models/novita.py)
# Browser Use CLI
Source: https://docs.browser-use.com/open-source/browser-use-cli
The Browser Use CLI (`browser-use`) gives coding agents a direct browser-control surface backed by [Browser Harness](https://github.com/browser-use/browser-harness):
- **Direct browser control** β agents run Python to do actions in the browser.
- **Three browser modes** β you can use with local Chrome or Chromium with your existing tabs, cookies, extensions, and logins; Browser Use cloud browsers; or any browser reachable through a CDP endpoint.
- **Agent-ready setup** β install the skill into Claude Code, Codex, and other coding agents so they know when and how to call the CLI.
Try out Browser Use CLI with an agent in [Browser Use Cloud](https://cloud.browser-use.com?utm_source=docs&utm_medium=browser-use-cli&utm_campaign=v4), or install the skill to try it yourself locally.
## Install the CLI
```bash
uv tool install browser-use
browser-use --help
```
For one-off runs without a permanent tool install, use `uvx browser-use`.
## Set Up Your Agent
Paste this setup prompt into Claude Code, Codex, or another coding agent:
```text
Install or upgrade browser-use with `uv tool install --python 3.12 --upgrade --force 'browser-use @ git+https://github.com/browser-use/browser-use.git'`, run `browser-use skill install`, and connect it to my browser. Follow https://github.com/browser-use/browser-use if setup or connection fails.
```
The skill is discoverable from [skills.sh](https://skills.sh/browser-use/browser-use/browser-use).
## Use Python Directly
Pass Python to the CLI. Use `uvx browser-use` for one-off runs, or `browser-use` if you installed it:
```bash
uvx browser-use <<'PY'
new_tab("https://example.com")
print(page_info())
PY
```
The `<<'PY'` form is for Unix-compatible shells such as bash, zsh, Git Bash, or WSL. In PowerShell, pipe a here-string instead:
```powershell
@'
new_tab("https://example.com")
print(page_info())
'@ | uvx browser-use
```
## Local Browser Setup
The default local flow attaches to your running Chrome or Chromium through CDP. This preserves the browser state the user already has locally: open tabs, cookies, extensions, and logged-in sessions. It is the right default for desktop work where the user can approve Chrome's remote-debugging prompt.
You can also point the CLI at any existing CDP browser by setting `BU_CDP_URL` or `BU_CDP_WS` before running `browser-use`. Use that for managed Chrome instances, Playwright-launched browsers, or infrastructure that already exposes a DevTools endpoint.
If the CLI cannot connect, run:
```bash
browser-use --doctor
```
If Chrome asks whether to allow remote debugging, approve it and rerun the command.
## Cloud Browsers
Use Browser Use cloud browsers when the agent runs on a headless machine, needs an isolated browser, needs parallel browser sessions, or needs Browser Use Cloud features such as persistent cloud profiles, proxy routing, CAPTCHA handling, and live browser viewing.
The Browser Harness-backed CLI keeps cloud sessions explicit. You authenticate once, start a named cloud browser, then use that name for later commands:
```bash
browser-use auth login
```
```bash
browser-use <<'PY'
start_remote_daemon("work")
PY
BU_NAME=work browser-use <<'PY'
new_tab("https://example.com")
print(page_info())
PY
```
Use short, task-specific names when you have multiple agents or sub-agents running in parallel. Each name maps to its own remote browser daemon.
Remote browsers bill until they stop or time out. When the task is done, ask whether to close the browser; if yes, run:
```bash
BU_NAME=work browser-use <<'PY'
stop_remote_daemon("work")
PY
```
## Useful Commands
```bash
browser-use --help
browser-use --doctor
browser-use auth login
browser-use auth status
browser-use skill show
browser-use telemetry status
```
# Browser Use Terminal
Source: https://docs.browser-use.com/open-source/browser-use-terminal
Browser Use Terminal is a Codex-style assistant for the browser.
Coding assistants like Claude Code and Codex work well because they give the model autonomy and a real environment to operate in. They provide tools, files, shell commands, history, resumable sessions, and a terminal UI where you can watch and steer the work.
Browser Use Terminal brings that pattern to browser automation. It gives an AI agent its own browser environment: it can control Chrome, see screenshots, inspect pages, run page JavaScript, save files, use browser profiles, handle secrets, and keep a history of what happened.
Learn more on the [Browser Use Terminal site](https://browser-use.com/terminal?utm_source=docs) or view the [Terminal GitHub repo](https://github.com/browser-use/terminal?utm_source=docs).
In practice, this means you can ask for browser work from your terminal:
```text
Find the cancellation policy for my current hotel reservation.
```
```text
Give this employee admin permission in Azure.
```
```text
Research the top Hacker News stories and summarize the points.
```
You can use Browser Use Terminal in four ways:
| Surface | What it is for |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **TUI** | The interactive terminal app you launch with `browser`. Best for normal, hands-on use. |
| **CLI** | Scriptable commands such as `browser-use-terminal run-openai`. Best for automation and one-off tasks. |
| **Python** | `browser_use.beta.Agent`, backed by the same Rust runtime. Best when you want browser-use code with terminal runtime behavior. |
| **Coding assistants** | A skill plus the `browser-use-terminal browser` commands let Claude Code, Codex, OpenCode, and other agents drive the browser. See [Use From Coding Assistants](#use-from-coding-assistants). |
Browser Use Terminal is separate from the lower-level `browser-use` CLI. Use
`browser` for the Terminal TUI, `browser-use-terminal` for Terminal task
commands, and `browser-use` for direct browser-control commands.
## Terms
- **TUI**: terminal user interface. This is the interactive app you open with `browser`.
- **CLI**: command-line interface. These are scriptable commands such as `browser-use-terminal run-openai`.
- **Headless browser**: a browser that runs without a visible window.
- **CDP**: Chrome DevTools Protocol. This lets Browser Use connect to an existing Chrome instance.
- **MCP**: Model Context Protocol. This lets the agent use tools from external MCP servers.
- **TOTP**: time-based one-time password. This is the six-digit code generated by authenticator apps for 2FA.
## Install
Install Browser Use Terminal:
```bash
curl -fsSL https://browser-use.com/terminal/install.sh | sh
```
Restart your shell or source your shell profile if the installer updates your `PATH`.
Verify the two terminal executables:
```bash
which browser
which browser-use-terminal
browser-use-terminal --help
```
Open the TUI:
```bash
browser
```
Set up Python usage in the same project where you will write your agent code:
```bash
uv venv --python 3.12
source .venv/bin/activate
uv pip install browser-use
```
## TUI Commands
In the TUI, type `/` to open the command palette. These are the main commands:
| Command | What it does |
| ------------------- | ----------------------------------------------------------------- |
| `/task` | Start a new task. |
| `/model` | Choose the model and provider. |
| `/auth` | Sign in to a provider. |
| `/browser` | Change the browser backend. |
| `/profile` | Choose the default Chrome profile. |
| `/history` | Browse previous tasks. |
| `/context` | Inspect context window attribution. |
| `/secrets` | Save passwords and 2FA setup keys for website logins. |
| `/import-passwords` | Import saved logins from 1Password. |
| `/domains` | Allow or block which sites the agent can visit. |
| `/sync-cookies` | Sync local cookies. |
| `/email` | Give the agent a disposable inbox for sign-ups, links, and codes. |
| `/goal` | Set or view the goal for a long-running task. |
| `/feedback` | Report a bug or share feedback. |
| `/update` | Install the latest release. |
| `/reload` | Restart the UI in this terminal. |
| `/exit` | Quit Browser Use Terminal. |
## Run Browser Tasks
### TUI
The TUI is the main Browser Use Terminal experience:
```bash
browser
```
Type a browser task. You can watch the agent work, interrupt it, steer it, and continue the same session later.
```text
Open my company's dashboard and summarize failed jobs from today.
```
```text
Log in to the vendor portal and download the latest invoice.
```
### CLI
Use one-shot commands for scripts, automation, and quick tasks:
```bash
browser-use-terminal --help
```
```bash
browser-use-terminal run-openai --model gpt-5.5 \
"Go to https://news.ycombinator.com and return the top stories with points"
```
Other provider commands:
```bash
browser-use-terminal run-anthropic --model claude-sonnet-4-6 "Research Browser Use"
browser-use-terminal run-openrouter --model openai/gpt-5.5 "Research Browser Use"
browser-use-terminal run-deepseek --model deepseek-v4-pro "Research Browser Use"
```
### Python
Use `browser_use.beta.Agent` to run Python code on top of the Rust terminal runtime:
```bash
uv pip install browser-use
```
```python
import asyncio
from browser_use.beta import Agent, BrowserProfile, ChatOpenAI
async def main():
agent = Agent(
task="Go to https://news.ycombinator.com and return the top stories with points.",
llm=ChatOpenAI(model="gpt-5.5"),
browser_profile=BrowserProfile(
headless=True,
window_size={"width": 1440, "height": 900},
allowed_domains=["news.ycombinator.com"],
),
)
history = await agent.run(max_steps=12)
print(history.final_result())
asyncio.run(main())
```
## Use From Coding Assistants
Browser Use Terminal plugs into any coding assistant that can run shell commands. A skill teaches the assistant the CLI, and the CLI gives it the full browser runtime: page interaction through Python helpers, screenshots saved as files, profiles, and more.
The fastest setup is to paste this URL into your assistant and let it bootstrap everything (install, skill registration, browser setup, verification):
```text
https://browser-use.com/skill
```
To set it up manually instead:
```bash
curl -fsSL https://browser-use.com/terminal/install.sh | sh
browser-use-terminal skill install
```
`skill install` writes the skill into every detected assistant home: `~/.claude/skills/` (Claude Code, also read by OpenCode), `~/.codex/skills/` (Codex), `~/.config/opencode/skills/`, and `~/.agents/skills/`. For other assistants, persist the output of `browser-use-terminal skill show` wherever that assistant reads instructions.
The assistant then drives the browser with commands:
```bash
browser-use-terminal browser exec <<'PY'
new_tab("https://example.com")
wait_for_load()
print(page_info()["title"])
print(capture_screenshot())
PY
```
How it works:
- The browser auto-connects per the remembered preference (`browser-use-terminal browser preference use local|cloud|managed-headless`) and persists across invocations; Python variables do not.
- Screenshots are saved as files and the absolute path is printed, so assistants view them with their native file tools: Claude Code `Read`, Codex `view_image`, OpenCode `read`, Gemini CLI `read_file`.
- `--session ` gives parallel workstreams isolated artifact dirs, event logs, and managed browsers.
- Stop persistent browsers with `browser-use-terminal browser recover stop-owned-browser` (managed) or `browser-use-terminal browser recover stop-owned-remote` (cloud).
- Everything is recorded in the same event log as the TUI: `browser-use-terminal events browser-cli-`.
## Configure Models
### TUI
Use `/auth` to sign in and configure credentials, then `/model` to choose the model:
```text
/auth
/model
```
This is the recommended setup path for normal interactive use.
### CLI
For one-shot commands and CI, set the provider key for the provider command you are using:
```bash
export OPENAI_API_KEY=...
export ANTHROPIC_API_KEY=...
export OPENROUTER_API_KEY=...
export DEEPSEEK_API_KEY=...
export BROWSER_USE_API_KEY=...
```
Then choose a provider command and model:
```bash
browser-use-terminal run-openai --model gpt-5.5 "Research Browser Use"
browser-use-terminal run-anthropic --model claude-sonnet-4-6 "Research Browser Use"
browser-use-terminal run-openrouter --model openai/gpt-5.5 "Research Browser Use"
browser-use-terminal run-deepseek --model deepseek-v4-pro "Research Browser Use"
```
### Python
Pass a supported browser-use model class to `Agent`:
```python
from browser_use.beta import Agent, ChatAnthropic
agent = Agent(
task="Find the latest Browser Use docs update",
llm=ChatAnthropic(model="claude-sonnet-4-6"),
)
```
Supported Python model classes:
| Python model class | Example |
| ------------------ | ------------------------------------------ |
| `ChatOpenAI` | `ChatOpenAI(model="gpt-5.5")` |
| `ChatAnthropic` | `ChatAnthropic(model="claude-sonnet-4-6")` |
| `ChatLiteLLM` | `ChatLiteLLM(model="openai/gpt-5.5")` |
| `ChatDeepSeek` | `ChatDeepSeek(model="deepseek-v4-pro")` |
| `ChatOpenRouter` | `ChatOpenRouter(model="openai/gpt-5.5")` |
## Choose A Browser
### TUI
Use `/browser` to choose how the agent should run the browser:
```text
/browser
```
Common choices are your local Chrome, a headless browser, or Browser Use Cloud.
Browser Use Cloud is the easiest option to get started: it gives you a free, one-click browser setup without managing a local Chrome profile.
Use `/profile` to choose the default Chrome profile:
```text
/profile
```
### CLI
Use terminal config or one-off config overrides for browser settings:
```bash
browser-use-terminal \
--config 'browser.headless=true' \
--config 'browser.window_size={width=1440,height=900}' \
run-openai "Open Hacker News"
```
### Python
Managed local browser:
```python
from browser_use.beta import Agent, BrowserProfile, ChatOpenAI
agent = Agent(
task="Open Hacker News",
llm=ChatOpenAI(model="gpt-5.5"),
browser_profile=BrowserProfile(
headless=True,
user_data_dir="./browser-profile",
window_size={"width": 1280, "height": 900},
),
)
```
Headed browser:
```python
agent = Agent(
task="Open Hacker News",
llm=ChatOpenAI(model="gpt-5.5"),
browser_profile=BrowserProfile(headless=False),
)
```
Browser Use Cloud:
Browser Use Cloud is the simplest remote browser option for Python too. Set `BROWSER_USE_API_KEY`, pass `use_cloud=True`, and the terminal runtime handles the cloud browser session.
```python
from browser_use.beta import Agent, BrowserSession, ChatOpenAI
agent = Agent(
task="Open Hacker News",
llm=ChatOpenAI(model="gpt-5.5"),
browser_session=BrowserSession(
use_cloud=True,
cloud_profile_id="profile-id",
cloud_proxy_country_code="US",
keep_alive=False,
),
)
```
Existing browser over CDP:
```python
from browser_use.beta import Agent, BrowserProfile, ChatOpenAI
agent = Agent(
task="Open Hacker News",
llm=ChatOpenAI(model="gpt-5.5"),
browser_profile=BrowserProfile(
cdp_url="http://127.0.0.1:9333",
user_agent="BrowserUseRemoteCDP/1.0",
),
)
```
## Use Secrets And Login
Secrets let the agent fill credentials without exposing raw values to the model.
### TUI
Use `/auth` for Browser Use account and model-provider authentication:
```text
/auth
```
Use `/secrets` to save website login secrets and 2FA setup keys:
```text
/secrets
```
Inside `/secrets`, press `Ctrl-O` to import logins from 1Password. You can also run:
```text
/import-passwords
```
Name a TOTP secret `otp` and paste the authenticator setup key, not the current six-digit code.
### CLI
Store a password:
```bash
printf '%s' "$PASSWORD" | browser-use-terminal secrets set \
--domain example.com \
--name password \
--stdin
```
Store a TOTP seed for 2FA:
```bash
printf '%s' "$TOTP_SEED" | browser-use-terminal secrets set \
--domain example.com \
--name otp \
--totp \
--stdin
```
Import saved logins from 1Password:
```bash
browser-use-terminal secrets import
browser-use-terminal secrets list
```
The import command uses the `op` CLI. `secrets list` prints metadata only, never secret values.
### Python
Python runs use the same terminal runtime and terminal state. Configure website secrets with the terminal commands above, then run the Python agent against the matching domain.
```python
from browser_use.beta import Agent, BrowserProfile, ChatOpenAI
agent = Agent(
task="Log in to example.com and summarize my dashboard.",
llm=ChatOpenAI(model="gpt-5.5"),
browser_profile=BrowserProfile(allowed_domains=["example.com"]),
)
```
## Restrict Domains
Domain policy controls where the browser can navigate.
### TUI
Use `/domains` to allow or block sites from the TUI:
```text
/domains
```
### CLI
```bash
browser-use-terminal domains allow news.ycombinator.com
browser-use-terminal domains deny '*.tracking.example'
browser-use-terminal domains list
browser-use-terminal domains clear
```
### Python
Pass domain policy through `BrowserProfile`:
```python
from browser_use.beta import BrowserProfile
profile = BrowserProfile(
allowed_domains=["news.ycombinator.com"],
prohibited_domains=["*.tracking.example"],
)
```
## Use MCP Servers
MCP servers add external tools to the agent.
### TUI
Add MCP servers to terminal config, then run the TUI normally:
```bash
browser
```
### CLI
Create an MCP config:
```toml
[mcp_servers.local]
transport = "stdio"
command = "python"
args = ["./server.py"]
```
Pass it when you run a task:
```bash
browser-use-terminal --mcp-config ./mcp.toml run-openai \
"Use the browser and MCP tools to complete this task"
```
### Python
Python terminal-backed runs can use terminal MCP configuration through the same terminal runtime. Configure MCP servers in terminal config before starting the Python run.
## Use Profiles And Config
Profiles let you keep separate terminal settings for different accounts, browsers, models, or workflows.
### TUI
Use `/profile` to choose the default Chrome profile:
```text
/profile
```
Open the terminal with a named terminal config profile:
```bash
browser --profile work
```
### CLI
The terminal reads config from:
```text
$BROWSER_USE_TERMINAL_HOME/config.toml
```
If `BROWSER_USE_TERMINAL_HOME` is not set, it uses:
```text
~/.browser-use-terminal
```
Use a named profile to layer `$BROWSER_USE_TERMINAL_HOME/.config.toml` on top of the base config:
```bash
browser-use-terminal --profile work run-openai "Research this pricing page"
```
Use `--state-dir` for an isolated run:
```bash
browser-use-terminal --state-dir /tmp/browser-use-terminal run-openai \
"Open Hacker News and summarize the front page"
```
### Python
Point Python at a terminal state directory:
```bash
export BROWSER_USE_TERMINAL_HOME=/path/to/state
```
Use a specific terminal binary:
```bash
export BROWSER_USE_TERMINAL_BINARY=/path/to/browser-use-terminal
```
## Troubleshooting Setup
### `browser` Or `browser-use-terminal` Not Found
Restart your terminal, then check whether the install location is on your `PATH`:
```bash
which browser
which browser-use-terminal
echo "$PATH"
```
If the commands are still missing, rerun the installer and copy any `PATH` instructions it prints:
```bash
curl -fsSL https://browser-use.com/terminal/install.sh | sh
```
### Which Command Should I Use?
| Goal | Command |
| ----------------------------------------- | --------------------------------------- |
| Open the interactive Terminal app | `browser` |
| Run a one-shot Terminal agent task | `browser-use-terminal run-openai "..."` |
| Use Terminal runtime from Python | `browser_use.beta.Agent` |
| Drive the browser from a coding assistant | `browser-use-terminal browser exec` |
| Register the skill with coding assistants | `browser-use-terminal skill install` |
| Directly control a browser with Python | `browser-use <<'PY' ... PY` |
### Python Cannot Find `browser_use.beta`
Install or upgrade the Python package in the same environment you are running:
```bash
uv pip install --upgrade browser-use
python -c "from browser_use.beta import Agent; print('ok')"
```
## Forwarded Python Settings
When you use `browser_use.beta.Agent`, these Python settings are forwarded to the Rust terminal SDK:
| Python setting | Terminal SDK field |
| ------------------------------------------------ | ---------------------------- |
| `llm.provider`, inferred from the chat model | `llm.provider` |
| `llm.model` | `llm.model` |
| `llm_timeout` | `llm.timeout` |
| `headless` | `browser.headless` |
| `keep_alive` | `browser.keep_alive` |
| `cloud_profile_id`, `profile_id` | `browser.profile_id` |
| `cloud_proxy_country_code`, `proxy_country_code` | `browser.proxy_country_code` |
| `cdp_url` | `browser.cdp_url` |
| `headers` / CDP headers | `browser.cdp_headers` |
| `user_agent` | `browser.user_agent` |
| `viewport` | `browser.viewport` |
| `window_size` | `browser.window_size` |
| `storage_state` | `browser.storage_state` |
| `downloads_path` | `browser.downloads_path` |
| `allowed_domains` | `browser.allowed_domains` |
| `prohibited_domains` | `browser.blocked_domains` |
| `state_dir` | `browser.state_dir` |
| `no_viewport` | `browser.no_viewport` |
| `accept_downloads` | `browser.accept_downloads` |
| `output_model_schema` | `output_schema` |
| `calculate_cost` | `calculate_cost` |
| `max_actions_per_step` | `max_actions_per_step` |
The same Python `Agent` instance can continue a terminal-backed session across follow-up runs.
### Cloud Browser Setup
Set `BROWSER_USE_API_KEY` and pass the cloud profile or proxy settings through `BrowserSession`.
### 1Password Import Setup
Install and sign in to the 1Password CLI:
```bash
op account list
```
Then import:
```bash
browser-use-terminal secrets import
```
### TOTP Setup
Store the base32 TOTP seed with `--totp`, not the current six-digit code:
```bash
printf '%s' "$BASE32_TOTP_SEED" | browser-use-terminal secrets set \
--domain example.com \
--name otp \
--totp \
--stdin
```
# Configuration
Source: https://docs.browser-use.com/open-source/customize/agent/basics
```python
from browser_use import Agent, ChatBrowserUse
agent = Agent(
task="Search for latest news about AI",
llm=ChatBrowserUse(),
)
async def main():
history = await agent.run(max_steps=100)
```
- `task`: The task you want to automate.
- `llm`: Your favorite LLM. See Supported Models.
The agent is executed using the async `run()` method:
- `max_steps` (default: `100`): Maximum number of steps an agent can take.
Check out all customizable parameters here.
# Prompting Guide
Source: https://docs.browser-use.com/open-source/customize/agent/prompting-guide
Prompting can drastically improve performance and solve existing limitations of the library.
### 1. Be Specific vs Open-Ended
**β Specific (Recommended)**
```python
task = """
1. Go to https://quotes.toscrape.com/
2. Use extract action with the query "first 3 quotes with their authors"
3. Save results to quotes.csv using write_file action
4. Do a google search for the first quote and find when it was written
"""
```
**β Open-Ended**
```python
task = "Go to web and make money"
```
### 2. Name Actions Directly
When you know exactly what the agent should do, reference actions by name:
```python
task = """
1. Use search action to find "Python tutorials"
2. Use click to open first result in a new tab
3. Use scroll action to scroll down 2 pages
4. Use extract to extract the names of the first 5 items
5. Wait for 2 seconds if the page is not loaded, refresh it and wait 10 sec
6. Use send_keys action with "Tab Tab ArrowDown Enter"
"""
```
See [Available Tools](/open-source/customize/tools/available) for the complete list of actions.
### 3. Handle interaction problems via keyboard navigation
Sometimes buttons cannot be clicked (you may have found a bug in the library - open an issue).
In many cases, you can work around this with keyboard navigation.
```python
task = """
If the submit button cannot be clicked:
1. Use send_keys action with "Tab Tab Enter" to navigate and activate
2. Or use send_keys with "ArrowDown ArrowDown Enter" for form submission
"""
```
### 4. Custom Actions Integration
```python
# When you have custom actions
@controller.action("Get 2FA code from authenticator app")
async def get_2fa_code():
# Your implementation
pass
task = """
Login with 2FA:
1. Enter username/password
2. When prompted for 2FA, use get_2fa_code action
3. NEVER try to extract 2FA codes from the page manually
4. ALWAYS use the get_2fa_code action for authentication codes
"""
```
### 5. Error Recovery
```python
task = """
Robust data extraction:
1. Go to openai.com to find their CEO
2. If navigation fails due to anti-bot protection:
- Use google search to find the CEO
3. If page times out, use go_back and try alternative approach
"""
```
The key to effective prompting is being specific about actions.
# Output Format
Source: https://docs.browser-use.com/open-source/customize/agent/output-format
## Agent History
The `run()` method returns an `AgentHistoryList` object with the complete execution history:
```python
history = await agent.run()
# Access useful information
history.urls() # List of visited URLs
history.screenshot_paths() # List of screenshot paths
history.screenshots() # List of screenshots as base64 strings
history.action_names() # Names of executed actions
history.extracted_content() # List of extracted content from all actions
history.errors() # List of errors (with None for steps without errors)
history.model_actions() # All actions with their parameters
history.model_outputs() # All model outputs from history
history.last_action() # Last action in history
# Analysis methods
history.final_result() # Get the final extracted content (last step)
history.is_done() # Check if agent completed successfully
history.is_successful() # Check if agent completed successfully (returns None if not done)
history.has_errors() # Check if any errors occurred
history.model_thoughts() # Get the agent's reasoning process (AgentBrain objects)
history.action_results() # Get all ActionResult objects from history
history.action_history() # Get truncated action history with essential fields
history.number_of_steps() # Get the number of steps in the history
history.total_duration_seconds() # Get total duration of all steps in seconds
# Structured output (when using output_model_schema)
history.structured_output # Property that returns parsed structured output
```
See all helper methods in the [AgentHistoryList source code](https://github.com/browser-use/browser-use/blob/main/browser_use/agent/views.py#L301).
## Structured Output
For structured output, use the `output_model_schema` parameter with a Pydantic model. [Example](https://github.com/browser-use/browser-use/blob/main/examples/features/custom_output.py).
# All Parameters
Source: https://docs.browser-use.com/open-source/customize/agent/all-parameters
## Available Parameters
### Core Settings
- `tools`: Registry of tools the agent can call. Example
- `skills` (or `skill_ids`): List of skill IDs to load (e.g., `['skill-uuid']` or `['*']` for all). Requires `BROWSER_USE_API_KEY`. Docs
- `browser`: Browser object where you can specify the browser settings.
- `output_model_schema`: Pydantic model class for structured output validation. [Example](https://github.com/browser-use/browser-use/blob/main/examples/features/custom_output.py)
### Vision & Processing
- `use_vision` (default: `"auto"`): Vision mode - `"auto"` includes screenshot tool but only uses vision when requested, `True` always includes screenshots, `False` never includes screenshots and excludes screenshot tool
- `vision_detail_level` (default: `'auto'`): Screenshot detail level - `'low'`, `'high'`, or `'auto'`
- `page_extraction_llm`: Separate LLM model for page content extraction. You can choose a small & fast model because it only needs to extract text from the page (default: same as `llm`)
### Fallback & Resilience
- `fallback_llm`: Backup LLM to use when the primary LLM fails. The primary LLM will first exhaust its own retry logic (typically 5 attempts with exponential backoff), and only then switch to the fallback. Triggers on rate limits (429), authentication errors (401), payment/credit errors (402), or server errors (500, 502, 503, 504). Once switched, the fallback is used for the rest of the run. [Example](https://github.com/browser-use/browser-use/blob/main/examples/features/fallback_model.py)
### Actions & Behavior
- `initial_actions`: List of actions to run before the main task without LLM. [Example](https://github.com/browser-use/browser-use/blob/main/examples/features/initial_actions.py)
- `max_actions_per_step` (default: `4`): Maximum actions per step, e.g. for form filling the agent can output 4 fields at once. We execute the actions until the page changes.
- `max_failures` (default: `3`): Maximum retries for steps with errors
- `final_response_after_failure` (default: `True`): If True, attempt to force one final model call with intermediate output after max_failures is reached
- `use_thinking` (default: `True`): Controls whether the agent uses its internal "thinking" field for explicit reasoning steps.
- `flash_mode` (default: `False`): Fast mode that skips evaluation, next goal and thinking and only uses memory. If `flash_mode` is enabled, it overrides `use_thinking` and disables the thinking process entirely. [Example](https://github.com/browser-use/browser-use/blob/main/examples/getting_started/05_fast_agent.py)
### System Messages
- `override_system_message`: Completely replace the default system prompt.
- `extend_system_message`: Add additional instructions to the default system prompt. [Example](https://github.com/browser-use/browser-use/blob/main/examples/features/custom_system_prompt.py)
### File & Data Management
- `save_conversation_path`: Path to save complete conversation history
- `save_conversation_path_encoding` (default: `'utf-8'`): Encoding for saved conversations
- `available_file_paths`: List of file paths the agent can access
- `sensitive_data`: Dictionary of sensitive data to handle carefully. [Example](https://github.com/browser-use/browser-use/blob/main/examples/features/sensitive_data.py)
### Visual Output
- `generate_gif` (default: `False`): Generate GIF of agent actions. Set to `True` or string path
- `include_attributes`: List of HTML attributes to include in page analysis
### Performance & Limits
- `max_history_items`: Maximum number of last steps to keep in the LLM memory. If `None`, we keep all steps.
- `llm_timeout` (default: `90`): Timeout in seconds for LLM calls
- `step_timeout` (default: `120`): Timeout in seconds for each step
- `directly_open_url` (default: `True`): If we detect a url in the task, we directly open it.
### Advanced Options
- `calculate_cost` (default: `False`): Calculate and track API costs
- `display_files_in_done_text` (default: `True`): Show file information in completion messages
### Backwards Compatibility
- `controller`: Alias for `tools` for backwards compatibility.
- `browser_session`: Alias for `browser` for backwards compatibility.
---
## Environment Variables
These environment variables can be used to tune agent and browser behavior without code changes. They are particularly useful for debugging, slow networks, or deployment-level tuning.
### Agent Timeouts
| Variable | Default | Description |
|----------|---------|-------------|
| `TIMEOUT_AgentEventBusStop` | `3.0` | Timeout in seconds for the agent's event bus to finish processing pending events during shutdown. |
### Browser Action Timeouts
| Variable | Default | Description |
|----------|---------|-------------|
| `TIMEOUT_NavigateToUrlEvent` | `15.0` | Timeout for page navigation |
| `TIMEOUT_ClickElementEvent` | `15.0` | Timeout for clicking elements |
| `TIMEOUT_ClickCoordinateEvent` | `15.0` | Timeout for clicking at coordinates |
| `TIMEOUT_TypeTextEvent` | `60.0` | Timeout for typing text (longer for large inputs) |
| `TIMEOUT_ScrollEvent` | `8.0` | Timeout for scrolling |
| `TIMEOUT_ScrollToTextEvent` | `15.0` | Timeout for scrolling to find text |
| `TIMEOUT_SendKeysEvent` | `60.0` | Timeout for sending keyboard shortcuts |
| `TIMEOUT_UploadFileEvent` | `30.0` | Timeout for file uploads |
| `TIMEOUT_GetDropdownOptionsEvent` | `15.0` | Timeout for fetching dropdown options |
| `TIMEOUT_SelectDropdownOptionEvent` | `8.0` | Timeout for selecting dropdown option |
| `TIMEOUT_GoBackEvent` | `15.0` | Timeout for browser back navigation |
| `TIMEOUT_GoForwardEvent` | `15.0` | Timeout for browser forward navigation |
| `TIMEOUT_RefreshEvent` | `15.0` | Timeout for page refresh |
| `TIMEOUT_WaitEvent` | `60.0` | Timeout for explicit wait actions |
| `TIMEOUT_ScreenshotEvent` | `15.0` | Timeout for taking screenshots |
| `TIMEOUT_BrowserStateRequestEvent` | `30.0` | Timeout for fetching browser state/DOM |
### Browser Lifecycle Timeouts
| Variable | Default | Description |
|----------|---------|-------------|
| `TIMEOUT_BrowserStartEvent` | `30.0` | Timeout for starting browser session |
| `TIMEOUT_BrowserStopEvent` | `45.0` | Timeout for stopping browser session |
| `TIMEOUT_BrowserLaunchEvent` | `30.0` | Timeout for launching browser process |
| `TIMEOUT_BrowserKillEvent` | `30.0` | Timeout for killing browser process |
| `TIMEOUT_BrowserConnectedEvent` | `30.0` | Timeout for CDP connection |
| `TIMEOUT_BrowserStoppedEvent` | `30.0` | Timeout for browser stopped confirmation |
| `TIMEOUT_BrowserErrorEvent` | `30.0` | Timeout for browser error events |
### Tab Management Timeouts
| Variable | Default | Description |
|----------|---------|-------------|
| `TIMEOUT_SwitchTabEvent` | `10.0` | Timeout for switching tabs |
| `TIMEOUT_CloseTabEvent` | `10.0` | Timeout for closing tabs |
| `TIMEOUT_TabCreatedEvent` | `30.0` | Timeout for tab creation events |
| `TIMEOUT_TabClosedEvent` | `10.0` | Timeout for tab closed events |
| `TIMEOUT_AgentFocusChangedEvent` | `10.0` | Timeout for focus change events |
| `TIMEOUT_TargetCrashedEvent` | `10.0` | Timeout for crash events |
### Navigation Event Timeouts
| Variable | Default | Description |
|----------|---------|-------------|
| `TIMEOUT_NavigationStartedEvent` | `30.0` | Timeout for navigation started events |
| `TIMEOUT_NavigationCompleteEvent` | `30.0` | Timeout for navigation complete events |
### Storage & Download Timeouts
| Variable | Default | Description |
|----------|---------|-------------|
| `TIMEOUT_SaveStorageStateEvent` | `45.0` | Timeout for saving cookies/localStorage |
| `TIMEOUT_StorageStateSavedEvent` | `30.0` | Timeout for storage save confirmation |
| `TIMEOUT_LoadStorageStateEvent` | `45.0` | Timeout for loading storage state |
| `TIMEOUT_StorageStateLoadedEvent` | `30.0` | Timeout for storage load confirmation |
| `TIMEOUT_FileDownloadedEvent` | `30.0` | Timeout for file download events |
### Example Usage
```bash
# Increase timeouts for slow network or complex pages
export TIMEOUT_NavigateToUrlEvent=30.0
export TIMEOUT_TypeTextEvent=120.0
export TIMEOUT_BrowserStateRequestEvent=60.0
# Increase agent shutdown timeout
export TIMEOUT_AgentEventBusStop=10.0
```
# Configuration
Source: https://docs.browser-use.com/open-source/customize/browser/basics
---
```python
from browser_use import Agent, Browser, ChatBrowserUse
browser = Browser(
headless=False, # Show browser window
window_size={'width': 1000, 'height': 700}, # Set window size
)
agent = Agent(
task='Search for Browser Use',
browser=browser,
llm=ChatBrowserUse(),
)
async def main():
await agent.run()
```
# Authentication
Source: https://docs.browser-use.com/open-source/customize/browser/authentication
Browser-Use supports multiple authentication strategies depending on your use case:
| Approach | Best For | Setup Effort |
|----------|----------|--------------|
| [Real Browser](#real-browser-profiles) | Personal automation, existing logins | Low |
| [Storage State](#storage-state-persistence) | Production, CI/CD, headless | Medium |
| [TOTP 2FA](#totp-2fa) | Sites with authenticator apps | Low |
| [Email and SMS 2FA](#email-and-sms-2fa) | Sites with email/SMS verification | Medium |
---
## Real Browser Profiles
Connect to your existing Chrome browser to reuse your authenticated sessions. No need to handle logins, cookies, or 2FA - if you are logged in on Chrome, the agent is, too.
See [Real Browser](/open-source/customize/browser/real-browser) for more details and platform paths.
You may need to close Chrome completely before running. Browser-Use launches Chrome in debug mode, which can conflict with existing Chrome processes.
```python
from browser_use import Agent, Browser, ChatBrowserUse
# Auto-detect Chrome and profile (cross-platform)
browser = Browser.from_system_chrome()
agent = Agent(
task='Check my Gmail inbox',
browser=browser,
llm=ChatBrowserUse(),
)
await agent.run()
```
---
## Storage State Persistence
Export cookies and localStorage from an authenticated browser, then load them in headless mode. Useful for production/CI where you cannot use a real browser profile.
See [Browser Parameters](/open-source/customize/browser/all-parameters#user-data--profiles) for all storage options.
### Export from Real Browser
```python
from browser_use import Browser
browser = Browser.from_system_chrome()
await browser.start()
await browser.export_storage_state('auth.json')
await browser.stop()
```
### Load in Headless Mode
```python
from browser_use import Agent, Browser, ChatBrowserUse
browser = Browser(storage_state='auth.json')
agent = Agent(
task='Check my notifications',
browser=browser,
llm=ChatBrowserUse(),
)
await agent.run()
```
### Auto-Save and Load
When you provide a `storage_state` path, Browser-Use automatically:
- Loads cookies from the file on startup (if it exists)
- Saves cookies to the file periodically and on shutdown
```python
browser = Browser(storage_state='session.json')
```
The file is created if it does not exist, and new cookies are merged with existing ones on each save.
### Storage State Format
The JSON file follows Playwright's format:
```json
{
"cookies": [
{
"name": "session_id",
"value": "abc123",
"domain": ".example.com",
"path": "/",
"expires": 1704067200,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
}
],
"origins": [
{
"origin": "https://example.com",
"localStorage": [
{"name": "auth_token", "value": "xyz789"}
]
}
]
}
```
---
## TOTP 2FA
For sites using authenticator apps (Google Authenticator, 1Password, etc.), Browser-Use can generate TOTP codes automatically.
See [Sensitive Data](/open-source/examples/templates/sensitive-data) for more on credential handling.
### How It Works
1. Get the TOTP secret key when setting up 2FA (usually shown as "manual entry" or "cannot scan QR code")
2. Pass the secret with `bu_2fa_code` suffix in `sensitive_data`
3. When the agent inputs `bu_2fa_code`, it generates a fresh 6-digit code
```python
from browser_use import Agent, ChatBrowserUse
# TOTP secret from your authenticator setup
# (NOT the 6-digit code - the secret key itself)
totp_secret = 'JBSWY3DPEHPK3PXP'
agent = Agent(
task='''
1. Go to https://example.com/login
2. Enter username x_user and password x_pass
3. When prompted for 2FA, enter bu_2fa_code
''',
sensitive_data={
'x_user': 'myusername',
'x_pass': 'mypassword',
'bu_2fa_code': totp_secret, # suffix must be bu_2fa_code
},
llm=ChatBrowserUse(),
)
await agent.run()
```
The placeholder name must end with `bu_2fa_code`. You can use any prefix: `google_bu_2fa_code`, `github_bu_2fa_code`, etc.
### Where to Find TOTP Secrets
- **1Password**: Edit item β One-Time Password β Show secret
- **Google Authenticator**: During setup, click "Can't scan it?" to see the key
- **Authy**: Export via desktop app settings
- **Most sites**: Look for "manual entry" or "setup key" during 2FA enrollment
---
## Email and SMS 2FA
For sites that send verification codes via email or SMS, use follow-up tasks to retrieve the code.
### With AgentMail
[AgentMail](https://agentmail.to) provides disposable inboxes for email verification:
```python
from agentmail import AsyncAgentMail
from browser_use import Agent, ChatBrowserUse, Tools, ActionResult
email_client = AsyncAgentMail()
inbox = await email_client.inboxes.create()
tools = Tools()
@tools.registry.action('Get email address for signup')
async def get_email_address():
return ActionResult(extracted_content=inbox.inbox_id)
@tools.registry.action('Get verification code from email')
async def get_verification_code():
emails = await email_client.inboxes.messages.list(inbox_id=inbox.inbox_id)
if emails.messages:
return ActionResult(extracted_content=emails.messages[0].text)
return ActionResult(error='No emails found')
agent = Agent(
task='Sign up at example.com, get verification code from email',
tools=tools,
llm=ChatBrowserUse(),
)
await agent.run()
```
See [`examples/integrations/agentmail/`](https://github.com/browser-use/browser-use/tree/main/examples/integrations/agentmail) for a more complete implementation with email waiting and parsing.
### With 1Password SDK
Retrieve codes from your password manager:
```python
import os
from onepassword.client import Client
from browser_use import Agent, Tools, ActionResult, ChatBrowserUse
tools = Tools()
@tools.registry.action('Get 2FA code from 1Password', domains=['*.google.com'])
async def get_1password_2fa():
client = await Client.authenticate(
auth=os.environ['OP_SERVICE_ACCOUNT_TOKEN'],
integration_name='Browser-Use',
integration_version='v1.0.0',
)
code = await client.secrets.resolve('op://Private/Google/One-time passcode')
return ActionResult(extracted_content=code)
agent = Agent(
task='Login to Google and check email',
tools=tools,
llm=ChatBrowserUse(),
)
await agent.run()
```
See [`examples/custom-functions/onepassword_2fa.py`](https://github.com/browser-use/browser-use/tree/main/examples/custom-functions/onepassword_2fa.py) for the full example.
### With Gmail API
Built-in Gmail integration for reading 2FA codes from your inbox:
```python
from browser_use import Agent, ChatBrowserUse, Tools
from browser_use.integrations.gmail import GmailService, register_gmail_actions
gmail_service = GmailService()
tools = Tools()
register_gmail_actions(tools, gmail_service=gmail_service)
agent = Agent(
task='Login to example.com, then get the verification code from Gmail',
tools=tools,
llm=ChatBrowserUse(),
)
await agent.run()
```
Requires Gmail API setup:
1. Enable Gmail API in [Google Cloud Console](https://console.cloud.google.com/)
2. Create OAuth 2.0 credentials (Desktop app)
3. Save credentials to `~/.config/browseruse/gmail_credentials.json`
See [`examples/integrations/gmail_2fa_integration.py`](https://github.com/browser-use/browser-use/tree/main/examples/integrations/gmail_2fa_integration.py) for setup with automatic credential validation.
---
## Security Best Practices
See [Secure Setup](/open-source/examples/templates/secure) for enterprise security with Azure OpenAI.
### Restrict Domains
Limit where the browser can navigate to prevent credential leaks:
```python
browser = Browser(
allowed_domains=['*.example.com', 'auth.example.com'],
)
```
### Disable Vision for Sensitive Pages
Prevent screenshots from being sent to the LLM:
```python
agent = Agent(
task='Login and check balance',
use_vision=False, # No screenshots sent to LLM
sensitive_data={'password': 'secret123'},
llm=ChatBrowserUse(),
)
```
### Domain-Specific Credentials
Route credentials to specific domains only:
```python
sensitive_data = {
'https://*.work.com': {
'work_user': 'alice@work.com',
'work_pass': 'work_password',
},
'https://personal.com': {
'personal_user': 'alice@gmail.com',
'personal_pass': 'personal_password',
},
}
```
---
## Cloud Browser Profiles
For production deployments, consider [Browser Use Cloud](https://cloud.browser-use.com), which provides:
- Persistent browser profiles in the cloud
- Pre-authenticated sessions
- No local Chrome installation required
- Built-in proxy and fingerprint management
```python
from browser_use import Agent, Browser, ChatBrowserUse
browser = Browser(cdp_url='wss://cloud.browser-use.com/...')
agent = Agent(
task='Check my orders',
browser=browser,
llm=ChatBrowserUse(),
)
await agent.run()
```
# Real Browser
Source: https://docs.browser-use.com/open-source/customize/browser/real-browser
This allows you to automate your existing Chrome browser, so you are already logged into your websites.
You may need to fully close Chrome before running these examples. Additionally, if Google search blocks automated browsers, use DuckDuckGo or other search engines instead.
## Basic Example
```python
import asyncio
from browser_use import Agent, Browser, ChatOpenAI
# Auto-selects first available Chrome profile
browser = Browser.from_system_chrome()
agent = Agent(
task='Visit https://duckduckgo.com and search for "browser-use founders"',
browser=browser,
llm=ChatOpenAI(model='gpt-4.1-mini'),
)
async def main():
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
```
## Choosing a Profile
Chrome supports multiple profiles. List and select the one you want:
```python
from browser_use import Browser
# List available profiles
profiles = Browser.list_chrome_profiles()
for p in profiles:
print(f"{p['directory']}: {p['name']}")
# Output:
# Profile 1: Work
# Profile 5: Personal
# Use a specific profile
browser = Browser.from_system_chrome(profile_directory='Profile 5')
```
## Manual Path Configuration
If auto-detection does not work, specify paths manually:
```python
browser = Browser(
executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
user_data_dir='~/Library/Application Support/Google/Chrome',
profile_directory='Default',
)
```
## How it Works
`Browser.from_system_chrome()` automatically detects:
| Platform | Executable Path | User Data Directory |
|----------|-----------------|---------------------|
| macOS | `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` | `~/Library/Application Support/Google/Chrome` |
| Windows | `C:\Program Files\Google\Chrome\Application\chrome.exe` | `%LocalAppData%\Google\Chrome\User Data` |
| Linux | `/usr/bin/google-chrome` or `/usr/bin/chromium` | `~/.config/google-chrome` |
# Remote Browser
Source: https://docs.browser-use.com/open-source/customize/browser/remote
### Browser-Use Cloud Browser or CDP URL
The easiest way to use a cloud browser is with the built-in Browser-Use cloud service:
```python
from browser_use import Agent, Browser, ChatBrowserUse
# Simple: Use Browser-Use cloud browser service
browser = Browser(
use_cloud=True, # Automatically provisions a cloud browser
)
# Advanced: Configure cloud browser parameters
# Using this settings can bypass any captcha protection on any website
browser = Browser(
cloud_profile_id='your-profile-id', # Optional: specific browser profile
cloud_proxy_country_code='us', # Optional: proxy location (us, uk, fr, it, jp, au, de, fi, ca, in)
cloud_timeout=30, # Optional: session timeout in minutes (MAX free: 15min, paid: 240min)
)
# Or use a CDP URL from any cloud browser provider
browser = Browser(
cdp_url="http://remote-server:9222" # Get a CDP URL from any provider
)
agent = Agent(
task="Your task here",
llm=ChatBrowserUse(),
browser=browser,
)
```
**Prerequisites:**
1. Get an API key from [cloud.browser-use.com](https://cloud.browser-use.com/new-api-key)
2. Set BROWSER_USE_API_KEY environment variable
**Cloud Browser Parameters:**
- `cloud_profile_id`: UUID of a browser profile (optional, uses default if not specified)
- `cloud_proxy_country_code`: Country code for proxy location - supports: us, uk, fr, it, jp, au, de, fi, ca, in
- `cloud_timeout`: Session timeout in minutes (free users: max 15 min, paid users: max 240 min)
**Benefits:**
- β No local browser setup required
- β Scalable and fast cloud infrastructure
- β Automatic provisioning and teardown
- β Built-in authentication handling
- β Optimized for browser automation
- β Global proxy support for geo-restricted content
### Third-Party Cloud Browsers
You can pass in a CDP URL from any remote browser
### Proxy Connection
```python
from browser_use import Agent, Browser, ChatBrowserUse
from browser_use.browser import ProxySettings
browser = Browser(
headless=False,
proxy=ProxySettings(
server="http://proxy-server:8080",
username="proxy-user",
password="proxy-pass"
),
cdp_url="http://remote-server:9222"
)
agent = Agent(
task="Your task here",
llm=ChatBrowserUse(),
browser=browser,
)
```
# All Parameters
Source: https://docs.browser-use.com/open-source/customize/browser/all-parameters
The `Browser` instance also provides all [Actor](/open-source/legacy/actor/all-parameters) methods for direct browser control (page management, element interactions, etc.).
## Core Settings
- `cdp_url`: CDP URL for connecting to existing browser instance (e.g., `"http://localhost:9222"`)
## Display & Appearance
- `headless` (default: `None`): Run browser without UI. Auto-detects based on display availability (`True`/`False`/`None`)
- `window_size`: Browser window size for headful mode. Use dict `{'width': 1920, 'height': 1080}` or `ViewportSize` object
- `window_position` (default: `{'width': 0, 'height': 0}`): Window position from top-left corner in pixels
- `viewport`: Content area size, same format as `window_size`. Use `{'width': 1280, 'height': 720}` or `ViewportSize` object
- `no_viewport` (default: `None`): Disable viewport emulation, content fits to window size
- `device_scale_factor`: Device scale factor (DPI). Set to `2.0` or `3.0` for high-resolution screenshots
## Browser Behavior
- `keep_alive` (default: `None`): Keep browser running after agent completes
- `allowed_domains`: Restrict navigation to specific domains. Domain pattern formats:
- `'example.com'` - Matches only `https://example.com/*`
- `'*.example.com'` - Matches `https://example.com/*` and any subdomain `https://*.example.com/*`
- `'http*://example.com'` - Matches both `http://` and `https://` protocols
- `'chrome-extension://*'` - Matches any Chrome extension URL
- **Security**: Wildcards in TLD (e.g., `example.*`) are **not allowed** for security
- Use list like `['*.google.com', 'https://example.com', 'chrome-extension://*']`
- **Performance**: Lists with 100+ domains are automatically optimized to sets for O(1) lookup. Pattern matching is disabled for optimized lists. Both `www.example.com` and `example.com` variants are checked automatically.
- `prohibited_domains`: Block navigation to specific domains. Uses same pattern formats as `allowed_domains`. When both `allowed_domains` and `prohibited_domains` are set, `allowed_domains` takes precedence. Examples:
- `['pornhub.com', '*.gambling-site.net']` - Block specific sites and all subdomains
- `['https://explicit-content.org']` - Block specific protocol/domain combination
- **Performance**: Lists with 100+ domains are automatically optimized to sets for O(1) lookup (same as `allowed_domains`)
- `enable_default_extensions` (default: `True`): Load automation extensions (uBlock Origin, cookie handlers, ClearURLs)
- `cross_origin_iframes` (default: `False`): Enable cross-origin iframe support (may cause complexity)
- `is_local` (default: `True`): Whether this is a local browser instance. Set to `False` for remote browsers. If we have a `executable_path` set, it will be automatically set to `True`. This can affect your download behavior.
## User Data & Profiles
- `user_data_dir` (default: auto-generated temp): Directory for browser profile data. Use `None` for incognito mode
- `profile_directory` (default: `'Default'`): Chrome profile subdirectory name (`'Profile 1'`, `'Work Profile'`, etc.)
- `storage_state`: Browser storage state (cookies, localStorage). Can be file path string or dict object
## Network & Security
- `proxy`: Proxy configuration using `ProxySettings(server='http://host:8080', bypass='localhost,127.0.0.1', username='user', password='pass')`
- `permissions` (default: `['clipboardReadWrite', 'notifications']`): Browser permissions to grant. Use list like `['camera', 'microphone', 'geolocation']`
- `headers`: Additional HTTP headers for connect requests (remote browsers only)
## Browser Launch
- `executable_path`: Path to browser executable for custom installations. Platform examples:
- macOS: `'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'`
- Windows: `'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'`
- Linux: `'/usr/bin/google-chrome'`
- `channel`: Browser channel (`'chromium'`, `'chrome'`, `'chrome-beta'`, `'msedge'`, etc.)
- `args`: Additional command-line arguments for the browser. Use list format: `['--disable-gpu', '--custom-flag=value', '--another-flag']`
- `env`: Environment variables for browser process. Use dict like `{'DISPLAY': ':0', 'LANG': 'en_US.UTF-8', 'CUSTOM_VAR': 'test'}`
- `chromium_sandbox` (default: `True` except in Docker): Enable Chromium sandboxing for security
- `devtools` (default: `False`): Open DevTools panel automatically (requires `headless=False`)
- `ignore_default_args`: List of default args to disable, or `True` to disable all. Use list like `['--enable-automation', '--disable-extensions']`
## Timing & Performance
- `minimum_wait_page_load_time` (default: `0.25`): Minimum time to wait before capturing page state in seconds
- `wait_for_network_idle_page_load_time` (default: `0.5`): Time to wait for network activity to cease in seconds
- `wait_between_actions` (default: `0.5`): Time to wait between agent actions in seconds
## AI Integration
- `highlight_elements` (default: `True`): Highlight interactive elements for AI vision
- `paint_order_filtering` (default: `True`): Enable paint order filtering to optimize DOM tree by removing elements hidden behind others. Slightly experimental
## Downloads & Files
- `accept_downloads` (default: `True`): Automatically accept all downloads
- `downloads_path`: Directory for downloaded files. Use string like `'./downloads'` or `Path` object
- `auto_download_pdfs` (default: `True`): Automatically download PDFs instead of viewing in browser
## Device Emulation
- `user_agent`: Custom user agent string. Example: `'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)'`
- `screen`: Screen size information, same format as `window_size`
## Recording & Debugging
Video recording requires additional optional dependencies. If these are not installed, no video will be saved and no error will be raised.
Install with:
```bash
pip install "browser-use[video]"
```
or:
```bash
pip install imageio[ffmpeg] numpy
```
- `record_video_dir`: Directory to save video recordings as `.mp4` files
- `record_video_size` (default: `ViewportSize`): The frame size (width, height) of the video recording.
- `record_video_framerate` (default: `30`): The framerate to use for the video recording.
- `record_har_path`: Path to save network trace files as `.har` format
- `traces_dir`: Directory to save complete trace files for debugging
- `record_har_content` (default: `'embed'`): HAR content mode (`'omit'`, `'embed'`, `'attach'`)
- `record_har_mode` (default: `'full'`): HAR recording mode (`'full'`, `'minimal'`)
## Advanced Options
- `disable_security` (default: `False`): β οΈ **NOT RECOMMENDED** - Disables all browser security features
- `deterministic_rendering` (default: `False`): β οΈ **NOT RECOMMENDED** - Forces consistent rendering but reduces performance
---
## Outdated BrowserProfile
For backward compatibility, you can pass all the parameters from above to the `BrowserProfile` and then to the `Browser`.
```python
from browser_use import BrowserProfile
profile = BrowserProfile(headless=False)
browser = Browser(browser_profile=profile)
```
## Browser vs BrowserSession
`Browser` is an alias for `BrowserSession` - they are exactly the same class:
Use `Browser` for cleaner, more intuitive code.
---
## Class Methods
### `Browser.from_system_chrome()`
Creates a Browser instance using your system's Chrome installation and profile. Automatically detects Chrome executable and user data directory for your platform.
```python
from browser_use import Browser
# Auto-select first available profile
browser = Browser.from_system_chrome()
# Or specify a profile
browser = Browser.from_system_chrome(profile_directory='Profile 1')
```
**Parameters:**
- `profile_directory` (default: `None`): Chrome profile to use (`'Default'`, `'Profile 1'`, etc.). If `None`, auto-selects the first available profile.
- `**kwargs`: Additional arguments passed to `Browser()` constructor (e.g., `headless=False`)
**Returns:** `Browser` instance configured to use your system Chrome
**Raises:** `RuntimeError` if Chrome is not found on your system
**Note:** You may need to fully close Chrome before using this, so Chrome profiles aren't used by multiple instances simultaneously.
---
### `Browser.list_chrome_profiles()`
Lists available Chrome profiles on the system.
```python
from browser_use import Browser
profiles = Browser.list_chrome_profiles()
for p in profiles:
print(f"{p['directory']}: {p['name']}")
# Output:
# Profile 1: Work
# Profile 5: Personal
```
**Returns:** List of dicts with `'directory'` and `'name'` keys
**Example return value:**
```python
[
{'directory': 'Default', 'name': 'Person 1'},
{'directory': 'Profile 1', 'name': 'Work'},
{'directory': 'Profile 5', 'name': 'Personal'}
]
```
# Overview
Source: https://docs.browser-use.com/open-source/customize/tools/basics
## Quick Example
```python
from browser_use import Agent, Tools, ActionResult, BrowserSession
tools = Tools()
@tools.action('Ask human for help with a question')
async def ask_human(question: str, browser_session: BrowserSession) -> ActionResult:
answer = input(f'{question} > ')
return ActionResult(extracted_content=f'The human responded with: {answer}')
agent = Agent(
task='Ask human for help',
llm=llm,
tools=tools,
)
```
**Important**: The parameter must be named exactly `browser_session` with type `BrowserSession` (not `browser: Browser`).
The agent injects parameters by name matching, so using the wrong name will cause your tool to fail silently.
Use `browser_session` parameter in tools for deterministic [Actor](/open-source/legacy/actor/basics) actions.
# Available Tools
Source: https://docs.browser-use.com/open-source/customize/tools/available
### Navigation & Browser Control
- **`search`** - Search queries (DuckDuckGo, Google, Bing)
- **`navigate`** - Navigate to URLs
- **`go_back`** - Go back in browser history
- **`wait`** - Wait for specified seconds
### Page Interaction
- **`click`** - Click elements by their index
- **`input`** - Input text into form fields
- **`upload_file`** - Upload files to file inputs
- **`scroll`** - Scroll the page up/down
- **`find_text`** - Scroll to specific text on page
- **`send_keys`** - Send special keys (Enter, Escape, etc.)
### JavaScript Execution
- **`evaluate`** - Execute custom JavaScript code on the page (for advanced interactions, shadow DOM, custom selectors, data extraction)
### Tab Management
- **`switch`** - Switch between browser tabs
- **`close`** - Close browser tabs
### Content Extraction
- **`extract`** - Extract data from webpages using LLM
### Visual Analysis
- **`screenshot`** - Request a screenshot in your next browser state for visual confirmation
### Form Controls
- **`dropdown_options`** - Get dropdown option values
- **`select_dropdown`** - Select dropdown options
### File Operations
- **`write_file`** - Write content to files
- **`read_file`** - Read file contents
- **`replace_file`** - Replace text in files
### Task Completion
- **`done`** - Complete the task (always available)
# Add Tools
Source: https://docs.browser-use.com/open-source/customize/tools/add
Examples:
- deterministic clicks
- file handling
- calling APIs
- human-in-the-loop
- browser interactions
- calling LLMs
- get 2fa codes
- send emails
- Playwright integration (see [GitHub example](https://github.com/browser-use/browser-use/blob/main/examples/browser/playwright_integration.py))
- ...
Simply add `@tools.action(...)` to your function.
```python
from browser_use import Tools, Agent, ActionResult
tools = 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}')
```
```python
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](#available-objects) below for the correct parameter names.
## Available Objects
Your function has access to these objects:
- **`browser_session: BrowserSession`** - Current browser session for CDP access
- **`cdp_client`** - Direct Chrome DevTools Protocol client
- **`page_extraction_llm: BaseChatModel`** - The LLM you pass into agent. This can be used to do a custom llm call here.
- **`file_system: FileSystem`** - File system access
- **`available_file_paths: list[str]`** - Available files for upload/processing
- **`has_sensitive_data: bool`** - Whether action contains sensitive data
## Browser Interaction Examples
You can use `browser_session` to directly interact with page elements using CSS selectors:
```python
from browser_use import Tools, Agent, ActionResult, BrowserSession
tools = 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
Available methods on `Element`:
- `click()` - Click the element
- `type(text: str)` - Type text into the element
- `get_text()` - Get element text content
- See `browser_use/actor/element.py` for more methods
## Pydantic Input
You can use Pydantic for the tool parameters:
```python
from pydantic import BaseModel
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"
```
## Domain Restrictions
Limit tools to specific domains:
```python
@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}'
```
## Advanced Example
For a comprehensive example of custom tools with Playwright integration, see:
**[Playwright Integration Example](https://github.com/browser-use/browser-use/blob/main/examples/browser/playwright_integration.py)**
This shows how to create custom actions that use Playwright's precise browser automation alongside Browser-Use.
## Common Pitfalls
The agent injects special parameters **by name**, not by type. Using incorrect parameter names is the most common cause of tools failing silently.
### β Wrong: Using `browser: Browser`
```python
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
```
### β Correct: Using `browser_session: BrowserSession`
```python
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')
```
### Key Points
1. **Use `browser_session: BrowserSession`** - not `browser: Browser`
2. **Use `async` functions** - recommended for consistency with browser operations
3. **Return `ActionResult`** - not plain strings (though strings work, `ActionResult` provides more control)
4. **Parameter names must match exactly** - see [Available Objects](#available-objects) for the full list of injectable parameters
# Remove Tools
Source: https://docs.browser-use.com/open-source/customize/tools/remove
```python
from browser_use import Tools
tools = Tools(exclude_actions=['search', 'wait'])
agent = Agent(task='...', llm=llm, tools=tools)
```
# Response Format
Source: https://docs.browser-use.com/open-source/customize/tools/response
Tools return results using `ActionResult` or simple strings.
## Return Types
```python
@tools.action('My tool')
def my_tool() -> str:
return "Task completed successfully"
@tools.action('Advanced tool')
def advanced_tool() -> ActionResult:
return ActionResult(
extracted_content="Main result",
long_term_memory="Remember this info",
error="Something went wrong",
is_done=True,
success=True,
attachments=["file.pdf"],
)
```
## ActionResult Properties
- `extracted_content` (default: `None`) - Main result passed to LLM, this is equivalent to returning a string.
- `include_extracted_content_only_once` (default: `False`) - Set to `True` for large content to include it only once in the LLM input.
- `long_term_memory` (default: `None`) - This is always included in the LLM input for all future steps.
- `error` (default: `None`) - Error message, we catch exceptions and set this automatically. This is always included in the LLM input.
- `is_done` (default: `False`) - Tool completes entire task
- `success` (default: `None`) - Task success (only valid with `is_done=True`)
- `attachments` (default: `None`) - Files to show user
- `metadata` (default: `None`) - Debug/observability data
## Why `extracted_content` and `long_term_memory`?
With this you control the context for the LLM.
### 1. Include short content always in context
```python
def simple_tool() -> str:
return "Hello, world!" # Keep in context for all future steps
```
### 2. Show long content once, remember subset in context
```python
return ActionResult(
extracted_content="[500 lines of product data...]", # Shows to LLM once
include_extracted_content_only_once=True, # Never show full output again
long_term_memory="Found 50 products" # Only this in future steps
)
```
We save the full `extracted_content` to files which the LLM can read in future steps.
### 3. Don't show long content, remember subset in context
```python
return ActionResult(
extracted_content="[500 lines of product data...]", # The LLM never sees this because `long_term_memory` overrides it and `include_extracted_content_only_once` is not used
long_term_memory="Saved user's favorite products", # This is shown to the LLM in future steps
)
```
## Terminating the Agent
Set `is_done=True` to stop the agent completely. Use when your tool finishes the entire task:
```python
@tools.action(description='Complete the task')
def finish_task() -> ActionResult:
return ActionResult(
extracted_content="Task completed!",
is_done=True, # Stops the agent
success=True # Task succeeded
)
```
# MCP Server
Source: https://docs.browser-use.com/open-source/customize/integrations/mcp-server
Browser Use can run as a local **Model Context Protocol (MCP)** server on your machine via stdio. This is the **free, open-source option** that gives you direct, low-level control over browser automation but requires your own LLM API keys.
Looking for a hosted solution? Use the [Cloud MCP Server](https://docs.browser-use.com/cloud/guides/mcp-server) instead β no setup required, just an API key.
## Quick Start
```bash
uvx --from 'browser-use[cli]' browser-use --mcp
```
The server will start in stdio mode, ready to accept MCP connections.
## Client Setup
```bash
claude mcp add browser-use -- uvx --from 'browser-use[cli]' browser-use --mcp
```
Add to your Claude Desktop config file:
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"browser-use": {
"command": "/Users/your-username/.local/bin/uvx",
"args": ["--from", "browser-use[cli]", "browser-use", "--mcp"],
"env": {
"OPENAI_API_KEY": "your-openai-api-key-here"
}
}
}
}
```
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"browser-use": {
"command": "uvx",
"args": ["--from", "browser-use[cli]", "browser-use", "--mcp"],
"env": {
"OPENAI_API_KEY": "your-openai-api-key-here"
}
}
}
}
```
Restart Claude Desktop after saving.
**macOS/Linux PATH Issue:** Claude Desktop may not find `uvx` in your PATH. Use the full path to `uvx` instead:
- Run `which uvx` in your terminal to find the location (usually `/Users/username/.local/bin/uvx` or `~/.local/bin/uvx`)
- Replace `"command": "uvx"` with the full path, e.g., `"command": "/Users/your-username/.local/bin/uvx"`
- Replace `your-username` with your actual username
**CLI Extras Required:** The `--from browser-use[cli]` flag installs the CLI extras needed for MCP server support.
Add to `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"browser-use": {
"command": "uvx",
"args": ["--from", "browser-use[cli]", "browser-use", "--mcp"],
"env": {
"OPENAI_API_KEY": "your-openai-api-key-here"
}
}
}
}
```
Add to `~/.codeium/windsurf/mcp_config.json`:
```json
{
"mcpServers": {
"browser-use": {
"command": "uvx",
"args": ["--from", "browser-use[cli]", "browser-use", "--mcp"],
"env": {
"OPENAI_API_KEY": "your-openai-api-key-here"
}
}
}
}
```
## Environment Variables
- `OPENAI_API_KEY` - Your OpenAI API key (required)
- `ANTHROPIC_API_KEY` - Your Anthropic API key (alternative to OpenAI)
- `BROWSER_USE_HEADLESS` - Set to `false` to show browser window
- `BROWSER_USE_DISABLE_SECURITY` - Set to `true` to disable browser security features
## Available Tools
The local MCP server exposes these low-level browser automation tools for direct control:
#### Autonomous Agent Tools
- **`retry_with_browser_use_agent`** - Run a complete browser automation task with an AI agent (use as last resort when direct control fails)
#### Direct Browser Control
- **`browser_navigate`** - Navigate to a URL
- **`browser_click`** - Click on an element by index
- **`browser_type`** - Type text into an element
- **`browser_get_state`** - Get current page state and interactive elements
- **`browser_scroll`** - Scroll the page
- **`browser_go_back`** - Go back in browser history
#### Tab Management
- **`browser_list_tabs`** - List all open browser tabs
- **`browser_switch_tab`** - Switch to a specific tab
- **`browser_close_tab`** - Close a tab
#### Content Extraction
- **`browser_extract_content`** - Extract structured content from the current page
#### Session Management
- **`browser_list_sessions`** - List all active browser sessions with details
- **`browser_close_session`** - Close a specific browser session by ID
- **`browser_close_all`** - Close all active browser sessions
## Example Usage
Once configured, you can ask your AI to perform browser automation tasks:
```
"Please navigate to example.com and take a screenshot"
"Search for 'browser automation' on Google and summarize the first 3 results"
"Go to GitHub, find the browser-use repository, and tell me about the latest release"
```
## Programmatic Usage
You can also connect to the MCP server programmatically:
```python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def use_browser_mcp():
# Connect to browser-use MCP server
server_params = StdioServerParameters(
command="uvx",
args=["--from", "browser-use[cli]", "browser-use", "--mcp"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Navigate to a website
result = await session.call_tool(
"browser_navigate",
arguments={"url": "https://example.com"}
)
print(result.content[0].text)
# Get page state
result = await session.call_tool(
"browser_get_state",
arguments={"include_screenshot": True}
)
print("Page state retrieved!")
asyncio.run(use_browser_mcp())
```
## Troubleshooting
**"CLI addon is not installed" Error**
Make sure you are using `--from 'browser-use[cli]'` in your uvx command:
```bash
uvx --from 'browser-use[cli]' browser-use --mcp
```
**"spawn uvx ENOENT" Error (macOS/Linux)**
Claude Desktop cannot find `uvx` in its PATH. Use the full path in your config:
- Run `which uvx` in terminal to find the location
- Update your config to use the full path (e.g., `/Users/your-username/.local/bin/uvx`)
**Browser doesn't start**
- Check that you have Chrome/Chromium installed
- Try setting `BROWSER_USE_HEADLESS=false` to see browser window
- Ensure no other browser instances are using the same profile
**API Key Issues**
- Verify your `OPENAI_API_KEY` is set correctly
- Check API key permissions and billing status
- Try using `ANTHROPIC_API_KEY` as an alternative
**Connection Issues in Claude Desktop**
- Restart Claude Desktop after config changes
- Check the config file syntax is valid JSON
- Verify the file path is correct for your OS
- Check logs at `~/Library/Logs/Claude/` (macOS) or `%APPDATA%\Claude\Logs\` (Windows)
**Debug Mode**
Enable debug logging by setting:
```bash
export BROWSER_USE_LOGGING_LEVEL=DEBUG
uvx --from 'browser-use[cli]' browser-use --mcp
```
## Security Considerations
- The MCP server has access to your browser and file system
- Only connect trusted MCP clients
- Be cautious with sensitive websites and data
- Consider running in a sandboxed environment for untrusted automation
## Next Steps
- Explore the [examples directory](https://github.com/browser-use/browser-use/tree/main/examples) for more usage patterns
- Check out [MCP documentation](https://modelcontextprotocol.io/) to learn more about the protocol
- Join our [Discord](https://link.browser-use.com/discord) for support and discussions
# Basics
Source: https://docs.browser-use.com/open-source/legacy/actor/basics
## Core Architecture
```mermaid
graph TD
A[Browser] --> B[Page]
B --> C[Element]
B --> D[Mouse]
B --> E[AI Features]
C --> F[DOM Interactions]
D --> G[Coordinate Operations]
E --> H[LLM Integration]
```
### Core Classes
- **Browser** (alias: **BrowserSession**): Main session manager
- **Page**: Represents a browser tab/iframe
- **Element**: Individual DOM element operations
- **Mouse**: Coordinate-based mouse operations
## Basic Usage
```python
from browser_use import Browser, Agent
from browser_use.llm.openai.chat import ChatOpenAI
async def main():
llm = ChatOpenAI(api_key="your-api-key")
browser = Browser()
await browser.start()
# 1. Actor: Precise navigation and element interactions
page = await browser.new_page("https://github.com/login")
email_input = await page.must_get_element_by_prompt("username field", llm=llm)
await email_input.fill("your-username")
# 2. Agent: AI-driven complex tasks
agent = Agent(browser=browser, llm=llm)
await agent.run("Complete login and navigate to my repositories")
await browser.stop()
```
## Important Notes
- **Not Playwright**: Actor is built on CDP, not Playwright. The API resembles Playwright as much as possible for easy migration, but is a subset.
- **Immediate Returns**: `get_elements_by_css_selector()` doesn't wait for visibility
- **Manual Timing**: You handle navigation timing and waiting
- **JavaScript Format**: `evaluate()` requires arrow function format: `() => {}`
# Examples
Source: https://docs.browser-use.com/open-source/legacy/actor/examples
## Page Management
```python
from browser_use import Browser
browser = Browser()
await browser.start()
# Create pages
page = await browser.new_page() # Blank tab
page = await browser.new_page("https://example.com") # With URL
# Get all pages
pages = await browser.get_pages()
current = await browser.get_current_page()
# Close page
await browser.close_page(page)
await browser.stop()
```
## Element Finding & Interactions
```python
page = await browser.new_page('https://github.com')
# CSS selectors (immediate return)
elements = await page.get_elements_by_css_selector("input[type='text']")
buttons = await page.get_elements_by_css_selector("button.submit")
# Element actions
await elements[0].click()
await elements[0].fill("Hello World")
await elements[0].hover()
# Page actions
await page.press("Enter")
screenshot = await page.screenshot()
```
## LLM-Powered Features
```python
from browser_use.llm.openai.chat import ChatOpenAI
from pydantic import BaseModel
llm = ChatOpenAI(api_key="your-api-key")
# Find elements using natural language
button = await page.get_element_by_prompt("login button", llm=llm)
await button.click()
# Extract structured data
class ProductInfo(BaseModel):
name: str
price: float
product = await page.extract_content(
"Extract product name and price",
ProductInfo,
llm=llm
)
```
## JavaScript Execution
```python
# Simple JavaScript evaluation
title = await page.evaluate('() => document.title')
# JavaScript with arguments
result = await page.evaluate('(x, y) => x + y', 10, 20)
# Complex operations
stats = await page.evaluate('''() => ({
url: location.href,
links: document.querySelectorAll('a').length
})''')
```
## Mouse Operations
```python
mouse = page.mouse
# Click at coordinates
await mouse.click(x=100, y=200)
# Drag and drop
await mouse.down()
await mouse.move(x=500, y=600)
await mouse.up()
# Scroll
await mouse.scroll(x=0, y=100, delta_y=-500)
```
## Best Practices
- Use `asyncio.sleep()` after actions that trigger navigation
- Check URL/title changes to verify state transitions
- Always check if elements exist before interaction
- Implement retry logic for flaky elements
- Call `browser.stop()` to clean up resources
# All Parameters
Source: https://docs.browser-use.com/open-source/legacy/actor/all-parameters
## Browser (BrowserSession)
Main browser session manager.
### Key Methods
```python
from browser_use import Browser
browser = Browser()
await browser.start()
# Page management
page = await browser.new_page("https://example.com")
pages = await browser.get_pages()
current = await browser.get_current_page()
await browser.close_page(page)
# To stop the browser session
await browser.stop()
```
### Constructor Parameters
See [Browser Parameters](/open-source/customize/browser/all-parameters) for complete configuration options.
## Page
Browser tab/iframe for page-level operations.
### Navigation
- `goto(url: str)` - Navigate to URL
- `go_back()`, `go_forward()`, `reload()` - History navigation
### Element Finding
- `get_elements_by_css_selector(selector: str) -> list[Element]` - CSS selector
- `get_element(backend_node_id: int) -> Element` - By CDP node ID
- `get_element_by_prompt(prompt: str, llm) -> Element | None` - AI-powered
- `must_get_element_by_prompt(prompt: str, llm) -> Element` - AI (raises if not found)
### JavaScript & Controls
- `evaluate(page_function: str, *args) -> str` - Execute JS (arrow function format)
- `press(key: str)` - Send keyboard input ("Enter", "Control+A")
- `set_viewport_size(width: int, height: int)` - Set viewport
- `screenshot(format='jpeg', quality=None) -> str` - Take screenshot
### Information
- `get_url() -> str`, `get_title() -> str` - Page info
- `mouse -> Mouse` - Get mouse interface
### AI Features
- `extract_content(prompt: str, structured_output: type[T], llm) -> T` - Extract data
## Element
Individual DOM element interactions.
### Interactions
- `click(button='left', click_count=1, modifiers=None)` - Click element
- `fill(text: str, clear=True)` - Fill input
- `hover()`, `focus()` - Mouse/focus actions
- `check()` - Toggle checkbox/radio
- `select_option(values: str | list[str])` - Select dropdown options
- `drag_to(target: Element | Position)` - Drag and drop
### Properties
- `get_attribute(name: str) -> str | None` - Get attribute
- `get_bounding_box() -> BoundingBox | None` - Position/size
- `get_basic_info() -> ElementInfo` - Complete element info
- `screenshot(format='jpeg') -> str` - Element screenshot
## Mouse
Coordinate-based mouse operations.
### Operations
- `click(x: int, y: int, button='left', click_count=1)` - Click at coordinates
- `move(x: int, y: int, steps=1)` - Move mouse
- `down(button='left')`, `up(button='left')` - Press/release buttons
- `scroll(x=0, y=0, delta_x=None, delta_y=None)` - Scroll at coordinates
# Quickstart
Source: https://docs.browser-use.com/open-source/legacy/sandbox/quickstart
Sandboxes are the **easiest way to run Browser-Use in production**. We handle agents, browsers, persistence, auth, cookies, and LLMs. It is also the **fastest way to deploy** - the agent runs right next to the browser, so latency is minimal.
Get your API key at [cloud.browser-use.com/new-api-key](https://cloud.browser-use.com/new-api-key) β new users get 5 free tasks.
## Basic Example
Wrap your function with `@sandbox()`:
```python
from browser_use import Browser, sandbox, ChatBrowserUse
from browser_use.agent.service import Agent
@sandbox()
async def my_task(browser: Browser):
agent = Agent(task="Find the top HN post", browser=browser, llm=ChatBrowserUse())
await agent.run()
await my_task()
```
## With Cloud Parameters
```python
@sandbox(
cloud_profile_id='your-profile-id', # Use saved cookies/auth
cloud_proxy_country_code='us', # Bypass captchas, cloudflare, geo-restrictions
cloud_timeout=60, # Max session time (minutes)
)
async def task(browser: Browser, url: str):
agent = Agent(task=f"Visit {url}", browser=browser, llm=ChatBrowserUse())
await agent.run()
await task(url="https://example.com")
```
**What each does:**
- `cloud_profile_id` - Use saved cookies/authentication from your cloud profile
- `cloud_proxy_country_code` - Route through country-specific proxy for stealth (bypass captchas, Cloudflare, geo-blocks)
- `cloud_timeout` - Maximum time browser stays open in minutes
---
For more parameters and events, see the other tabs in this section.
# Events
Source: https://docs.browser-use.com/open-source/legacy/sandbox/events
## Live Browser View
```python
@sandbox(on_browser_created=lambda data: print(f'ποΈ {data.live_url}'))
async def task(browser: Browser):
agent = Agent(task="your task", browser=browser, llm=ChatBrowserUse())
await agent.run()
```
## All Events
```python
from browser_use.sandbox import BrowserCreatedData, LogData, ResultData, ErrorData
@sandbox(
on_browser_created=lambda data: print(f'Live: {data.live_url}'),
on_log=lambda log: print(f'{log.level}: {log.message}'),
on_result=lambda result: print('Done!'),
on_error=lambda error: print(f'Error: {error.error}'),
)
async def task(browser: Browser):
# Your code
```
All callbacks can be sync or async.
# All Parameters
Source: https://docs.browser-use.com/open-source/legacy/sandbox/all-parameters
## Reference
| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `BROWSER_USE_API_KEY` | `str` | API key (or env var) | Required |
| `cloud_profile_id` | `str` | Browser profile UUID | `None` |
| `cloud_proxy_country_code` | `str` | us, uk, fr, it, jp, au, de, fi, ca, in | `None` |
| `cloud_timeout` | `int` | Minutes (max: 15 free, 240 paid) | `None` |
| `on_browser_created` | `Callable` | Live URL callback | `None` |
| `on_log` | `Callable` | Log event callback | `None` |
| `on_result` | `Callable` | Success callback | `None` |
| `on_error` | `Callable` | Error callback | `None` |
## Example
```python
@sandbox(
cloud_profile_id='550e8400-e29b-41d4-a716-446655440000',
cloud_proxy_country_code='us',
cloud_timeout=60,
on_browser_created=lambda data: print(f'Live: {data.live_url}'),
)
async def task(browser: Browser):
agent = Agent(task="your task", browser=browser, llm=ChatBrowserUse())
await agent.run()
```
# Fast Agent
Source: https://docs.browser-use.com/open-source/examples/templates/fast-agent
```python
import asyncio
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, BrowserProfile
# Speed optimization instructions for the model
SPEED_OPTIMIZATION_PROMPT = """
Speed optimization instructions:
- Be extremely concise and direct in your responses
- Get to the goal as quickly as possible
- Use multi-action sequences whenever possible to reduce steps
"""
async def main():
# 1. Use fast LLM - Llama 4 on Groq for ultra-fast inference
from browser_use import ChatGroq
llm = ChatGroq(
model='meta-llama/llama-4-maverick-17b-128e-instruct',
temperature=0.0,
)
# from browser_use import ChatGoogle
# llm = ChatGoogle(model='gemini-flash-lite-latest')
# 2. Create speed-optimized browser profile
browser_profile = BrowserProfile(
minimum_wait_page_load_time=0.1,
wait_between_actions=0.1,
headless=False,
)
# 3. Define a speed-focused task
task = """
1. Go to reddit https://www.reddit.com/search/?q=browser+agent&type=communities
2. Click directly on the first 5 communities to open each in new tabs
3. Find out what the latest post is about, and switch directly to the next tab
4. Return the latest post summary for each page
"""
# 4. Create agent with all speed optimizations
agent = Agent(
task=task,
llm=llm,
flash_mode=True, # Disables thinking in the LLM output for maximum speed
browser_profile=browser_profile,
extend_system_message=SPEED_OPTIMIZATION_PROMPT,
)
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
```
## Speed Optimization Techniques
### 1. Fast LLM Models
```python
# Groq - Ultra-fast inference
from browser_use import ChatGroq
llm = ChatGroq(model='meta-llama/llama-4-maverick-17b-128e-instruct')
# Google Gemini Flash - Optimized for speed
from browser_use import ChatGoogle
llm = ChatGoogle(model='gemini-flash-lite-latest')
```
### 2. Browser Optimizations
```python
browser_profile = BrowserProfile(
minimum_wait_page_load_time=0.1, # Reduce wait time
wait_between_actions=0.1, # Faster action execution
headless=True, # No GUI overhead
)
```
### 3. Agent Optimizations
```python
agent = Agent(
task=task,
llm=llm,
flash_mode=True, # Skip LLM thinking process
extend_system_message=SPEED_PROMPT, # Optimize LLM behavior
)
```
# Follow up tasks
Source: https://docs.browser-use.com/open-source/examples/templates/follow-up-tasks
## Chain Agent Tasks
Keep your browser session alive and chain multiple tasks together. Perfect for conversational workflows or multi-step processes.
```python
from dotenv import load_dotenv
from browser_use import Agent, Browser
load_dotenv()
import asyncio
async def main():
browser = Browser(keep_alive=True)
await browser.start()
agent = Agent(task='search for browser-use.', browser_session=browser)
await agent.run(max_steps=2)
agent.add_new_task('return the title of first result')
await agent.run()
await browser.kill()
asyncio.run(main())
```
## How It Works
1. **Persistent Browser**: `Browser(keep_alive=True)` prevents browser from closing between tasks
2. **Task Chaining**: Use `agent.add_new_task()` to add follow-up tasks
3. **Context Preservation**: Agent maintains memory and browser state across tasks
4. **Interactive Flow**: Perfect for conversational interfaces
5. **Break down long flows**: If you have very long flows, you can keep the browser alive and send new agents to it.
The browser session remains active throughout the entire chain, preserving all cookies, local storage, and page state.
# Parallel Agents
Source: https://docs.browser-use.com/open-source/examples/templates/parallel-browser
```python
import asyncio
from browser_use import Agent, Browser, ChatOpenAI
async def main():
# Create 3 separate browser instances
browsers = [
Browser(
user_data_dir=f'./temp-profile-{i}',
headless=False,
)
for i in range(3)
]
# Create 3 agents with different tasks
agents = [
Agent(
task='Search for "browser automation" on Google',
browser=browsers[0],
llm=ChatOpenAI(model='gpt-4.1-mini'),
),
Agent(
task='Search for "AI agents" on DuckDuckGo',
browser=browsers[1],
llm=ChatOpenAI(model='gpt-4.1-mini'),
),
Agent(
task='Visit Wikipedia and search for "web scraping"',
browser=browsers[2],
llm=ChatOpenAI(model='gpt-4.1-mini'),
),
]
# Run all agents in parallel
tasks = [agent.run() for agent in agents]
results = await asyncio.gather(*tasks, return_exceptions=True)
print('π All agents completed!')
```
> **Note:** This is experimental, and agents might conflict each other.
# Playwright Integration
Source: https://docs.browser-use.com/open-source/examples/templates/playwright-integration
## Key Features
1. Browser-Use and Playwright sharing the same Chrome instance via CDP
2. Take actions with Playwright and continue with Browser-Use actions
3. Let the agent call Playwright functions like screenshot or click on selectors for deterministic steps
## Installation
```bash
uv pip install playwright aiohttp
```
## Full Example
```python
import asyncio
import os
import subprocess
import sys
import tempfile
from pydantic import BaseModel, Field
# Check for required dependencies first - before other imports
try:
import aiohttp # type: ignore
from playwright.async_api import Browser, Page, async_playwright # type: ignore
except ImportError as e:
print(f'β Missing dependencies for this example: {e}')
print('This example requires: playwright aiohttp')
print('Install with: uv add playwright aiohttp')
print('Also run: playwright install chromium')
sys.exit(1)
from browser_use import Agent, BrowserSession, ChatOpenAI, Tools
from browser_use.agent.views import ActionResult
# Global Playwright browser instance - shared between custom actions
playwright_browser: Browser | None = None
playwright_page: Page | None = None
# Custom action parameter models
class PlaywrightFillFormAction(BaseModel):
"""Parameters for Playwright form filling action."""
customer_name: str = Field(..., description='Customer name to fill')
phone_number: str = Field(..., description='Phone number to fill')
email: str = Field(..., description='Email address to fill')
size_option: str = Field(..., description='Size option (small/medium/large)')
class PlaywrightScreenshotAction(BaseModel):
"""Parameters for Playwright screenshot action."""
filename: str = Field(default='playwright_screenshot.png', description='Filename for screenshot')
quality: int | None = Field(default=None, description='JPEG quality (1-100), only for .jpg/.jpeg files')
class PlaywrightGetTextAction(BaseModel):
"""Parameters for getting text using Playwright selectors."""
selector: str = Field(..., description='CSS selector to get text from. Use "title" for page title.')
async def start_chrome_with_debug_port(port: int = 9222):
"""
Start Chrome with remote debugging enabled.
Returns the Chrome process.
"""
# Create temporary directory for Chrome user data
user_data_dir = tempfile.mkdtemp(prefix='chrome_cdp_')
# Chrome launch command
chrome_paths = [
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', # macOS
'/usr/bin/google-chrome', # Linux
'/usr/bin/chromium-browser', # Linux Chromium
'chrome', # Windows/PATH
'chromium', # Generic
]
chrome_exe = None
for path in chrome_paths:
if os.path.exists(path) or path in ['chrome', 'chromium']:
try:
# Test if executable works
test_proc = await asyncio.create_subprocess_exec(
path, '--version', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
await test_proc.wait()
chrome_exe = path
break
except Exception:
continue
if not chrome_exe:
raise RuntimeError('β Chrome not found. Please install Chrome or Chromium.')
# Chrome command arguments
cmd = [
chrome_exe,
f'--remote-debugging-port={port}',
f'--user-data-dir={user_data_dir}',
'--no-first-run',
'--no-default-browser-check',
'--disable-extensions',
'about:blank', # Start with blank page
]
# Start Chrome process
process = await asyncio.create_subprocess_exec(*cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# Wait for Chrome to start and CDP to be ready
cdp_ready = False
for _ in range(20): # 20 second timeout
try:
async with aiohttp.ClientSession() as session:
async with session.get(
f'http://localhost:{port}/json/version', timeout=aiohttp.ClientTimeout(total=1)
) as response:
if response.status == 200:
cdp_ready = True
break
except Exception:
pass
await asyncio.sleep(1)
if not cdp_ready:
process.terminate()
raise RuntimeError('β Chrome failed to start with CDP')
return process
playwright_instance = None
async def connect_playwright_to_cdp(cdp_url: str):
"""
Connect Playwright to the same Chrome instance Browser-Use is using.
This enables custom actions to use Playwright functions.
"""
global playwright_browser, playwright_page, playwright_instance
playwright_instance = await async_playwright().start()
playwright_browser = await playwright_instance.chromium.connect_over_cdp(cdp_url)
# Get or create a page
if playwright_browser and playwright_browser.contexts and playwright_browser.contexts[0].pages:
playwright_page = playwright_browser.contexts[0].pages[0]
elif playwright_browser:
context = await playwright_browser.new_context()
playwright_page = await context.new_page()
# Create custom tools that use Playwright functions
tools = Tools()
@tools.registry.action(
"Fill out a form using Playwright's precise form filling capabilities. This uses Playwright selectors for reliable form interaction.",
param_model=PlaywrightFillFormAction,
)
async def playwright_fill_form(params: PlaywrightFillFormAction, browser_session: BrowserSession):
"""
Custom action that uses Playwright to fill forms with high precision.
This demonstrates how to create Browser-Use actions that leverage Playwright's capabilities.
"""
try:
if not playwright_page:
return ActionResult(error='Playwright not connected. Run setup first.')
# Filling form with Playwright's precise selectors
# Wait for form to be ready and fill basic fields
await playwright_page.wait_for_selector('input[name="custname"]', timeout=10000)
await playwright_page.fill('input[name="custname"]', params.customer_name)
await playwright_page.fill('input[name="custtel"]', params.phone_number)
await playwright_page.fill('input[name="custemail"]', params.email)
# Handle size selection - check if it's a select dropdown or radio buttons
size_select = playwright_page.locator('select[name="size"]')
size_radio = playwright_page.locator(f'input[name="size"][value="{params.size_option}"]')
if await size_select.count() > 0:
# It's a select dropdown
await playwright_page.select_option('select[name="size"]', params.size_option)
elif await size_radio.count() > 0:
# It's radio buttons
await playwright_page.check(f'input[name="size"][value="{params.size_option}"]')
else:
raise ValueError(f'Could not find size input field for value: {params.size_option}')
# Get form data to verify it was filled
form_data = {}
form_data['name'] = await playwright_page.input_value('input[name="custname"]')
form_data['phone'] = await playwright_page.input_value('input[name="custtel"]')
form_data['email'] = await playwright_page.input_value('input[name="custemail"]')
# Get size value based on input type
if await size_select.count() > 0:
form_data['size'] = await playwright_page.input_value('select[name="size"]')
else:
# For radio buttons, find the checked one
checked_radio = playwright_page.locator('input[name="size"]:checked')
if await checked_radio.count() > 0:
form_data['size'] = await checked_radio.get_attribute('value')
else:
form_data['size'] = 'none selected'
success_msg = f'β Form filled successfully with Playwright: {form_data}'
return ActionResult(
extracted_content=success_msg, include_in_memory=True, long_term_memory=f'Filled form with: {form_data}'
)
except Exception as e:
error_msg = f'β Playwright form filling failed: {str(e)}'
return ActionResult(error=error_msg)
@tools.registry.action(
"Take a screenshot using Playwright's screenshot capabilities with high quality and precision.",
param_model=PlaywrightScreenshotAction,
)
async def playwright_screenshot(params: PlaywrightScreenshotAction, browser_session: BrowserSession):
"""
Custom action that uses Playwright's advanced screenshot features.
"""
try:
if not playwright_page:
return ActionResult(error='Playwright not connected. Run setup first.')
# Taking screenshot with Playwright
# Use Playwright's screenshot with full page capture
screenshot_kwargs = {'path': params.filename, 'full_page': True}
# Add quality parameter only for JPEG files
if params.quality is not None and params.filename.lower().endswith(('.jpg', '.jpeg')):
screenshot_kwargs['quality'] = params.quality
await playwright_page.screenshot(**screenshot_kwargs)
success_msg = f'β Screenshot saved as {params.filename} using Playwright'
return ActionResult(
extracted_content=success_msg, include_in_memory=True, long_term_memory=f'Screenshot saved: {params.filename}'
)
except Exception as e:
error_msg = f'β Playwright screenshot failed: {str(e)}'
return ActionResult(error=error_msg)
@tools.registry.action(
"Extract text from elements using Playwright's powerful CSS selectors and XPath support.", param_model=PlaywrightGetTextAction
)
async def playwright_get_text(params: PlaywrightGetTextAction, browser_session: BrowserSession):
"""
Custom action that uses Playwright's advanced text extraction with CSS selectors and XPath.
"""
try:
if not playwright_page:
return ActionResult(error='Playwright not connected. Run setup first.')
# Extracting text with Playwright selectors
# Handle special selectors
if params.selector.lower() == 'title':
# Use page.title() for title element
text_content = await playwright_page.title()
result_data = {
'selector': 'title',
'text_content': text_content,
'inner_text': text_content,
'tag_name': 'TITLE',
'is_visible': True,
}
else:
# Use Playwright's robust element selection and text extraction
element = playwright_page.locator(params.selector).first
if await element.count() == 0:
error_msg = f'β No element found with selector: {params.selector}'
return ActionResult(error=error_msg)
text_content = await element.text_content()
inner_text = await element.inner_text()
# Get additional element info
tag_name = await element.evaluate('el => el.tagName')
is_visible = await element.is_visible()
result_data = {
'selector': params.selector,
'text_content': text_content,
'inner_text': inner_text,
'tag_name': tag_name,
'is_visible': is_visible,
}
success_msg = f'β Extracted text using Playwright: {result_data}'
return ActionResult(
extracted_content=str(result_data),
include_in_memory=True,
long_term_memory=f'Extracted from {params.selector}: {result_data["text_content"]}',
)
except Exception as e:
error_msg = f'β Playwright text extraction failed: {str(e)}'
return ActionResult(error=error_msg)
async def main():
"""
Main function demonstrating Browser-Use + Playwright integration with custom actions.
"""
print('π Advanced Playwright + Browser-Use Integration with Custom Actions')
chrome_process = None
try:
# Step 1: Start Chrome with CDP debugging
chrome_process = await start_chrome_with_debug_port()
cdp_url = 'http://localhost:9222'
# Step 2: Connect Playwright to the same Chrome instance
await connect_playwright_to_cdp(cdp_url)
# Step 3: Create Browser-Use session connected to same Chrome
browser_session = BrowserSession(cdp_url=cdp_url)
# Step 4: Create AI agent with our custom Playwright-powered tools
agent = Agent(
task="""
Please help me demonstrate the integration between Browser-Use and Playwright:
1. First, navigate to https://httpbin.org/forms/post
2. Use the 'playwright_fill_form' action to fill the form with these details:
- Customer name: "Alice Johnson"
- Phone: "555-9876"
- Email: "alice@demo.com"
- Size: "large"
3. Take a screenshot using the 'playwright_screenshot' action and save it as "form_demo.png"
4. Extract the title of the page using 'playwright_get_text' action with selector "title"
5. Finally, submit the form and tell me what happened
This demonstrates how Browser-Use AI can orchestrate tasks while using Playwright's precise capabilities for specific operations.
""",
llm=ChatOpenAI(model='gpt-4.1-mini'),
tools=tools, # Our custom tools with Playwright actions
browser_session=browser_session,
)
print('π― Starting AI agent with custom Playwright actions...')
# Step 5: Run the agent - it will use both Browser-Use actions and our custom Playwright actions
result = await agent.run()
# Keep browser open briefly to see results
print(f'β Integration demo completed! Result: {result}')
await asyncio.sleep(2) # Brief pause to see results
except Exception as e:
print(f'β Error: {e}')
raise
finally:
# Clean up resources
if playwright_browser:
await playwright_browser.close()
if playwright_instance:
await playwright_instance.stop()
if chrome_process:
chrome_process.terminate()
try:
await asyncio.wait_for(chrome_process.wait(), 5)
except TimeoutError:
chrome_process.kill()
print('β Cleanup complete')
if __name__ == '__main__':
# Run the advanced integration demo
asyncio.run(main())
```
# Sensitive Data
Source: https://docs.browser-use.com/open-source/examples/templates/sensitive-data
For comprehensive authentication guidance including real browser profiles, storage state, and 2FA, see the [Authentication Guide](/open-source/customize/browser/authentication).
```python
import os
from browser_use import Agent, Browser, ChatOpenAI
os.environ['ANONYMIZED_TELEMETRY'] = "false"
company_credentials = {'x_user': 'your-real-username@email.com', 'x_pass': 'your-real-password123'}
# Option 1: Secrets available for all websites
sensitive_data = company_credentials
# Option 2: Secrets per domain with regex
# sensitive_data = {
# 'https://*.example-staging.com': company_credentials,
# 'http*://test.example.com': company_credentials,
# 'https://example.com': company_credentials,
# 'https://google.com': {'g_email': 'user@gmail.com', 'g_pass': 'google_password'},
# }
agent = Agent(
task='Log into example.com with username x_user and password x_pass',
sensitive_data=sensitive_data,
use_vision=False, # Disable vision to prevent LLM seeing sensitive data in screenshots
llm=ChatOpenAI(model='gpt-4.1-mini'),
)
async def main():
await agent.run()
```
## How it Works
1. **Text Filtering**: The LLM only sees placeholders (`x_user`, `x_pass`), we filter your sensitive data from the input text.
2. **DOM Actions**: Real values are injected directly into form fields after the LLM call
## Best Practices
- Use `Browser(allowed_domains=[...])` to restrict navigation
- Set `use_vision=False` to prevent screenshot leaks
- Use `storage_state='./auth.json'` for login cookies instead of passwords when possible
# Secure Setup
Source: https://docs.browser-use.com/open-source/examples/templates/secure
## Secure Setup with Azure OpenAI
Enterprise-grade security with Azure OpenAI, data privacy protection, and restricted browser access.
```python
import asyncio
import os
from dotenv import load_dotenv
load_dotenv()
os.environ['ANONYMIZED_TELEMETRY'] = 'false'
from browser_use import Agent, BrowserProfile, ChatAzureOpenAI
# Azure OpenAI configuration
api_key = os.getenv('AZURE_OPENAI_KEY')
azure_endpoint = os.getenv('AZURE_OPENAI_ENDPOINT')
llm = ChatAzureOpenAI(model='gpt-4.1-mini', api_key=api_key, azure_endpoint=azure_endpoint)
# Secure browser configuration
browser_profile = BrowserProfile(
allowed_domains=['*google.com', 'browser-use.com'],
enable_default_extensions=False
)
# Sensitive data filtering
sensitive_data = {'company_name': 'browser-use'}
# Create secure agent
agent = Agent(
task='Find the founders of the sensitive company_name',
llm=llm,
browser_profile=browser_profile,
sensitive_data=sensitive_data
)
async def main():
await agent.run(max_steps=10)
asyncio.run(main())
```
## Security Features
**Azure OpenAI:**
- NOT used to train OpenAI models
- NOT shared with other customers
- Hosted entirely within Azure
- 30-day retention (or zero with Limited Access Program)
**Browser Security:**
- `allowed_domains`: Restrict navigation to trusted sites
- `enable_default_extensions=False`: Disable potentially dangerous extensions
- `sensitive_data`: Filter sensitive information from LLM input
For enterprise deployments contact support@browser-use.com.
# More Examples
Source: https://docs.browser-use.com/open-source/examples/templates/more-examples
### π Browse All Examples
**[View Complete Examples Directory β](https://github.com/browser-use/browser-use/tree/main/examples)**
### π€ Contributing Examples
Have a great use case? **[Submit a pull request](https://github.com/browser-use/browser-use/pulls)** with your example!
# Ad-Use (Ad Generator)
Source: https://docs.browser-use.com/open-source/examples/apps/ad-use
This demo requires browser-use v0.7.6+.
## Features
1. Agent visits your target website
2. Captures brand name, tagline, and key selling points
3. Takes a clean screenshot for design reference
4. Creates scroll-stopping Instagram image ads with π
5. Generates viral TikTok video ads with Veo3
6. Supports parallel generation of multiple ads
## Setup
Make sure the newest version of browser-use is installed (with screenshot functionality):
```bash
pip install -U browser-use
```
Export your Gemini API key, get it from: [Google AI Studio](https://makersuite.google.com/app/apikey)
```
export GOOGLE_API_KEY='your-google-api-key-here'
```
Clone the repo and cd into the app folder
```bash
git clone https://github.com/browser-use/browser-use.git
cd browser-use/examples/apps/ad-use
```
## Normal Usage
```bash
# Basic - Generate Instagram image ad (default)
python ad_generator.py --url https://www.apple.com/iphone-16-pro/
# Generate TikTok video ad with Veo3
python ad_generator.py --tiktok --url https://www.apple.com/iphone-16-pro/
# Generate multiple ads in parallel
python ad_generator.py --instagram --count 3 --url https://www.apple.com/iphone-16-pro/
python ad_generator.py --tiktok --count 2 --url https://www.apple.com/iphone-16-pro/
# Debug Mode - See the browser in action
python ad_generator.py --url https://www.apple.com/iphone-16-pro/ --debug
```
## Command Line Options
- `--url`: Landing page URL to analyze
- `--instagram`: Generate Instagram image ad (default if no flag specified)
- `--tiktok`: Generate TikTok video ad using Veo3
- `--count N`: Generate N ads in parallel (default: 1)
- `--debug`: Show browser window and enable verbose logging
## Programmatic Usage
```python
import asyncio
from ad_generator import create_ad_from_landing_page
async def main():
results = await create_ad_from_landing_page(
url="https://your-landing-page.com",
debug=False
)
print(f"Generated ads: {results}")
asyncio.run(main())
```
## Output
Generated ads are saved in the `output/` directory with:
- **PNG image files** (ad_timestamp.png) - Instagram ads generated with Gemini 2.5 Flash Image
- **MP4 video files** (ad_timestamp.mp4) - TikTok ads generated with Veo3
- **Analysis files** (analysis_timestamp.txt) - Browser agent analysis and prompts used
- **Landing page screenshots** (landing_page_timestamp.png) - Reference screenshots
## Source Code
Full implementation: [https://github.com/browser-use/browser-use/tree/main/examples/apps/ad-use](https://github.com/browser-use/browser-use/tree/main/examples/apps/ad-use)
# Vibetest-Use (Automated QA)
Source: https://docs.browser-use.com/open-source/examples/apps/vibetest-use
Requires **browser-use < v0.5.0** and Playwright Chromium. Currently getting an update to v0.7.6+.
## Features
1. Launches multiple headless (or visible) Browser-Use agents in parallel
2. Crawls your site and records screenshots, broken links & a11y issues
3. Works on production URLs *and* `localhost` dev servers
4. Simple natural-language prompts via MCP in Cursor / Claude Code
## Quick Start
```bash
# 1. Clone repo
git clone https://github.com/browser-use/vibetest-use.git
cd vibetest-use
# 2. Create & activate env
uv venv --python 3.11
source .venv/bin/activate
# 3. Install project
uv pip install -e .
# 4. Install browser runtime once
uvx browser-use install
```
### 1) Claude Code
```bash
# Register the MCP server
claude mcp add vibetest /full/path/to/vibetest-use/.venv/bin/vibetest-mcp \
-e GOOGLE_API_KEY="your_api_key"
# Inside a Claude chat
> /mcp
# βΏ MCP Server Status
# β’ vibetest: connected
```
### 2) Cursor (manual MCP entry)
1. Open **Settings β MCP**
2. Click **Add Server** and paste:
```json
{
"mcpServers": {
"vibetest": {
"command": "/full/path/to/vibetest-use/.venv/bin/vibetest-mcp",
"env": {
"GOOGLE_API_KEY": "your_api_key"
}
}
}
}
```
## Basic Prompts
```
> Vibetest my website with 5 agents: browser-use.com
> Run vibetest on localhost:3000
> Run a headless vibetest on localhost:8080 with 10 agents
```
### Parameters
* **URL** β any `https` or `http` host or `localhost:port`
* **Agents** β `3` by default; more agents = deeper coverage
* **Headless** β say *headless* to hide the browser, omit to watch it live
## Requirements
* Python 3.11+
* Google API key (Gemini flash used for analysis)
* Cursor / Claude with MCP support
## Source Code
Full implementation: [https://github.com/browser-use/vibetest-use](https://github.com/browser-use/vibetest-use)
# News-Use (News Monitor)
Source: https://docs.browser-use.com/open-source/examples/apps/news-use
This demo requires browser-use v0.7.7+.
## Features
1. Agent visits any news website automatically
2. Finds and clicks the most recent headline article
3. Extracts title, URL, posting time, and full content
4. Generates short/long summaries with sentiment analysis
5. Persistent deduplication across monitoring sessions
## Setup
Make sure the newest version of browser-use is installed:
```bash
pip install -U browser-use
```
Export your Gemini API key, get it from: [Google AI Studio](https://makersuite.google.com/app/apikey)
```bash
export GOOGLE_API_KEY='your-google-api-key-here'
```
Clone the repo, cd to the app
```bash
git clone https://github.com/browser-use/browser-use.git
cd browser-use/examples/apps/news-use
```
## Usage Examples
```bash
# One-time extraction - Get the latest article and exit
python news_monitor.py --once
# Monitor Bloomberg continuously (default)
python news_monitor.py
# Monitor TechCrunch every 60 seconds
python news_monitor.py --url https://techcrunch.com --interval 60
# Debug mode - See browser in action
python news_monitor.py --once --debug
```
## Output Format
Articles are displayed with timestamp, sentiment emoji, and summary:
```
[2025-09-11 02:49:21] - π’ - Klarna's IPO raises $1.4B, benefiting existing investors
[2025-09-11 02:54:15] - π΄ - Tech layoffs continue as major firms cut workforce
[2025-09-11 02:59:33] - π‘ - Federal Reserve maintains interest rates unchanged
```
**Sentiment Indicators:**
- π’ **Positive** - Good news, growth, success stories
- π‘ **Neutral** - Factual reporting, announcements, updates
- π΄ **Negative** - Challenges, losses, negative events
## Data Persistence
All extracted articles are saved to `news_data.json` with complete metadata:
```json
{
"hash": "a1b2c3d4...",
"pulled_at": "2025-09-11T02:49:21Z",
"data": {
"title": "Klarna's IPO pops, raising $1.4B",
"url": "https://techcrunch.com/2025/09/11/klarna-ipo/",
"posting_time": "12:11 PM PDT Β· September 10, 2025",
"short_summary": "Klarna's IPO raises $1.4B, benefiting existing investors like Sequoia.",
"long_summary": "Fintech Klarna successfully IPO'd on the NYSE...",
"sentiment": "positive"
}
}
```
## Programmatic Usage
```python
import asyncio
from news_monitor import extract_latest_article
async def main():
# Extract latest article from any news site
result = await extract_latest_article(
site_url="https://techcrunch.com",
debug=False
)
if result["status"] == "success":
article = result["data"]
print(f"π° {article['title']}")
print(f"π Sentiment: {article['sentiment']}")
print(f"π Summary: {article['short_summary']}")
asyncio.run(main())
```
## Advanced Configuration
```python
# Custom monitoring with filters
async def monitor_with_filters():
while True:
result = await extract_latest_article("https://bloomberg.com")
if result["status"] == "success":
article = result["data"]
# Only alert on negative market news
if article["sentiment"] == "negative" and "market" in article["title"].lower():
send_alert(article)
await asyncio.sleep(300) # Check every 5 minutes
```
## Source Code
Full implementation: [https://github.com/browser-use/browser-use/tree/main/examples/apps/news-use](https://github.com/browser-use/browser-use/tree/main/examples/apps/news-use)
# Msg-Use (WhatsApp Sender)
Source: https://docs.browser-use.com/open-source/examples/apps/msg-use
This demo requires browser-use v0.7.7+.
## Features
1. Agent logs into WhatsApp Web automatically
2. Parses natural language scheduling instructions
3. Composes personalized messages using AI
4. Schedules messages for future delivery or sends immediately
5. Persistent session (no repeated QR scanning)
## Setup
Make sure the newest version of browser-use is installed:
```bash
pip install -U browser-use
```
Export your Gemini API key, get it from: [Google AI Studio](https://makersuite.google.com/app/apikey)
```bash
export GOOGLE_API_KEY='your-gemini-api-key-here'
```
Clone the repo and cd into the app folder
```bash
git clone https://github.com/browser-use/browser-use.git
cd browser-use/examples/apps/msg-use
```
## Initial Login
First-time setup requires QR code scanning:
```bash
python login.py
```
- Scan QR code when browser opens
- Session will be saved for future use
## Normal Usage
1. **Edit your schedule** in `messages.txt`:
```
- Send "Hi" to Magnus on the 13.06 at 18:15
- Tell hinge date (Camila) at 20:00 that I miss her
- Send happy birthday message to sister on the 15.06
- Remind mom to pick up the car next tuesday
```
2. **Test mode** - See what will be sent:
```bash
python scheduler.py --test
```
3. **Run scheduler**:
```bash
python scheduler.py
# Debug Mode - See the browser in action
python scheduler.py --debug
# Auto Mode - Respond to unread messages every ~30 minutes
python scheduler.py --auto
```
## Programmatic Usage
```python
import asyncio
from scheduler import schedule_messages
async def main():
messages = [
"Send hello to John at 15:30",
"Remind Sarah about meeting tomorrow at 9am"
]
await schedule_messages(messages, debug=False)
asyncio.run(main())
```
## Example Output
The scheduler processes natural language and outputs structured results:
```json
[
{
"contact": "Magnus",
"original_message": "Hi",
"composed_message": "Hi",
"scheduled_time": "2025-06-13 18:15"
},
{
"contact": "Camila",
"original_message": "I miss her",
"composed_message": "I miss you β€οΈ",
"scheduled_time": "2025-06-14 20:00"
},
{
"contact": "sister",
"original_message": "happy birthday message",
"composed_message": "Happy birthday! π Wishing you an amazing day, sis! Hope you have the best birthday ever! β€οΈππ",
"scheduled_time": "2025-06-15 09:00"
}
]
```
## Source Code
Full implementation: [https://github.com/browser-use/browser-use/tree/main/examples/apps/msg-use](https://github.com/browser-use/browser-use/tree/main/examples/apps/msg-use)
# Overview
Source: https://docs.browser-use.com/open-source/examples/skills/overview
Browser Use ships a set of [agent skills](https://www.skills.sh/browser-use/browser-use) β self-contained `SKILL.md` bundles that teach a coding agent (Claude Code, Cursor, OpenClaw, Hermes, and others) how to use Browser Use. Each skill is installable from [skills.sh](https://www.skills.sh/browser-use/browser-use) with one command.
## Install
Every skill installs through the [skills CLI](https://www.skills.sh) with the same pattern β swap in the skill name with `--skill`:
```bash
npx skills add https://github.com/browser-use/browser-use --skill
```
For example, to install the QA skill:
```bash
npx skills add https://github.com/browser-use/browser-use --skill qa
```
The skills CLI drops the skill into your agent's skills directory (e.g. `.claude/skills/` for Claude Code). Your agent picks it up automatically β no extra wiring.
## Available skills
[browser-use](https://docs.browser-use.com/open-source/examples/skills/browser-use)
Drive a browser directly from the CLI β navigate, click, fill forms, screenshot, and extract data.
[cloud](https://docs.browser-use.com/open-source/examples/skills/cloud)
Reference for Browser Use Cloud β the hosted REST API (v2 & v3) and the Python/TypeScript SDKs.
[open-source](https://docs.browser-use.com/open-source/examples/skills/open-source)
Reference for writing Python against the `browser-use` library β Agent, Browser, Tools, and more.
[qa](https://docs.browser-use.com/open-source/examples/skills/qa)
QA-test any site or local dev server and return a 1β5 quality score with evidence.
[remote-browser](https://docs.browser-use.com/open-source/examples/skills/remote-browser)
Control a headless browser from a sandboxed remote machine (cloud VMs, CI, coding agents).
[x402](https://docs.browser-use.com/open-source/examples/skills/x402)
Pay for Browser Use Cloud per request from a crypto wallet β no signup or API key.
## Source
All skills live in the [`skills/` directory](https://github.com/browser-use/browser-use/tree/main/skills) of the `browser-use` repo.
# browser-use
Source: https://docs.browser-use.com/open-source/examples/skills/browser-use
The `browser-use` skill teaches your agent the [Browser Use CLI](/open-source/browser-use-cli). The CLI runs Python in the browser to do actions online. The agent can connect to your real Chrome, preserving logins, or to a Browser Use cloud browser.
## Install
```text
Install or upgrade browser-use with `uv tool install --python 3.12 --upgrade --force 'browser-use @ git+https://github.com/browser-use/browser-use.git'`, run `browser-use skill install`, and connect it to my browser. Follow https://github.com/browser-use/browser-use if setup or connection fails.
```
## Links
[skills.sh](https://www.skills.sh/browser-use/browser-use/browser-use)
[Source](https://github.com/browser-use/browser-use/tree/main/skills/browser-use)
# cloud
Source: https://docs.browser-use.com/open-source/examples/skills/cloud
The `cloud` skill gives your agent a reference for [Browser Use Cloud](https://docs.browser-use.com/cloud/quickstart): the REST API (v2 and v3), the `browser-use-sdk` (Python and TypeScript), `X-Browser-Use-API-Key` authentication, cloud sessions, browser profiles and profile sync, CDP WebSocket access, stealth browsers, residential proxies, CAPTCHA handling, webhooks, workspaces, the skills marketplace, `liveUrl` streaming, pricing, and integration patterns (chat UI, subagents, n8n/Make/Zapier, Playwright/Puppeteer/Selenium).
For the open-source Python library (`Agent`, `Browser`, `Tools`), use the [`open-source`](/open-source/examples/skills/open-source) skill instead.
## Install
```bash
npx skills add https://github.com/browser-use/browser-use --skill cloud
```
## Links
[skills.sh](https://www.skills.sh/browser-use/browser-use/cloud)
[Source](https://github.com/browser-use/browser-use/tree/main/skills/cloud)
# open-source
Source: https://docs.browser-use.com/open-source/examples/skills/open-source
The `open-source` skill gives your agent a reference for writing Python against the [`browser-use` library](/open-source/quickstart): `Agent`, `Browser`, and `Tools` configuration, supported LLM models (15+ providers), the Actor API, custom tools, lifecycle hooks, MCP server setup, sensitive-data handling, prompting strategies, and monitoring/observability with Laminar or OpenLIT.
For the Cloud API/SDK, use the [`cloud`](/open-source/examples/skills/cloud) skill. To drive a browser directly via CLI, use the [`browser-use`](/open-source/examples/skills/browser-use) skill.
## Install
```bash
npx skills add https://github.com/browser-use/browser-use --skill open-source
```
## Links
[skills.sh](https://www.skills.sh/browser-use/browser-use/open-source)
[Source](https://github.com/browser-use/browser-use/tree/main/skills/open-source)
# qa
Source: https://docs.browser-use.com/open-source/examples/skills/qa
The `qa` skill drives a website with a real browser, judges how well it does the thing you asked about, and returns a **score from 1 (broken) to 5 (excellent)** with evidence β the deliverable is a verdict, not a screenshot dump. Use it to test, QA, evaluate, or score a site, page, flow, or app, including a local dev server (e.g. `localhost:5173`) which it tunnels out automatically. It runs on a real Browser Use cloud browser.
## Install
```bash
npx skills add https://github.com/browser-use/browser-use --skill qa
```
## Links
[skills.sh](https://www.skills.sh/browser-use/browser-use/qa)
[Source](https://github.com/browser-use/browser-use/tree/main/skills/qa)
# remote-browser
Source: https://docs.browser-use.com/open-source/examples/skills/remote-browser
The `remote-browser` skill is for agents running on **sandboxed remote machines** (cloud VMs, CI, coding agents) that need to control a headless browser. It uses the same [Browser Use CLI](/open-source/browser-use-cli) workflow as the [`browser-use`](/open-source/examples/skills/browser-use) skill β `open`, `state`, `click`, `input`, `screenshot`, `close` β plus headless Chromium, cloud browsers, CDP connection, and tunnels to expose local dev servers.
## Install
```bash
npx skills add https://github.com/browser-use/browser-use --skill remote-browser
```
## Links
[skills.sh](https://www.skills.sh/browser-use/browser-use/remote-browser)
[Source](https://github.com/browser-use/browser-use/tree/main/skills/remote-browser)
# x402
Source: https://docs.browser-use.com/open-source/examples/skills/x402
The `x402` skill walks your agent through setting up [Browser Use Cloud payments with x402](https://docs.browser-use.com/cloud/guides/x402) β pay per request from a crypto wallet (USDC on Base mainnet), with no signup, API key, or credit card. It guides wallet setup, funding, writing the key to `.env`, and a ~$1 test run. The SDK is the easiest path, and non-SDK flows are available via x402-aware client libraries. Use it when you want pay-per-use access without an API key.
## Install
```bash
npx skills add https://github.com/browser-use/browser-use --skill x402
```
## Links
[skills.sh](https://www.skills.sh/browser-use/browser-use/x402)
[Source](https://github.com/browser-use/browser-use/tree/main/skills/x402)
# Local Development Setup
Source: https://docs.browser-use.com/open-source/development/setup/local-setup
## Welcome to Browser Use Development!
```bash
git clone https://github.com/browser-use/browser-use
cd browser-use
uv sync --all-extras --dev
# or pip install -U git+https://github.com/browser-use/browser-use.git@main
```
## Configuration
Set up your environment variables:
```bash
# Copy the example environment file
cp .env.example .env
# set logging level
# BROWSER_USE_LOGGING_LEVEL=debug
```
## Helper Scripts
For common development tasks
```bash
# Complete setup script - installs uv, creates a venv, and installs dependencies
./bin/setup.sh
# Run all pre-commit hooks (formatting, linting, type checking)
./bin/lint.sh
# Run the core test suite that's executed in CI
./bin/test.sh
```
## Run examples
```bash
uv run examples/simple.py
```
# Contribution Guide
Source: https://docs.browser-use.com/open-source/development/setup/contribution-guide
## Mission
- Make developers happy
- Do more clicks than human
- Tell your computer what to do, and it gets it done.
- Make agents faster and more reliable.
## What to work on?
- This space is moving fast. We have 10 ideas daily. Let us exchange some.
- Browse our [GitHub Issues](https://github.com/browser-use/browser-use/issues)
- Check out our most active issues on [Discord](https://discord.gg/zXJJHtJf3k)
- Get inspiration in [`#showcase-your-work`](https://discord.com/channels/1303749220842340412/1305549200678850642) channel
## What makes a great PR?
1. Why do we need this PR?
2. Include a demo screenshot/gif
3. Make sure the PR passes all CI tests
4. Keep your PR focused on a single feature
## How?
1. Fork the repository
2. Create a new branch for your feature
3. Submit a PR
We are overwhelmed with Issues. Feel free to bump your issues/PRs with comments periodically if you need faster feedback.
# Lifecycle Hooks
Source: https://docs.browser-use.com/open-source/customize/hooks
Browser-Use provides lifecycle hooks that allow you to execute custom code at specific points during the agent's execution.
Hook functions can be used to read and modify agent state while running, implement custom logic, change configuration, integrate the Agent with external applications.
## Available Hooks
Currently, Browser-Use provides the following hooks:
| Hook | Description | When it is called |
| --------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `on_step_start` | Executed at the beginning of each agent step | Before the agent processes the current state and decides on the next action |
| `on_step_end` | Executed at the end of each agent step | After the agent has executed all the actions for the current step, before it starts the next step |
```python
await agent.run(on_step_start=..., on_step_end=...)
```
Each hook should be an `async` callable function that accepts the `agent` instance as its only parameter.
### Basic Example
```python
import asyncio
from pathlib import Path
from browser_use import Agent, ChatOpenAI
from browser_use.browser.events import ScreenshotEvent
async def my_step_hook(agent: Agent):
# inside a hook you can access all the state and methods under the Agent object:
# agent.settings, agent.state, agent.task
# agent.tools, agent.llm, agent.browser_session
# agent.pause(), agent.resume(), agent.add_new_task(...), etc.
# You also have direct access to the browser state
state = await agent.browser_session.get_browser_state_summary()
current_url = state.url
visit_log = agent.history.urls()
previous_url = visit_log[-2] if len(visit_log) >= 2 else None
print(f'Agent was last on URL: {previous_url} and is now on {current_url}')
cdp_session = await agent.browser_session.get_or_create_cdp_session()
# Example: Get page HTML content
doc = await cdp_session.cdp_client.send.DOM.getDocument(session_id=cdp_session.session_id)
html_result = await cdp_session.cdp_client.send.DOM.getOuterHTML(
params={'nodeId': doc['root']['nodeId']}, session_id=cdp_session.session_id
)
page_html = html_result['outerHTML']
# Example: Take a screenshot using the event system
screenshot_event = agent.browser_session.event_bus.dispatch(ScreenshotEvent(full_page=False))
await screenshot_event
result = await screenshot_event.event_result(raise_if_any=True, raise_if_none=True)
# Example: pause agent execution and resume it based on some custom code
if '/finished' in current_url:
agent.pause()
Path('result.txt').write_text(page_html)
input('Saved "finished" page content to result.txt, press [Enter] to resume...')
agent.resume()
async def main():
agent = Agent(
task='Search for the latest news about AI',
llm=ChatOpenAI(model='gpt-5-mini'),
)
await agent.run(
on_step_start=my_step_hook,
# on_step_end=...
max_steps=10,
)
if __name__ == '__main__':
asyncio.run(main())
```
## Data Available in Hooks
When working with agent hooks, you have access to the entire `Agent` instance. Here are some useful data points you can access:
- `agent.task` provides the main task, `agent.add_new_task(...)` allows you to queue up a new one
- `agent.tools` gives access to the `Tools()` object and `Registry()` containing the available actions
- `agent.tools.registry.execute_action('click', {'index': 123}, browser_session=agent.browser_session)`
- `agent.sensitive_data` contains the sensitive data dict, which can be updated in-place to add/remove/modify items
- `agent.settings` contains all the configuration options passed to the `Agent(...)` at init time
- `agent.llm` provides direct access to the main LLM object (e.g. `ChatOpenAI`)
- `agent.state` provides access to internal state, including agent thoughts, outputs, actions, and more
- `agent.history` gives access to historical data from the agent's execution:
- `agent.history.model_thoughts()`: Reasoning from Browser Use's model.
- `agent.history.model_outputs()`: Raw outputs from the Browser Use's model.
- `agent.history.model_actions()`: Actions taken by the agent
- `agent.history.extracted_content()`: Content extracted from web pages
- `agent.history.urls()`: URLs visited by the agent
- `agent.browser_session` provides direct access to the `BrowserSession` and CDP interface
- `agent.browser_session.agent_focus_target_id`: Get the current target ID the agent is focused on
- `agent.browser_session.get_or_create_cdp_session()`: Get the current CDP session for browser interaction
- `agent.browser_session.get_tabs()`: Get all tabs currently open
- `agent.browser_session.get_current_page_url()`: Get the URL of the current active tab
- `agent.browser_session.get_current_page_title()`: Get the title of the current active tab
## Tips for Using Hooks
- **Avoid blocking operations**: Since hooks run in the same execution thread as the agent, keep them efficient and avoid blocking operations.
- **Use custom tools instead**: Hooks are fairly advanced. Most use cases can be implemented with [custom tools](/open-source/customize/tools/basics) instead.
- **Increase step_timeout**: If your hook is doing something that takes a long time, you can increase the `step_timeout` parameter in the `Agent(...)` constructor.
---
# Observability
Source: https://docs.browser-use.com/open-source/development/monitoring/observability
## Overview
Browser Use has a native integration with [Laminar](https://laminar.sh) - open-source platform for monitoring and analyzing error patterns in AI agents.
Laminar SDK automatically captures **agent execution steps, costs and browser session recordings** of Browser Use agent.
Browser session recordings allow developers to see full video replay of the browser session, which is useful for debugging Browser Use agent.
## Setup
Install Laminar python SDK.
```bash
pip install lmnr
```
Register on [Laminar Cloud](https://laminar.sh) or [self-host Laminar](https://github.com/lmnr-ai/lmnr), create a project and get the project API key from your project settings. Set the `LMNR_PROJECT_API_KEY` environment variable.
```bash
export LMNR_PROJECT_API_KEY=
```
## Usage
Initialize Laminar at the top of your project, and both Browser Use agent traces and session recordings will be automatically captured.
```python {7-9}
from browser_use import Agent, ChatGoogle
import asyncio
from lmnr import Laminar
import os
# At initialization time, Laminar auto-instruments
# Browser Use and any browser you use (local or remote)
Laminar.initialize(project_api_key=os.getenv('LMNR_PROJECT_API_KEY'))
async def main():
agent = Agent(
task="go to ycombinator.com, summarize 3 startups from the latest batch",
llm=ChatGoogle(model="gemini-2.5-flash"),
)
await agent.run()
asyncio.run(main())
```
## Viewing Traces
You can view traces in the Laminar UI by going to the traces tab in your project.
When you select a trace, you can see both the browser session recording and the agent execution steps.
Timeline of the browser session is synced with the agent execution steps.
In the trace view, you can also see the agent's current step, the tool it is using, and the tool's input and output.
## Laminar
To learn more about how you can trace and evaluate your Browser Use agent with Laminar, check out [Laminar docs](https://docs.lmnr.ai).
## Browser Use Cloud Authentication
Browser Use can sync your agent runs to the cloud for easy viewing and sharing. Authentication is required to protect your data.
### Quick Setup
```bash
# Authenticate once to enable cloud sync for all future runs
browser-use auth
# Or if using module directly:
python -m browser_use.cli auth
```
**Note**: Cloud sync is enabled by default. If you have disabled it, you can re-enable with `export BROWSER_USE_CLOUD_SYNC=true`.
### Manual Authentication
```python
# Authenticate from code after task completion
from browser_use import Agent
agent = Agent(task="your task")
await agent.run()
# Later, authenticate for future runs
await agent.authenticate_cloud_sync()
```
### Reset Authentication
```bash
# Force re-authentication with a different account
rm ~/.config/browseruse/cloud_auth.json
browser-use auth
```
**Note**: Authentication uses OAuth Device Flow - you must complete the auth process while the command is running. Links expire when the polling stops.
# OpenLIT
Source: https://docs.browser-use.com/open-source/development/monitoring/openlit
## Overview
Browser Use has native integration with [OpenLIT](https://github.com/openlit/openlit) - an open-source opentelemetry-native platform that provides complete, granular traces for every task your browser-use agent performsβfrom high-level agent invocations down to individual browser actions.
Read more about OpenLIT in the [OpenLIT docs](https://docs.openlit.io).
## Setup
Install OpenLIT alongside Browser Use:
```bash
pip install openlit browser-use
```
## Usage
OpenLIT provides automatic, comprehensive instrumentation with **zero code changes** beyond initialization:
```python {5-6}
from browser_use import Agent, Browser, ChatOpenAI
import asyncio
import openlit
# Initialize OpenLIT - that's it!
openlit.init()
async def main():
browser = Browser()
llm = ChatOpenAI(
model="gpt-4o",
)
agent = Agent(
task="Find the number trending post on Hacker news",
llm=llm,
browser=browser,
)
history = await agent.run()
return history
if __name__ == "__main__":
history = asyncio.run(main())
```
## Viewing Traces
OpenLIT provides a powerful dashboard where you can:
### Monitor Execution Flows
See the complete execution tree with timing information for every span. Click on any `invoke_model` span to see the exact prompt sent to the LLM and the complete response with agent reasoning.
### Track Costs and Token Usage
- Cost breakdown by agent, task, and model
- Token usage per LLM call with full input/output visibility
- Compare costs across different LLM providers
- Identify expensive prompts and optimize them
### Debug Failures with Agent Thoughts
When an automation fails, you can:
- See exactly which step failed
- Read the agent's thinking at the failure point
- Check the browser state and available elements
- Analyze whether the failure was due to bad reasoning or bad information
- Fix the root cause with full context
### Performance Optimization
- Identify slow steps (LLM calls vs browser actions vs HTTP requests)
- Compare execution times across runs
- Optimize max_steps and max_actions_per_step
- Track HTTP request latency for page navigations
## Configuration
### Custom OpenTelemetry Endpoint Configuration
```python
import openlit
# Configure custom OTLP endpoints
openlit.init(
otlp_endpoint="http://localhost:4318",
application_name="my-browser-automation",
environment="production"
)
```
### Environment Variables
You can also configure OpenLIT via environment variables:
```bash
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_SERVICE_NAME="browser-automation"
export OTEL_ENVIRONMENT="production"
```
### Self-Hosted OpenLIT
If you prefer to keep your data on-premises:
```bash
# Using Docker
docker run -d \
-p 4318:4318 \
-p 3000:3000 \
openlit/openlit:latest
# Access dashboard at http://localhost:3000
```
## Integration with Existing Tools
OpenLIT uses OpenTelemetry internally, so it integrates seamlessly with:
- **Jaeger** - Distributed tracing visualization
- **Prometheus** - Metrics collection and alerting
- **Grafana** - Custom dashboards and analytics
- **Datadog** - APM and log management
- **New Relic** - Full-stack observability
- **Elastic APM** - Application performance monitoring
Simply configure OpenLIT to export to your existing OTLP-compatible endpoint.
# Telemetry
Source: https://docs.browser-use.com/open-source/development/monitoring/telemetry
## Overview
Browser Use is free under the MIT license. To help us continue improving the library, we collect usage telemetry with [PostHog](https://posthog.com). Telemetry may include usage metadata and task-level data such as task instructions, URLs visited, action traces, errors, and final results. We may use this information to operate, debug, secure, analyze, develop, and improve Browser Use and related offerings, including by creating aggregated, de-identified, or sanitized datasets and workflow patterns in accordance with our Terms of Service and Privacy Policy.
## Opting Out
You can disable telemetry by setting the environment variable:
```bash .env
ANONYMIZED_TELEMETRY=false
```
Or in your Python code:
```python
import os
os.environ["ANONYMIZED_TELEMETRY"] = "false"
```
Even when enabled, telemetry has zero impact on the library's performance. Code is available in [Telemetry
Service](https://github.com/browser-use/browser-use/tree/main/browser_use/telemetry).
## Legal
By using Browser Use services, you agree to our [Terms of Service](https://browser-use.com/legal/terms-of-service) and
[Privacy Policy](https://browser-use.com/privacy/).
# Costs
Source: https://docs.browser-use.com/open-source/development/monitoring/costs
## Cost Tracking
To track token usage and costs, enable cost calculation:
```python
from browser_use import Agent, ChatBrowserUse
agent = Agent(
task="Search for latest news about AI",
llm=ChatBrowserUse(),
calculate_cost=True # Enable cost tracking
)
history = await agent.run()
# Get usage from history
print(f"Token usage: {history.usage}")
# Or get from usage summary
usage_summary = await agent.token_cost_service.get_usage_summary()
print(f"Usage summary: {usage_summary}")
```
# Get Help
Source: https://docs.browser-use.com/open-source/development/get-help
1. Check our [GitHub Issues](https://github.com/browser-use/browser-use/issues)
2. Ask in our [Discord community](https://link.browser-use.com/discord)
3. Get support for your enterprise with support@browser-use.com