bro
🔮 We've abstracted away the chaos of the web so you can focus on building.
bro is a stealth agentic browser built to handle everything from everyday pages to the most complex and well-protected websites. It lets you and your agents reliably navigate the web and extract data at scale without getting blocked.
Instead of juggling low-level CDP commands, managing infrastructure and handling proxies, you control a fully headed, actual rendered Chrome browser through a simple, agents-friendly Python library. Every session runs on an isolated VM instance - you don't share compute resources or IPs.
Features
- Zero-headache API: 🧘♂️ Whether you're navigating, extracting data or parsing DOM, every command has complex underlying logic built-in - it keeps the agent in a single tab, handles dynamic page loads, automatically retries failures, handles downloads, manages timeouts and CDP syncs.
- Two powerful modes:
- Autopilot: 🤖 Let
broautonomously navigate and extract structured data on the fly. - Manual: 🕹️ Get full, deterministic control of the browser via agent-friendly commands.
- Autopilot: 🤖 Let
- Stealth features: 🥷 Clean browser fingerprints, human-like interaction, customizable network routing, and proxy tracking.
- Flexible & cost-effective: 📉 Cut costs by customizing proxy and AI configurations based on your specific task.
Installation
Install the package via pip (requires Python 3.8+):
pip install bro-api-sdk
Getting a Token (Sign Up)
To use the bro-api-sdk, you need an API key. You can get one by signing up:
- Sign up manually via UI: Visit https://getbro.ws/auth to sign up and get your API token.
- Sign Up with Agent: If you want your AI agent to sign up on your behalf, just give it this prompt: https://getbro.ws/signup_prompt.md
Quick Start Examples
Below are a couple of examples showcasing how easy it is to use bro to handle the browser. Both use a straightforward session context manager that handles all lifecycle and cleanup automatically.
1. Parsing Text and URLs
Extracting clean text and URLs directly from the rendered page layout.
from bro import BroClient, commands
# Initialize the client
client = BroClient(api_key="your_api_key_here")
# Use a context manager to ensure the session is properly stopped
with client.create_session() as session:
print(f"Session started: {session.session_id}")
# Execute commands sequentially in a batch
result = session.execute([
commands.open_url(url="https://news.ycombinator.com/"),
commands.parse_text(),
commands.parse_urls()
])
if result.get("status") == "done":
# parse_text returns a raw string natively
print("--- Text ---")
print(result["response"]["commands"][1]["data"])
# parse_urls returns a dictionary containing 'links' and 'images' arrays
print("--- URLs ---")
print(result["response"]["commands"][2]["data"])
print(f"\n--- Session Usage Stats ---")
if session.billing:
print(f"Total billed: ${session.billing.get('total_billed', 0):.4f}")
2. Extracting data using Autopilot extract command
If you already have a target URL, you can extract structured data directly, including automatically clicking "Next" to traverse multiple pages. The AI will analyze the DOM and visual data on the page to extract JSON for you based on your schema.
import json
from bro import BroClient, commands
client = BroClient(api_key="your_api_key_here")
with client.create_session() as session:
print(f"Session started: {session.session_id}")
result = session.execute([
commands.open_url(url="https://news.ycombinator.com/"),
commands.extract(
data_instruction="Extract a list of top publications on this page",
json_schema=[{
"title": "<post title>",
"link": "<post URL>",
"points": "<number of points>"
}],
model_size="medium",
paginate=True, # Let AI find the 'Next' button and merge data
pages_to_paginate=2 # Max pages to navigate through
)
])
if result.get("status") == "done":
for cmd in result.get("response", {}).get("commands", []):
if cmd.get("command") == "extract":
print(f"\nExtracted Data:\n{json.dumps(cmd.get('data'), indent=2)}")
print(f"\n--- Session Usage Stats ---")
if session.billing:
print(f"Total billed: ${session.billing.get('total_billed', 0):.4f}")
if session.tokens:
print(f"LLM Tokens: {session.tokens.get('total', 0)}")
3. AI Actions & Data Extraction
You can combine commands to navigate complex flows before extracting data. This example uses Autopilot to type into a search box, press enter, and extract the top results.
import json
from bro import BroClient, commands
client = BroClient(api_key="your_api_key_here")
with client.create_session(
enable_proxy=True,
proxy_tier="basic",
proxy_policy="extended",
country="US"
) as session:
session_id = session.session_id
print(f"Session started: {session.session_id}, stream: {session.stream_url}")
print("\nExecuting commands")
batch_result = session.execute([
commands.open_url(url="https://news.ycombinator.com"),
commands.act(
instruction="type 'llm' in the search box",
max_steps=2,
model_size='medium'
),
commands.press(keys='enter'),
commands.extract(
data_instruction="Extract the top 5 news titles and their links.",
json_schema=[{
"title": "<title of the publication>",
"url": "<direct URL to the publication>",
"summary": "<summary of the publication, less than 10 words>",
"company_mentioned": "<company name mentioned in the publication, set a primary company if multiple have been mentioned>",
}],
model_size="small"
)
])
if batch_result["status"] == "done":
commands_executed = batch_result.get("response", {}).get("commands", [])
for i, cmd in enumerate(commands_executed):
cmd_name = cmd.get("command", "unknown")
data = cmd.get("data", {})
if cmd_name == "extract":
output = data.get("extracted_json")
elif cmd_name == "act":
output = data.get("action_steps")
else:
output = data
print(f"\n--- [{i}] {cmd_name.upper()} ---")
print(json.dumps(output, indent=2))
if session_id:
print("\n--- Final Session Stats ---")
final_stats = client.get_session(session_id).metadata
print(json.dumps(final_stats, indent=2))
Full Documentation
For the comprehensive SDK documentation, including all available commands, API references, advanced configurations, and integrations, please visit:
Release files for bro-api-sdk 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bro_api_sdk-0.1.1.tar.gz | 23.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bro_api_sdk-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.0 kB
Release files / bro_api_sdk-0.1.1.tar.gz
| Download URL | bro_api_sdk-0.1.1.tar.gz |
|---|---|
| Size | 23.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7c057d322e2d4553e2c14b7942456b7f859deb3cd19b319667e0979cb6318b3
|
|
BLAKE2b-256 checksum How to use checksums |
ba1208aed5f953c7d093a57a9e40556fba2e3ab477690b9c51310eae2b574204
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / bro_api_sdk-0.1.1-py3-none-any.whl
| Download URL | bro_api_sdk-0.1.1-py3-none-any.whl |
|---|---|
| Size | 22.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d6acc3e461aef59d83b307261277df9b36ede17ff1df4977be00c40eaf0ac488
|
|
BLAKE2b-256 checksum How to use checksums |
39fd8fd24d9d70140ba7bdfbcf2bd142e678a225c39de1619faf18383e9e59f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|