ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
@@ -0,0 +1,17 @@
|
||||
# Docs
|
||||
|
||||
The official documentation for Browser Use. The docs are published to [Browser Use Docs](https://docs.browser-use.com).
|
||||
|
||||
### Development
|
||||
|
||||
Install the [Mintlify CLI](https://www.npmjs.com/package/mintlify) to preview the documentation changes locally. To install, use the following command
|
||||
|
||||
```
|
||||
npm i -g mintlify
|
||||
```
|
||||
|
||||
Run the following command at the root of your documentation (where mint.json is)
|
||||
|
||||
```
|
||||
mintlify dev
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: "Authentication"
|
||||
description: "Learn how to authenticate with the Browser Use Cloud API"
|
||||
icon: "lock"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
The Browser Use Cloud API uses API keys to authenticate requests. You can obtain an API key from your [Browser Use Cloud dashboard](https://cloud.browser-use.com/settings/api-keys).
|
||||
|
||||
## API Keys
|
||||
|
||||
All API requests must include your API key in the `Authorization` header:
|
||||
|
||||
```bash
|
||||
Authorization: Bearer YOUR_API_KEY
|
||||
```
|
||||
|
||||
Keep your API keys secure and do not share them in publicly accessible areas such as GitHub, client-side code, or in your browser's developer tools. API keys should be stored securely in environment variables or a secure key management system.
|
||||
|
||||
## Example Request
|
||||
|
||||
Here's an example of how to include your API key in a request using Python:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
API_KEY = 'your_api_key_here'
|
||||
BASE_URL = 'https://api.browser-use.com/api/v1'
|
||||
HEADERS = {'Authorization': f'Bearer {API_KEY}'}
|
||||
|
||||
response = requests.get(f'{BASE_URL}/me', headers=HEADERS)
|
||||
print(response.json())
|
||||
```
|
||||
|
||||
## Verifying Authentication
|
||||
|
||||
You can verify that your API key is valid by making a request to the `/api/v1/me` endpoint. See the [Me endpoint documentation](/api-reference/api-v1/me) for more details.
|
||||
|
||||
## API Key Security
|
||||
|
||||
To ensure the security of your API keys:
|
||||
|
||||
1. **Never share your API key** in publicly accessible areas
|
||||
2. **Rotate your API keys** periodically
|
||||
3. **Use environment variables** to store API keys in your applications
|
||||
4. **Implement proper access controls** for your API keys
|
||||
5. **Monitor API key usage** for suspicious activity
|
||||
|
||||
If you believe your API key has been compromised, you should immediately revoke it and generate a new one from your Browser Use Cloud dashboard.
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: "Cloud SDK"
|
||||
description: "Learn how to set up your own Browser Use Cloud SDK"
|
||||
icon: "code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
This guide walks you through setting up your own Browser Use Cloud SDK.
|
||||
|
||||
## Building your own client (OpenAPI)
|
||||
|
||||
<Note>
|
||||
This approach is recommended **only** if you need to run simple tasks and
|
||||
**don’t require fine-grained control**.
|
||||
</Note>
|
||||
|
||||
The best way to build your own client is to use our [OpenAPI specification](http://api.browser-use.com/openapi.json) to generate a type-safe client library.
|
||||
|
||||
### Python
|
||||
|
||||
Use [openapi-python-client](https://github.com/openapi-generators/openapi-python-client) to generate a modern Python client:
|
||||
|
||||
```bash
|
||||
# Install the generator
|
||||
pipx install openapi-python-client --include-deps
|
||||
|
||||
# Generate the client
|
||||
openapi-python-client generate --url http://api.browser-use.com/openapi.json
|
||||
```
|
||||
|
||||
This will create a Python package with full type hints, modern dataclasses, and async support.
|
||||
|
||||
### TypeScript/JavaScript
|
||||
|
||||
Use [OpenAPI TS](https://openapi-ts.dev/) library to generate a type safe TypeScript client for the Browser Use API.
|
||||
|
||||
The following guide shows how to create a simple type-safe `fetch` client, but you can also use other generators.
|
||||
|
||||
- React Query - https://openapi-ts.dev/openapi-react-query/
|
||||
- SWR - https://openapi-ts.dev/swr-openapi/
|
||||
|
||||
|
||||
<CodeGroup>
|
||||
```bash npm
|
||||
npm install openapi-fetch
|
||||
npm install -D openapi-typescript typescript
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn add openapi-fetch
|
||||
yarn add -D openapi-typescript typescript
|
||||
```
|
||||
```bash pnpm
|
||||
pnpm add openapi-fetch
|
||||
pnpm add -D openapi-typescript typescript
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
"openapi:gen": "openapi-typescript https://api.browser-use.com/openapi.json -o ./src/lib/api/v1.d.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
pnpm openapi:gen
|
||||
```
|
||||
|
||||
```ts
|
||||
// client.ts
|
||||
|
||||
'use client'
|
||||
|
||||
import createClient from 'openapi-fetch'
|
||||
import { paths } from '@/lib/api/v1'
|
||||
|
||||
export type Client = ReturnType<typeof createClient<paths>>
|
||||
|
||||
export const client = createClient<paths>({
|
||||
baseUrl: 'https://api.browser-use.com/',
|
||||
|
||||
// NOTE: You can get your API key from https://cloud.browser-use.com/billing!
|
||||
headers: { Authorization: `Bearer ${apiKey}` },
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
<Note>
|
||||
Need help? Contact our support team at support@browser-use.com or join our
|
||||
[Discord community](https://link.browser-use.com/discord)
|
||||
</Note>
|
||||
@@ -0,0 +1,199 @@
|
||||
---
|
||||
title: "V1 Implementation"
|
||||
description: "Learn how to implement the Browser Use API in Python"
|
||||
icon: "code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
This guide shows how to implement common API patterns using Python. We'll create a complete example that creates and monitors a browser automation task.
|
||||
|
||||
## Basic Implementation
|
||||
|
||||
For all settings see [Run Task](/api-reference/api-v1/run-task).
|
||||
|
||||
Here's a simple implementation using Python's `requests` library to stream the task steps:
|
||||
|
||||
```python
|
||||
import json
|
||||
import time
|
||||
|
||||
import requests
|
||||
|
||||
API_KEY = 'your_api_key_here'
|
||||
BASE_URL = 'https://api.browser-use.com/api/v1'
|
||||
HEADERS = {'Authorization': f'Bearer {API_KEY}'}
|
||||
|
||||
|
||||
def create_task(instructions: str):
|
||||
"""Create a new browser automation task"""
|
||||
response = requests.post(f'{BASE_URL}/run-task', headers=HEADERS, json={'task': instructions})
|
||||
return response.json()['id']
|
||||
|
||||
|
||||
def get_task_status(task_id: str):
|
||||
"""Get current task status"""
|
||||
response = requests.get(f'{BASE_URL}/task/{task_id}/status', headers=HEADERS)
|
||||
return response.json()
|
||||
|
||||
|
||||
def get_task_details(task_id: str):
|
||||
"""Get full task details including output"""
|
||||
response = requests.get(f'{BASE_URL}/task/{task_id}', headers=HEADERS)
|
||||
return response.json()
|
||||
|
||||
|
||||
def wait_for_completion(task_id: str, poll_interval: int = 2):
|
||||
"""Poll task status until completion"""
|
||||
count = 0
|
||||
unique_steps = []
|
||||
while True:
|
||||
details = get_task_details(task_id)
|
||||
new_steps = details['steps']
|
||||
# use only the new steps that are not in unique_steps.
|
||||
if new_steps != unique_steps:
|
||||
for step in new_steps:
|
||||
if step not in unique_steps:
|
||||
print(json.dumps(step, indent=4))
|
||||
unique_steps = new_steps
|
||||
count += 1
|
||||
status = details['status']
|
||||
|
||||
if status in ['finished', 'failed', 'stopped']:
|
||||
return details
|
||||
time.sleep(poll_interval)
|
||||
|
||||
|
||||
def main():
|
||||
task_id = create_task('Open https://www.google.com and search for openai')
|
||||
print(f'Task created with ID: {task_id}')
|
||||
task_details = wait_for_completion(task_id)
|
||||
print(f"Final output: {task_details['output']}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
## Task Control Example
|
||||
|
||||
Here's how to implement task control with pause/resume functionality:
|
||||
|
||||
```python
|
||||
def control_task():
|
||||
# Create a new task
|
||||
task_id = create_task("Go to google.com and search for Browser Use")
|
||||
|
||||
# Wait for 5 seconds
|
||||
time.sleep(5)
|
||||
|
||||
# Pause the task
|
||||
requests.put(f"{BASE_URL}/pause-task?task_id={task_id}", headers=HEADERS)
|
||||
print("Task paused! Check the live preview.")
|
||||
|
||||
# Wait for user input
|
||||
input("Press Enter to resume...")
|
||||
|
||||
# Resume the task
|
||||
requests.put(f"{BASE_URL}/resume-task?task_id={task_id}", headers=HEADERS)
|
||||
|
||||
# Wait for completion
|
||||
result = wait_for_completion(task_id)
|
||||
print(f"Task completed with output: {result['output']}")
|
||||
```
|
||||
|
||||
## Structured Output Example
|
||||
|
||||
Here's how to implement a task with structured JSON output:
|
||||
|
||||
```python
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import requests
|
||||
from pydantic import BaseModel
|
||||
from typing import List
|
||||
|
||||
|
||||
API_KEY = os.getenv("API_KEY")
|
||||
BASE_URL = 'https://api.browser-use.com/api/v1'
|
||||
HEADERS = {
|
||||
"Authorization": f"Bearer {API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
|
||||
# Define output schema using Pydantic
|
||||
class SocialMediaCompany(BaseModel):
|
||||
name: str
|
||||
market_cap: float
|
||||
headquarters: str
|
||||
founded_year: int
|
||||
|
||||
|
||||
class SocialMediaCompanies(BaseModel):
|
||||
companies: List[SocialMediaCompany]
|
||||
|
||||
|
||||
def create_structured_task(instructions: str, schema: dict):
|
||||
"""Create a task that expects structured output"""
|
||||
payload = {
|
||||
"task": instructions,
|
||||
"structured_output_json": json.dumps(schema)
|
||||
}
|
||||
response = requests.post(f"{BASE_URL}/run-task", headers=HEADERS, json=payload)
|
||||
response.raise_for_status()
|
||||
return response.json()["id"]
|
||||
|
||||
|
||||
def wait_for_task_completion(task_id: str, poll_interval: int = 5):
|
||||
"""Poll task status until it completes"""
|
||||
while True:
|
||||
response = requests.get(f"{BASE_URL}/task/{task_id}/status", headers=HEADERS)
|
||||
response.raise_for_status()
|
||||
status = response.json()
|
||||
if status == "finished":
|
||||
break
|
||||
elif status in ["failed", "stopped"]:
|
||||
raise RuntimeError(f"Task {task_id} ended with status: {status}")
|
||||
print("Waiting for task to finish...")
|
||||
time.sleep(poll_interval)
|
||||
|
||||
|
||||
def fetch_task_output(task_id: str):
|
||||
"""Retrieve the final task result"""
|
||||
response = requests.get(f"{BASE_URL}/task/{task_id}", headers=HEADERS)
|
||||
response.raise_for_status()
|
||||
return response.json()["output"]
|
||||
|
||||
|
||||
def main():
|
||||
schema = SocialMediaCompanies.model_json_schema()
|
||||
task_id = create_structured_task(
|
||||
"Get me the top social media companies by market cap",
|
||||
schema
|
||||
)
|
||||
print(f"Task created with ID: {task_id}")
|
||||
|
||||
wait_for_task_completion(task_id)
|
||||
print("Task completed!")
|
||||
|
||||
output = fetch_task_output(task_id)
|
||||
print("Raw output:", output)
|
||||
|
||||
try:
|
||||
parsed = SocialMediaCompanies.model_validate_json(output)
|
||||
print("Parsed output:")
|
||||
print(parsed)
|
||||
except Exception as e:
|
||||
print(f"Failed to parse structured output: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
<Note>
|
||||
Remember to handle your API key securely and implement proper error handling
|
||||
in production code.
|
||||
</Note>
|
||||
@@ -0,0 +1,393 @@
|
||||
---
|
||||
title: "N8N + Browser Use Cloud"
|
||||
description: "Learn how to integrate Browser Use Cloud API with n8n using a practical workflow example (competitor research)."
|
||||
icon: "plug"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
> **TL;DR** – In **3 minutes** you can have an n8n workflow that:
|
||||
>
|
||||
> 1. Shows a form asking for a competitor’s name
|
||||
> 2. Starts a Browser Use task that crawls the web and extracts **pricing, jobs, new features & announcements**
|
||||
> 3. Waits for the task to finish via a **webhook**
|
||||
> 4. Formats the output and drops a rich message into Slack
|
||||
|
||||
You can grab the workflow JSON below – copy it and import it into n8n, plug in your API keys and hit _Execute_ 🚀.
|
||||
|
||||
---
|
||||
|
||||
## Why use Browser Use in n8n?
|
||||
|
||||
• **Autonomous browsing** – Browser Use opens pages like a real user, follows links, clicks buttons and reads DOM content.
|
||||
|
||||
• **Structured output** – You tell the agent _exactly_ which fields you need. No brittle regex or XPaths.
|
||||
|
||||
• **Scales effortlessly** – Kick off hundreds of tasks and monitor them through the Cloud API.
|
||||
|
||||
n8n glues everything together so your team gets the data instantly—no Python scripts or CRON jobs needed.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Browser Use Cloud API key** – grab one from your [Billing page](https://cloud.browser-use.com/billing).
|
||||
2. **n8n instance** – self-hosted or n8n.cloud. (The screenshots below use n8n 1.45+.)
|
||||
3. **Slack Incoming Webhook URL** – create one in your Slack workspace.
|
||||
|
||||
Add both secrets to n8n’s credential manager:
|
||||
|
||||
```env title=".env example"
|
||||
BROWSER_USE_API_KEY="sk-…"
|
||||
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/…"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Import the template
|
||||
|
||||
1. Copy the [workflow JSON](#workflow-json) below to your clipboard.
|
||||
2. In n8n create a new workflow and paste the JSON.
|
||||
3. Replace the _Browser-Use API Key_ credential and _Slack Incoming Webhook URL_ with yours.
|
||||
|
||||
---
|
||||
|
||||
## How the workflow works
|
||||
|
||||
### 1. `Form Trigger` – collect the competitor’s name
|
||||
|
||||
A public n8n form with a single required field. When a user submits, the workflow fires instantly.
|
||||
|
||||
### 2. `HTTP Request – Browser Use Run Task`
|
||||
|
||||
We POST to `/api/v1/run-task` with the following body:
|
||||
|
||||
```json title="run-task payload"
|
||||
{
|
||||
"task": "Do exhaustive research on {{ $json[\"Competitor Name\"] }} and extract all pricing information, job postings, new features and announcements",
|
||||
"save_browser_data": true,
|
||||
"structured_output_json": {
|
||||
"pricing": {
|
||||
"plans": ["string"],
|
||||
"prices": ["string"],
|
||||
"features": ["string"]
|
||||
},
|
||||
"jobs": {
|
||||
"titles": ["string"],
|
||||
"departments": ["string"],
|
||||
"locations": ["string"]
|
||||
},
|
||||
"new_features": { "titles": ["string"], "description": ["string"] },
|
||||
"announcements": { "titles": ["string"], "description": ["string"] }
|
||||
},
|
||||
"metadata": { "source": "n8n-competitor-demo" }
|
||||
}
|
||||
```
|
||||
|
||||
Important bits:
|
||||
|
||||
• `structured_output_json` tells the agent which keys to return – no post-processing required.
|
||||
• We tag the task with `metadata.source` so the webhook can filter only _our_ jobs.
|
||||
|
||||
### 3. `Webhook` + `IF` – wait for task completion
|
||||
|
||||
Browser Use sends a webhook when anything happens to a task (see our [Webhooks guide](/cloud/v1/webhooks) for setup details). We expose an n8n Webhook node at `/get-research-data` and let the agent call it.
|
||||
|
||||
We only proceed when **both** conditions are true:
|
||||
|
||||
- `payload.status == "finished"`
|
||||
- `payload.metadata.source == "n8n-competitor-demo"`
|
||||
|
||||
### 4. `Get Task Details`
|
||||
|
||||
The webhook body includes the `session_id`. We fetch the full task record so we get the `output` field containing the structured JSON from step 2.
|
||||
|
||||
### 5. `Code – Generate Slack message`
|
||||
|
||||
A short JS snippet turns the JSON into a nicely-formatted Slack block with emojis and bullet points. Feel free to tweak the formatting.
|
||||
|
||||
### 6. `HTTP Request – Send to Slack`
|
||||
|
||||
Finally we POST the message to your incoming webhook and celebrate 🎉.
|
||||
|
||||
---
|
||||
|
||||
## Customize as you want
|
||||
|
||||
This workflow is just the starting point – Browser Use + n8n gives you endless possibilities. Here are some ideas:
|
||||
|
||||
| Want to... | How to do it |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Extract different data** | Edit `structured_output_json` to specify exactly what fields you need (pricing, reviews, contact info, etc.) and adjust the JS formatter. |
|
||||
| **Send to Teams/Email/Notion** | Swap the last Slack node for Teams, Gmail, or any of n8n's 400+ connectors. |
|
||||
| **Run automatically** | Replace the Form trigger with a Cron trigger for daily/weekly competitor monitoring. |
|
||||
| **Monitor multiple competitors** | Use a Google Sheets trigger with a list of companies and loop through them. |
|
||||
| **Add AI analysis** | Pipe the extracted data through OpenAI/Claude to generate insights and summaries. |
|
||||
| **Create alerts** | Set up conditional logic to only notify when competitors announce new features or price changes. |
|
||||
| **Build a dashboard** | Send data to Airtable, Notion, or Google Sheets to build a real-time competitor intelligence dashboard. |
|
||||
|
||||
The beauty of Browser Use is that it handles the complex web browsing while you focus on building the perfect workflow for your needs.
|
||||
|
||||
---
|
||||
|
||||
## Workflow JSON
|
||||
|
||||
<Accordion title="n8n Workflow JSON (click to expand)">
|
||||
```json id="workflow-json"
|
||||
{
|
||||
"name": "Competitor Intelligence Workflow with webhooks",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "get-research-data",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
-480,
|
||||
176
|
||||
],
|
||||
"id": "81166dab-eb91-4627-b773-1aa7f7bd86ee",
|
||||
"name": "Webhook",
|
||||
"webhookId": "025bc4bf-00c0-47d4-bd5f-79046674d017"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict",
|
||||
"version": 2
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "8d9701b6-1dc2-4e55-9fe4-ef1735ff1ebc",
|
||||
"leftValue": "={{ $json.body.payload.status }}",
|
||||
"rightValue": "finished",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "equals",
|
||||
"name": "filter.operator.equals"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7cf18a23-f3d8-4a70-a77c-c286a231fc7f",
|
||||
"leftValue": "={{ $json.body.payload.metadata.source }}",
|
||||
"rightValue": "n8n-competitor-demo",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "equals",
|
||||
"name": "filter.operator.equals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2.2,
|
||||
"position": [
|
||||
-256,
|
||||
176
|
||||
],
|
||||
"id": "b38737cc-0b8a-4a76-930f-362eb5de9ef9",
|
||||
"name": "If"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"formTitle": "Run Competitor Analysis",
|
||||
"formFields": {
|
||||
"values": [
|
||||
{
|
||||
"fieldLabel": "Competitor Name",
|
||||
"placeholder": "(e.g. OpenAI)",
|
||||
"requiredField": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.formTrigger",
|
||||
"typeVersion": 2.2,
|
||||
"position": [
|
||||
-336,
|
||||
-64
|
||||
],
|
||||
"id": "fcfc33dd-7d8a-460b-838d-955c65416aea",
|
||||
"name": "On form submission",
|
||||
"webhookId": "b2712d5b-14ae-424b-8733-fe6e77cebd43"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.browser-use.com/api/v1/run-task",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpBearerAuth",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"task\": \"Do exhaustive research on {{ $json['Competitor Name'] }} and extract all pricing information, job postings, new features and announcements\",\n \"save_browser_data\": true,\n \"structured_output_json\": \"{\\n \\\"pricing\\\": {\\n \\\"plans\\\": [\\\"string\\\"],\\n \\\"prices\\\": [\\\"string\\\"],\\n \\\"features\\\": [\\\"string\\\"]\\n },\\n \\\"jobs\\\": {\\n \\\"titles\\\": [\\\"string\\\"],\\n \\\"departments\\\": [\\\"string\\\"],\\n \\\"locations\\\": [\\\"string\\\"]\\n },\\n \\\"new_features\\\": {\\n \\\"titles\\\": [\\\"string\\\"],\\n \\\"description\\\": [\\\"string\\\"]\\n },\\n \\\"announcements\\\": {\\n \\\"titles\\\": [\\\"string\\\"],\\n \\\"description\\\": [\\\"string\\\"]\\n }\\n}\",\n\"metadata\": {\"source\": \"n8n-competitor-demo\"}\n} ",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
-112,
|
||||
-64
|
||||
],
|
||||
"id": "d10bef40-e2a3-41ff-a507-4f365c13dc52",
|
||||
"name": "BrowserUse Run Task",
|
||||
"credentials": {
|
||||
"httpBearerAuth": {
|
||||
"id": "peg6MzgmJNRMCMnT",
|
||||
"name": "Browser-Use API Key"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"url": "=https://api.browser-use.com/api/v1/task/{{ $('Webhook').item.json.body.payload.session_id }}",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpBearerAuth",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
0,
|
||||
144
|
||||
],
|
||||
"id": "e49c28ff-11a2-4195-94ab-ca5796572c34",
|
||||
"name": "Get Task details",
|
||||
"credentials": {
|
||||
"httpBearerAuth": {
|
||||
"id": "peg6MzgmJNRMCMnT",
|
||||
"name": "Browser-Use API Key"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const output_data = $input.first().json.output;\nconst data = JSON.parse(output_data);\n\nconst pricing = data?.pricing;\nconst jobs = data?.jobs;\nconst newFeatures = data?.new_features;\nconst announcements = data?.announcements;\n\n// Helper function to format arrays as bullet points\nconst formatAsBullets = (arr, prefix = \"• \" => {\n if (!arr || arr.length === 0) return \"• N/A\";\n return arr.map(item => `${prefix}${item}`).join(\"\\n\");\n};\n\nreturn {\n text: `🏷️ *Pricing*\\nPlans:\\n${formatAsBullets(pricing?.plans)}\\n\\nPrices:\\n${formatAsBullets(pricing?.prices)}\\n\\nFeatures:\\n${formatAsBullets(pricing?.features)}\\n\\n💼 *Jobs*\\nTitles:\\n${formatAsBullets(jobs?.titles)}\\n\\nDepartments:\\n${formatAsBullets(jobs?.departments)}\\n\\nLocations:\\n${formatAsBullets(jobs?.locations)}\\n\\n✨ *New Features*\\nTitles:\\n${formatAsBullets(newFeatures?.titles)}\\n\\nDescription:\\n${formatAsBullets(newFeatures?.description)}\\n\\n📢 *Announcements*\\n${formatAsBullets(announcements?.description)}`\n};"
|
||||
},
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
208,
|
||||
144
|
||||
],
|
||||
"id": "54bc087d-237d-438a-b688-bcbec25d9c45",
|
||||
"name": "Generate Slack message"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "",
|
||||
"sendBody": true,
|
||||
"bodyParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
"value": "={{ $json.text }}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
432,
|
||||
144
|
||||
],
|
||||
"id": "969a16f0-677b-4e46-a8bb-57a80b5daf07",
|
||||
"name": "Send to Slack"
|
||||
}
|
||||
],
|
||||
"pinData": {},
|
||||
"connections": {
|
||||
"Webhook": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "If",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"If": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Get Task details",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"On form submission": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "BrowserUse Run Task",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Get Task details": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Generate Slack message",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Generate Slack message": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send to Slack",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": true,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"versionId": "f3b38678-4821-41ad-952c-df9bbba40fc8",
|
||||
"meta": {
|
||||
"templateCredsSetupCompleted": true,
|
||||
"instanceId": "7a1d1fd830bae2a00010153cf810fd67e0c87b8ae64ceb62273c87183efda365"
|
||||
},
|
||||
"id": "qmhqkZH8DhISWMmc",
|
||||
"tags": []
|
||||
}
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
Copy everything between the braces, import into n8n and you're good to go.
|
||||
|
||||
<Note>
|
||||
Having trouble? Ping us in the #integrations channel on
|
||||
[Discord](https://link.browser-use.com/discord) – we’re happy to help.
|
||||
</Note>
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: "Pricing"
|
||||
description: "Browser Use Cloud API pricing structure and cost breakdown"
|
||||
icon: "dollar-sign"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
The Browser Use Cloud API pricing consists of two components:
|
||||
|
||||
1. **Task Initialization Cost**: $0.01 per started task
|
||||
2. **Task Step Cost**: Additional cost based on the specific model used for each step
|
||||
|
||||
## LLM Model Step Pricing
|
||||
|
||||
> **Limited Time Offer**: O3 model pricing reduced from $0.03 to $0.01 per step!
|
||||
|
||||
The following table shows the total cost per step for each available LLM model:
|
||||
|
||||
| Model | Cost per Step |
|
||||
| -------------------------------- | ------------- |
|
||||
| GPT-4.1 | $0.025 |
|
||||
| GPT-4.1 mini | $0.0075 |
|
||||
| O4 mini | $0.02 |
|
||||
| O3 | $0.01 |
|
||||
| Gemini 2.5 Flash | $0.0075 |
|
||||
| Gemini 2.5 Pro | $0.025 |
|
||||
| Claude 3.7 Sonnet (2025-02-19) | $0.03 |
|
||||
| Claude Sonnet 4 (2025-05-14) | $0.03 |
|
||||
| Llama 4 Maverick 17B Instruct | $0.01 |
|
||||
|
||||
## Example Cost Calculations
|
||||
|
||||
**Using GPT-4.1 for a 10 step task:**
|
||||
- Task initialization: $0.01
|
||||
- 10 steps × $0.025 per step = $0.25
|
||||
- **Total cost: $0.26**
|
||||
|
||||
**Using O3 for a 10 step task (Limited Time Offer):**
|
||||
- Task initialization: $0.01
|
||||
- 10 steps × $0.01 per step = $0.10
|
||||
- **Total cost: $0.11**
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: "Quickstart"
|
||||
description: "Learn how to get started with the Browser Use Cloud API"
|
||||
icon: "cloud"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<img
|
||||
className="block dark:hidden rounded-2xl"
|
||||
src="/images/cloud-banner.png"
|
||||
alt="Browser Use Cloud Banner"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block rounded-2xl"
|
||||
src="/images/cloud-banner-dark.png"
|
||||
alt="Browser Use Cloud Banner"
|
||||
/>
|
||||
|
||||
<Note>
|
||||
You need an active subscription and an API key from
|
||||
[cloud.browser-use.com/billing](https://cloud.browser-use.com/billing). For
|
||||
detailed pricing information, see our [pricing page](/cloud/v1/pricing).
|
||||
</Note>
|
||||
|
||||
## Creating Your First Agent
|
||||
|
||||
To understand how the API works visit the [Run Task](/api-reference/api-v1/run-task?playground=open) page.
|
||||
|
||||
```bash
|
||||
curl -X POST https://api.browser-use.com/api/v1/run-task \
|
||||
-H "Authorization: Bearer your_api_key_here" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"task": "Go to google.com and search for Browser Use"
|
||||
}'
|
||||
```
|
||||
|
||||
`run-task` API returns a task ID, which you can query to get the task status, live preview URL, and the result output.
|
||||
|
||||
<Note>
|
||||
To play around with the API, you can use the [Browser Use Cloud
|
||||
Playground](https://cloud.browser-use.com/playground).
|
||||
</Note>
|
||||
|
||||
For the full implementation guide see the [Implementation](/cloud/v1/implementation) page.
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: "Search API"
|
||||
description: "Get started with Browser Use's search endpoints to extract content from websites"
|
||||
icon: "magnifying-glass"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Warning>
|
||||
**🧪 BETA - This API is in beta - it may change and might not be available at
|
||||
all times.**
|
||||
</Warning>
|
||||
|
||||
## Why Browser Use Over Traditional Search?
|
||||
|
||||
**Browser Use actually browses websites like a human** while other tools return cached data from landing pages. Browser Use navigates deep into sites in real-time:
|
||||
|
||||
- 🔍 **Deep navigation**: Clicks through menus, forms, and multiple pages to find buried content
|
||||
- 🚀 **Always current**: Live prices, breaking news, real-time analytics - not cached results
|
||||
- 🎯 **No stale data**: See exactly what's on the page right now
|
||||
- 🌐 **Dynamic content**: Handles JavaScript, forms, and interactive elements
|
||||
- 🏠 **No surface limitations**: Gets data from pages that require navigation or interaction
|
||||
|
||||
**Other tools see yesterday's front door. Browser Use explores today's whole house.**
|
||||
|
||||
## Quick Start
|
||||
|
||||
The Search API allows you to quickly extract relevant content from websites using AI. There are two main endpoints:
|
||||
|
||||
💡 **Complete working examples** are available in the [examples/search](https://github.com/browser-use/browser-use/tree/main/examples/search) folder.
|
||||
|
||||
### Simple Search
|
||||
|
||||
Search Google and extract content from multiple top results:
|
||||
|
||||
```python
|
||||
import aiohttp
|
||||
import asyncio
|
||||
|
||||
async def simple_search():
|
||||
payload = {
|
||||
"query": "latest AI news",
|
||||
"max_websites": 5,
|
||||
"depth": 2
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Authorization": "Bearer YOUR_API_KEY",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
"https://api.browser-use.com/api/v1/simple-search",
|
||||
json=payload,
|
||||
headers=headers
|
||||
) as response:
|
||||
result = await response.json()
|
||||
return result
|
||||
|
||||
asyncio.run(simple_search())
|
||||
```
|
||||
|
||||
### Search URL
|
||||
|
||||
Extract content from a specific URL:
|
||||
|
||||
```python
|
||||
async def search_url():
|
||||
payload = {
|
||||
"url": "https://browser-use.com/#pricing",
|
||||
"query": "Find pricing information for Browser Use",
|
||||
"depth": 2
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Authorization": "Bearer YOUR_API_KEY",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
"https://api.browser-use.com/api/v1/search-url",
|
||||
json=payload,
|
||||
headers=headers
|
||||
) as response:
|
||||
result = await response.json()
|
||||
return result
|
||||
|
||||
asyncio.run(search_url())
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
- **query**: Search query or content to extract
|
||||
- **depth**: How deep to navigate within each website (2-5, default: 2)
|
||||
- `depth=2`: Checks main page + 1 click deeper
|
||||
- `depth=3`: Checks main page + 2 clicks deeper
|
||||
- `depth=5`: Thoroughly explores multiple navigation levels
|
||||
- **max_websites**: Number of websites to process (simple-search only, default: 5)
|
||||
- **url**: Target URL to extract from (search-url only)
|
||||
|
||||
## Pricing
|
||||
|
||||
### Simple Search
|
||||
|
||||
**Cost per request**: `1 cent × depth × max_websites`
|
||||
|
||||
Example: depth=2, max_websites=3 = 6 cents per request
|
||||
|
||||
### Search URL
|
||||
|
||||
**Cost per request**: `1 cent × depth`
|
||||
|
||||
Example: depth=2 = 2 cents per request
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
title: "Webhooks"
|
||||
description: "Learn how to integrate webhooks with Browser Use Cloud API"
|
||||
icon: "code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
Webhooks allow you to receive real-time notifications about events in your Browser Use tasks. This guide will show you how to set up and verify webhook endpoints.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<Note>
|
||||
You need an active subscription to create webhooks. See your billing page
|
||||
[cloud.browser-use.com/billing](https://cloud.browser-use.com/billing)
|
||||
</Note>
|
||||
|
||||
## Setting Up Webhooks
|
||||
|
||||
To receive webhook notifications, you need to:
|
||||
|
||||
1. Create an endpoint that can receive HTTPS POST requests
|
||||
2. Configure your webhook URL in the Browser Use dashboard
|
||||
3. Implement signature verification to ensure webhook authenticity
|
||||
|
||||
<Note>
|
||||
When adding a webhook URL in the dashboard, it must be a valid HTTPS URL that can receive POST requests.
|
||||
On creation, we will send a test payload `{"type": "test", "timestamp": "2024-03-21T12:00:00Z", "payload": {"test": "ok"}}` to verify the endpoint is working correctly before creating the actual webhook!
|
||||
</Note>
|
||||
|
||||
## Webhook Events
|
||||
|
||||
Browser Use sends various types of events. Each event has a specific type and payload structure.
|
||||
|
||||
### Event Types
|
||||
|
||||
Currently supported events:
|
||||
|
||||
| Event Type | Description |
|
||||
| -------------------------- | -------------------------------- |
|
||||
| `agent.task.status_update` | Status updates for running tasks |
|
||||
|
||||
### Task Status Updates
|
||||
|
||||
The `agent.task.status_update` event includes the following statuses:
|
||||
|
||||
| Status | Description |
|
||||
| -------------- | -------------------------------------- |
|
||||
| `initializing` | A task is initializing |
|
||||
| `started` | A Task has started (browser available) |
|
||||
| `paused` | A task has been paused mid execution |
|
||||
| `stopped` | A task has been stopped mid execution |
|
||||
| `finished` | A task has finished |
|
||||
|
||||
## Webhook Payload Structure
|
||||
|
||||
Each webhook call includes:
|
||||
|
||||
- A JSON payload with event details
|
||||
- `X-Browser-Use-Timestamp` header with the current timestamp
|
||||
- `X-Browser-Use-Signature` header for verification
|
||||
|
||||
The payload follows this structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "agent.task.status_update",
|
||||
"timestamp": "2025-05-25T09:22:22.269116+00:00",
|
||||
"payload": {
|
||||
"session_id": "cd9cc7bf-e3af-4181-80a2-73f083bc94b4",
|
||||
"task_id": "5b73fb3f-a3cb-4912-be40-17ce9e9e1a45",
|
||||
"status": "finished",
|
||||
"metadata": {
|
||||
"campaign": "q4-automation",
|
||||
"team": "marketing"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The webhook payload now includes a `metadata` field containing any custom key-value pairs that were provided when the task was created. This allows you to correlate webhook events with your internal tracking systems.
|
||||
|
||||
## Implementing Webhook Verification
|
||||
|
||||
To ensure webhook authenticity, you must verify the signature. Here's an example implementation in Python using FastAPI:
|
||||
|
||||
```python
|
||||
import uvicorn
|
||||
import hmac
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
|
||||
from fastapi import FastAPI, Request, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
SECRET_KEY = os.environ['SECRET_KEY']
|
||||
|
||||
def verify_signature(payload: dict, timestamp: str, received_signature: str) -> bool:
|
||||
message = f'{timestamp}.{json.dumps(payload, separators=(",", ":"), sort_keys=True)}'
|
||||
expected_signature = hmac.new(SECRET_KEY.encode(), message.encode(), hashlib.sha256).hexdigest()
|
||||
return hmac.compare_digest(expected_signature, received_signature)
|
||||
|
||||
@app.post('/webhook')
|
||||
async def webhook(request: Request):
|
||||
body = await request.json()
|
||||
|
||||
timestamp = request.headers.get('X-Browser-Use-Timestamp')
|
||||
signature = request.headers.get('X-Browser-Use-Signature')
|
||||
if not timestamp or not signature:
|
||||
raise HTTPException(status_code=400, detail='Missing timestamp or signature')
|
||||
|
||||
if not verify_signature(body, timestamp, signature):
|
||||
raise HTTPException(status_code=403, detail='Invalid signature')
|
||||
|
||||
# Handle different event types
|
||||
event_type = body.get('type')
|
||||
if event_type == 'agent.task.status_update':
|
||||
# Handle task status update
|
||||
print('Task status update received:', body['payload'])
|
||||
elif event_type == 'test':
|
||||
# Handle test webhook
|
||||
print('Test webhook received:', body['payload'])
|
||||
else:
|
||||
print('Unknown event type:', event_type)
|
||||
|
||||
return {'status': 'success', 'message': 'Webhook received'}
|
||||
|
||||
if __name__ == '__main__':
|
||||
uvicorn.run(app, host='0.0.0.0', port=4242)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always verify signatures**: Never process webhook payloads without verifying the signature
|
||||
2. **Handle retries**: Browser Use will retry failed webhook deliveries up to 5 times
|
||||
3. **Respond quickly**: Return a 200 response as soon as you've verified the signature
|
||||
4. **Process asynchronously**: Handle the webhook payload processing in a background task
|
||||
5. **Monitor failures**: Set up monitoring for webhook delivery failures
|
||||
6. **Handle unknown events**: Implement graceful handling of new event types that may be added in the future
|
||||
|
||||
<Note>
|
||||
Need help? Contact our support team at support@browser-use.com or join our
|
||||
[Discord community](https://link.browser-use.com/discord)
|
||||
</Note>
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: "All Parameters"
|
||||
description: "Complete API reference for Browser Actor classes, methods, and parameters including BrowserSession, Page, Element, and Mouse"
|
||||
icon: "list"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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](../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_existing=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
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: "Basics"
|
||||
description: "Low-level Playwright-like browser automation with direct and full CDP control and precise element interactions"
|
||||
icon: "code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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 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 sorta 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: `() => {}`
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: "Examples"
|
||||
description: "Comprehensive examples for Browser Actor automation tasks including forms, JavaScript, mouse operations, and AI features"
|
||||
icon: "code-simple"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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 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 = await 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
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "All Parameters"
|
||||
description: "Complete reference for all agent configuration options"
|
||||
icon: "sliders"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Available Parameters
|
||||
|
||||
### Core Settings
|
||||
- `tools`: Registry of [our tools](https://github.com/browser-use/browser-use/blob/main/browser_use/tools/service.py) the agent can call. [Example for custom tools](https://github.com/browser-use/browser-use/tree/main/examples/custom-functions)
|
||||
- `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: `True`): Enable/disable vision capabilities for processing screenshots
|
||||
- `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`)
|
||||
|
||||
### 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: `10`): Maximum actions per step, e.g. for form filling the agent can output 10 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.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: "Basics"
|
||||
description: ""
|
||||
icon: "play"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
```python
|
||||
from browser_use import Agent, ChatOpenAI
|
||||
|
||||
agent = Agent(
|
||||
task="Search for latest news about AI",
|
||||
llm=ChatOpenAI(model="gpt-4.1-mini"),
|
||||
)
|
||||
|
||||
async def main():
|
||||
history = await agent.run(max_steps=100)
|
||||
```
|
||||
|
||||
- `task`: The task you want to automate.
|
||||
- `llm`: Your favorite LLM. See <a href="/customize/supported-models">Supported Models</a>.
|
||||
|
||||
|
||||
The agent is executed using the async `run()` method:
|
||||
|
||||
- `max_steps` (default: `100`): Maximum number of steps an agent can take.
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: "Output Format"
|
||||
description: ""
|
||||
icon: "arrow-right-to-bracket"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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).
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: "Prompting Guide"
|
||||
description: "Tips and tricks "
|
||||
icon: "lightbulb"
|
||||
---
|
||||
|
||||
Prompting can trasticly 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_structured_data 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_google action to find "Python tutorials"
|
||||
2. Use click_element_by_index to open first result in a new tab
|
||||
3. Use scroll action to scroll down 2 pages
|
||||
4. Use extract_structured_data 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](/customize/tools/available) for the complete list of actions.
|
||||
|
||||
|
||||
### 3. Handle interaction problems via keyboard navigation
|
||||
|
||||
Sometimes buttons can't be clicked (you found a bug in the library - open an issue).
|
||||
Good news - often you can work around it 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.
|
||||
@@ -0,0 +1,254 @@
|
||||
---
|
||||
title: "Supported Models"
|
||||
description: "Choose your favorite LLM"
|
||||
icon: "robot"
|
||||
|
||||
---
|
||||
|
||||
### Recommendations
|
||||
|
||||
- Best accuracy: `O3`
|
||||
- Fastest: `llama4` on groq
|
||||
- Balanced: fast + cheap + clever: `gemini-2.5-flash` or `gpt-4.1-mini`
|
||||
|
||||
|
||||
### OpenAI [example](https://github.com/browser-use/browser-use/blob/main/examples/models/gpt-4.1.py)
|
||||
|
||||
`O3` model is recommended for best performance.
|
||||
|
||||
```python
|
||||
from browser_use import Agent, ChatOpenAI
|
||||
|
||||
# Initialize the model
|
||||
llm = ChatOpenAI(
|
||||
model="o3",
|
||||
)
|
||||
|
||||
# Create agent with the model
|
||||
agent = Agent(
|
||||
task="...", # Your task here
|
||||
llm=llm
|
||||
)
|
||||
```
|
||||
|
||||
Required environment variables:
|
||||
|
||||
```bash .env
|
||||
OPENAI_API_KEY=
|
||||
```
|
||||
|
||||
<Info>
|
||||
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).
|
||||
</Info>
|
||||
|
||||
### Anthropic [example](https://github.com/browser-use/browser-use/blob/main/examples/models/claude-4-sonnet.py)
|
||||
|
||||
```python
|
||||
from browser_use import Agent, ChatAnthropic
|
||||
|
||||
# Initialize the model
|
||||
llm = ChatAnthropic(
|
||||
model="claude-sonnet-4-0",
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
```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=
|
||||
```
|
||||
|
||||
### Gemini [example](https://github.com/browser-use/browser-use/blob/main/examples/models/gemini.py)
|
||||
|
||||
> [!IMPORTANT] `GEMINI_API_KEY` was the old environment var name, it should be called `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=
|
||||
```
|
||||
|
||||
### AWS Bedrock [example](https://github.com/browser-use/browser-use/blob/main/examples/models/aws.py)
|
||||
|
||||
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.
|
||||
|
||||
#### General AWS Bedrock (supports all providers)
|
||||
|
||||
```python
|
||||
from browser_use import Agent, 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, 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)
|
||||
|
||||
```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=
|
||||
```
|
||||
|
||||
## Ollama
|
||||
|
||||
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: [{"go_to_url": "google.com"}]` instead of `[{"go_to_url": {"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=
|
||||
```
|
||||
|
||||
|
||||
## Other models (DeepSeek, Novita, X...)
|
||||
|
||||
We support all other models that can be called via OpenAI compatible API. We are open to PRs for more providers.
|
||||
|
||||
**Examples available:**
|
||||
- [DeepSeek](https://github.com/browser-use/browser-use/blob/main/examples/models/deepseek-chat.py)
|
||||
- [Novita](https://github.com/browser-use/browser-use/blob/main/examples/models/novita.py)
|
||||
- [OpenRouter](https://github.com/browser-use/browser-use/blob/main/examples/models/openrouter.py)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: "All Parameters"
|
||||
description: "Complete reference for all browser configuration options"
|
||||
icon: "sliders"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Note>
|
||||
The `Browser` instance also provides all [Actor](/customize/actor/all-parameters) methods for direct browser control (page management, element interactions, etc.).
|
||||
</Note>
|
||||
|
||||
## 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://*']`
|
||||
- `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 effect 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:4242', 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
|
||||
|
||||
- `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.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: "Basics"
|
||||
description: ""
|
||||
icon: "play"
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
|
||||
```python
|
||||
from browser_use import Agent, Browser, ChatOpenAI
|
||||
|
||||
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=ChatOpenAI(model='gpt-4.1-mini'),
|
||||
)
|
||||
|
||||
|
||||
async def main():
|
||||
await agent.run()
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: "Real Browser"
|
||||
description: ""
|
||||
icon: "arrow-right-to-bracket"
|
||||
---
|
||||
|
||||
Connect your existing Chrome browser to preserve authentication.
|
||||
|
||||
## Basic Example
|
||||
|
||||
```python
|
||||
from browser_use import Agent, Browser, ChatOpenAI
|
||||
|
||||
# Connect to your existing Chrome browser
|
||||
browser = Browser(
|
||||
executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
||||
user_data_dir='~/Library/Application Support/Google/Chrome',
|
||||
profile_directory='Default',
|
||||
)
|
||||
|
||||
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()
|
||||
```
|
||||
|
||||
> **Note:** You need to fully close chrome before running this example. Also, Google blocks this approach currently so we use DuckDuckGo instead.
|
||||
|
||||
|
||||
|
||||
|
||||
## How it Works
|
||||
|
||||
1. **`executable_path`** - Path to your Chrome installation
|
||||
2. **`user_data_dir`** - Your Chrome profile folder (keeps cookies, extensions, bookmarks)
|
||||
3. **`profile_directory`** - Specific profile name (Default, Profile 1, etc.)
|
||||
|
||||
|
||||
## Platform Paths
|
||||
|
||||
```python
|
||||
# macOS
|
||||
executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
|
||||
user_data_dir='~/Library/Application Support/Google/Chrome'
|
||||
|
||||
# Windows
|
||||
executable_path='C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
|
||||
user_data_dir='%LOCALAPPDATA%\\Google\\Chrome\\User Data'
|
||||
|
||||
# Linux
|
||||
executable_path='/usr/bin/google-chrome'
|
||||
user_data_dir='~/.config/google-chrome'
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: "Remote Browser"
|
||||
description: ""
|
||||
icon: "cloud"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
### 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, ChatOpenAI
|
||||
|
||||
# Use Browser-Use cloud browser service
|
||||
browser = Browser(
|
||||
use_cloud=True, # Automatically provisions a cloud browser
|
||||
# cdp_url="http://remote-server:9222" # CDP URL from your favorite browser provider like AnchorBrowser, HyperBrowser, BrowserBase, Steel.dev, etc.
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
task="Your task here",
|
||||
llm=ChatOpenAI(model='gpt-4.1-mini'),
|
||||
browser=browser,
|
||||
)
|
||||
```
|
||||
|
||||
**Prerequisites:**
|
||||
1. Get an API key from [cloud.browser-use.com](https://cloud.browser-use.com)
|
||||
2. Set BROWSER_USE_API_KEY environment variable
|
||||
|
||||
**Benefits:**
|
||||
- ✅ No local browser setup required
|
||||
- ✅ Scalable and fast cloud infrastructure
|
||||
- ✅ Automatic provisioning and teardown
|
||||
- ✅ Built-in authentication handling
|
||||
- ✅ Optimized for browser automation
|
||||
|
||||
### Third-Party Cloud Browsers
|
||||
Get a CDP URL from your favorite browser provider like AnchorBrowser, HyperBrowser, BrowserBase, Steel.dev, etc.
|
||||
|
||||
|
||||
|
||||
|
||||
### Proxy Connection
|
||||
|
||||
```python
|
||||
|
||||
from browser_use import Agent, Browser, ChatOpenAI
|
||||
from browser_use.browser import ProxySettings
|
||||
|
||||
browser = Browser(
|
||||
headless=False,
|
||||
proxy=ProxySettings(
|
||||
server="http://proxy-server:4242",
|
||||
username="proxy-user",
|
||||
password="proxy-pass"
|
||||
)
|
||||
cdp_url="http://remote-server:9222"
|
||||
)
|
||||
|
||||
|
||||
agent = Agent(
|
||||
task="Your task here",
|
||||
llm=ChatOpenAI(model='gpt-4.1-mini'),
|
||||
browser=browser,
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "Lifecycle Hooks"
|
||||
description: "Customize agent behavior with lifecycle hooks"
|
||||
icon: "Wrench"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
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's 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` lets you see what the main task is, `agent.add_new_task(...)` lets you queue up a new one
|
||||
- `agent.tools` give access to the `Tools()` object and `Registry()` containing the available actions
|
||||
- `agent.tools.registry.execute_action('click_element_by_index', {'index': 123}, browser_session=agent.browser_session)`
|
||||
- `agent.context` lets you access any user-provided context object passed in to `Agent(context=...)`
|
||||
- `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` gives direct access to the main LLM object (e.g. `ChatOpenAI`)
|
||||
- `agent.state` gives access to lots of internal state, including agent thoughts, outputs, actions, etc.
|
||||
- `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` gives direct access to the `BrowserSession` and CDP interface
|
||||
- `agent.browser_session.agent_focus`: Get the current CDP session 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 things can be implemented with [custom tools](/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.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,191 @@
|
||||
---
|
||||
title: "MCP Server"
|
||||
description: "Expose browser-use capabilities via Model Context Protocol for AI assistants like Claude Desktop"
|
||||
icon: "server"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The MCP (Model Context Protocol) Server allows you to expose browser-use's browser automation capabilities to AI assistants like Claude Desktop, Cline, and other MCP-compatible clients. This enables AI assistants to perform web automation tasks directly through browser-use.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Start MCP Server
|
||||
|
||||
```bash
|
||||
uvx browser-use --mcp
|
||||
```
|
||||
|
||||
The server will start in stdio mode, ready to accept MCP connections.
|
||||
|
||||
## Claude Desktop Integration
|
||||
|
||||
The most common use case is integrating with Claude Desktop. Add this configuration to your Claude Desktop config file:
|
||||
|
||||
### macOS
|
||||
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"browser-use": {
|
||||
"command": "uvx",
|
||||
"args": ["browser-use", "--mcp"],
|
||||
"env": {
|
||||
"OPENAI_API_KEY": "your-openai-api-key-here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Windows
|
||||
Edit `%APPDATA%\Claude\claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"browser-use": {
|
||||
"command": "uvx",
|
||||
"args": ["browser-use", "--mcp"],
|
||||
"env": {
|
||||
"OPENAI_API_KEY": "your-openai-api-key-here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
You can configure browser-use through 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 MCP server exposes these browser automation tools:
|
||||
|
||||
### 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 with Claude Desktop, you can ask Claude 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"
|
||||
```
|
||||
|
||||
Claude will use the MCP server to execute these tasks through browser-use.
|
||||
|
||||
## 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=["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
|
||||
|
||||
### Common Issues
|
||||
|
||||
**"MCP SDK is required" Error**
|
||||
```bash
|
||||
uv pip install 'browser-use'
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug logging by setting:
|
||||
```bash
|
||||
export BROWSER_USE_LOG_LEVEL=DEBUG
|
||||
uvx 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/mcp) 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
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: "Add Tools"
|
||||
description: ""
|
||||
icon: "plus"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
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
|
||||
|
||||
tools = Tools()
|
||||
|
||||
@tools.action(description='Ask human for help with a question')
|
||||
def ask_human(question: str) -> ActionResult:
|
||||
answer = input(f'{question} > ')
|
||||
return 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.
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
## 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.
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
title: "Available Tools"
|
||||
description: "Here is the [source code](https://github.com/browser-use/browser-use/blob/main/browser_use/tools/service.py) for the default tools:"
|
||||
icon: "list"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
### Navigation & Browser Control
|
||||
- **`search_google`** - Search queries in Google
|
||||
- **`go_to_url`** - Navigate to URLs
|
||||
- **`go_back`** - Go back in browser history
|
||||
- **`wait`** - Wait for specified seconds
|
||||
|
||||
### Page Interaction
|
||||
- **`click_element_by_index`** - Click elements by their index
|
||||
- **`input_text`** - Input text into form fields
|
||||
- **`upload_file_to_element`** - Upload files to file inputs
|
||||
- **`scroll`** - Scroll the page up/down
|
||||
- **`scroll_to_text`** - Scroll to specific text on page
|
||||
- **`send_keys`** - Send special keys (Enter, Escape, etc.)
|
||||
|
||||
### Tab Management
|
||||
- **`switch_tab`** - Switch between browser tabs
|
||||
- **`close_tab`** - Close browser tabs
|
||||
|
||||
### Content Extraction
|
||||
- **`extract_structured_data`** - Extract data from webpages using LLM
|
||||
|
||||
### Form Controls
|
||||
- **`get_dropdown_options`** - Get dropdown option values
|
||||
- **`select_dropdown_option`** - Select dropdown options
|
||||
|
||||
### File Operations
|
||||
- **`write_file`** - Write content to files
|
||||
- **`read_file`** - Read file contents
|
||||
- **`replace_file_str`** - Replace text in files
|
||||
|
||||
### Task Completion
|
||||
- **`done`** - Complete the task (always available)
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "Basics"
|
||||
description: "Tools are the functions that the agent has to interact with the world."
|
||||
icon: "play"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
## Quick Example
|
||||
|
||||
|
||||
```python
|
||||
from browser_use import Tools, ActionResult, Browser
|
||||
|
||||
tools = Tools()
|
||||
|
||||
@tools.action('Ask human for help with a question')
|
||||
def ask_human(question: str, browser: Browser) -> ActionResult:
|
||||
answer = input(f'{question} > ')
|
||||
return f'The human responded with: {answer}'
|
||||
|
||||
agent = Agent(
|
||||
task='Ask human for help',
|
||||
llm=llm,
|
||||
tools=tools,
|
||||
)
|
||||
```
|
||||
|
||||
<Note>
|
||||
Use `browser` parameter in tools for deterministic [Actor](/customize/actor/basics) actions.
|
||||
</Note>
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "Remove Tools"
|
||||
description: "You can exclude default tools:"
|
||||
icon: "minus"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
```python
|
||||
from browser_use import Tools
|
||||
|
||||
tools = Tools(exclude_actions=['search_google', 'wait'])
|
||||
agent = Agent(task='...', llm=llm, tools=tools)
|
||||
```
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: "Tool Response"
|
||||
description: ""
|
||||
icon: "arrow-turn-down-left"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
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. Dont 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
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
title: 'Development'
|
||||
description: 'Preview changes locally to update your docs'
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**Prerequisite**: Please install Node.js (version 19 or higher) before proceeding.
|
||||
</Info>
|
||||
|
||||
Follow these steps to install and run Mintlify on your operating system:
|
||||
|
||||
**Step 1**: Install Mintlify:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash npm
|
||||
npm i -g mintlify
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn global add mintlify
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
**Step 2**: Navigate to the docs directory (where the `mint.json` file is located) and execute the following command:
|
||||
|
||||
```bash
|
||||
mintlify dev
|
||||
```
|
||||
|
||||
A local preview of your documentation will be available at `http://localhost:3000`.
|
||||
|
||||
### Custom Ports
|
||||
|
||||
By default, Mintlify uses port 3000. You can customize the port Mintlify runs on by using the `--port` flag. To run Mintlify on port 3333, for instance, use this command:
|
||||
|
||||
```bash
|
||||
mintlify dev --port 3333
|
||||
```
|
||||
|
||||
If you attempt to run Mintlify on a port that's already in use, it will use the next available port:
|
||||
|
||||
```md
|
||||
Port 3000 is already in use. Trying 3001 instead.
|
||||
```
|
||||
|
||||
## Mintlify Versions
|
||||
|
||||
Please note that each CLI release is associated with a specific version of Mintlify. If your local website doesn't align with the production version, please update the CLI:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash npm
|
||||
npm i -g mintlify@latest
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn global upgrade mintlify
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Validating Links
|
||||
|
||||
The CLI can assist with validating reference links made in your documentation. To identify any broken links, use the following command:
|
||||
|
||||
```bash
|
||||
mintlify broken-links
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
<Tip>
|
||||
Unlimited editors available under the [Pro
|
||||
Plan](https://mintlify.com/pricing) and above.
|
||||
</Tip>
|
||||
|
||||
If the deployment is successful, you should see the following:
|
||||
|
||||
<Frame>
|
||||
<img src="/images/checks-passed.png" style={{ borderRadius: '0.5rem' }} />
|
||||
</Frame>
|
||||
|
||||
## Code Formatting
|
||||
|
||||
We suggest using extensions on your IDE to recognize and format MDX. If you're a VSCode user, consider the [MDX VSCode extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) for syntax highlighting, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title='Error: Could not load the "sharp" module using the darwin-arm64 runtime'>
|
||||
|
||||
This may be due to an outdated version of node. Try the following:
|
||||
1. Remove the currently-installed version of mintlify: `npm remove -g mintlify`
|
||||
2. Upgrade to Node v19 or higher.
|
||||
3. Reinstall mintlify: `npm install -g mintlify`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Issue: Encountering an unknown error">
|
||||
|
||||
Solution: Go to the root of your device and delete the \~/.mintlify folder. Afterwards, run `mintlify dev` again.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
Curious about what changed in the CLI version? [Check out the CLI changelog.](https://www.npmjs.com/package/mintlify?activeTab=versions)
|
||||
|
||||
# Development Workflow
|
||||
|
||||
## Branches
|
||||
- **`stable`**: Mirrors the latest stable release. This branch is updated only when a new stable release is published (every few weeks).
|
||||
- **`main`**: The primary development branch. This branch is updated frequently (every hour or more).
|
||||
|
||||
## Tags
|
||||
- **`x.x.x`**: Stable release tags. These are created for stable releases and updated every few weeks.
|
||||
- **`x.x.xrcXX`**: Pre-release tags. These are created for unstable pre-releases and updated every Friday at 5 PM UTC.
|
||||
|
||||
## Workflow Summary
|
||||
1. **Push to `main`**:
|
||||
- Runs pre-commit hooks to fix formatting.
|
||||
- Executes tests to ensure code quality.
|
||||
|
||||
2. **Release a new version**:
|
||||
- If the tag is a pre-release (`x.x.xrcXX`), the package is pushed to PyPI as a pre-release.
|
||||
- If the tag is a stable release (`x.x.x`), the package is pushed to PyPI as a stable release, and the `stable` branch is updated to match the release.
|
||||
|
||||
3. **Scheduled Pre-Releases**:
|
||||
- Every Friday at 5 PM UTC, a new pre-release tag (`x.x.xrcXX`) is created from the `main` branch and pushed to the repository.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: "Get Help"
|
||||
description: "More than 20k developers help each other"
|
||||
icon: "circle-question"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
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
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: "Observability"
|
||||
description: "Trace Browser Use's agent execution steps and browser sessions"
|
||||
icon: "eye"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Browser Use has a native integration with [Laminar](https://lmnr.ai) - open-source platform for tracing, evals and labeling of AI agents.
|
||||
Read more about Laminar in the [Laminar docs](https://docs.lmnr.ai).
|
||||
|
||||
## Setup
|
||||
|
||||
|
||||
|
||||
Register on [Laminar Cloud](https://lmnr.ai) and get the key from your project settings.
|
||||
Set the `LMNR_PROJECT_API_KEY` environment variable.
|
||||
```bash
|
||||
pip install 'lmnr[all]'
|
||||
export LMNR_PROJECT_API_KEY=<your-project-api-key>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Then, you simply initialize the Laminar at the top of your project and both Browser Use and session recordings will be automatically traced.
|
||||
|
||||
```python {5-8}
|
||||
from browser_use import Agent, ChatOpenAI
|
||||
import asyncio
|
||||
|
||||
from lmnr import Laminar, Instruments
|
||||
# this line auto-instruments Browser Use and any browser you use (local or remote)
|
||||
Laminar.initialize(project_api_key="...", disabled_instruments={Instruments.BROWSER_USE})
|
||||
|
||||
async def main():
|
||||
agent = Agent(
|
||||
task="open google, search Laminar AI",
|
||||
llm=ChatOpenAI(model="gpt-4.1-mini"),
|
||||
)
|
||||
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, timeline highlights indicate the agent's current step synced with the browser session.
|
||||
In the trace view, you can also see the agent's current step, the tool it's using, and the tool's input and output. Tools are highlighted in the timeline with a yellow color.
|
||||
|
||||
<img className="block" src="/images/laminar.png" alt="Laminar" />
|
||||
|
||||
## Laminar
|
||||
|
||||
To learn more about tracing and evaluating your browser agents, check out the [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've 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.
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "Telemetry"
|
||||
description: "Understanding Browser Use's telemetry"
|
||||
icon: "chart-mixed"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Browser Use is free under the MIT license. To help us continue improving the library, we collect anonymous usage data with [PostHog](https://posthog.com) . This information helps us understand how the library is used, fix bugs more quickly, and prioritize new features.
|
||||
|
||||
|
||||
## 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"
|
||||
```
|
||||
|
||||
<Note>
|
||||
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).
|
||||
</Note>
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: 'n8n Integration'
|
||||
description: 'Learn how to integrate Browser Use with n8n workflows'
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
# Browser Use n8n Integration
|
||||
|
||||
Browser Use can be integrated with [n8n](https://n8n.io), a workflow automation platform, using our community node. This integration allows you to trigger browser automation tasks directly from your n8n workflows.
|
||||
|
||||
## Installing the n8n Community Node
|
||||
|
||||
There are several ways to install the Browser Use community node in n8n:
|
||||
|
||||
### Using n8n Desktop or Cloud
|
||||
|
||||
1. Navigate to **Settings > Community Nodes**
|
||||
2. Click on **Install**
|
||||
3. Enter `n8n-nodes-browser-use` in the **Name** field
|
||||
4. Click **Install**
|
||||
|
||||
### Using a Self-hosted n8n Instance
|
||||
|
||||
Run the following command in your n8n installation directory:
|
||||
|
||||
```bash
|
||||
npm install n8n-nodes-browser-use
|
||||
```
|
||||
|
||||
### For Development
|
||||
|
||||
If you want to develop with the n8n node:
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/draphonix/n8n-nodes-browser-use.git
|
||||
```
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
cd n8n-nodes-browser-use
|
||||
npm install
|
||||
```
|
||||
3. Build the code:
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
4. Link to your n8n installation:
|
||||
```bash
|
||||
npm link
|
||||
```
|
||||
5. In your n8n installation directory:
|
||||
```bash
|
||||
npm link n8n-nodes-browser-use
|
||||
```
|
||||
|
||||
## Setting Up Browser Use Cloud API Credentials
|
||||
|
||||
To use the Browser Use node in n8n, you need to configure API credentials:
|
||||
|
||||
1. Sign up for an account at [Browser Use Cloud](https://cloud.browser-use.com)
|
||||
2. Navigate to the Settings or API section
|
||||
3. Generate or copy your API key
|
||||
4. In n8n, create a new credential:
|
||||
- Go to **Credentials** tab
|
||||
- Click **Create New**
|
||||
- Select **Browser Use Cloud API**
|
||||
- Enter your API key
|
||||
- Save the credential
|
||||
|
||||
## Using the Browser Use Node
|
||||
|
||||
Once installed, you can add the Browser Use node to your workflows:
|
||||
|
||||
1. In your workflow editor, search for "Browser Use" in the nodes panel
|
||||
2. Add the node to your workflow
|
||||
3. Set-up the credentials
|
||||
4. Choose your saved credentials
|
||||
5. Select an operation:
|
||||
- **Run Task**: Execute a browser automation task with natural language instructions
|
||||
- **Get Task**: Retrieve task details
|
||||
- **Get Task Status**: Check task execution status
|
||||
- **Pause/Resume/Stop Task**: Control running tasks
|
||||
- **Get Task Media**: Retrieve screenshots, videos, or PDFs
|
||||
- **List Tasks**: Get a list of tasks
|
||||
|
||||
### Example: Running a Browser Task
|
||||
|
||||
Here's a simple example of how to use the Browser Use node to run a browser task:
|
||||
|
||||
1. Add the Browser Use node to your workflow
|
||||
2. Select the "Run Task" operation
|
||||
3. In the "Instructions" field, enter a natural language description of what you want the browser to do, for example:
|
||||
```
|
||||
Go to example.com, take a screenshot of the homepage, and extract all the main heading texts
|
||||
```
|
||||
4. Optionally enable "Save Browser Data" to preserve cookies and session information
|
||||
5. Connect the node to subsequent nodes to process the results
|
||||
|
||||
## Workflow Examples
|
||||
|
||||
The Browser Use n8n node enables various automation scenarios:
|
||||
|
||||
- **Web Scraping**: Extract data from websites on a schedule
|
||||
- **Form Filling**: Automate data entry across web applications
|
||||
- **Monitoring**: Check website status and capture visual evidence
|
||||
- **Report Generation**: Generate PDFs or screenshots of web dashboards
|
||||
- **Multi-step Processes**: Chain browser tasks together using session persistence
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues with the Browser Use node:
|
||||
|
||||
- Verify your API key is valid and has sufficient credits
|
||||
- Check that your instructions are clear and specific
|
||||
- For complex tasks, consider breaking them into multiple steps
|
||||
- Refer to the [Browser Use documentation](https://docs.browser-use.com) for instruction best practices
|
||||
|
||||
## Resources
|
||||
|
||||
- [n8n Community Nodes Documentation](https://docs.n8n.io/integrations/community-nodes/)
|
||||
- [Browser Use Documentation](https://docs.browser-use.com)
|
||||
- [Browser Use Cloud](https://cloud.browser-use.com)
|
||||
- [n8n-nodes-browser-use GitHub Repository](https://github.com/draphonix/n8n-nodes-browser-use)
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: "Roadmap"
|
||||
description: "Future plans and upcoming features for Browser Use"
|
||||
icon: "road"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
Big things coming soon!
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
title: "Contribution Guide"
|
||||
description: ""
|
||||
icon: "handshake"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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's 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.
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: "Local Setup"
|
||||
description: "We're excited to have you join our community of contributors. "
|
||||
icon: "laptop-code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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
|
||||
```
|
||||
@@ -0,0 +1,329 @@
|
||||
{
|
||||
"$schema": "https://mintlify.com/docs.json",
|
||||
"theme": "aspen",
|
||||
"name": "Browser Use",
|
||||
"colors": {
|
||||
"primary": "#FE750E",
|
||||
"light": "#FFF7ED",
|
||||
"dark": "#C2410C"
|
||||
},
|
||||
"favicon": "/favicon.ico",
|
||||
"contextual": {
|
||||
"options": [
|
||||
"copy",
|
||||
"view"
|
||||
]
|
||||
},
|
||||
"fonts": {
|
||||
"family": "Geist"
|
||||
},
|
||||
"integrations": {
|
||||
"posthog": {
|
||||
"apiKey": "phc_F8JMNjW1i2KbGUTaW1unnDdLSPCoyc52SGRU0JecaUh"
|
||||
}
|
||||
},
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/customize/supported-models",
|
||||
"destination": "/customize/agent/supported-models"
|
||||
},
|
||||
{
|
||||
"source": "/customize/agent-settings",
|
||||
"destination": "/customize/agent/all-parameters"
|
||||
},
|
||||
{
|
||||
"source": "/customize/browser-settings",
|
||||
"destination": "/customize/browser/all-parameters"
|
||||
},
|
||||
{
|
||||
"source": "/customize/custom-functions",
|
||||
"destination": "/customize/tools/add"
|
||||
},
|
||||
{
|
||||
"source": "/customize/system-prompt",
|
||||
"destination": "/customize/agent/all-parameters#system-messages"
|
||||
},
|
||||
{
|
||||
"source": "/development/evaluations",
|
||||
"destination": "/development/setup/contribution-guide"
|
||||
},
|
||||
{
|
||||
"source": "/cli",
|
||||
"destination": "/quickstart"
|
||||
},
|
||||
{
|
||||
"source": "/development/local-setup",
|
||||
"destination": "/development/setup/local-setup"
|
||||
},
|
||||
{
|
||||
"source": "/development/contribution-guide",
|
||||
"destination": "/development/setup/contribution-guide"
|
||||
},
|
||||
{
|
||||
"source": "/development/telemetry",
|
||||
"destination": "/development/monitoring/telemetry"
|
||||
},
|
||||
{
|
||||
"source": "/development/observability",
|
||||
"destination": "/development/monitoring/observability"
|
||||
},
|
||||
{
|
||||
"source": "/development/hooks",
|
||||
"destination": "/customize/hooks"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/chain-agents",
|
||||
"destination": "/customize/examples/follow-up-tasks"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/fast-agent",
|
||||
"destination": "/examples/templates/fast-agent"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/follow-up-tasks",
|
||||
"destination": "/examples/templates/follow-up-tasks"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/parallel-browser",
|
||||
"destination": "/examples/templates/parallel-browser"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/playwright-integration",
|
||||
"destination": "/examples/templates/playwright-integration"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/sensitive-data",
|
||||
"destination": "/examples/templates/sensitive-data"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/secure",
|
||||
"destination": "/examples/templates/secure"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/more-examples",
|
||||
"destination": "/examples/templates/more-examples"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/ad-use",
|
||||
"destination": "/examples/apps/ad-use"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/vibetest-use",
|
||||
"destination": "/examples/apps/vibetest-use"
|
||||
},
|
||||
{
|
||||
"source": "/customize/examples/prompting-guide",
|
||||
"destination": "/customize/agent/prompting-guide"
|
||||
}
|
||||
],
|
||||
"navigation": {
|
||||
"tabs": [
|
||||
{
|
||||
"tab": "Library",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Get Started",
|
||||
"pages": [
|
||||
"introduction",
|
||||
"quickstart",
|
||||
"quickstart_llm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Customize",
|
||||
"pages": [
|
||||
{
|
||||
"group": "Agent",
|
||||
"icon": "robot",
|
||||
"isDefaultOpen": true,
|
||||
"pages": [
|
||||
"customize/agent/basics",
|
||||
"customize/agent/supported-models",
|
||||
"customize/agent/prompting-guide",
|
||||
"customize/agent/output-format",
|
||||
"customize/agent/all-parameters"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Browser",
|
||||
"icon": "window",
|
||||
"isDefaultOpen": false,
|
||||
"pages": [
|
||||
"customize/browser/basics",
|
||||
"customize/browser/real-browser",
|
||||
"customize/browser/remote",
|
||||
"customize/browser/all-parameters"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Tools",
|
||||
"icon": "wrench",
|
||||
"isDefaultOpen": false,
|
||||
"pages": [
|
||||
"customize/tools/basics",
|
||||
"customize/tools/available",
|
||||
"customize/tools/add",
|
||||
"customize/tools/remove",
|
||||
"customize/tools/response"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Actor",
|
||||
"icon": "terminal",
|
||||
"isDefaultOpen": false,
|
||||
"pages": [
|
||||
"customize/actor/basics",
|
||||
"customize/actor/examples",
|
||||
"customize/actor/all-parameters"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Integration",
|
||||
"icon": "plug",
|
||||
"isDefaultOpen": false,
|
||||
"pages": [
|
||||
"customize/mcp-server"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Examples",
|
||||
"pages": [
|
||||
{
|
||||
"group": "Templates",
|
||||
"icon": "folder",
|
||||
"pages": [
|
||||
"examples/templates/fast-agent",
|
||||
"examples/templates/follow-up-tasks",
|
||||
"examples/templates/parallel-browser",
|
||||
"examples/templates/playwright-integration",
|
||||
"examples/templates/sensitive-data",
|
||||
"examples/templates/secure",
|
||||
"examples/templates/more-examples"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Apps",
|
||||
"icon": "box-open",
|
||||
"pages": [
|
||||
"examples/apps/ad-use",
|
||||
"examples/apps/vibetest-use",
|
||||
"examples/apps/news-use",
|
||||
"examples/apps/msg-use"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Development",
|
||||
"pages": [
|
||||
{
|
||||
"group": "Contribution",
|
||||
"icon": "github",
|
||||
"isDefaultOpen": true,
|
||||
"pages": [
|
||||
"development/setup/local-setup",
|
||||
"development/setup/contribution-guide"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Advanced",
|
||||
"icon": "gear",
|
||||
"isDefaultOpen": false,
|
||||
"pages": [
|
||||
"customize/hooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Monitoring",
|
||||
"icon": "chart-mixed",
|
||||
"isDefaultOpen": false,
|
||||
"pages": [
|
||||
"development/monitoring/observability",
|
||||
"development/monitoring/telemetry"
|
||||
]
|
||||
},
|
||||
"development/get-help"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "Cloud",
|
||||
"hidden": true,
|
||||
"versions": [
|
||||
{
|
||||
"version": "v1",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Get Started",
|
||||
"pages": [
|
||||
"cloud/v1/quickstart",
|
||||
"cloud/v1/search",
|
||||
"cloud/v1/pricing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Guides",
|
||||
"pages": [
|
||||
"cloud/v1/implementation",
|
||||
"cloud/v1/custom-sdk",
|
||||
"cloud/v1/webhooks",
|
||||
"cloud/v1/authentication",
|
||||
"cloud/v1/n8n-browser-use-integration"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "REST API reference",
|
||||
"openapi": "https://api.browser-use.com/api/v1/openapi.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"logo": {
|
||||
"light": "/logo/light.svg",
|
||||
"dark": "/logo/dark.svg",
|
||||
"href": "https://browser-use.com"
|
||||
},
|
||||
"api": {
|
||||
"playground": {
|
||||
"display": "interactive"
|
||||
},
|
||||
"examples": {
|
||||
"languages": [
|
||||
"javascript",
|
||||
"curl",
|
||||
"python"
|
||||
],
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"navbar": {
|
||||
"links": [
|
||||
{
|
||||
"label": "Github",
|
||||
"href": "https://github.com/browser-use/browser-use"
|
||||
},
|
||||
{
|
||||
"label": "Discord",
|
||||
"href": "https://link.browser-use.com/discord"
|
||||
}
|
||||
],
|
||||
"primary": {
|
||||
"type": "button",
|
||||
"label": "Browser Use Cloud",
|
||||
"href": "https://cloud.browser-use.com"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"socials": {
|
||||
"x": "https://x.com/browser_use",
|
||||
"github": "https://github.com/browser-use/browser-use",
|
||||
"linkedin": "https://linkedin.com/company/browser-use"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: "Ad-Use (Ad Generator)"
|
||||
description: "Generate Instagram image ads and TikTok video ads from landing pages using browser agents, Google's Nano Banana 🍌, and Veo3."
|
||||
icon: "image"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Note>
|
||||
This demo requires browser-use v0.7.6+.
|
||||
</Note>
|
||||
|
||||
<video
|
||||
controls
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://github.com/user-attachments/assets/7fab54a9-b36b-4fba-ab98-a438f2b86b7e">
|
||||
</video>
|
||||
|
||||
## 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)
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: "Msg-Use (WhatsApp Sender)"
|
||||
description: "AI-powered WhatsApp message scheduler using browser agents and Gemini. Schedule personalized messages in natural language."
|
||||
icon: "message"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Note>
|
||||
This demo requires browser-use v0.7.7+.
|
||||
</Note>
|
||||
|
||||
<video
|
||||
controls
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://browser-use.github.io/media/demos/msg_use.mp4">
|
||||
</video>
|
||||
|
||||
## 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)
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: "News-Use (News Monitor)"
|
||||
description: "Monitor news websites and extract articles with sentiment analysis using browser agents and Google Gemini."
|
||||
icon: "newspaper"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Note>
|
||||
This demo requires browser-use v0.7.7+.
|
||||
</Note>
|
||||
|
||||
<video
|
||||
controls
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://browser-use.github.io/media/demos/news_use.mp4">
|
||||
</video>
|
||||
|
||||
## 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)
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: "Vibetest-Use (Automated QA)"
|
||||
description: "Run multi-agent Browser-Use tests to catch UI bugs, broken links, and accessibility issues before they ship."
|
||||
icon: "bug"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Note>
|
||||
Requires **browser-use < v0.5.0** and Playwright Chromium. Currently getting an update to v0.7.6+.
|
||||
</Note>
|
||||
|
||||
<video
|
||||
controls
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="https://github.com/user-attachments/assets/6450b5b7-10e5-4019-82a4-6d726dbfbe1f">
|
||||
</video>
|
||||
|
||||
## 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
|
||||
playwright install chromium --with-deps --no-shell
|
||||
```
|
||||
|
||||
### 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:4242 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)
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
title: "Fast Agent"
|
||||
description: "Optimize agent performance for maximum speed and efficiency."
|
||||
icon: "bolt"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
```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-2.5-flash')
|
||||
|
||||
# 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-2.5-flash')
|
||||
```
|
||||
|
||||
### 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
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: "Follow up tasks"
|
||||
description: "Follow up tasks with the same browser session."
|
||||
icon: "link"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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**: `BrowserProfile(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.
|
||||
|
||||
<Note>
|
||||
The browser session remains active throughout the entire chain, preserving all cookies, local storage, and page state.
|
||||
</Note>
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "More Examples"
|
||||
description: "Explore additional examples and use cases on GitHub."
|
||||
icon: "arrow-up-right-from-square"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
### 🔗 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!
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: "Parallel Agents"
|
||||
description: "Run multiple agents in parallel with separate browser instances"
|
||||
icon: "copy"
|
||||
---
|
||||
|
||||
```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.
|
||||
@@ -0,0 +1,393 @@
|
||||
---
|
||||
title: "Playwright Integration"
|
||||
description: "Advanced example showing Playwright and Browser-Use working together"
|
||||
icon: "wand-magic-sparkles"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
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 = await async_playwright().start()
|
||||
playwright_browser = await playwright.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 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())
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: "Secure Setup"
|
||||
description: "Azure OpenAI with data privacy and security configuration."
|
||||
icon: "shield-check"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
|
||||
<Note>
|
||||
For enterprise deployments contact support@browser-use.com.
|
||||
</Note>
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
title: "Sensitive Data"
|
||||
description: "Handle secret information securely and avoid sending PII & passwords to the LLM."
|
||||
icon: "shield"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
```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
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,13 @@
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_7_13)">
|
||||
<path d="M97.8916 39.0448C82.6177 33.1997 95.2199 10.8169 74.212 11.3849C48.5413 12.0793 8.31528 52.4518 12.4236 78.6851C14.4652 91.6755 24.6096 86.2218 29.3732 88.1154C32.5364 89.3652 36.2792 95.0083 40.3245 95.9047C22.4293 106.193 -0.556809 96.397 0.0102912 74.3423C0.829435 41.86 47.7474 -5.25386 81.1937 0.477571C99.8702 3.68414 102.189 23.5422 97.8916 39.0448Z" fill="white"/>
|
||||
<path d="M24.8115 57.7541L39.6068 71.7166C49.0332 80.1875 74.061 94.9706 85.403 84.9469C98.774 73.1306 70.495 32.3162 57.4769 25.802L68.9069 20.6639C86.7138 33.6796 113.783 75.9836 91.7294 94.4025C77.5014 106.282 54.5655 96.2204 41.0811 87.3707C30.8103 80.6294 15.9647 70.9591 24.8115 57.7415V57.7541Z" fill="white"/>
|
||||
<path d="M40.3373 4.75723C35.5485 4.88347 31.8055 11.1199 28.2895 12.2182C25.1642 13.1903 20.8414 10.5266 16.1408 14.0487C11.0495 17.8613 12.7891 36.0655 3.02233 40.5976C-2.98893 22.9362 0.75354 1.8789 22.4672 0.0736228C24.1433 -0.0652445 42.7822 1.17195 40.3373 4.74463V4.75723Z" fill="white"/>
|
||||
<path d="M76.1025 57.754C84.1175 71.0348 69.5871 86.2092 57.489 74.1025L76.1025 57.754Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7_13">
|
||||
<rect width="100" height="100" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 238 KiB |
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "Introduction"
|
||||
description: "Automate browser tasks in plain text. "
|
||||
icon: "book-open"
|
||||
---
|
||||
|
||||
<img
|
||||
className="block dark:hidden rounded-2xl"
|
||||
src="/images/browser-use-banner.png"
|
||||
alt="Browser Use Logo"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:block rounded-2xl"
|
||||
src="/images/browser-use-banner-dark.png"
|
||||
alt="Browser Use Logo"
|
||||
/>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Local Setup" icon="terminal" href="/quickstart">
|
||||
Open-source Python library.
|
||||
</Card>
|
||||
<Card
|
||||
title="Cloud Setup"
|
||||
icon="cloud"
|
||||
href="https://docs.cloud.browser-use.com"
|
||||
color="#FE750E"
|
||||
>
|
||||
Scale up with our cloud.
|
||||
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,144 @@
|
||||
---
|
||||
title: "Human Quickstart"
|
||||
description: ""
|
||||
icon: "rocket"
|
||||
---
|
||||
|
||||
|
||||
## 1. Fast setup
|
||||
|
||||
<Tabs>
|
||||
<Tab title="uv">
|
||||
```bash create environment
|
||||
uv venv --python 3.12
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="pip">
|
||||
```bash create environment with python >= 3.11
|
||||
python3.12 -m venv .venv
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Mac/Linux">
|
||||
```bash activate environment
|
||||
source .venv/bin/activate
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Windows">
|
||||
```bash activate environment
|
||||
.venv\Scripts\activate
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Tabs>
|
||||
<Tab title="uv">
|
||||
```bash install browser-use & chromium
|
||||
uv pip install browser-use
|
||||
uvx playwright install chromium --with-deps
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="pip">
|
||||
```bash install browser-use & chromium
|
||||
pip install browser-use
|
||||
pip install playwright && playwright install chromium --with-deps
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## 2. Choose your favorite LLM
|
||||
Create a `.env` file and add your API key. Don't have one? Start with a [free Gemini key](https://aistudio.google.com/app/u/1/apikey?pli=1).
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Mac/Linux">
|
||||
```bash create .env file
|
||||
touch .env
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Windows">
|
||||
```cmd create .env file
|
||||
echo. > .env
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Google">
|
||||
```bash add your key to .env file
|
||||
GEMINI_API_KEY=
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="OpenAI">
|
||||
```bash add your key to .env file
|
||||
OPENAI_API_KEY=
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Anthropic">
|
||||
```bash add your key to .env file
|
||||
ANTHROPIC_API_KEY=
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
See [Supported Models](/customize/supported-models) for more.
|
||||
|
||||
## 3. Run your first agent
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Google">
|
||||
```python agent.py
|
||||
from browser_use import Agent, ChatGoogle
|
||||
from dotenv import load_dotenv
|
||||
import asyncio
|
||||
|
||||
load_dotenv()
|
||||
|
||||
async def main():
|
||||
llm = ChatGoogle(model="gemini-2.5-flash")
|
||||
task = "Find the number 1 post on Show HN"
|
||||
agent = Agent(task=task, llm=llm)
|
||||
await agent.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="OpenAI">
|
||||
```python agent.py
|
||||
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())
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Anthropic">
|
||||
```python agent.py
|
||||
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())
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: "LLM Quickstart"
|
||||
description: ""
|
||||
icon: "brain"
|
||||
---
|
||||
|
||||
|
||||
|
||||
1. Copy all content [🔗 from here](https://docs.browser-use.com/llms-full.txt) (~32k tokens)
|
||||
2. Paste it into your favorite coding agent (Cursor, Claude, ChatGPT ...).
|
||||