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

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
@@ -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
**dont 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 competitors 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 n8ns 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 competitors 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) were 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>