# Browser Use Open Source β€” Full Documentation # Browser Use Open Source Source: https://docs.browser-use.com/open-source/introduction Browser Use Open Source Browser Use Open Source [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 ## 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