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,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&nbsp; < 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