Metadata-Version: 2.4
Name: bro-api-sdk
Version: 0.1.0
Summary: The browser layer for AI agents, workflows, and data pipelines.
License: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests
Requires-Dist: pydantic>=2.0.0
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: responses; extra == "test"
Dynamic: license-file

# bro-sdk

🔮 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 `bro` autonomously navigate and extract structured data on the fly.
  - **Manual:** 🕹️ Get full, deterministic control of the browser via agent-friendly commands.
- **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+):

```bash
pip install bro-sdk
```

## Getting a Token (Sign Up)

To use the `bro-sdk`, you need an API key. You can get one by signing up:

- **Sign up manually via UI:** Visit [https://getbro.ws/auth](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](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.

```python
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.

```python
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.

```python
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:

👉 **[Full SDK Docs](https://getbro.ws/sdk_full.md)**
