> ## Documentation Index
> Fetch the complete documentation index at: https://docs.altrina.com/llms.txt
> Use this file to discover all available pages before exploring further.

# BrowserAgent

> Simple one-line interface for browser automation

## Overview

The `BrowserAgent` class provides the simplest way to automate browsers with the Altrina API. It's designed for quick scripts and straightforward automation tasks.

```python theme={null}
from altrina_sdk import BrowserAgent

agent = BrowserAgent("YOUR_API_KEY")
result = agent.run("Go to example.com and extract the title")
```

## Constructor

```python theme={null}
BrowserAgent(
    api_key: str = None,
    residential_ip: bool = False,
    viewport_width: int = 1920,
    viewport_height: int = 1080,
    max_duration_minutes: int = 30,
    model: str = "claude-sonnet-4-20250514",
    persist_session: bool = False,
    verbose: bool = False
)
```

### Parameters

<ParamField path="api_key" type="string" default="None">
  Your Altrina API key. If not provided, uses the `ALTRINA_API_KEY` environment variable.
</ParamField>

<ParamField path="residential_ip" type="boolean" default="False">
  Whether to use residential IP proxy for geo-restricted content.
</ParamField>

<ParamField path="viewport_width" type="integer" default="1920">
  Browser viewport width in pixels (320-4096).
</ParamField>

<ParamField path="viewport_height" type="integer" default="1080">
  Browser viewport height in pixels (320-4096).
</ParamField>

<ParamField path="max_duration_minutes" type="integer" default="30">
  Maximum duration for the browser session in minutes (1-240).
</ParamField>

<ParamField path="model" type="string" default="claude-sonnet-4-20250514">
  AI model for action selection. Options:

  * `"claude-sonnet-4-20250514"` - Claude Sonnet (default, best overall)
  * `"gpt-4o"` - GPT-4
  * `"gemini/gemini-2.5-flash"` - Gemini Flash (fastest)
</ParamField>

<ParamField path="persist_session" type="boolean" default="False">
  Persist browser profile (cookies, localStorage, etc.) across sessions. When `False` (default), each method call starts with a fresh browser profile. When `True`, the browser profile is tied to your account and persists across calls, maintaining logged-in state and other browser data. Useful for tasks that require staying logged in.
</ParamField>

<ParamField path="verbose" type="boolean" default="False">
  Whether to print progress updates during execution.
</ParamField>

### Example

```python theme={null}
# Simple usage with defaults
agent = BrowserAgent("YOUR_API_KEY")

# Custom configuration
agent = BrowserAgent(
    api_key="YOUR_API_KEY",
    residential_ip=True,
    viewport_width=1366,
    viewport_height=768,
    max_duration_minutes=10,
    model="gpt-4o",
    persist_session=False,  # Fresh profile each time (default)
    verbose=True
)

# For tasks requiring persistent login
auth_agent = BrowserAgent(
    api_key="YOUR_API_KEY",
    persist_session=True  # Maintains cookies/login across calls
)
```

## Methods

### run()

Execute a browser automation task with natural language instructions.

```python theme={null}
def run(
    directive: str,
    initial_url: str = None,
    timeout: float = None
) -> JobResult
```

#### Parameters

<ParamField path="directive" type="string" required>
  Natural language instruction describing what the browser should do.
</ParamField>

<ParamField path="initial_url" type="string" default="None">
  Starting URL for the browser session. If not provided, the agent will navigate based on the directive.
</ParamField>

<ParamField path="timeout" type="float" default="None">
  Maximum time to wait for completion in seconds. If None, waits indefinitely.
</ParamField>

#### Returns

Returns a `JobResult` object with:

* `output`: The extracted data or result
* `status`: Job status (completed/failed)
* `credits_used`: Number of credits consumed
* `error`: Error message if failed
* `is_successful`: Boolean indicating success

#### Example

```python theme={null}
# Simple extraction
result = agent.run("Go to news.ycombinator.com and get the top story title")
print(result.output)

# With initial URL
result = agent.run(
    "Extract all product prices",
    initial_url="https://shop.example.com/products"
)

# With timeout
result = agent.run(
    "Complete the checkout process",
    timeout=120  # 2 minutes
)

# Check success
if result.is_successful:
    print(f"Success: {result.output}")
else:
    print(f"Failed: {result.error}")
```

### extract()

Extract specific data from a webpage.

```python theme={null}
def extract(
    url: str,
    data_description: str,
    timeout: float = None
) -> JobResult
```

#### Parameters

<ParamField path="url" type="string" required>
  The URL to extract data from.
</ParamField>

<ParamField path="data_description" type="string" required>
  Description of what data to extract.
</ParamField>

<ParamField path="timeout" type="float" default="None">
  Maximum time to wait for completion in seconds.
</ParamField>

#### Example

```python theme={null}
# Extract structured data
result = agent.extract(
    url="https://github.com/trending",
    data_description="repository names, stars, and programming languages"
)

# Access the extracted data
for repo in result.output:
    print(f"{repo['name']}: {repo['stars']} stars ({repo['language']})")
```

### search\_and\_extract()

Search for a query and extract data from the results.

```python theme={null}
def search_and_extract(
    query: str,
    num_results: int = 10,
    data_description: str = None,
    timeout: float = None
) -> JobResult
```

#### Parameters

<ParamField path="query" type="string" required>
  The search query.
</ParamField>

<ParamField path="num_results" type="integer" default="10">
  Number of search results to extract.
</ParamField>

<ParamField path="data_description" type="string" default="None">
  Specific data to extract from results. If None, extracts title, URL, and description.
</ParamField>

<ParamField path="timeout" type="float" default="None">
  Maximum time to wait for completion in seconds.
</ParamField>

#### Example

```python theme={null}
# Search and extract with defaults
result = agent.search_and_extract("Python tutorials", num_results=5)

# Extract specific data from search results
result = agent.search_and_extract(
    query="best laptops 2024",
    num_results=10,
    data_description="product name, price, ratings, and key features"
)

for item in result.output:
    print(f"{item['name']}: ${item['price']} - {item['rating']} stars")
```

### fill\_form()

Fill and submit a form on a webpage.

```python theme={null}
def fill_form(
    url: str,
    form_data: dict,
    submit: bool = True,
    timeout: float = None
) -> JobResult
```

#### Parameters

<ParamField path="url" type="string" required>
  The URL of the page containing the form.
</ParamField>

<ParamField path="form_data" type="dict" required>
  Dictionary of form field names/IDs and their values.
</ParamField>

<ParamField path="submit" type="boolean" default="True">
  Whether to submit the form after filling.
</ParamField>

<ParamField path="timeout" type="float" default="None">
  Maximum time to wait for completion in seconds.
</ParamField>

#### Example

```python theme={null}
# Fill a contact form
result = agent.fill_form(
    url="https://example.com/contact",
    form_data={
        "name": "John Doe",
        "email": "john@example.com",
        "subject": "Product Inquiry",
        "message": "I'm interested in learning more about your products."
    }
)

# Fill without submitting
result = agent.fill_form(
    url="https://example.com/signup",
    form_data={
        "username": "testuser",
        "password": "secure_password"
    },
    submit=False  # Just fill, don't submit
)
```

### click()

Click on an element on a webpage.

```python theme={null}
def click(
    url: str,
    element_description: str,
    timeout: float = None
) -> JobResult
```

#### Parameters

<ParamField path="url" type="string" required>
  The URL of the page.
</ParamField>

<ParamField path="element_description" type="string" required>
  Natural language description of what to click.
</ParamField>

<ParamField path="timeout" type="float" default="None">
  Maximum time to wait for completion in seconds.
</ParamField>

#### Example

```python theme={null}
# Click a button
result = agent.click(
    url="https://example.com",
    element_description="the 'Sign Up' button in the header"
)

# Click a link
result = agent.click(
    url="https://example.com/products",
    element_description="the 'View Details' link for the first product"
)
```

### screenshot()

Take a screenshot of a webpage.

```python theme={null}
def screenshot(
    url: str,
    full_page: bool = False,
    timeout: float = None
) -> JobResult
```

#### Parameters

<ParamField path="url" type="string" required>
  The URL to screenshot.
</ParamField>

<ParamField path="full_page" type="boolean" default="False">
  Whether to capture the full page or just the viewport.
</ParamField>

<ParamField path="timeout" type="float" default="None">
  Maximum time to wait for completion in seconds.
</ParamField>

#### Example

```python theme={null}
# Screenshot visible viewport
result = agent.screenshot("https://example.com")

# Full page screenshot
result = agent.screenshot(
    url="https://example.com/long-article",
    full_page=True
)

# The screenshot URL is in the output
screenshot_url = result.output["screenshot_url"]
print(f"Screenshot saved at: {screenshot_url}")
```

## Complete Examples

### E-commerce Price Monitoring

```python theme={null}
from altrina_sdk import BrowserAgent
from datetime import datetime

agent = BrowserAgent("YOUR_API_KEY", residential_ip=True)

# Monitor product prices
products = [
    "https://amazon.com/dp/B08N5WRWNW",  # Echo Dot
    "https://amazon.com/dp/B07FZ8S74R",  # Kindle
]

price_data = []
for product_url in products:
    result = agent.extract(
        url=product_url,
        data_description="product name, current price, and availability"
    )
    
    if result.is_successful:
        price_data.append({
            "url": product_url,
            "data": result.output,
            "timestamp": datetime.now().isoformat()
        })

# Save price history
import json
with open("price_history.json", "w") as f:
    json.dump(price_data, f, indent=2)
```

### News Aggregation

```python theme={null}
from altrina_sdk import BrowserAgent

agent = BrowserAgent("YOUR_API_KEY", verbose=True)

# Aggregate news from multiple sources
news_sites = {
    "TechCrunch": "https://techcrunch.com",
    "The Verge": "https://www.theverge.com",
    "Ars Technica": "https://arstechnica.com"
}

all_headlines = []
for site_name, site_url in news_sites.items():
    result = agent.extract(
        url=site_url,
        data_description="the top 5 article headlines and their URLs"
    )
    
    if result.is_successful:
        for article in result.output:
            all_headlines.append({
                "source": site_name,
                **article
            })

# Display aggregated news
for headline in all_headlines[:10]:  # Top 10
    print(f"[{headline['source']}] {headline['title']}")
    print(f"  → {headline['url']}\n")
```

### Form Automation

```python theme={null}
from altrina_sdk import BrowserAgent
import csv

agent = BrowserAgent("YOUR_API_KEY")

# Read data from CSV
with open("contacts.csv", "r") as f:
    contacts = list(csv.DictReader(f))

# Submit multiple forms
for contact in contacts:
    result = agent.fill_form(
        url="https://example.com/newsletter-signup",
        form_data={
            "email": contact["email"],
            "first_name": contact["first_name"],
            "last_name": contact["last_name"],
            "company": contact.get("company", ""),
            "subscribe_newsletter": True
        }
    )
    
    if result.is_successful:
        print(f"✅ Signed up: {contact['email']}")
    else:
        print(f"❌ Failed for {contact['email']}: {result.error}")
```

## Error Handling

Always implement proper error handling:

```python theme={null}
from altrina_sdk import BrowserAgent
from altrina.exceptions import (
    AuthenticationError,
    RateLimitError,
    TimeoutError,
    ValidationError
)

agent = BrowserAgent("YOUR_API_KEY")

try:
    result = agent.run("Your task here", timeout=60)
    
    if result.is_successful:
        print(f"Success: {result.output}")
    else:
        print(f"Task failed: {result.error}")
        
except AuthenticationError:
    print("Invalid API key. Check your credentials.")
    
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds.")
    
except TimeoutError as e:
    print(f"Task timed out after {e.timeout_seconds} seconds.")
    
except ValidationError as e:
    print(f"Invalid parameters: {e.errors}")
    
except Exception as e:
    print(f"Unexpected error: {e}")
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use Specific Instructions">
    ```python theme={null}
    # ❌ Vague
    agent.run("Get data")

    # ✅ Specific
    agent.run("""
        Go to example.com/products and extract:
        - Product names
        - Prices (with currency)
        - Availability status
        - Product URLs
        Format as JSON list
    """)
    ```
  </Accordion>

  <Accordion title="Set Appropriate Timeouts">
    ```python theme={null}
    # Quick tasks
    result = agent.extract(url, "title", timeout=30)

    # Complex workflows
    result = agent.run("Multi-step checkout", timeout=300)

    # No timeout for very long tasks
    result = agent.run("Scrape entire catalog")
    ```
  </Accordion>

  <Accordion title="Use Residential IPs When Needed">
    ```python theme={null}
    # For geo-restricted or anti-bot sites
    agent = BrowserAgent(
        api_key="YOUR_API_KEY",
        residential_ip=True  # Use residential proxy
    )
    ```
  </Accordion>

  <Accordion title="Persist Sessions for Authenticated Tasks">
    ```python theme={null}
    # ❌ Don't use persist_session for one-off scraping
    agent = BrowserAgent(persist_session=False)  # Default
    result = agent.extract("https://public-site.com", "data")

    # ✅ Use persist_session for multi-step authenticated workflows
    auth_agent = BrowserAgent(persist_session=True)

    # First call: logs in and saves cookies
    auth_agent.run("Go to myapp.com and log in with credentials")

    # Subsequent calls: already logged in
    auth_agent.run("Navigate to dashboard and extract data")
    auth_agent.run("Go to settings and update preferences")
    ```
  </Accordion>

  <Accordion title="Monitor Credit Usage">
    ```python theme={null}
    total_credits = 0

    for task in tasks:
        result = agent.run(task)
        total_credits += result.credits_used
        print(f"Task credits: {result.credits_used}")

    print(f"Total credits used: {total_credits}")
    ```
  </Accordion>
</AccordionGroup>

## See Also

* [AltrinaClient](/sdk/sync-client) - Full-featured client with job management
* [AsyncAltrinaClient](/sdk/async-client) - For concurrent operations
* [Error Handling](/sdk/error-handling) - Comprehensive error handling guide
* [Advanced Examples](/sdk/advanced-examples) - Complex real-world scenarios
