chore: import upstream snapshot with attribution
Test Browser Use CLI Install / uv pip install (ubuntu-latest) (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use from local wheel (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use[cli] from PyPI (push) Failing after 1s
package / pip-install-on-macos-latest-py-3.11 (push) Has been skipped
package / pip-install-on-macos-latest-py-3.13 (push) Has been skipped
package / pip-install-on-ubuntu-latest-py-3.11 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.13 (push) Has been skipped
cloud_evals / trigger_cloud_eval_image_build (push) Failing after 1s
docker / build_publish_image (push) Failing after 1s
Test Browser Use CLI Install / browser-use skill sync (push) Failing after 1s
lint / code-style (push) Failing after 0s
lint / type-checker (push) Failing after 1s
package / pip-build (push) Failing after 1s
lint / syntax-errors (push) Failing after 3s
package / pip-install-on-ubuntu-latest-py-3.13 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.11 (push) Has been skipped
test / ${{ matrix.test_filename }} (push) Has been skipped
test / evaluate-tasks (push) Has been skipped
test / setup-chromium (push) Failing after 2s
test / find_tests (push) Failing after 2s
Test Browser Use CLI Install / uv pip install (windows-latest) (push) Has been cancelled
Test Browser Use CLI Install / uv pip install (macos-latest) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:02:32 +08:00
commit 4cd2d4af2b
475 changed files with 121829 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
"""
Show how to use sample_images to add image context for your task
"""
import asyncio
import base64
from pathlib import Path
from typing import Any
from dotenv import load_dotenv
from browser_use import Agent
from browser_use.llm import ChatOpenAI
from browser_use.llm.messages import ContentPartImageParam, ContentPartTextParam, ImageURL
# Load environment variables
load_dotenv()
def image_to_base64(image_path: str) -> str:
"""
Convert image file to base64 string.
Args:
image_path: Path to the image file
Returns:
Base64 encoded string of the image
Raises:
FileNotFoundError: If image file doesn't exist
IOError: If image file cannot be read
"""
image_file = Path(image_path)
if not image_file.exists():
raise FileNotFoundError(f'Image file not found: {image_path}')
try:
with open(image_file, 'rb') as f:
encoded_string = base64.b64encode(f.read())
return encoded_string.decode('utf-8')
except OSError as e:
raise OSError(f'Failed to read image file: {e}')
def create_sample_images() -> list[ContentPartTextParam | ContentPartImageParam]:
"""
Create image context for the agent.
Returns:
list of content parts containing text and image data
"""
# Image path - replace with your actual image path
image_path = 'sample_image.png'
# Image context configuration
image_context: list[dict[str, Any]] = [
{
'type': 'text',
'value': (
'The following image explains the google layout. '
'The image highlights several buttons with red boxes, '
'and next to them are corresponding labels in red text.\n'
'Each label corresponds to a button as follows:\n'
'Label 1 is the "image" button.'
),
},
{'type': 'image', 'value': image_to_base64(image_path)},
]
# Convert to content parts
content_parts = []
for item in image_context:
if item['type'] == 'text':
content_parts.append(ContentPartTextParam(text=item['value']))
elif item['type'] == 'image':
content_parts.append(
ContentPartImageParam(
image_url=ImageURL(
url=f'data:image/jpeg;base64,{item["value"]}',
media_type='image/jpeg',
),
)
)
return content_parts
async def main() -> None:
"""
Main function to run the browser agent with image context.
"""
# Task configuration
task_str = 'goto https://www.google.com/ and click image button'
# Initialize the language model
model = ChatOpenAI(model='gpt-4.1')
# Create sample images for context
try:
sample_images = create_sample_images()
except (FileNotFoundError, OSError) as e:
print(f'Error loading sample images: {e}')
print('Continuing without sample images...')
sample_images = []
# Initialize and run the agent
agent = Agent(task=task_str, llm=model, sample_images=sample_images)
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
+64
View File
@@ -0,0 +1,64 @@
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
from browser_use.browser import BrowserProfile, BrowserSession
llm = ChatOpenAI(model='gpt-4o-mini')
# Example task: Try to navigate to various sites including blocked ones
task = 'Navigate to example.com, then try to go to x.com, then facebook.com, and finally visit google.com. Tell me which sites you were able to access.'
prohibited_domains = [
'x.com', # Block X (formerly Twitter) - "locked the f in"
'twitter.com', # Block Twitter (redirects to x.com anyway)
'facebook.com', # Lock the F in Facebook too
'*.meta.com', # Block all Meta properties (wildcard pattern)
'*.adult-site.com', # Block all subdomains of adult sites
'https://explicit-content.org', # Block specific protocol/domain
'gambling-site.net', # Block gambling sites
]
# Note: For lists with 100+ domains, automatic optimization kicks in:
# - Converts list to set for O(1) lookup (blazingly fast!)
# - Pattern matching (*.domain) is disabled for large lists
# - Both www.example.com and example.com variants are checked automatically
# Perfect for ad blockers or large malware domain lists (e.g., 400k+ domains)
browser_session = BrowserSession(
browser_profile=BrowserProfile(
prohibited_domains=prohibited_domains,
headless=False, # Set to True to run without visible browser
user_data_dir='~/.config/browseruse/profiles/blocked-demo',
),
)
agent = Agent(
task=task,
llm=llm,
browser_session=browser_session,
)
async def main():
print('Demo: Blocked Domains Feature - "Lock the F in" Edition')
print("We're literally locking the F in Facebook and X!")
print(f'Prohibited domains: {prohibited_domains}')
print('The agent will try to visit various sites, but blocked domains will be prevented.')
print()
await agent.run(max_steps=10)
input('Press Enter to close the browser...')
await browser_session.kill()
if __name__ == '__main__':
asyncio.run(main())
+51
View File
@@ -0,0 +1,51 @@
"""
Generate CSV files with automatic normalization.
The agent's file system automatically normalizes CSV output using Python's csv module,
so fields containing commas, quotes, or empty values are properly handled per RFC 4180.
This means the agent doesn't need to worry about manual quoting — it's fixed at the
infrastructure level.
Common LLM mistakes that are auto-corrected:
- Unquoted fields containing commas (e.g. "San Francisco, CA" without quotes)
- Unescaped double quotes inside fields
- Inconsistent empty field handling
- Stray blank lines
"""
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatBrowserUse
async def main():
agent = Agent(
task=(
'Go to https://en.wikipedia.org/wiki/List_of_largest_cities and extract the top 10 cities. '
'Create a CSV file called "top_cities.csv" with columns: rank, city name, country, population. '
'Make sure to include all cities even if some data is missing — leave those cells empty.'
),
llm=ChatBrowserUse(model='bu-2-0'),
)
history = await agent.run()
# Check the generated CSV file
if agent.file_system:
csv_file = agent.file_system.get_file('top_cities.csv')
if csv_file:
print('\nGenerated CSV content:')
print(csv_file.content)
print(f'\nFile saved to: {agent.file_system.get_dir() / csv_file.full_name}')
if __name__ == '__main__':
asyncio.run(main())
+55
View File
@@ -0,0 +1,55 @@
"""
Show how to use custom outputs.
@dev You need to add OPENAI_API_KEY to your environment variables.
"""
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from pydantic import BaseModel
from browser_use import Agent, ChatOpenAI
class Post(BaseModel):
post_title: str
post_url: str
num_comments: int
hours_since_post: int
class Posts(BaseModel):
posts: list[Post]
async def main():
task = 'Go to hackernews show hn and give me the first 5 posts'
model = ChatOpenAI(model='gpt-4.1-mini')
agent = Agent(task=task, llm=model, output_model_schema=Posts)
history = await agent.run()
result = history.final_result()
if result:
parsed: Posts = Posts.model_validate_json(result)
for post in parsed.posts:
print('\n--------------------------------')
print(f'Title: {post.post_title}')
print(f'URL: {post.post_url}')
print(f'Comments: {post.num_comments}')
print(f'Hours since post: {post.hours_since_post}')
else:
print('No result')
if __name__ == '__main__':
asyncio.run(main())
+38
View File
@@ -0,0 +1,38 @@
import asyncio
import json
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
extend_system_message = (
'REMEMBER the most important RULE: ALWAYS open first a new tab and go first to url wikipedia.com no matter the task!!!'
)
# or use override_system_message to completely override the system prompt
async def main():
task = 'do google search to find images of Elon Musk'
model = ChatOpenAI(model='gpt-4.1-mini')
agent = Agent(task=task, llm=model, extend_system_message=extend_system_message)
print(
json.dumps(
agent.message_manager.system_prompt.model_dump(exclude_unset=True),
indent=4,
)
)
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
+34
View File
@@ -0,0 +1,34 @@
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, Browser, ChatGoogle
api_key = os.getenv('GOOGLE_API_KEY')
if not api_key:
raise ValueError('GOOGLE_API_KEY is not set')
llm = ChatGoogle(model='gemini-2.5-flash', api_key=api_key)
browser = Browser(downloads_path='~/Downloads/tmp')
async def run_download():
agent = Agent(
task='Go to "https://file-examples.com/" and download the smallest doc file. then go back and get the next file.',
llm=llm,
browser=browser,
)
await agent.run(max_steps=25)
if __name__ == '__main__':
asyncio.run(run_download())
+55
View File
@@ -0,0 +1,55 @@
"""
Example: Using a fallback LLM model.
When the primary LLM fails with rate limits (429), authentication errors (401),
payment/credit errors (402), or server errors (500, 502, 503, 504), the agent
automatically switches to the fallback model and continues execution.
Note: The primary LLM will first exhaust its own retry logic (typically 5 attempts
with exponential backoff) before the fallback is triggered. This means transient errors
are handled by the provider's built-in retries, and the fallback only kicks in when
the provider truly can't recover.
This is useful for:
- High availability: Keep your agent running even when one provider has issues
- Cost optimization: Use a cheaper model as fallback when the primary is rate limited
- Multi-provider resilience: Switch between OpenAI, Anthropic, Google, etc.
@dev You need to add OPENAI_API_KEY and ANTHROPIC_API_KEY to your environment variables.
"""
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent
from browser_use.llm import ChatAnthropic, ChatOpenAI
llm = ChatAnthropic(model='claude-sonnet-4-0')
fallback_llm = ChatOpenAI(model='gpt-4o')
agent = Agent(
task='Go to github.com and find the browser-use repository',
llm=llm,
fallback_llm=fallback_llm,
)
async def main():
result = await agent.run()
print(result)
# You can check if fallback was used:
if agent.is_using_fallback_llm:
print('Note: Agent switched to fallback LLM during execution')
print(f'Current model: {agent.current_llm_model}')
if __name__ == '__main__':
asyncio.run(main())
+24
View File
@@ -0,0 +1,24 @@
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()
if __name__ == '__main__':
asyncio.run(main())
+32
View File
@@ -0,0 +1,32 @@
import asyncio
import os
import sys
from browser_use.browser.profile import BrowserProfile
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent
profile = BrowserProfile(keep_alive=True)
task = """Go to reddit.com"""
async def main():
agent = Agent(task=task, browser_profile=profile)
await agent.run(max_steps=1)
while True:
user_response = input('\n👤 New task or "q" to quit: ')
agent.add_new_task(f'New task: {user_response}')
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
+31
View File
@@ -0,0 +1,31 @@
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
llm = ChatOpenAI(model='gpt-4.1-mini')
initial_actions = [
{'navigate': {'url': 'https://www.google.com', 'new_tab': True}},
{'navigate': {'url': 'https://en.wikipedia.org/wiki/Randomness', 'new_tab': True}},
]
agent = Agent(
task='What theories are displayed on the page?',
initial_actions=initial_actions,
llm=llm,
)
async def main():
await agent.run(max_steps=10)
if __name__ == '__main__':
asyncio.run(main())
+47
View File
@@ -0,0 +1,47 @@
"""
Setup:
1. Get your API key from https://cloud.browser-use.com/new-api-key
2. Set environment variable: export BROWSER_USE_API_KEY="your-key"
"""
import asyncio
import os
import sys
# Add the parent directory to the path so we can import browser_use
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent
from browser_use.llm.browser_use.chat import ChatBrowserUse
# task from GAIA
task = """
If Eliud Kipchoge could maintain his record-making marathon pace indefinitely, how many thousand hours would it take him to run the distance between the Earth and the Moon its closest approach?
Please use the minimum perigee value on the Wikipedia page for the Moon when carrying out your calculation.
Round your result to the nearest 1000 hours and do not use any comma separators if necessary.
"""
async def main():
llm = ChatBrowserUse(model='bu-2-0')
agent = Agent(
task=task,
llm=llm,
use_judge=True,
judge_llm=llm,
ground_truth='16', # The TRUE answer is 17 but we put 16 to demonstrate judge can detect when the answer is wrong.
)
history = await agent.run()
# Get the judgement result
if history.is_judged():
judgement = history.judgement()
print(f'Agent history judgement: {judgement}')
if __name__ == '__main__':
asyncio.run(main())
+117
View File
@@ -0,0 +1,117 @@
"""
Example: Using large blocklists (400k+ domains) with automatic optimization
This example demonstrates:
1. Loading a real-world blocklist (HaGeZi's Pro++ with 439k+ domains)
2. Automatic conversion to set for O(1) lookup performance
3. Testing that blocked domains are actually blocked
Performance: ~0.02ms per domain check (50,000+ checks/second!)
"""
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
from browser_use.browser import BrowserProfile, BrowserSession
llm = ChatOpenAI(model='gpt-4.1-mini')
def load_blocklist_from_url(url: str) -> list[str]:
"""Load and parse a blocklist from a URL.
Args:
url: URL to the blocklist file
Returns:
List of domain strings (comments and empty lines removed)
"""
import urllib.request
print(f'📥 Downloading blocklist from {url}...')
domains = []
with urllib.request.urlopen(url) as response:
for line in response:
line = line.decode('utf-8').strip()
# Skip comments and empty lines
if line and not line.startswith('#'):
domains.append(line)
print(f'✅ Loaded {len(domains):,} domains')
return domains
async def main():
# Load HaGeZi's Pro++ blocklist (blocks ads, tracking, malware, etc.)
# Source: https://github.com/hagezi/dns-blocklists
blocklist_url = 'https://gitlab.com/hagezi/mirror/-/raw/main/dns-blocklists/domains/pro.plus.txt'
print('=' * 70)
print('🚀 Large Blocklist Demo - 439k+ Blocked Domains')
print('=' * 70)
print()
# Load the blocklist
prohibited_domains = load_blocklist_from_url(blocklist_url)
# Sample some blocked domains to test
test_blocked = [prohibited_domains[0], prohibited_domains[1000], prohibited_domains[-1]]
print(f'\n📋 Sample blocked domains: {", ".join(test_blocked[:3])}')
print(f'\n🔧 Creating browser with {len(prohibited_domains):,} blocked domains...')
print(' (Auto-optimizing to set for O(1) lookup performance)')
# Create browser with the blocklist
# The list will be automatically optimized to a set for fast lookups
browser_session = BrowserSession(
browser_profile=BrowserProfile(
prohibited_domains=prohibited_domains,
headless=False,
user_data_dir='~/.config/browseruse/profiles/blocklist-demo',
),
)
# Task: Try to visit a blocked domain and a safe domain
blocked_site = test_blocked[0] # Will be blocked
safe_site = 'github.com' # Will be allowed
task = f"""
Try to navigate to these websites and report what happens:
1. First, try to visit https://{blocked_site}
2. Then, try to visit https://{safe_site}
Tell me which sites you were able to access and which were blocked.
"""
agent = Agent(
task=task,
llm=llm,
browser_session=browser_session,
)
print(f'\n🤖 Agent task: Try to visit {blocked_site} (blocked) and {safe_site} (allowed)')
print('\n' + '=' * 70)
await agent.run(max_steps=5)
print('\n' + '=' * 70)
print('✅ Demo complete!')
print(f'💡 The blocklist with {len(prohibited_domains):,} domains was optimized to a set')
print(' for instant O(1) domain checking (vs slow O(n) pattern matching)')
print('=' * 70)
input('\nPress Enter to close the browser...')
await browser_session.kill()
if __name__ == '__main__':
asyncio.run(main())
+31
View File
@@ -0,0 +1,31 @@
"""
Simple try of the agent.
@dev You need to add OPENAI_API_KEY to your environment variables.
"""
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
# video: https://preview.screen.studio/share/clenCmS6
llm = ChatOpenAI(model='gpt-4.1-mini')
agent = Agent(
task='open 3 tabs with elon musk, sam altman, and steve jobs, then go back to the first and stop',
llm=llm,
)
async def main():
await agent.run()
asyncio.run(main())
+51
View File
@@ -0,0 +1,51 @@
import asyncio
import os
import sys
from pathlib import Path
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import ChatOpenAI
from browser_use.agent.service import Agent
from browser_use.browser import BrowserProfile, BrowserSession
browser_session = BrowserSession(
browser_profile=BrowserProfile(
keep_alive=True,
headless=False,
record_video_dir=Path('./tmp/recordings'),
user_data_dir='~/.config/browseruse/profiles/default',
)
)
llm = ChatOpenAI(model='gpt-4.1-mini')
# NOTE: This is experimental - you will have multiple agents running in the same browser session
async def main():
await browser_session.start()
agents = [
Agent(task=task, llm=llm, browser_session=browser_session)
for task in [
'Search Google for weather in Tokyo',
'Check Reddit front page title',
'Look up Bitcoin price on Coinbase',
# 'Find NASA image of the day',
# 'Check top story on CNN',
# 'Search latest SpaceX launch date',
# 'Look up population of Paris',
# 'Find current time in Sydney',
# 'Check who won last Super Bowl',
# 'Search trending topics on Twitter',
]
]
print(await asyncio.gather(*[agent.run() for agent in agents]))
await browser_session.kill()
if __name__ == '__main__':
asyncio.run(main())
+55
View File
@@ -0,0 +1,55 @@
import asyncio
import os
import sys
from pprint import pprint
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
from browser_use.agent.views import AgentHistoryList
from browser_use.browser import BrowserProfile, BrowserSession
from browser_use.browser.profile import ViewportSize
llm = ChatOpenAI(model='gpt-4.1-mini')
async def main():
browser_session = BrowserSession(
browser_profile=BrowserProfile(
headless=False,
traces_dir='./tmp/result_processing',
window_size=ViewportSize(width=1280, height=1000),
user_data_dir='~/.config/browseruse/profiles/default',
)
)
await browser_session.start()
try:
agent = Agent(
task="go to google.com and type 'OpenAI' click search and give me the first url",
llm=llm,
browser_session=browser_session,
)
history: AgentHistoryList = await agent.run(max_steps=3)
print('Final Result:')
pprint(history.final_result(), indent=4)
print('\nErrors:')
pprint(history.errors(), indent=4)
# e.g. xPaths the model clicked on
print('\nModel Outputs:')
pprint(history.model_actions(), indent=4)
print('\nThoughts:')
pprint(history.model_thoughts(), indent=4)
finally:
await browser_session.stop()
if __name__ == '__main__':
asyncio.run(main())
+141
View File
@@ -0,0 +1,141 @@
"""
Example: Rerunning saved agent history with variable detection and substitution
This example shows how to:
1. Run an agent and save its history (including initial URL navigation)
2. Detect variables in the saved history (emails, names, dates, etc.)
3. Rerun the history with substituted values (different data)
4. Get AI-generated summary of rerun completion (with screenshot analysis)
Useful for:
- Debugging agent behavior
- Testing changes with consistent scenarios
- Replaying successful workflows with different data
- Understanding what values can be substituted in reruns
- Getting automated verification of rerun success
Note: Initial actions (like opening URLs from tasks) are now automatically
saved to history and will be replayed during rerun, so you don't need to
worry about manually specifying URLs when rerunning.
AI Features During Rerun:
1. AI Step for Extract Actions:
When an 'extract' action is replayed, the rerun automatically uses AI to
re-analyze the current page content (since it may have changed with new data).
This ensures the extracted content reflects the current state, not cached results.
2. AI Summary:
At the end of the rerun, an AI summary analyzes the final screenshot and
execution statistics to determine success/failure.
Custom LLM Usage:
# Option 1: Use agent's LLM (default)
results = await agent.load_and_rerun(history_file)
# Option 2: Use custom LLMs for AI steps and summary
from browser_use.llm import ChatOpenAI
custom_llm = ChatOpenAI(model='gpt-4.1-mini')
results = await agent.load_and_rerun(
history_file,
ai_step_llm=custom_llm, # For extract action re-evaluation
summary_llm=custom_llm, # For final summary
)
The AI summary will be the last item in results and will have:
- extracted_content: The summary text
- success: Whether rerun was successful
- is_done: Always True for summary
"""
import asyncio
from pathlib import Path
from browser_use import Agent
from browser_use.llm import ChatBrowserUse
async def main():
# Example task to demonstrate history saving and rerunning
history_file = Path('agent_history.json')
task = 'Go to https://browser-use.github.io/stress-tests/challenges/reference-number-form.html and fill the form with example data and submit and extract the refernence number.'
llm = ChatBrowserUse(model='bu-2-0')
# Optional: Use custom LLMs for AI features during rerun
# Uncomment to use a custom LLM:
# from browser_use.llm import ChatOpenAI
# custom_llm = ChatOpenAI(model='gpt-4.1-mini')
# ai_step_llm = custom_llm # For re-evaluating extract actions
# summary_llm = custom_llm # For final summary
ai_step_llm = None # Set to None to use agent's LLM (default)
summary_llm = None # Set to None to use agent's LLM (default)
# Step 1: Run the agent and save history
print('=== Running Agent ===')
agent = Agent(task=task, llm=llm, max_actions_per_step=1)
await agent.run(max_steps=10)
agent.save_history(history_file)
print(f'✓ History saved to {history_file}')
# Step 2: Detect variables in the saved history
print('\n=== Detecting Variables ===')
variables = agent.detect_variables()
if variables:
print(f'Found {len(variables)} variable(s):')
for var_name, var_info in variables.items():
format_info = f' (format: {var_info.format})' if var_info.format else ''
print(f'{var_name}: "{var_info.original_value}"{format_info}')
else:
print('No variables detected in history')
# Step 3: Rerun the history with substituted values
if variables:
print('\n=== Rerunning History (Substituted Values) ===')
# Create new values for the detected variables
new_values = {}
for var_name, var_info in variables.items():
# Map detected variables to new values
if var_name == 'email':
new_values[var_name] = 'jane.smith@example.com'
elif var_name == 'full_name':
new_values[var_name] = 'Jane Smith'
elif var_name.startswith('full_name_'):
new_values[var_name] = 'General Information'
elif var_name == 'first_name':
new_values[var_name] = 'Jane'
elif var_name == 'date':
new_values[var_name] = '1995-05-15'
elif var_name == 'country':
new_values[var_name] = 'Canada'
# You can add more variable substitutions as needed
if new_values:
print(f'Substituting {len(new_values)} variable(s):')
for var_name, new_value in new_values.items():
old_value = variables[var_name].original_value
print(f'{var_name}: "{old_value}""{new_value}"')
# Rerun with substituted values and optional custom LLMs
substitute_agent = Agent(task='', llm=llm)
results = await substitute_agent.load_and_rerun(
history_file,
variables=new_values,
ai_step_llm=ai_step_llm, # For extract action re-evaluation
summary_llm=summary_llm, # For final summary
max_step_interval=20,
delay_between_actions=1,
)
# Display AI-generated summary (last result)
if results and results[-1].is_done:
summary = results[-1]
print('\n📊 AI Summary:')
print(f' Summary: {summary.extracted_content}')
print(f' Success: {summary.success}')
print('✓ History rerun with substituted values complete')
else:
print('\n⚠️ No variables detected, skipping substitution rerun')
if __name__ == '__main__':
asyncio.run(main())
+43
View File
@@ -0,0 +1,43 @@
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
from browser_use.browser import BrowserProfile, BrowserSession
llm = ChatOpenAI(model='gpt-4.1-mini')
task = (
"go to google.com and search for openai.com and click on the first link then extract content and scroll down - what's there?"
)
allowed_domains = ['google.com']
browser_session = BrowserSession(
browser_profile=BrowserProfile(
executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
allowed_domains=allowed_domains,
user_data_dir='~/.config/browseruse/profiles/default',
),
)
agent = Agent(
task=task,
llm=llm,
browser_session=browser_session,
)
async def main():
await agent.run(max_steps=25)
input('Press Enter to close the browser...')
await browser_session.kill()
asyncio.run(main())
+51
View File
@@ -0,0 +1,51 @@
"""
Save any webpage as a PDF using the save_as_pdf action.
The agent can save the current page as a PDF at any point during a task.
Supports custom filenames, paper sizes (Letter, A4, Legal, A3, Tabloid),
landscape orientation, and background printing.
By default the PDF includes page metadata in the margins (just like Chrome's
Print dialog): the date in the header and the page URL plus page numbers in the
footer. Pass display_header_footer=False for a clean PDF, or supply custom
header_template / footer_template HTML to control exactly what's printed.
Setup:
1. Get your API key from https://cloud.browser-use.com/new-api-key
2. Set environment variable: export BROWSER_USE_API_KEY="your-key"
"""
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatBrowserUse
async def main():
agent = Agent(
task=(
'Go to https://news.ycombinator.com and save the front page as a PDF named "hackernews". '
'Then go to https://en.wikipedia.org/wiki/Web_browser and save just that article as a PDF in A4 format.'
),
llm=ChatBrowserUse(model='bu-2-0'),
)
history = await agent.run()
# Print paths of any PDF files the agent saved
print('\nSaved files:')
for result in history.action_results():
if result.attachments:
for path in result.attachments:
print(f' {path}')
if __name__ == '__main__':
asyncio.run(main())
+96
View File
@@ -0,0 +1,96 @@
# Goal: Automates webpage scrolling with various scrolling actions, including element-specific scrolling.
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
from browser_use.browser import BrowserProfile, BrowserSession
if not os.getenv('OPENAI_API_KEY'):
raise ValueError('OPENAI_API_KEY is not set')
"""
Example: Enhanced 'Scroll' action with page amounts and element-specific scrolling.
This script demonstrates the new enhanced scrolling capabilities:
1. PAGE-LEVEL SCROLLING:
- Scrolling by specific page amounts using 'num_pages' parameter (0.5, 1.0, 2.0, etc.)
- Scrolling up or down using the 'down' parameter
- Uses JavaScript window.scrollBy() or smart container detection
2. ELEMENT-SPECIFIC SCROLLING:
- NEW: Optional 'index' parameter to scroll within specific elements
- Perfect for dropdowns, sidebars, and custom UI components
- Uses direct scrollTop manipulation (no mouse events that might close dropdowns)
- Automatically finds scroll containers in the element hierarchy
- Falls back to page scrolling if no container found
3. IMPLEMENTATION DETAILS:
- Does NOT use mouse movement or wheel events
- Direct DOM manipulation for precision and reliability
- Container-aware scrolling prevents unwanted side effects
"""
llm = ChatOpenAI(model='gpt-4.1-mini')
browser_profile = BrowserProfile(headless=False)
browser_session = BrowserSession(browser_profile=browser_profile)
# Example 1: Basic page scrolling with custom amounts
agent1 = Agent(
task="Navigate to 'https://en.wikipedia.org/wiki/Internet' and scroll down by one page - then scroll up by 0.5 pages - then scroll down by 0.25 pages - then scroll down by 2 pages.",
llm=llm,
browser_session=browser_session,
)
# Example 2: Element-specific scrolling (dropdowns and containers)
agent2 = Agent(
task="""Go to https://semantic-ui.com/modules/dropdown.html#/definition and:
1. Scroll down in the left sidebar by 2 pages
2. Then scroll down 1 page in the main content area
3. Click on the State dropdown and scroll down 1 page INSIDE the dropdown to see more states
4. The dropdown should stay open while scrolling inside it""",
llm=llm,
browser_session=browser_session,
)
# Example 3: Text-based scrolling alternative
agent3 = Agent(
task="Navigate to 'https://en.wikipedia.org/wiki/Internet' and scroll to the text 'The vast majority of computer'",
llm=llm,
browser_session=browser_session,
)
async def main():
print('Choose which scrolling example to run:')
print('1. Basic page scrolling with custom amounts (Wikipedia)')
print('2. Element-specific scrolling (Semantic UI dropdowns)')
print('3. Text-based scrolling (Wikipedia)')
choice = input('Enter choice (1-3): ').strip()
if choice == '1':
print('🚀 Running Example 1: Basic page scrolling...')
await agent1.run()
elif choice == '2':
print('🚀 Running Example 2: Element-specific scrolling...')
await agent2.run()
elif choice == '3':
print('🚀 Running Example 3: Text-based scrolling...')
await agent3.run()
else:
print('❌ Invalid choice. Running Example 1 by default...')
await agent1.run()
if __name__ == '__main__':
asyncio.run(main())
+83
View File
@@ -0,0 +1,83 @@
"""
Azure OpenAI example with data privacy and high-scale configuration.
Environment Variables Required:
- AZURE_OPENAI_KEY (or AZURE_OPENAI_API_KEY)
- AZURE_OPENAI_ENDPOINT
- AZURE_OPENAI_DEPLOYMENT (optional)
DATA PRIVACY WITH AZURE OPENAI:
✅ Good News: No Training on Your Data by Default
Azure OpenAI Service already protects your data:
✅ NOT used to train OpenAI models
✅ NOT shared with other customers
✅ NOT accessible to OpenAI directly
✅ NOT used to improve Microsoft/third-party products
✅ Hosted entirely within Azure (not OpenAI's servers)
⚠️ Default Data Retention (30 Days)
- Prompts and completions stored for up to 30 days
- Purpose: Abuse monitoring and compliance
- Access: Microsoft authorized personnel (only if abuse detected)
🔒 How to Disable Data Logging Completely
Apply for Microsoft's "Limited Access Program":
1. Contact Microsoft Azure support
2. Submit Limited Access Program request
3. Demonstrate legitimate business need
4. After approval: Zero data logging, immediate deletion, no human review
For high-scale deployments (500+ agents), consider:
- Multiple deployments across regions
How to Verify This Yourself, that there is no data logging:
- Network monitoring: Run with network monitoring tools
- Firewall rules: Block all domains except Azure OpenAI and your target sites
Contact us if you need help with this: support@browser-use.com
"""
import asyncio
import os
import sys
from dotenv import load_dotenv
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
load_dotenv()
os.environ['ANONYMIZED_TELEMETRY'] = 'false'
from browser_use import Agent, BrowserProfile, ChatAzureOpenAI
# Configuration LLM
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)
# Configuration Task
task = 'Find the founders of the sensitive company_name'
# Configuration Browser (optional)
browser_profile = BrowserProfile(allowed_domains=['*google.com', 'browser-use.com'], enable_default_extensions=False)
# Sensitive data (optional) - {key: sensitive_information} - we filter out the sensitive_information from any input to the LLM, it will only work with placeholder.
# By default we pass screenshots to the LLM which can contain your information. Set use_vision=False to disable this.
# If you trust your LLM endpoint, you don't need to worry about this.
sensitive_data = {'company_name': 'browser-use'}
# Create Agent
agent = Agent(task=task, llm=llm, browser_profile=browser_profile, sensitive_data=sensitive_data) # type: ignore
async def main():
await agent.run(max_steps=10)
asyncio.run(main())
+47
View File
@@ -0,0 +1,47 @@
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
# Initialize the model
llm = ChatOpenAI(
model='gpt-4.1',
temperature=0.0,
)
# Simple case: the model will see x_name and x_password, but never the actual values.
# sensitive_data = {'x_name': 'my_x_name', 'x_password': 'my_x_password'}
# Advanced case: domain-specific credentials with reusable data
# Define a single credential set that can be reused
company_credentials: dict[str, str] = {'telephone': '9123456789', 'email': 'user@example.com', 'name': 'John Doe'}
# Map the same credentials to multiple domains for secure access control
# Type annotation to satisfy pyright
sensitive_data: dict[str, str | dict[str, str]] = {
# 'https://example.com': company_credentials,
# 'https://admin.example.com': company_credentials,
# 'https://*.example-staging.com': company_credentials,
# 'http*://test.example.com': company_credentials,
'httpbin.org': company_credentials,
# # You can also add domain-specific credentials
# 'https://google.com': {'g_email': 'user@gmail.com', 'g_pass': 'google_password'}
}
# Update task to use one of the credentials above
task = 'Go to https://httpbin.org/forms/post and put the secure information in the relevant fields.'
agent = Agent(task=task, llm=llm, sensitive_data=sensitive_data)
async def main():
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
@@ -0,0 +1,27 @@
import asyncio
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent, ChatOpenAI
# This uses a bigger model for the planning
# And a smaller model for the page content extraction
# THink of it like a subagent which only task is to extract content from the current page
llm = ChatOpenAI(model='gpt-4.1')
small_llm = ChatOpenAI(model='gpt-4.1-mini')
task = 'Find the founders of browser-use in ycombinator, extract all links and open the links one by one'
agent = Agent(task=task, llm=llm, page_extraction_llm=small_llm)
async def main():
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
+43
View File
@@ -0,0 +1,43 @@
import asyncio
import os
import random
import sys
from browser_use.llm.google.chat import ChatGoogle
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from dotenv import load_dotenv
load_dotenv()
from browser_use import Agent
llm = ChatGoogle(model='gemini-3-flash-preview', temperature=1.0)
def check_is_task_stopped():
async def _internal_check_is_task_stopped() -> bool:
if random.random() < 0.1:
print('[TASK STOPPER] Task is stopped')
return True
else:
print('[TASK STOPPER] Task is not stopped')
return False
return _internal_check_is_task_stopped
task = """
Go to https://browser-use.github.io/stress-tests/challenges/wufoo-style-form.html and complete the Wufoo-style form by filling in all required fields and submitting.
"""
agent = Agent(task=task, llm=llm, flash_mode=True, register_should_stop_callback=check_is_task_stopped(), max_actions_per_step=1)
async def main():
await agent.run(max_steps=30)
if __name__ == '__main__':
asyncio.run(main())
+25
View File
@@ -0,0 +1,25 @@
import asyncio
from pathlib import Path
from browser_use import Agent, Browser, ChatOpenAI
# NOTE: To use this example, install imageio[ffmpeg], e.g. with uv pip install "browser-use[video]"
async def main():
browser_session = Browser(record_video_dir=Path('./tmp/recordings'))
agent = Agent(
task='Go to github.com/trending then navigate to the first trending repository and report how many commits it has.',
llm=ChatOpenAI(model='gpt-4.1-mini'),
browser_session=browser_session,
)
await agent.run(max_steps=5)
# The video will be saved automatically when the agent finishes and the session closes.
print('Agent run finished. Check the ./tmp/recordings directory for the video.')
if __name__ == '__main__':
asyncio.run(main())