Top SitesHerd - Browser Superpowers & MCP Servers for AI Agents

Machine Readiness

Stored receipt and evidence

Overall

30

Readable

100

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

robots, llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Open robots.txt
User-agent: *
Allow: /

Sitemap: https://herd.garden/sitemap.xml

Document

llms.txt

Open llms.txt
Herd Documentation
==


Herd is a powerful platform and SDK for automating your own browser, ten or millions of them. Similar to Puppeteer but with support for multiple devices and real-time events, and no infrastructure to setup.


Document: Automation Basics
URL: https://herd.garden/docs/automation-basics

# Automation Basics

Welcome to Monitoro Herd! This guide will walk you through creating your first browser automation step-by-step. We'll start with the basics and gradually build up to more complex examples, explaining each concept along the way.

## javascript

## JavaScript SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your JavaScript environment and install the Herd SDK:

1. Make sure you have Node.js installed (version 14 or higher recommended)
2. Create a new project directory
3. Install the SDK using npm:

Code (bash):
npm install @monitoro/herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (javascript):
// Import the Herd client
import { HerdClient } from '@monitoro/herd';

// Initialize the client with your API URL and token
const client = new HerdClient('your-token');

// Always initialize the client before using it
await client.initialize();
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

After initializing the client, you need to connect to a device (browser) that will perform the automation:

Code (javascript):
// Get a list of available devices
const devices = await client.listDevices();

// Connect to the first available device
const device = devices[0];

console.log(`Connected to device: ${device.id}`);

This code retrieves all devices registered to your account and connects to the first one. In a production environment, you might want to select a specific device based on its properties or availability.

### Creating a Page and Navigating

Now that you're connected to a device, you can create a new browser page and navigate to a website:

Code (javascript):
// Create a new page in the browser
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com');

console.log('Successfully navigated to example.com');

The `goto` method loads the specified URL and waits for the page to load. By default, it waits until the page's `load` event is fired, but you can customize this behavior with options.

### Extracting Basic Information

One of the most common automation tasks is extracting information from web pages. Here's how to extract basic elements:

Code (javascript):
// Extract content using CSS selectors
const content = await page.extract({
  title: 'h1',           // Extracts the main heading
  description: 'p',      // Extracts the first paragraph
  link: 'a'              // Extracts the first link text
});

// Display the extracted content
console.log('Extracted content:');
console.log(`Title: ${content.title}`);
console.log(`Description: ${content.description}`);
console.log(`Link: ${content.link}`);

The `extract` method uses CSS selectors to find elements on the page and extract their text content. This is a powerful way to scrape structured data from websites.

### Proper Resource Management

Always remember to close resources when you're done with them to prevent memory leaks:

Code (javascript):
// Close the page when done
await page.close();

// Close the client connection
await client.close();

### Putting It All Together

Here's a complete example that combines all the steps above into a single function:

Code (javascript):
import { HerdClient } from '@monitoro/herd';

async function runBasicAutomation() {
  const client = new HerdClient('your-token');
  
  try {
    // Initialize the client
    await client.initialize();
    console.log('Client initialized successfully');
    
    // Get the first available device
    const devices = await client.listDevices();
    if (devices.length === 0) {
      throw new Error('No devices available');
    }
    const device = devices[0];
    console.log(`Connected to device: ${device.id}`);
    
    // Create a new page
    const page = await device.newPage();
    console.log('New page created');
    
    // Navigate to a website
    console.log('Navigating to example.com...');
    await page.goto('https://example.com');
    console.log('Navigation complete');
    
    // Extract content
    console.log('Extracting content...');
    const content = await page.extract({
      title: 'h1',
      description: 'p',
      link: 'a'
    });
    
    // Display the extracted content
    console.log('\nExtracted content:');
    console.log(`Title: ${content.title}`);
    console.log(`Description: ${content.description}`);
    console.log(`Link: ${content.link}`);
    
  } catch (error) {
    console.error('Error during automation:', error);
  } finally {
    // Always close the client when done
    console.log('Closing client connection...');
    await client.close();
    console.log('Client connection closed');
  }
}

// Run the automation
runBasicAutomation();

### Interacting with Web Pages

Now let's explore how to interact with elements on a page. This includes clicking buttons, typing text, and handling forms.

#### Finding Elements

Before interacting with an element, you need to find it on the page:

Code (javascript):
// Find an element using a CSS selector
const searchBox = await page.$('input[name="q"]');

// Check if the element was found
if (searchBox) {
  console.log('Search box found');
} else {
  console.log('Search box not found');
}

The `


  
  
  
  
  herd.garden | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   method returns the first element that matches the CSS selector, or `null` if no element is found.

#### Typing Text

To type text into an input field:

Code (javascript):
// Type text into an input field
await page.type('input[name="q"]', 'Monitoro Herd automation');
console.log('Text entered into search box');

The `type` method finds the element using the CSS selector and simulates typing the specified text.

#### Clicking Elements

To click a button or link:

Code (javascript):
// Click a button
await page.click('input[type="submit"]');
console.log('Search button clicked');

By default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:

Code (javascript):
// Click and wait for navigation
await page.click('input[type="submit"]', { 
  waitForNavigation: 'networkidle2' 
});
console.log('Search button clicked and navigation completed');

The `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.

#### Waiting for Elements

Sometimes you need to wait for elements to appear on the page:

Code (javascript):
// Wait for an element to appear
await page.waitForSelector('#search');
console.log('Search results have loaded');

This is useful when dealing with dynamic content that loads after the initial page load.

#### Search Engine Example

Let's put these concepts together in a search engine example:

Code (javascript):
async function searchExample() {
  const client = new HerdClient('your-token');
  
  try {
    await client.initialize();
    const devices = await client.listDevices();
    const device = devices[0];
    const page = await device.newPage();
    
    // Navigate to a search engine
    console.log('Navigating to Google...');
    await page.goto('https://www.google.com');
    
    // Type in the search box
    console.log('Entering search query...');
    await page.type('input[name="q"]', 'Monitoro Herd automation');
    
    // Submit the search form and wait for results
    console.log('Submitting search...');
    await page.click('input[type="submit"]', { 
      waitForNavigation: 'networkidle2' 
    });
    
    // Wait for results to load completely
    console.log('Waiting for search results...');
    await page.waitForSelector('#search');
    
    // Extract search result titles
    console.log('Extracting search results...');
    const searchResults = await page.extract({
      titles: {
        _$r: '#search .g h3',  // _$r extracts multiple elements
        text: ':root'           // For each match, get its text
      }
    });
    
    // Display the search result titles
    console.log('\nSearch Results:');
    searchResults.titles.forEach((result, index) => {
      console.log(`${index + 1}. ${result.text}`);
    });
    
  } catch (error) {
    console.error('Error:', error);
  } finally {
    await client.close();
  }
}

## python

## Python SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your Python environment and install the Herd SDK:

1. Make sure you have Python 3.8+ installed
2. Create a virtual environment (recommended)
3. Install the SDK using pip:

Code (bash):
pip install monitoro-herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (python):
# Import the Herd client
from monitoro_herd import HerdClient

# Initialize the client with your API URL and token
client = HerdClient('your-token')

# Always initialize the client before using it
client.initialize()
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

Next, connect to a device that will run your automation:

Code (python):
# Get available devices
devices = await client.list_devices()

# Connect to the first device
device = devices[0]

print(f"Connected to device: {device.id}")

### Creating a Page and Navigating

Now create a browser page and navigate to a website:

Code (python):
# Create a new page
page = await device.new_page()

# Navigate to a website
await page.goto("https://example.com")

print("Successfully navigated to example.com")

### Extracting Basic Information

Extract information from the page using CSS selectors:

Code (python):
# Extract basic information
data = await page.extract({
    "title": "h1",          # Main heading
    "description": "p",     # First paragraph
    "link": "a"             # First link text
})

# Display the extracted data
print("Extracted data:")
print(f"Title: {data['title']}")
print(f"Description: {data['description']}")
print(f"Link: {data['link']}")

### Resource Management

Always close resources when you're done:

Code (python):
# Close the page
await page.close()

# Close the client
await client.close()

### Complete Basic Example

Here's a complete example putting all these concepts together:

Code (python):
import asyncio
from monitoro_herd import HerdClient

async def basic_extraction():
    # Initialize the client
    client = HerdClient("your-token")
    
    try:
        # Initialize the connection
        await client.initialize()
        print("Client initialized successfully")
        
        # Get the first available device
        devices = await client.list_devices()
        if not devices:
            raise Exception("No devices available")
        device = devices[0]
        print(f"Connected to device: {device.id}")
        
        # Create a new page
        page = await device.new_page()
        print("New page created")
        
        # Navigate to a website
        print("Navigating to example.com...")
        await page.goto("https://example.com")
        print("Navigation complete")
        
        # Extract data using simple selectors
        print("Extracting content...")
        data = await page.extract({
            "title": "h1",
            "description": "p",
            "link": "a"
        })
        
        # Display the extracted data
        print("\nExtracted data:")
        print(f"Title: {data['title']}")
        print(f"Description: {data['description']}")
        print(f"Link: {data['link']}")
        
    except Exception as e:
        print(f"Error during automation: {e}")
    finally:
        # Always close resources
        print("Closing client connection...")
        await client.close()
        print("Client connection closed")

# Run the async function
asyncio.run(basic_extraction())

### Working with Lists and Structured Data

One of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.

#### The `_$r` Selector

To extract multiple elements that match a pattern, use the `_$r` (repeat) selector:

Code (python):
# Extract a list of items
data = await page.extract({
    "items": {
        "_$r": ".item",       # Find all elements with class "item"
        "name": ".item-name", # For each item, get the name
        "price": ".price"     # For each item, get the price
    }
})

# Access the extracted items
for item in data["items"]:
    print(f"Name: {item['name']}, Price: {item['price']}")

The `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.

#### Extracting Attributes

Sometimes you need to extract an attribute rather than the text content:

Code (python):
# Extract links and their href attributes
data = await page.extract({
    "links": {
        "_$r": "a",              # Find all links
        "text": ":root",         # Get the link text
        "url": {
            "_
quot;: ":root", # Reference the same element "attribute": "href" # Get its href attribute } } }) # Display the links for link in data["links"]: print(f"Link: {link['text']} -> {link['url']}") #### Hacker News Example Let's put these concepts together to scrape stories from Hacker News: Code (python): import asyncio from monitoro_herd import HerdClient async def scrape_hacker_news(): client = HerdClient("your-token") try: await client.initialize() devices = await client.list_devices() device = devices[0] page = await device.new_page() # Navigate to Hacker News print("Navigating to Hacker News...") await page.goto("https://news.ycombinator.com") # Extract stories and their metadata print("Extracting stories...") data = await page.extract({ # Extract the story elements "stories": { "_$r": ".athing", # Each story row "title": ".titleline > a", # Story title "site": ".sitestr", # Source website "link": { "_
quot;: ".titleline > a", # Story link "attribute": "href" # Get the URL } }, # Extract the metadata (points, author, etc.) "metadata": { "_$r": ".subline", # Metadata rows "points": ".score", # Points count "author": ".hnuser", # Author username "time": ".age" # Submission time } }) # Combine stories with their metadata # (They're in separate lists but in the same order) combined_stories = list(zip(data["stories"], data["metadata"])) # Display the first 3 stories print(f"\nExtracted {len(combined_stories)} stories:") for i, (story, meta) in enumerate(combined_stories[:3]): print(f"\nStory {i+1}:") print(f"Title: {story['title']}") if "site" in story: print(f"Site: {story['site']}") print(f"Link: {story['link']}") if "points" in meta: print(f"Points: {meta['points']}") if "author" in meta: print(f"Author: {meta['author']}") if "time" in meta: print(f"Posted: {meta['time']}") finally: await page.close() await client.close() # Run the function asyncio.run(scrape_hacker_news()) ## Tips for Successful Automation 1. **Start Simple**: Begin with basic extractions before moving to complex interactions 2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely 3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks 4. **Close Resources**: Always close pages and clients when done to avoid resource leaks 5. **Test Incrementally**: Build your automation step by step, testing each part 6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods 7. **Debug with Screenshots**: Take screenshots during automation to see what's happening ## Next Steps Now that you've created your first automation, you can: - Explore more complex selectors and extraction patterns - Learn how to handle authentication and login flows - Set up scheduled automations for regular data collection - Integrate with your existing systems via APIs == Document: Data Extraction URL: https://herd.garden/docs/data-extraction # Data Extraction Welcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines. ## Understanding Selectors Herd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system. ### Basic Extraction ## javascript The simplest form of extraction uses CSS selectors to target elements: Code (javascript): // Extract basic text content const data = await page.extract({ title: 'h1', // Extracts the main heading description: 'p', // Extracts the first paragraph link: 'a' // Extracts the first link text }); console.log(data.title); // "Welcome to Our Website" console.log(data.description); // "This is our homepage." ## python The simplest form of extraction uses CSS selectors to target elements: Code (python): # Extract basic text content data = await page.extract({ "title": "h1", # Extracts the main heading "description": "p", # Extracts the first paragraph "link": "a" # Extracts the first link text }) print(data["title"]) # "Welcome to Our Website" print(data["description"]) # "This is our homepage." ### Advanced Selector Syntax ## javascript For more complex extraction needs, use the expanded object syntax: Code (javascript): const data = await page.extract({ title: { _$: 'h1', // CSS selector attribute: 'id' // Extract the ID attribute instead of text }, price: { _$: '.price', // Target price element pipes: ['parseNumber'] // Apply transformation } }); ## python For more complex extraction needs, use the expanded object syntax: Code (python): data = await page.extract({ "title": { "_
quot;: "h1", # CSS selector "attribute": "id" # Extract the ID attribute instead of text }, "price": { "_
quot;: ".price", # Target price element "pipes": ["parseNumber"] # Apply transformation } }) ### Extracting Lists of Items ## javascript To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (javascript): const data = await page.extract({ items: { _$r: '.item', // Find all elements with class "item" title: 'h2', // For each item, get the title price: '.price', // For each item, get the price date: 'time' // For each item, get the date } }); // Access the extracted items data.items.forEach(item => { console.log(`${item.title}: ${item.price}, Posted: ${item.date}`); }); ## python To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (python): data = await page.extract({ "items": { "_$r": ".item", # Find all elements with class "item" "title": "h2", # For each item, get the title "price": ".price", # For each item, get the price "date": "time" # For each item, get the date } }) # Access the extracted items for item in data["items"]: print(f"{item['title']}: {item['price']}, Posted: {item['date']}") ### Nested Extraction ## javascript You can nest selectors to extract hierarchical data: Code (javascript): const data = await page.extract({ product: { name: '.product-name', details: { _$: '.product-details', specs: { _$r: '.spec-item', label: '.spec-label', value: '.spec-value' } } } }); ## python You can nest selectors to extract hierarchical data: Code (python): data = await page.extract({ "product": { "name": ".product-name", "details": { "_
quot;: ".product-details", "specs": { "_$r": ".spec-item", "label": ".spec-label", "value": ".spec-value" } } } }) ## Special Selectors Herd provides special selectors to handle various extraction scenarios: ### Root Selector (`:root`) The `:root` selector refers to the current element in context: ## javascript Code (javascript): const data = await page.extract({ items: { _$r: '.item', someElement: ':root', // Extract text of the .item element itself classes: { _$: ':root', attribute: 'class' // Extract class attribute of the same element } } }); ## python Code (python): data = await page.extract({ "items": { "_$r": ".item", "someElement": ":root", # Extract text of the .item element itself "classes": { "_
quot;: ":root", "attribute": "class" # Extract class attribute of the same element } } }) ### Property Extraction You can extract JavaScript properties from elements: ## javascript Code (javascript): const data = await page.extract({ dimensions: { _$: '.box', property: 'getBoundingClientRect' // Get element dimensions }, html: { _$: '.content', property: 'innerHTML' // Get inner HTML } }); ## python Code (python): data = await page.extract({ "dimensions": { "_
quot;: ".box", "property": "getBoundingClientRect" # Get element dimensions }, "html": { "_
quot;: ".content", "property": "innerHTML" # Get inner HTML } }) ## Transformation Pipelines Herd includes powerful transformation pipelines to process extracted data: ### Available Transformations | Pipe | Description | Example Input | Example Output | |------|-------------|--------------|----------------| | `trim` | Removes whitespace from start/end | `" Hello "` | `"Hello"` | | `toLowerCase` | Converts text to lowercase | `"HELLO"` | `"hello"` | | `toUpperCase` | Converts text to uppercase | `"hello"` | `"HELLO"` | | `parseNumber` | Extracts numbers from text | `"$1,2K.45"` | `1200.45` | | `parseDate` | Converts text to date | `"2024-01-15"` | `"2024-01-15T00:00:00.000Z"` | | `parseDateTime` | Converts text to datetime | `"2024-01-15T12:00:00Z"` | `"2024-01-15T12:00:00.000Z"` | ### Using Transformations Apply transformations using the `pipes` property: ## javascript Code (javascript): const data = await page.extract({ price: { _$: '.price', pipes: ['parseNumber'] // Convert "$1,234.56" to 1234.56 }, title: { _$: 'h1', pipes: ['trim', 'toLowerCase'] // Apply multiple transformations } }); ## python Code (python): data = await page.extract({ "price": { "_
quot;: ".price", "pipes": ["parseNumber"] # Convert "$1,234.56" to 1234.56 }, "title": { "_
quot;: "h1", "pipes": ["trim", "toLowerCase"] # Apply multiple transformations } }) ### Handling Currency and Large Numbers The `parseNumber` transformation handles various formats: ## javascript Code (javascript): const data = await page.extract({ price1: { _$: '.price-1', // Contains "$1,234.56" pipes: ['parseNumber'] // Result: 1234.56 }, price2: { _$: '.price-2', // Contains "$1.5M" pipes: ['parseNumber'] // Result: 1500000 }, price3: { _$: '.price-3', // Contains "1.5T€" pipes: ['parseNumber'] // Result: 1500000000000 } }); ## python Code (python): data = await page.extract({ "price1": { "_
quot;: ".price-1", # Contains "$1,234.56" "pipes": ["parseNumber"] # Result: 1234.56 }, "price2": { "_
quot;: ".price-2", # Contains "$1.5M" "pipes": ["parseNumber"] # Result: 1500000 }, "price3": { "_
quot;: ".price-3", # Contains "1.5T€" "pipes": ["parseNumber"] # Result: 1500000000000 } }) ## Real-World Examples Let's look at some practical examples of data extraction: ### E-commerce Product Listing Extract products from a search results page: ## javascript Code (javascript): const searchResults = await page.extract({ products: { _$r: '[data-component-type="s-search-result"]', title: { _$: 'h2 .a-link-normal', pipes: ['trim'] }, price: { _$: '.a-price .a-offscreen', pipes: ['parseNumber'] }, rating: { _$: '.a-icon-star-small .a-icon-alt', pipes: ['trim'] }, reviews: { _$: '.a-size-base.s-underline-text', pipes: ['trim'] } } }); ## python Code (python): searchResults = await page.extract({ "products": { "_$r": '[data-component-type="s-search-result"]', "title": { "_
quot;: "h2 .a-link-normal", "pipes": ["trim"] }, "price": { "_
quot;: ".a-price .a-offscreen", "pipes": ["parseNumber"] }, "rating": { "_
quot;: ".a-icon-star-small .a-icon-alt", "pipes": ["trim"] }, "reviews": { "_
quot;: ".a-size-base.s-underline-text", "pipes": ["trim"] } } }) ### News Article List Extract articles from a news site: ## javascript Code (javascript): const articles = await page.extract({ items: { _$r: '.item', title: { _$: 'h2', pipes: ['trim', 'toLowerCase'] }, price: { _$: '.price', pipes: ['parseNumber'] }, date: { _$: 'time', pipes: ['parseDate'] } } }); ## python Code (python): articles = await page.extract({ "items": { "_$r": ".item", "title": { "_
quot;: "h2", "pipes": ["trim", "toLowerCase"] }, "price": { "_
quot;: ".price", "pipes": ["parseNumber"] }, "date": { "_
quot;: "time", "pipes": ["parseDate"] } } }) ## Advanced Techniques ### Handling Dynamic Content For dynamic content that loads after the page is ready: ## javascript Code (javascript): // Wait for dynamic content to load await page.waitForElement('#dynamic span'); // Then extract the content const data = await page.extract({ content: '#dynamic span' }); ## python Code (python): # Wait for dynamic content to load await page.waitForElement('#dynamic span') # Then extract the content data = await page.extract({ "content": "#dynamic span" }) ### Extracting Page Metadata Extract information about the page itself: ## javascript Code (javascript): const pageInfo = await page.extract({ title: 'title', metaDescription: 'meta[name="description"]', canonicalUrl: { _$: 'link[rel="canonical"]', attribute: 'href' } }); ## python Code (python): pageInfo = await page.extract({ "title": "title", "metaDescription": 'meta[name="description"]', "canonicalUrl": { "_
quot;: 'link[rel="canonical"]', "attribute": "href" } }) ## Tips for Effective Extraction 1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction 2. **Test Incrementally**: Build your extraction schema step by step, testing each part 3. **Handle Missing Data**: Always account for elements that might not exist on the page 4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed 5. **Combine with Interactions**: For complex sites, interact with the page before extraction ## Next Steps Now that you understand Herd's data extraction system, you can: - Create complex extraction schemas for any website - Transform raw data into structured, usable formats - Build powerful automations that collect and process web data == Document: Getting Started URL: https://herd.garden/docs/getting-started # Getting Started with Herd This guide will help you get up and running with Herd quickly to run your first trail. ## What is Herd? Herd connects AI Agents to websites using your own browser credentials. It enables you to: - **Run Trails** - pre-built automations for specific websites and tasks - **Extract data and interact with websites** using your logged-in browser sessions - **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude ## Quick Start ### 1. Install the Browser Extension Chrome Edge Brave ### 2. Register Your Browser After installing the extension: 1. Click the Herd icon in your browser toolbar 2. Sign in with your Herd account (or create one) 3. Name your device and register it ![Browser Registration](https://herd.garden/register-device.png) ### 3. Install the Herd SDK Install the Herd SDK using npm: ## npm Code (bash): npm install -g @monitoro/herd ## yarn Code (bash): yarn global add @monitoro/herd ## pnpm Code (bash): pnpm add -g @monitoro/herd ### 4. Run Your First Trail The browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out: Code (bash): herd trail run @herd/browser -a markdown -p '{"url": "https://example.com"}' That's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config: Code (json): { "mcpServers": { "browser": { "command": "herd", "args": [ "trail", "server", "@herd/browser" ] } } } ## For Developers You can also automate your browser with the Herd SDK. Connect to it with your AI agents or code: ## javascript Code (javascript): // Connect to your Herd device const client = new HerdClient('your-token'); await client.initialize(); const devices = await client.listDevices(); const device = devices[0]; // Create a new page and navigate const page = await device.newPage(); await page.goto("https://example.com"); // Extract data using simple selectors const data = await page.extract({ title: "h1", description: "p", link: "a" }); console.log("Extracted data:", data); ## python Code (python): from monitoro_herd import HerdClient # Connect to your Herd device client = HerdClient("your-token") await client.initialize() devices = await client.list_devices() device = devices[0] # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Extract data using simple selectors data = await page.extract({ "title": "h1", "description": "p", "link": "a" }) print("Extracted data:", data) ## What's Next? Now that you've run your first trail, you can: - [Explore available trails](/trails) - Browse pre-built trails for various websites - [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages - [Create your own trail](/docs/trails-automations) - Build and share your own custom trails ## Need Help? If you encounter any issues during setup: - Make sure your browser extension is correctly installed and you're signed in - Check that your device is registered in the [device dashboard](/devices) - Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions .browser-btn { display: inline-flex; align-items: center; padding: 0.2rem 1rem; background-color: #1f2937; color: white; border-radius: 0.375rem; font-size: 1.2rem; font-weight: 500; text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.1); } .browser-btn:hover { background-color: #374151; } == Document: Trails Automations URL: https://herd.garden/docs/trails-automations # Trails Trails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process. ## javascript Trails are fully supported in the JavaScript SDK. ## Creating a Trail A trail defines the following components: - **urls.ts**: Exports an array of URL definitions - **selectors.ts**: Exports an array of selector configurations - **actions.ts**: Exports action classes that implement the `TrailAction` interface A trail at the minimum has the following structure: Code: google-search/ urls.ts selectors.ts actions.ts package.json The `package.json` file defines the trail and its dependencies: Code (json): { "name": "google-search", "description": "Search google for webpages.", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } You should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code. ## Trail Implementation Guide ### Step 1: Set up the trail structure Create a new directory for your trail with the following files: Code: my-trail/ urls.ts selectors.ts actions.ts package.json Add the basic package.json configuration: Code (json): { "name": "my-trail", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } ### Step 2: Define URLs In `urls.ts`, export an array of URL definitions that your trail will interact with: Code (typescript): export default [{ "id": "my-url", "template": "https://example.com/path?param1={param1}&param2={param2}", "description": "Description of what this URL represents", "examples": [ { "param1": "value1", "param2": "value2" } ], "params": { "param1": { "type": "string", "required": true, "description": "Description of param1" }, "param2": { "type": "string", "required": false, "default": "defaultValue", "description": "Description of param2" } } }]; ### Step 3: Define Selectors In `selectors.ts`, export an array of selector configurations that define how to extract data from web pages: Code (typescript): export default [{ "id": "my-selector", "value": { "dataKey": { "_$r": "#main-container", "title": { "_
quot;: ".title" }, "description": { "_
quot;: ".description" }, "link": { "_
quot;: "a.link", "attribute": "href" } } }, "description": "Selector for extracting specific data", "examples": [ { "urlId": "my-url", "urlParams": { "param1": "value1", "param2": "value2" } } ] }]; ### Step 4: Implement Actions In `actions.ts`, define one or more action classes that implement the `TrailAction` interface: Code (typescript): import type { Device, TrailAction, TrailActionManifest, TrailRunResources } from "@monitoro/herd"; export class MyTrailAction implements TrailAction { manifest: TrailActionManifest = { name: "my-action", description: "Description of what this action does", params: { param1: { type: "string", description: "Description of param1" }, param2: { type: "number", description: "Description of param2", default: 10 } }, result: { type: "array", description: "Description of the result", items: { type: "object", properties: { property1: { type: "string" }, property2: { type: "number" } } } }, examples: [ { "param1": "value1", "param2": 10 } ] } async test(device: Device, params: Record, resources: TrailRunResources) { try { const result = await this.run(device, params, resources); // Validate result if (!result || result.length === 0) { return { status: "error", message: "No results found", result: [] }; } return { status: "success", result }; } catch (e) { return { status: "error", message: `Error: ${e}`, result: null }; } } async run(device: Device, params: Record, resources: TrailRunResources) { const { param1, param2 } = params; const page = await device.newPage(); try { // Navigate to URL using the URL template from urls.ts await page.goto(resources.url('my-url', { param1, param2 })); // Extract data using selectors from selectors.ts const extracted = await page.extract(resources.selector('my-selector')); // Process extracted data const results = (extracted as any)?.dataKey || []; // Return processed results return results; } finally { await page.close(); } } } ### Step 5: Testing and debugging Use the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest): Code (bash): herd trail test --action my-trail You can also watch for changes in the trail and re-run tests: Code (bash): herd trail test --action my-trail --watch # or herd trail test -a my-trail -w And you can also test selectors only: Code (bash): herd trail test --selector my-selector And watch for changes in the selectors: Code (bash): herd trail test --selector my-selector --watch # or herd trail test -s my-selector -w ### Step 6: Publish your trail Publishing is coming soon! ### Best Practices 1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc. 2. **Performance**: Minimize page loads and extract as much data as possible from each page. 3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain. 4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios. 5. **Versioning**: Increment your trail's version in package.json when making changes. ## python Trails support for Python SDK is coming soon. Stay tuned for updates! In the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them. ==

Document

llms-full.txt

Open llms-full.txt
Herd Documentation
================================================================================

Document: Alternative Herd Vs Apify
URL: https://herd.garden/docs/alternative-herd-vs-apify

# Herd vs Apify: A Cost-Effective Alternative for Web Automation

Apify is a popular platform for web scraping and automation, but its cloud-based infrastructure can be costly and limiting. Herd offers a compelling alternative with similar capabilities but a fundamentally different approach that eliminates infrastructure costs and provides more control over your automation.

## Quick Comparison

| Feature | Herd | Apify |
| --- | --- | --- |
| **Primary Focus** | Browser automation & web scraping | Web scraping platform with cloud infrastructure |
| **Infrastructure** | Uses your existing browser | Cloud-based platform with managed instances |
| **Pricing Model** | Flat rate subscription | Usage-based pricing |
| **Browser Control** | Direct control of your browser | Remote control of cloud browsers |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome/Chromium in cloud |
| **Setup Required** | Simple browser extension | No browser setup (cloud-based) |
| **Authentication** | Uses existing browser sessions | Requires manual setup |
| **Data Extraction** | Built-in extraction tools | Various actor-based extraction tools |
| **Resource Usage** | Minimal (shared with browser) | Separate cloud resources (higher cost) |
| **Customization** | Full control of local environment | Limited to platform capabilities |

## Key Differences in Depth

### Infrastructure and Pricing Model

**Apify:**
- Cloud-based platform with usage-based pricing
- Costs scale with computation time and resource usage
- Requires paid proxy services for many use cases
- Monthly subscription plus usage-based fees

**Herd:**
- Uses your existing browser and computer
- No cloud infrastructure required
- Direct control of your local resources 
- Supports Chrome, Edge, Brave, Arc, Opera
- No additional infrastructure costs
- No separate compute units to pay for
- Simple and predictable pricing

### Browser Control and Authentication

**Apify:**
- Operates browsers in the cloud
- Must manually set up authentication flows
- Sessions are isolated and temporary
- Limited access to browser-specific features

**Herd:**
- Direct control of your own browser
- Uses your existing authenticated sessions
- Persistent cookies and storage between runs
- Full access to browser capabilities and extensions

### Setup and Customization

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Simple setup code
import { HerdClient } from '@monitoro/herd';

// Connect to your own browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

## apify

Code (javascript):
// Install the Apify SDK
npm install apify

// Create an actor
import { Actor } from 'apify';

// Run in Apify cloud environment
await Actor.init();

// Launch a browser in the cloud
const browser = await Actor.launchPuppeteer();
const page = await browser.newPage();
await page.goto('https://example.com');

// Must manually handle stopping the actor
await Actor.exit();

### Data Extraction Capabilities

**Apify:**
- Offers pre-built actors for common websites
- Large marketplace of ready-made solutions
- Extraction limited to what actors provide
- Can become expensive for large-scale extraction

**Herd:**
- Powerful built-in extraction API
- Simple selector-based data retrieval
- Access to authenticated content
- Extract data without usage limits

## Use Case Comparisons

### Web Scraping with Authentication

## herd-auth

Code (javascript):
// Using Herd with an already authenticated browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Access a site where you're already logged in
const page = await device.newPage();
await page.goto('https://account.example.com/dashboard');

// Extract authenticated data directly
const userData = await page.extract({
  username: '.user-profile .username',
  accountType: '.account-type',
  balance: '.account-balance',
  transactions: {
    _$r: '.transaction-item',
    date: '.transaction-date',
    amount: '.transaction-amount',
    description: '.transaction-description'
  }
});

console.log(userData);
await client.close();

## apify-auth

Code (javascript):
// Using Apify with manual authentication
import { Actor } from 'apify';

await Actor.init();
const browser = await Actor.launchPuppeteer();
const page = await browser.newPage();

// Need to manually log in first
await page.goto('https://example.com/login');
await page.type('#username', 'your-username');
await page.type('#password', 'your-password');
await page.click('.login-button');
await page.waitForNavigation();

// Now navigate to the dashboard
await page.goto('https://account.example.com/dashboard');

// Extract data with multiple evaluations
const username = await page.$eval('.user-profile .username', el => el.textContent);
const accountType = await page.$eval('.account-type', el => el.textContent);
const balanceText = await page.$eval('.account-balance', el => el.textContent);
const balance = parseFloat(balanceText.replace(/[^0-9.-]+/g, ''));

// Extract transaction data
const transactions = await page.$eval('.transaction-item', items => 
  items.map(item => ({
    date: item.querySelector('.transaction-date').textContent,
    amount: item.querySelector('.transaction-amount').textContent,
    description: item.querySelector('.transaction-description').textContent
  }))
);

const userData = {
  username,
  accountType,
  balance,
  transactions
};

console.log(userData);
await Actor.exit();

### Multi-Page Crawling

## herd-crawl

Code (javascript):
// Using Herd for multi-page crawling
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Collect all product links first
const productLinks = await page.extract({
  links: {
    _$r: '.product-card a',
    url: { attribute: 'href' }
  }
});

// Visit each product page and extract details
const products = [];
for (const { url } of productLinks.links) {
  await page.goto(url);
  
  const productData = await page.extract({
    name: '.product-name',
    price: '.product-price',
    description: '.product-description',
    specs: {
      _$r: '.spec-item',
      name: '.spec-name',
      value: '.spec-value'
    }
  });
  
  products.push(productData);
}

console.log(products);
await client.close();

## apify-crawl

Code (javascript):
// Using Apify for multi-page crawling
import { Actor, PuppeteerCrawler } from 'apify';

await Actor.init();

// Define the crawler
const crawler = new PuppeteerCrawler({
  async requestHandler({ request, page }) {
    console.log(`Processing ${request.url}...`);
    
    if (request.userData.detailPage) {
      // Extract product details
      const productData = {
        url: request.url,
        name: await page.$eval('.product-name', el => el.textContent),
        price: await page.$eval('.product-price', el => el.textContent),
        description: await page.$eval('.product-description', el => el.textContent),
        specs: await page.$eval('.spec-item', items => 
          items.map(item => ({
            name: item.querySelector('.spec-name').textContent,
            value: item.querySelector('.spec-value').textContent
          }))
        )
      };
      
      // Save the extracted data
      await Actor.pushData(productData);
    } else {
      // On the listing page, extract links to products
      const productLinks = await page.$eval('.product-card a', links => 
        links.map(link => link.href)
      );
      
      // Enqueue product detail pages
      for (const url of productLinks) {
        await crawler.requestQueue.addRequest({
          url,
          userData: { detailPage: true }
        });
      }
    }
  },
  maxRequestsPerCrawl: 100,
});

// Start with the product listing page
await crawler.run(['https://example.com/products']);

await Actor.exit();

## Migration Guide: From Apify to Herd

Transitioning from Apify to Herd is straightforward. Here's a guide to help you migrate:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   npm install @monitoro/herd

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Apify | Herd | Notes |
| --- | --- | --- |
| `Actor.init()` | `const client = new HerdClient(apiUrl, token)`  `await client.initialize()` | Herd uses a simple client-server model |
| `Actor.launchPuppeteer()` | `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `browser.newPage()` | `await device.newPage()` | Similar API |
| `page.goto(url)` | `await page.goto(url)` | Identical usage |
| `page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd has a more powerful extraction API |
| `Actor.pushData(data)` | Store data directly in your code | No platform-specific storage |
| `Actor.exit()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Handling Authentication

**Apify:**

Code (javascript):
// Manual login process
await page.goto('https://example.com/login');
await page.type('#username', 'user');
await page.type('#password', 'pass');
await page.click('#login-button');

**Herd:**

Code (javascript):
// Simply use your already authenticated browser
await page.goto('https://example.com/dashboard');  // Already logged in

## Why Choose Herd Over Apify?

### 1. Cost Efficiency

Herd eliminates the need for cloud infrastructure, resulting in:
- No usage-based computation costs
- No proxy costs for most use cases
- Significant cost savings for regular automation
- Predictable pricing independent of usage volume

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to handle authentication flows in code
- Access to sites with complex auth (2FA, CAPTCHA)
- Use existing cookies, local storage, and sessions

### 3. Local Control and Privacy

Herd provides:
- Full control over the automation environment
- Higher privacy (data stays on your machine)
- Direct access to local resources when needed
- No dependence on third-party cloud infrastructure

### 4. Simpler Development Experience

Herd offers:
- More intuitive APIs for common tasks
- Real-time debugging in your browser
- No need to deploy or manage cloud resources
- Faster iteration during development

## Get Started with Herd Today

Ready to try a more flexible alternative to Apify? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide all the capabilities you need for web automation and scraping at a fraction of the cost of cloud-based solutions like Apify.

================================================================================

Document: Alternative Herd Vs Browserbase
URL: https://herd.garden/docs/alternative-herd-vs-browserbase

# Herd vs Browserbase: No-Infrastructure Browser Automation

Browserbase provides cloud-based headless browsers for automation and AI applications. While it offers a reliable platform for running browser instances, Herd takes a fundamentally different approach by leveraging your existing browsers, eliminating infrastructure costs and complexity.

## Quick Comparison

| Feature | Herd | Browserbase |
| --- | --- | --- |
| **Browser Location** | Your local machine | Cloud-based infrastructure |
| **Infrastructure Needed** | None (uses your browser) | Managed cloud infrastructure |
| **Pricing Model** | Flat subscription | Usage-based pricing |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium in cloud |
| **Latency** | Minimal (1-hop) | Higher (multiple hops) |
| **Authentication** | Uses existing browser sessions | Requires manual setup |
| **Framework Support** | JavaScript/Python SDKs | Stagehand, Playwright, Puppeteer, Selenium |
| **Setup Required** | Browser extension installation | No installation (cloud-based) |
| **Resource Constraints** | Depends on local resources | Limited by pricing tier |

## Key Differences in Depth

### Infrastructure and Cost Model

**Browserbase:**
- Runs browsers on managed cloud infrastructure
- Costs scale with usage and session duration
- Requires networking between your code and cloud
- Additional costs for premium features like proxies

**Herd:**
- Uses browsers already installed on your machine
- No cloud infrastructure required
- Direct access to your local machine resources
- Supports Chrome, Edge, Brave, Arc, Opera
- Fixed, predictable pricing not tied to usage
- Local execution with minimal network overhead
- No additional infrastructure costs to manage

### Setup and Integration

## herd

Code (javascript):
// Simple installation - no code required
// 1. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox/Safari not supported)
// 2. Connect your browser to Herd

// Simple connection to your browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a new page
const page = await device.newPage();
await page.goto('https://example.com');

## browserbase

Code (javascript):
// Install the SDK
npm install browserbase

// Connect to cloud infrastructure
import { Browserbase } from 'browserbase';

const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create a session on cloud infrastructure
const session = await bb.sessions.create({
  timeout: 60, // Session timeout in seconds
});

// Create a page in the cloud browser
const page = await session.newPage();
await page.goto('https://example.com');

### Session Management and Performance

**Browserbase:**
- Cloud-based sessions with timeout limits
- Performance dependent on cloud resources and network
- Sessions isolated from local environment
- Must explicitly manage session lifecycle

**Herd:**
- Direct access to local browser sessions
- Local performance without network latency
- Integrated with your local environment
- Sessions persist with your browser

### Authentication and User Context

**Browserbase:**
- Requires implementing authentication for each session
- Isolated sessions without access to existing cookies
- Must manually handle login flows
- Credentials need to be stored and managed

**Herd:**
- Uses your browser's existing authenticated sessions
- Access to all cookies, local storage, and session data
- No need to implement authentication flows
- Use sites you're already logged into

## Use Case Comparisons

### Web Automation for Logged-in Services

## herd-auth

Code (javascript):
// Using Herd with pre-authenticated browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Directly access authenticated service
const page = await device.newPage();
await page.goto('https://app.example.com/dashboard');  // Already logged in

// Perform actions on authenticated page
await page.click('.create-new-button');
await page.type('#item-name', 'New Item');
await page.click('.save-button');

// Verify result
const confirmationText = await page.$eval('.confirmation', el => el.textContent);
console.log(confirmationText);

## browserbase-auth

Code (javascript):
// Using Browserbase with manual authentication
const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create cloud browser session
const session = await bb.sessions.create({
  timeout: 300,  // Longer timeout for auth flow
});

// Create page and handle login manually
const page = await session.newPage();

// Navigate to login page
await page.goto('https://app.example.com/login');

// Fill login form
await page.type('#email', 'user@example.com');
await page.type('#password', 'your-secure-password');
await page.click('#login-button');

// Wait for login to complete
await page.waitForNavigation();

// Now navigate to dashboard
await page.goto('https://app.example.com/dashboard');

// Perform actions on authenticated page
await page.click('.create-new-button');
await page.type('#item-name', 'New Item');
await page.click('.save-button');

// Verify result
const confirmationText = await page.$eval('.confirmation', el => el.textContent);
console.log(confirmationText);

// Must explicitly end session
await session.close();

### Data Extraction at Scale

## herd-extract

Code (javascript):
// Using Herd for data extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Open multiple pages for parallel extraction
const pages = await Promise.all([1, 2, 3].map(() => device.newPage()));

// Extract data from multiple sources in parallel
const results = await Promise.all(pages.map(async (page, index) => {
  await page.goto(`https://example.com/category/${index+1}`);
  
  // Use Herd's extraction API
  const data = await page.extract({
    categoryName: '.category-header h1',
    items: {
      _$r: '.product-item',
      title: '.product-title',
      price: '.product-price',
      rating: '.rating-value'
    }
  });
  
  return data;
}));

// Close pages when done
await Promise.all(pages.map(page => page.close()));
await client.close();

console.log(results);

## browserbase-extract

Code (javascript):
// Using Browserbase for data extraction
const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create separate sessions for parallel extraction
const sessions = await Promise.all([1, 2, 3].map(() => 
  bb.sessions.create({ timeout: 120 })
));

// Extract data from multiple sources
const results = await Promise.all(sessions.map(async (session, index) => {
  const page = await session.newPage();
  await page.goto(`https://example.com/category/${index+1}`);
  
  // Extract data using Puppeteer-style selectors
  const categoryName = await page.$eval('.category-header h1', el => el.textContent);
  
  const itemElements = await page.$('.product-item');
  const items = [];
  
  for (const element of itemElements) {
    const title = await element.$eval('.product-title', el => el.textContent);
    const price = await element.$eval('.product-price', el => el.textContent);
    
    let rating = null;
    try {
      rating = await element.$eval('.rating-value', el => el.textContent);
    } catch (e) {
      // Element might not exist
    }
    
    items.push({ title, price, rating });
  }
  
  // Must close session when done
  await session.close();
  
  return { categoryName, items };
}));

console.log(results);

## Migration Guide: From Browserbase to Herd

Transitioning from Browserbase to Herd is straightforward. Here's a guide to help you migrate:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Browserbase | Herd | Notes |
| --- | --- | --- |
| `new Browserbase({ api_key })` | `new HerdClient(apiUrl, token)`  `await client.initialize()` | Herd uses a client-server architecture |
| `bb.sessions.create()` | `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `session.newPage()` | `await device.newPage()` | Similar API |
| `await page.goto(url)` | `await page.goto(url)` | Identical usage |
| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |
| `await page.click(selector)` | `await page.click(selector)` | Identical usage |
| `await page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd offers a more powerful extraction API |
| `await session.close()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Framework Integration

**Browserbase:**

Code (javascript):
// Browserbase with Playwright
const { chromium } = require('playwright');
const browser = await chromium.connectOverCDP(session.wsEndpoint);
const page = await browser.newPage();

**Herd:**

Code (javascript):
// Herd uses its own API directly
const page = await device.newPage();
// Direct integrations with testing frameworks available

## Why Choose Herd Over Browserbase?

### 1. No Cloud Infrastructure Required

Herd eliminates the need for cloud infrastructure, providing:
- Zero dependency on remote browser instances
- No need to manage cloud resources
- Reduced latency with local execution
- Complete isolation from cloud service disruptions

### 2. Cost Predictability and Efficiency

Herd offers a more predictable and often lower cost:
- No usage-based billing surprises
- No charges based on session duration
- No additional costs for scaling automation
- Fixed costs regardless of automation volume

### 3. Use Existing Browser State and Auth

With Herd, you can leverage your browser's existing state:
- Use sites you're already logged into
- Access to all browser extensions
- Utilize stored passwords and authentication
- No need to manage credentials in code

### 4. Lower Latency and Higher Performance

Herd provides performance advantages with local execution:
- No network latency between code and browser
- Faster execution of automation tasks
- Direct access to local resources
- No timeout limitations on sessions

## Get Started with Herd Today

Ready to try a more flexible alternative to Browserbase? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide all the capabilities you need for web automation without the complexity and costs of cloud-based infrastructure.

================================================================================

Document: Alternative Herd Vs Firecrawl
URL: https://herd.garden/docs/alternative-herd-vs-firecrawl

# Herd vs Firecrawl: Flexible Browser Automation and Data Extraction

Firecrawl is a specialized web scraping and crawling tool designed primarily for extracting and cleaning web content, especially for use with LLMs. While Firecrawl offers powerful crawling capabilities, Herd provides a more comprehensive browser automation solution with greater flexibility and control over the browsing experience.

## Quick Comparison

| Feature | Herd | Firecrawl |
| --- | --- | --- |
| **Primary Focus** | Complete browser automation | Web crawling and content extraction |
| **Infrastructure** | Uses your existing browser | Cloud-based crawling infrastructure |
| **Pricing Model** | Flat subscription | Usage-based pricing |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Managed cloud browsers |
| **Browser Control** | Full interactive browser control | Limited to crawling and extraction |
| **Authentication** | Uses existing browser sessions | Limited authentication capabilities |
| **Content Processing** | Raw and structured data extraction | Optimized for clean text/markdown output |
| **Usage Flexibility** | General-purpose automation | Specialized for content crawling |
| **Interactive Workflows** | Supports complex interactions | Limited to extraction patterns |

## Key Differences in Depth

### Primary Focus and Capabilities

**Firecrawl:**
- Specialized in high-quality web content extraction
- Optimized for converting websites to clean markdown
- Focused on crawling through website links
- Built primarily for LLM data ingestion
- Limited interactive capabilities

**Herd:**
- Complete browser automation platform
- Full interactive control of browser actions
- Supports Chrome, Edge, Brave, Arc, Opera
- Supports both data extraction and automation workflows
- General-purpose browser control
- Rich interaction with web applications

### Infrastructure and Execution Model

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Connect to your existing browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Full browser automation capabilities
const page = await device.newPage();
await page.goto('https://example.com');

## firecrawl

Code (javascript):
// Install the Firecrawl SDK
npm install @mendable/firecrawl-js

// Connect to Firecrawl's cloud service
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Send request to cloud-based crawling service
const result = await app.scrapeUrl('example.com');
console.log(result.markdown);

### Data Extraction Approaches

**Firecrawl:**
- Specializes in converting HTML to clean markdown
- Automatically handles JavaScript rendering
- Built-in content cleaning and formatting
- Output optimized for LLM consumption
- Limited customization of extraction patterns

**Herd:**
- Flexible data extraction patterns
- CSS selector-based extraction
- Support for complex nested data structures
- Raw data access and custom transformations
- Complete control over extraction logic

## Use Case Comparisons

### Website Content Extraction

## herd-extract

Code (javascript):
// Using Herd for content extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/article');

// Extract structured content with control over the format
const articleData = await page.extract({
  title: '.article-title',
  author: '.author-name',
  published: {
    _$: '.publish-date',
    pipes: ['parseDate']
  },
  content: '.article-body',
  tags: {
    _$r: '.tag',
    text: ':root'
  }
});

console.log(articleData);
await client.close();

## firecrawl-extract

Code (javascript):
// Using Firecrawl for content extraction
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Simple URL-based extraction
const scrapeResult = await app.scrapeUrl('https://example.com/article');

if (scrapeResult.success) {
  // Get the clean markdown content
  console.log(scrapeResult.markdown);
  
  // Access metadata
  console.log(scrapeResult.metadata);
} else {
  console.error('Failed to scrape:', scrapeResult.error);
}

### Interactive Web Automation

## herd-automation

Code (javascript):
// Using Herd for interactive web automation
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();

// Navigate to a web application
await page.goto('https://app.example.com/dashboard');

// Fill out a form
await page.click('.create-new-button');
await page.type('#title-input', 'New Project');
await page.type('#description-input', 'This is a test project created by automation');
await page.select('#category-select', 'development');

// Upload a file
const fileInput = await page.$('input[type="file"]');
await fileInput.uploadFile('/path/to/local/file.pdf');

// Submit the form
await page.click('.submit-button');

// Wait for confirmation and extract result
await page.waitForSelector('.success-message');
const confirmationText = await page.$eval('.success-message', el => el.textContent);
console.log('Form submitted successfully:', confirmationText);

await client.close();

## firecrawl-automation

Code (javascript):
// Firecrawl has limited interactive capabilities
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// For interactive tasks like form submission, 
// Firecrawl has limited capabilities, primarily focused
// on crawling and content extraction.

// You could use the actions feature for limited interactions:
const result = await app.scrapeUrl('https://app.example.com', {
  actions: [
    { type: 'click', selector: '.login-button' },
    { type: 'wait', time: 2000 }
    // Limited set of basic actions available
  ]
});

// But complex workflows like file uploads or 
// multi-step interactions require a more 
// comprehensive automation tool like Herd

### Multi-Page Crawling

## herd-crawl

Code (javascript):
// Using Herd for custom crawling
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Extract all product links
const productLinks = await page.extract({
  links: {
    _$r: '.product-card a',
    url: { attribute: 'href' }
  }
});

// Custom crawling logic with full control
const productDetails = [];
for (const { url } of productLinks.links) {
  // Navigate to each product page
  await page.goto(url);
  
  // Extract detailed information
  const product = await page.extract({
    name: '.product-name',
    price: '.product-price',
    description: '.product-description',
    inStock: '.stock-status'
  });
  
  productDetails.push(product);
  
  // You can implement custom logic: only continue if conditions are met
  if (productDetails.length >= 10) break;
}

console.log(productDetails);
await client.close();

## firecrawl-crawl

Code (javascript):
// Using Firecrawl for website crawling
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Crawl an entire site
const crawlResult = await app.crawlWebsite('example.com', {
  maxPages: 10,  // Limit the crawl
  includeSitemap: true, // Use sitemap if available
  followExternalLinks: false // Stay on the same domain
});

if (crawlResult.success) {
  // Access all crawled pages
  for (const page of crawlResult.pages) {
    console.log(`Page: ${page.url}`);
    console.log(`Content: ${page.markdown}`);
  }
} else {
  console.error('Crawl failed:', crawlResult.error);
}

## Migration Guide: From Firecrawl to Herd

Transitioning from Firecrawl to Herd is straightforward. Here's a guide to help you migrate:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Firecrawl | Herd | Notes |
| --- | --- | --- |
| `new FirecrawlApp({ apiKey })` | `new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `app.scrapeUrl(url)` | `const page = await device.newPage()`  `await page.goto(url)`  `const data = await page.extract(...)` | More granular control in Herd |
| `result.markdown` | Custom extraction patterns with formatting | More flexible data extraction options |
| `app.crawlWebsite(domain)` | Custom crawling logic implemented with Herd's navigation and extraction APIs | Full control over crawling behavior |

### 3. Implementing Markdown Conversion

If you specifically need markdown output like Firecrawl provides:

Code (javascript):
// Helper function to convert extracted HTML to markdown
function htmlToMarkdown(html) {
  // Use a library like turndown
  const turndownService = new TurndownService();
  return turndownService.turndown(html);
}

// Extract with Herd and convert to markdown
const content = await page.extract({
  body: {
    _$: '.article-content',
    attribute: 'innerHTML'
  }
});

## Why Choose Herd Over Firecrawl?

### 1. Comprehensive Browser Control

Herd provides full browser automation capabilities:
- Complete interactive control beyond just crawling
- Support for complex user interactions
- Ability to automate any browser-based workflow
- Full access to browser APIs and capabilities

### 2. Flexible Authentication and Sessions

Herd's approach offers significant authentication advantages:
- Use your existing authenticated browser sessions
- No need to implement login flows
- Support for complex authentication scenarios
- Access to secure content without credential management

### 3. Customizable Extraction and Processing

Herd gives you complete control over data extraction:
- Custom extraction patterns for any website structure
- Flexible transformation of extracted data
- Support for complex nested data extraction
- Processing options beyond just markdown conversion

### 4. Broader Use Case Support

Herd supports a wider range of automation scenarios:
- Form submission and interactive workflows
- File uploads and downloads
- Conditional logic based on page content
- Testing and verification workflows

## Get Started with Herd Today

Ready to try a more flexible alternative to Firecrawl? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide enhanced capabilities for both content extraction and browser automation, giving you more control and flexibility than specialized crawling tools like Firecrawl.

================================================================================

Document: Alternative Herd Vs Mcp Sdk
URL: https://herd.garden/docs/alternative-herd-vs-mcp-sdk

# Herd vs MCP SDK: Streamlined Browser Automation

The Model Context Protocol (MCP) SDK provides browser automation capabilities primarily focused on AI agent integration. While MCP SDK offers powerful integration with Large Language Models, Herd provides a more accessible and straightforward approach to browser automation with simplified setup and direct browser control.

## Quick Comparison

| Feature | Herd | MCP SDK |
| --- | --- | --- |
| **Primary Focus** | General browser automation | AI agent browser automation |
| **Infrastructure** | Uses your existing browser | Requires separate browser setup |
| **API Design** | Simple, direct browser control | Protocol-oriented architecture |
| **Integration** | JavaScript/Python SDKs | Multiple languages supported |
| **Setup Complexity** | Simple browser extension | More complex server configuration |
| **Authentication** | Uses existing browser sessions | Requires manual configuration |
| **Learning Curve** | Shallow, familiar browser API | Steeper with protocol concepts |
| **Use Cases** | General automation and extraction | AI agent browsing tasks |

## Key Differences in Depth

### Focus and Architecture

**MCP SDK:**
- Designed primarily for AI model integration
- Protocol-based communication model
- Server-client architecture
- Focus on enabling AI agents to browse
- More complex protocol implementation

**Herd:**
- Direct browser automation focus
- Simple client-browser connection
- Intuitive API design
- Supports Chrome, Edge, Brave, Arc, Opera
- Streamlined API for common tasks
- Designed for developers first
- Lower implementation complexity

### Setup and Integration

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Simple direct connection to your browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

## mcp

Code (javascript):
// Install MCP SDK
npm install mcp-browser-automation

// Set up the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({
  port: 8000,
  // Additional configuration for the server
});

// Start the server
await server.start();

// Client side needs to implement MCP protocol
// to communicate with the server

// Then through MCP protocol interactions:
// 1. Create a browser session
// 2. Navigate to URL
// 3. Interact with page

### Integration with AI Systems

**MCP SDK:**
- Designed specifically for AI model integration
- Protocol-based approach for AI agents
- Built to enable AI systems to browse the web
- Complex implementation for general use cases
- Strong focus on AI agent capabilities

**Herd:**
- General-purpose browser automation
- Can be integrated with AI systems through standard APIs
- Simpler implementation for most use cases
- Direct browser control paradigm
- Focus on developer experience and simplicity

## Use Case Comparisons

### Basic Web Automation

## herd-auto

Code (javascript):
// Using Herd for basic web automation
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a new page
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com/login');

// Fill login form
await page.type('#username', 'test_user');
await page.type('#password', 'password123');
await page.click('.login-button');

// Wait for navigation and verify login
await page.waitForSelector('.dashboard');
const welcomeText = await page.$eval('.welcome-message', el => el.textContent);
console.log('Login successful:', welcomeText);

await client.close();

## mcp-auto

Code (javascript):
// Using MCP SDK for basic web automation
// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// For client-side interaction, implement the MCP protocol
// This is a simplified example showing the concept
const response = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'createSession',
    params: {}
  })
});
const { sessionId } = await response.json();

// Navigate to a website
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'navigate',
    sessionId,
    params: { url: 'https://example.com/login' }
  })
});

// Fill login form (multiple requests needed)
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'type',
    sessionId,
    params: { selector: '#username', text: 'test_user' }
  })
});

// Additional requests for password and clicking login button
// ...

// MCP SDK is more verbose for simple automation tasks
// and requires protocol knowledge

### Data Extraction Tasks

## herd-extract

Code (javascript):
// Using Herd for data extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Extract data using Herd's powerful extraction API
const productData = await page.extract({
  title: '.page-title',
  products: {
    _$r: '.product-item',  // Repeat for all products
    name: '.product-name',
    price: '.product-price',
    rating: '.rating-stars',
    available: '.stock-status'
  }
});

console.log(productData);
await client.close();

## mcp-extract

Code (javascript):
// Using MCP SDK for data extraction
// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// For client-side extraction, implement the MCP protocol
// This is a simplified example showing the concept
const response = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'createSession',
    params: {}
  })
});
const { sessionId } = await response.json();

// Navigate to the products page
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'navigate',
    sessionId,
    params: { url: 'https://example.com/products' }
  })
});

// Extract the page title
const titleResponse = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'evaluate',
    sessionId,
    params: { 
      script: "document.querySelector('.page-title').textContent" 
    }
  })
});
const { result: title } = await titleResponse.json();

// Extract product data would require more complex script execution
// or multiple requests to get all the product information
// ...

// MCP SDK requires more complex orchestration for data extraction
// compared to Herd's simplified extraction API

### AI Integration

## herd-ai

Code (javascript):
// Using Herd with AI integration
// First, set up Herd client as usual
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a function to handle AI requests for web content
async function fetchWebContentForAI(url, query) {
  const page = await device.newPage();
  await page.goto(url);
  
  // Extract relevant content based on the AI query
  const content = await page.extract({
    title: 'h1',
    mainContent: '.main-content',
    relevantSections: {
      _$r: '.content-section',
      heading: 'h2',
      text: 'p'
    }
  });
  
  // Close the page when done
  await page.close();
  
  // Return the content for AI processing
  return content;
}

// Example usage with an AI system
const aiPrompt = "Summarize the information about machine learning from example.com";
const url = "https://example.com/machine-learning";

// Get the content for the AI
const webContent = await fetchWebContentForAI(url, "machine learning");

// Feed the content to the AI system
const aiResponse = await callAISystem(aiPrompt, webContent);
console.log(aiResponse);

await client.close();

// This pattern keeps the AI integration simple and separate from
// the browser automation concerns

## mcp-ai

Code (javascript):
// Using MCP SDK with AI integration
// MCP is specifically designed for this use case

// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// This server can now be used by AI agents through the MCP protocol
console.log('MCP Browser Automation server is running on port 8000');

// When an AI system wants to browse, it would send requests like:
/*
{
  "action": "createSession",
  "params": {}
}
*/

// And receive responses like:
/*
{
  "sessionId": "session123",
  "status": "success"
}
*/

// The AI can then navigate, interact with pages, and extract content
// through the MCP protocol

// This architecture is optimized for AI systems that implement
// the MCP protocol, but requires more complex integration
// than direct SDK usage like Herd offers

## Migration Guide: From MCP SDK to Herd

Transitioning from MCP SDK to Herd simplifies your browser automation code. Here's a migration guide:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| MCP SDK | Herd | Notes |
| --- | --- | --- |
| MCP server setup | `new HerdClient(apiUrl, token)`  `await client.initialize()` | No server needed with Herd |
| Session creation via protocol | `const devices = await client.listDevices()`  `const device = devices[0]` | Simplified session management |
| Navigation requests | `const page = await device.newPage()`  `await page.goto(url)` | Direct browser control |
| Element interactions via protocol | `await page.click(selector)`  `await page.type(selector, text)` | Simpler interaction API |
| Data extraction with custom scripts | `await page.extract(selectors)` | Powerful extraction API |
| Session closing via protocol | `await client.close()` | Simple cleanup |

### 3. AI Integration Approach

**MCP SDK:**

Code (javascript):
// AI systems implement MCP protocol directly
// Complex integration but designed for AI

// AI system would send requests like:
const request = {
  action: "evaluateElement",
  params: { selector: ".content", attribute: "textContent" }
};
// And process responses

**Herd:**

Code (javascript):
// Build an adapter layer for AI integration
async function getWebContent(url, aiQuery) {
  // Use Herd to fetch and extract the content
  const page = await device.newPage();
  await page.goto(url);
  const content = await page.extract({ /* ... */ });
  await page.close();
  return content;
}

// Then use this in your AI system
const content = await getWebContent(url, query);
const aiResponse = await yourAISystem.process(content);

### 4. Simpler Setup

Herd simplifies your automation workflow:

- No need to run a server process
- Uses your existing browser
- Simple browser extension rather than complex setup
- Supports Chrome, Edge, Brave, Arc, Opera
- Works with browsers you're already using every day

## Why Choose Herd Over MCP SDK?

### 1. Simpler Developer Experience

Herd provides a more straightforward approach to browser automation:
- No complex protocol implementation
- Direct browser control API
- Familiar programming model
- Lower learning curve

### 2. Less Infrastructure to Manage

Herd eliminates the need for additional infrastructure:
- No server to set up and maintain
- Uses your existing browser
- Simpler deployment architecture
- Fewer moving parts

### 3. Powerful Built-in Capabilities

Herd includes powerful features out of the box:
- Sophisticated data extraction API
- Session and cookie management
- Authentication handling
- Browser state persistence

### 4. Broader Applicability

While MCP SDK focuses on AI integration, Herd supports:
- General browser automation
- Web scraping and data extraction
- Testing and monitoring
- Process automation

## Get Started with Herd

Ready to try a more straightforward alternative to MCP SDK? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation tasks with its intuitive API and direct browser control, providing a more accessible alternative to protocol-based approaches like MCP SDK.

================================================================================

Document: Alternative Herd Vs Monitoro
URL: https://herd.garden/docs/alternative-herd-vs-monitoro

# Herd vs Monitoro: Complementary Browser Tools

Herd and Monitoro are sister products created by the same team, designed to serve complementary but distinct purposes. While Herd provides programmatic browser control and multi-browser orchestration capabilities, Monitoro focuses on no-code monitoring and data extraction. Understanding their differences helps you choose the right tool for your specific needs.

## Quick Comparison

| Feature | Herd | Monitoro |
| --- | --- | --- |
| **Primary Focus** | Browser automation & orchestration | Website monitoring & data extraction |
| **Core Function** | Programmatic browser control | Monitoring webpages for changes |
| **Target User** | Developers & automation teams | Non-technical users & business teams |
| **Coding Required** | Yes (JavaScript/Python) | No (visual interface) |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Edge, Brave |
| **Browser Orchestration** | Multiple browsers and devices | Single-focus monitoring |
| **Implementation** | JavaScript/Python SDK | No-code browser extension |
| **Data Processing** | Programmatic data workflows | Automated alerts and integrations |
| **Best For** | Complex automation needs | Monitoring & simple data extraction |

## Understanding the Difference

### Herd

Herd is designed for **programmatic browser control and orchestration**, allowing developers to:
- Automate complex web tasks across multiple browsers
- Extract data from websites at scale
- Leverage their existing browsers for automation
- Build persistent automation workflows
- Orchestrate multiple browser instances simultaneously
- Create sophisticated data processing pipelines
- Works with Chrome, Edge, Brave, Arc, Opera

### Monitoro

Monitoro is designed for **no-code webpage monitoring and alerts**, allowing anyone to:
- Track changes on websites without coding
- Set up alerts when specific data changes
- Extract structured data from webpages
- Send notifications to various channels (Slack, Discord, etc.)
- Create automated workflows based on webpage changes
- Integrate with tools like Google Sheets and Airtable

## When to Use Each Tool

## herd-use

**Use Herd when you need to:**

- Create complex automation scripts
- Orchestrate multiple browsers
- Build sophisticated data extraction pipelines
- Integrate browser automation into your application
- Control browsers programmatically
- Run continuous automation jobs
- Implement advanced web interaction patterns
- Scale automation across multiple devices

**Example use cases:**
- Large-scale data extraction projects
- Multi-step workflow automation
- Integration testing across browsers
- Sophisticated web monitoring systems
- Building browser-based APIs
- Authentication-required data access

## monitoro-use

**Use Monitoro when you need to:**

- Monitor websites for changes without coding
- Get alerts when specific data changes
- Extract data and send it to other tools
- Create simple automations based on website changes
- Set up monitoring dashboards
- Share monitoring alerts with teams

**Example use cases:**
- Price monitoring on e-commerce sites
- Tracking product availability
- Monitoring competitor websites
- Setting up alerts for new content
- Syncing web data to spreadsheets
- Creating webhooks for website changes

## Implementation Comparison

### Herd Implementation

## herd-js

Code (javascript):
// Using Herd for browser automation
import { HerdClient } from '@monitoro/herd';

// Initialize the client
const client = new HerdClient('your-token');
await client.initialize();

// Get a device
const devices = await client.listDevices();
const device = devices[0];

// Create a new page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

// Interact with the page
await page.type('#search', 'automation');
await page.click('.search-button');

// Extract data
const results = await page.extract({
  titles: {
    _$r: '.result-item',
    title: '.item-title',
    description: '.item-description'
  }
});

console.log(results);
await client.close();

## herd-py

Code (python):
# Using Herd for browser automation
from monitoro_herd import HerdClient

# Initialize the client
client = HerdClient('your-token')
client.initialize()

# Get a device
devices = client.list_devices()
device = devices[0]

# Create a new page and automate it
page = device.new_page()
page.goto('https://example.com')

# Interact with the page
page.type('#search', 'automation')
page.click('.search-button')

# Extract data
results = page.extract({
  "titles": {
    "_$r": ".result-item",
    "title": ".item-title",
    "description": ".item-description"
  }
})

print(results)
client.close()

### Monitoro Implementation

Monitoro works through a no-code interface:

1. **Install the Monitoro browser extension**
2. **Create a monitor:**
   - Navigate to the webpage you want to monitor
   - Use the Monitoro interface to select elements to track
   - Set up conditions for when alerts should trigger
   - Configure how often the page should be checked

3. **Configure integrations:**
   - Connect to notification channels like Discord, Slack, or Telegram
   - Set up data destinations like Google Sheets or Airtable
   - Create webhooks for custom integrations

Code:
# No code required for Monitoro - it's all done through the visual interface

# Example monitoring workflow:
1. Set up a monitor for a product page on an e-commerce site
2. Configure it to check for price changes or "In Stock" status
3. Set up alerts to Discord when conditions are met
4. Configure Google Sheets integration to log all price changes

## Using Herd and Monitoro Together

These tools can work together in a complementary fashion:

1. **Use Monitoro for initial monitoring and alerts:**
   - Set up no-code monitors for important websites
   - Get alerted when specific changes occur
   - Collect initial data in spreadsheets

2. **Use Herd for advanced follow-up automation:**
   - Trigger Herd workflows based on Monitoro alerts
   - Perform complex interactions beyond Monitoro's capabilities
   - Extract deeper data that requires authentication or multiple steps
   - Orchestrate actions across multiple browsers

### Example workflow:

1. Monitoro monitors competitor pricing and alerts when prices change
2. A webhook from Monitoro triggers a Herd automation
3. Herd performs a deep analysis across multiple pages, including login-required areas
4. Herd generates a comprehensive report and updates internal systems

## When to Upgrade from Monitoro to Herd

Consider upgrading from Monitoro to Herd when:

1. You need to go beyond simple monitoring to complex automation
2. Your workflows require orchestration of multiple browsers
3. You need to access authenticated areas of websites
4. You require sophisticated data processing capabilities
5. You need programmatic control over browser behavior
6. Your team has development resources for coding solutions

## monitoro-simple

Code:
# Monitoro approach (no-code)

1. Set up a monitor for an e-commerce product page
2. Configure it to check price every hour
3. Send price alerts to Slack channel
4. Log all prices to Google Sheets

## herd-advanced

Code (javascript):
// Herd advanced solution

import { HerdClient } from '@monitoro/herd';

async function monitorPrices() {
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  // Open multiple pages for parallel extraction
  const productUrls = [
    'https://example.com/product/1',
    'https://example.com/product/2',
    'https://example.com/product/3'
  ];
  
  // Login first to access special pricing
  const page = await device.newPage();
  await page.goto('https://example.com/login');
  await page.type('#email', process.env.USERNAME);
  await page.type('#password', process.env.PASSWORD);
  await page.click('#login-button');
  await page.waitForNavigation();
  
  // Now check all products in parallel
  const priceData = [];
  for (const url of productUrls) {
    await page.goto(url);
    
    const data = await page.extract({
      productId: {
        _$: '.product-id',
        regex: 'ID: (.*)'
      },
      regularPrice: '.regular-price',
      salePrice: '.sale-price',
      memberPrice: '.member-price',
      availability: '.stock-status',
      shipping: '.shipping-info'
    });
    
    // Compare with historical data in database
    const priceChanged = await comparePriceWithHistory(data);
    if (priceChanged) {
      // Send custom notification with detailed info
      await sendDetailedAlert(data);
      // Update database with new price info
      await updatePriceDatabase(data);
    }
    
    priceData.push(data);
  }
  
  await client.close();
  return priceData;
}

// Run on schedule
setInterval(monitorPrices, 3600000); // Every hour

## Why Use Both Herd and Monitoro?

### 1. Complementary Capabilities

- **Monitoro:** Fast, no-code setup for basic monitoring needs
- **Herd:** Developer-focused tool for complex automation requirements

### 2. Different Team Members, Different Needs

- **Business Teams:** Can use Monitoro without technical skills
- **Developers:** Can use Herd for advanced customization
- **Operations:** Can set up Monitoro for quick insights
- **Engineering:** Can build on those insights with Herd

### 3. Staged Implementation

Monitoro and Herd support a natural progression:
- Start with simple Monitoro monitoring
- Identify areas that need deeper automation
- Implement targeted Herd solutions for those areas
- Maintain both for their distinct advantages

## Get Started with Herd and Monitoro

Ready to implement a complete browser automation and monitoring solution?

### For Herd:

1. [Create a Herd account](/register)
2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

### For Monitoro:

1. Visit [Monitoro.co](https://monitoro.co) to sign up
2. Install the Monitoro browser extension
3. Navigate to the website you want to monitor
4. Use the visual interface to set up your first monitor

Choose the right tool for each specific need, or use them together for a comprehensive web monitoring and automation solution.

================================================================================

Document: Alternative Herd Vs Puppeteer
URL: https://herd.garden/docs/alternative-herd-vs-puppeteer

# Herd vs Puppeteer: A Better Alternative for Browser Automation

In the world of browser automation and web scraping, Puppeteer has long been a popular choice for developers. However, Herd provides a compelling alternative that addresses many of Puppeteer's limitations while offering unique advantages for modern development workflows.

## Quick Comparison

| Feature | Herd | Puppeteer |
| --- | --- | --- |
| **Browser Type** | Your existing browser | Separate Chromium instance |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium, Chrome (limited Firefox) |
| **Infrastructure Requirements** | None (uses your browser) | Requires separate browser instances |
| **Authentication** | Uses existing sessions | Requires manual setup |
| **Setup Complexity** | Simple extension installation | More complex setup |
| **Programming Languages** | JavaScript, Python | JavaScript/TypeScript only |
| **Session Management** | Persistent across runs | Must be rebuilt each run |
| **Resource Usage** | Minimal (shared with browser) | High (separate processes) |

## Key Differences in Depth

### Infrastructure Requirements

**Puppeteer:**
- Requires installing and managing separate Chromium instances
- Needs dedicated resources for each browser instance
- Increases infrastructure costs in cloud environments
- Requires managing updates to the Chromium engine

**Herd:**
- Uses your existing browser installation
- No additional browser instances to manage
- Significantly lower resource utilization
- Leverages native browser capabilities

### Setup and Installation Process

## herd

Code (bash):
# Install the Herd SDK
npm install @monitoro/herd

# Then install the browser extension and connect your browser
# That's it! No browser installation or management needed

## puppeteer

Code (bash):
# Install Puppeteer
npm install puppeteer

# Puppeteer will download and manage its own Chromium instance
# You'll need to handle this in deployment environments
# Additional setup for proxies, authentication, etc.

### Browser Support

**Puppeteer:**
- Primarily designed for Chrome/Chromium browsers
- Limited experimental support for Firefox
- No support for Safari or Edge

**Herd:**
- Works with Chrome, Edge, Brave, Arc, Opera 
- Consistent experience across all supported Chromium-based browsers

### Authentication and Session Handling

**Puppeteer:**
- Sessions must be recreated for each new Puppeteer instance
- Requires manually handling cookies and authentication flows
- Accessing logged-in state requires additional code
- Difficult to use existing authenticated sessions

**Herd:**
- Uses your existing browser's authenticated sessions
- No need to handle authentication separately
- Persistent cookies and storage between sessions
- Access to browser extensions that manage authentication

## Use Case Comparisons

### Data Extraction

## herd-extract

Code (javascript):
// Initialize the client and connect to your browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Extract data using simple selectors
const page = await device.newPage();
await page.goto('https://example.com');
const data = await page.extract({
  title: 'h1',
  description: 'p',
  links: {
    _$r: 'a',  // Extract all links
    href: { attribute: 'href' },
    text: ':root'
  }
});

console.log(data);

## puppeteer-extract

Code (javascript):
// Launch a separate browser instance
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');

// Extract data with multiple evaluations
const data = {
  title: await page.$eval('h1', el => el.textContent),
  description: await page.$eval('p', el => el.textContent),
  links: await page.$eval('a', elements => 
    elements.map(el => ({
      href: el.getAttribute('href'),
      text: el.textContent
    }))
  )
};

console.log(data);
await browser.close();

### Web Automation

## herd-auto

Code (javascript):
// Initialize and connect to your browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Use the existing browser with current sessions
const page = await device.newPage();
await page.goto('https://myapp.com/dashboard'); // Already logged in

// Interact with the page
await page.click('.new-item-button');
await page.type('#item-name', 'New Task');
await page.click('.save-button');

// Process results
const notification = await page.waitForSelector('.success-message');
console.log(notification.textContent);

## puppeteer-auto

Code (javascript):
// Launch a separate browser instance
const browser = await puppeteer.launch();
const page = await browser.newPage();

// Need to handle login first
await page.goto('https://myapp.com/login');
await page.type('#username', 'user@example.com');
await page.type('#password', 'password');
await page.click('.login-button');
await page.waitForNavigation();

// Now navigate to dashboard after login
await page.goto('https://myapp.com/dashboard');

// Interact with the page
await page.click('.new-item-button');
await page.type('#item-name', 'New Task');
await page.click('.save-button');

// Process results
const notification = await page.waitForSelector('.success-message');
console.log(await notification.evaluate(el => el.textContent));
await browser.close();

## Migration Guide: From Puppeteer to Herd

Transitioning from Puppeteer to Herd is straightforward. Here's a simple migration guide:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   npm install @monitoro/herd

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Puppeteer | Herd | Notes |
| --- | --- | --- |
| `const browser = await puppeteer.launch()` | `const client = new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `const page = await browser.newPage()` | `const page = await device.newPage()` | Similar API, different source |
| `await page.goto(url)` | `await page.goto(url)` | Identical usage |
| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |
| `await page.click(selector)` | `await page.click(selector)` | Identical usage |
| `await page.$eval(selector, fn)` | `const element = await page.$(selector)`  `await element.evaluate(fn)` | Slightly different approach |
| `await page.screenshot()` | `await page.screenshot()` | Identical usage |
| `await browser.close()` | `await client.close()` | Browser stays open, just disconnects client |

## Why Choose Herd Over Puppeteer?

### 1. No Infrastructure Management

Herd eliminates the need to maintain separate browser instances, significantly reducing:
- Memory and CPU usage
- Infrastructure costs for cloud deployments
- Maintenance overhead for browser updates

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to handle authentication flows in code
- Access to sites that require complex authentication
- Use existing cookies, local storage, and sessions

### 3. Cross-Browser Compatibility

While Puppeteer is primarily focused on Chromium:
- Herd works across Chrome, Edge, and Brave
- Same code works on any supported browser
- Test on multiple browsers with minimal configuration changes

### 4. Simpler Development Experience

Herd provides:
- More intuitive APIs for common tasks
- Better debugging experience (view automation in real browser)
- Easier integration with existing workflows

## Get Started with Herd Today

Ready to try a better alternative to Puppeteer? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation workflows while reducing infrastructure costs and complexity.

================================================================================

Document: Alternative Herd Vs Selenium
URL: https://herd.garden/docs/alternative-herd-vs-selenium

# Herd vs Selenium: A More Efficient Browser Automation Alternative

Selenium has been the industry standard for browser automation for many years, but its architecture presents significant challenges for modern development workflows. Herd offers a compelling alternative that addresses many of Selenium's pain points while providing a more intuitive experience.

## Quick Comparison

| Feature | Herd | Selenium |
| --- | --- | --- |
| **Driver Requirements** | No drivers needed | Requires WebDriver for each browser |
| **Browser Type** | Your existing browser | Creates new browser instances |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Firefox, Edge, Safari, IE |
| **Infrastructure** | Uses your existing browser | Requires WebDriver servers |
| **Authentication** | Uses existing sessions | Requires manual setup |
| **Programming Languages** | JavaScript, Python | Java, Python, C#, Ruby, JavaScript |
| **Setup Complexity** | Simple browser extension | WebDriver setup for each browser |
| **Maintenance Required** | Minimal (browser updates only) | High (drivers must match browser versions) |
| **Session Management** | Persistent across runs | Must be rebuilt each run |

## Key Differences in Depth

### Driver and Infrastructure Requirements

**Selenium:**
- Requires installation and management of WebDrivers for each browser
- WebDrivers must be kept in sync with browser versions
- Separate browser instances for automation
- Complex setup in CI/CD environments
- High resource usage (separate process for each browser)

**Herd:**
- No WebDrivers or separate drivers needed
- Works directly with your installed browser
- No version synchronization issues
- Simple setup in any environment
- Low resource usage (shares existing browser process)

### Setup and Installation Process

## herd

Code (bash):
# JavaScript
npm install @monitoro/herd

# Python
pip install herd-client

# Then install the browser extension and connect your browser
# That's it! No WebDrivers or browser drivers to manage

## selenium

Code (bash):
# JavaScript
npm install selenium-webdriver

# Python
pip install selenium

# Additionally, you must:
# 1. Download the correct WebDriver for each browser
# 2. Ensure WebDriver versions match browser versions
# 3. Add WebDrivers to your PATH or specify their location
# 4. Update WebDrivers when browsers update

### Browser Support and Consistency

**Selenium:**
- Supports all major browsers including Chrome, Firefox, Safari, Edge, and IE
- Requires separate WebDriver configurations for each browser
- May exhibit inconsistent behavior across different browsers
- Requires updates when browsers update

**Herd:**
- Supports Chrome, Edge, Brave, Arc, Opera
- Uniform behavior across supported Chromium-based browsers
- No additional configuration needed for different browsers

### Authentication and Session Handling

**Selenium:**
- Sessions are isolated and temporary
- Requires manually handling authentication steps
- Session storage is cleared between runs
- Difficult to use existing authenticated sessions

**Herd:**
- Uses your browser's existing authenticated sessions
- Access sites you're already logged into
- Persistent cookies and storage
- Access to browser extensions that manage authentication

## Use Case Comparisons

### Web Testing

## herd-test

Code (javascript):
// JavaScript
import { HerdClient } from '@monitoro/herd';

async function runTest() {
  // Connect to your existing browser
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  // Create a new page for testing
  const page = await device.newPage();
  await page.goto('https://example.com');
  
  // Test interactions
  await page.click('.nav-item');
  await page.waitForSelector('.content-loaded');
  
  // Assert condition
  const header = await page.$('.header');
  const text = await header.getText();
  console.assert(text.includes('Expected Text'), 'Header text verification failed');
  
  // Cleanup
  await page.close();
  await client.close();
}

runTest();

## selenium-test

Code (javascript):
// JavaScript
import { Builder, By, until } from 'selenium-webdriver';

async function runTest() {
  // Launch a separate browser instance with WebDriver
  const driver = await new Builder()
    .forBrowser('chrome')
    .build();
  
  try {
    // Navigate to the test site
    await driver.get('https://example.com');
    
    // Test interactions
    await driver.findElement(By.css('.nav-item')).click();
    await driver.wait(until.elementLocated(By.css('.content-loaded')), 5000);
    
    // Assert condition
    const header = await driver.findElement(By.css('.header'));
    const text = await header.getText();
    console.assert(text.includes('Expected Text'), 'Header text verification failed');
  } finally {
    // Always close the browser
    await driver.quit();
  }
}

runTest();

### Data Extraction

## herd-extract

Code (javascript):
// JavaScript
import { HerdClient } from '@monitoro/herd';

async function extractData() {
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  const page = await device.newPage();
  await page.goto('https://example.com/products');
  
  // Extract product data with a single call
  const products = await page.extract({
    items: {
      _$r: '.product-card',  // Repeat for each product card
      name: '.product-name',
      price: '.product-price',
      rating: '.product-rating',
      inStock: '.stock-status'
    }
  });
  
  console.log(products.items);
  await client.close();
}

extractData();

## selenium-extract

Code (javascript):
// JavaScript
import { Builder, By } from 'selenium-webdriver';

async function extractData() {
  const driver = await new Builder()
    .forBrowser('chrome')
    .build();
  
  try {
    await driver.get('https://example.com/products');
    
    // Extract product data with multiple queries
    const productElements = await driver.findElements(By.css('.product-card'));
    
    const products = [];
    for (const element of productElements) {
      const name = await element.findElement(By.css('.product-name')).getText();
      const price = await element.findElement(By.css('.product-price')).getText();
      
      let rating = '';
      try {
        rating = await element.findElement(By.css('.product-rating')).getText();
      } catch (e) {
        // Element might not exist
        rating = 'N/A';
      }
      
      let inStock = false;
      try {
        const stockText = await element.findElement(By.css('.stock-status')).getText();
        inStock = stockText.includes('In Stock');
      } catch (e) {
        // Element might not exist
      }
      
      products.push({ name, price, rating, inStock });
    }
    
    console.log(products);
  } finally {
    await driver.quit();
  }
}

extractData();

## Migration Guide: From Selenium to Herd

Transitioning from Selenium to Herd is straightforward. Here's a guide to help you migrate your existing code:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   # JavaScript
   npm install @monitoro/herd
   
   # Python
   pip install herd-client

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Selenium | Herd | Notes |
| --- | --- | --- |
| `new Builder().forBrowser().build()` | `new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `driver.get(url)` | `await page.goto(url)` | Similar syntax |
| `driver.findElement(By.css(selector))` | `await page.$(selector)` | Herd uses CSS selectors directly |
| `element.sendKeys(text)` | `await element.type(text)` | Different method name |
| `element.click()` | `await element.click()` | Identical usage |
| `driver.wait(until.elementLocated())` | `await page.waitForSelector(selector)` | Similar functionality |
| `driver.quit()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Handling Multiple Browsers

**Selenium:**

Code (javascript):
const chrome = await new Builder().forBrowser('chrome').build();
const firefox = await new Builder().forBrowser('firefox').build();

**Herd:**

Code (javascript):
// Connect to different browsers that are registered as devices
const chromiumDevice = devices.find(d => d.name === 'Chrome Browser');

## Why Choose Herd Over Selenium?

### 1. No WebDriver Headaches

Herd eliminates the need for WebDrivers, solving the most common Selenium pain points:
- No driver version compatibility issues
- No driver installation or updates needed
- No broken tests due to browser updates

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to write and maintain authentication code
- Access to sites requiring complex authentication
- Use existing cookies, local storage, and sessions

### 3. Simplified Setup and Maintenance

Herd significantly reduces the overhead of browser automation:
- No complex CI/CD configuration
- No driver path management
- No browser version tracking

### 4. Intuitive API for Modern Development

Herd provides:
- Clean, Promise-based API
- Powerful data extraction capabilities
- Better debugging experience (view automation in your browser)

## Get Started with Herd Today

Ready to try a more efficient alternative to Selenium? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation workflows while eliminating the most common frustrations of working with Selenium.

================================================================================

Document: Automation Basics
URL: https://herd.garden/docs/automation-basics

# Automation Basics

Welcome to Monitoro Herd! This guide will walk you through creating your first browser automation step-by-step. We'll start with the basics and gradually build up to more complex examples, explaining each concept along the way.

## javascript

## JavaScript SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your JavaScript environment and install the Herd SDK:

1. Make sure you have Node.js installed (version 14 or higher recommended)
2. Create a new project directory
3. Install the SDK using npm:

Code (bash):
npm install @monitoro/herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (javascript):
// Import the Herd client
import { HerdClient } from '@monitoro/herd';

// Initialize the client with your API URL and token
const client = new HerdClient('your-token');

// Always initialize the client before using it
await client.initialize();
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

After initializing the client, you need to connect to a device (browser) that will perform the automation:

Code (javascript):
// Get a list of available devices
const devices = await client.listDevices();

// Connect to the first available device
const device = devices[0];

console.log(`Connected to device: ${device.id}`);

This code retrieves all devices registered to your account and connects to the first one. In a production environment, you might want to select a specific device based on its properties or availability.

### Creating a Page and Navigating

Now that you're connected to a device, you can create a new browser page and navigate to a website:

Code (javascript):
// Create a new page in the browser
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com');

console.log('Successfully navigated to example.com');

The `goto` method loads the specified URL and waits for the page to load. By default, it waits until the page's `load` event is fired, but you can customize this behavior with options.

### Extracting Basic Information

One of the most common automation tasks is extracting information from web pages. Here's how to extract basic elements:

Code (javascript):
// Extract content using CSS selectors
const content = await page.extract({
  title: 'h1',           // Extracts the main heading
  description: 'p',      // Extracts the first paragraph
  link: 'a'              // Extracts the first link text
});

// Display the extracted content
console.log('Extracted content:');
console.log(`Title: ${content.title}`);
console.log(`Description: ${content.description}`);
console.log(`Link: ${content.link}`);

The `extract` method uses CSS selectors to find elements on the page and extract their text content. This is a powerful way to scrape structured data from websites.

### Proper Resource Management

Always remember to close resources when you're done with them to prevent memory leaks:

Code (javascript):
// Close the page when done
await page.close();

// Close the client connection
await client.close();

### Putting It All Together

Here's a complete example that combines all the steps above into a single function:

Code (javascript):
import { HerdClient } from '@monitoro/herd';

async function runBasicAutomation() {
  const client = new HerdClient('your-token');
  
  try {
    // Initialize the client
    await client.initialize();
    console.log('Client initialized successfully');
    
    // Get the first available device
    const devices = await client.listDevices();
    if (devices.length === 0) {
      throw new Error('No devices available');
    }
    const device = devices[0];
    console.log(`Connected to device: ${device.id}`);
    
    // Create a new page
    const page = await device.newPage();
    console.log('New page created');
    
    // Navigate to a website
    console.log('Navigating to example.com...');
    await page.goto('https://example.com');
    console.log('Navigation complete');
    
    // Extract content
    console.log('Extracting content...');
    const content = await page.extract({
      title: 'h1',
      description: 'p',
      link: 'a'
    });
    
    // Display the extracted content
    console.log('\nExtracted content:');
    console.log(`Title: ${content.title}`);
    console.log(`Description: ${content.description}`);
    console.log(`Link: ${content.link}`);
    
  } catch (error) {
    console.error('Error during automation:', error);
  } finally {
    // Always close the client when done
    console.log('Closing client connection...');
    await client.close();
    console.log('Client connection closed');
  }
}

// Run the automation
runBasicAutomation();

### Interacting with Web Pages

Now let's explore how to interact with elements on a page. This includes clicking buttons, typing text, and handling forms.

#### Finding Elements

Before interacting with an element, you need to find it on the page:

Code (javascript):
// Find an element using a CSS selector
const searchBox = await page.$('input[name="q"]');

// Check if the element was found
if (searchBox) {
  console.log('Search box found');
} else {
  console.log('Search box not found');
}

The `


  
  
  
  
  herd.garden | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   method returns the first element that matches the CSS selector, or `null` if no element is found.

#### Typing Text

To type text into an input field:

Code (javascript):
// Type text into an input field
await page.type('input[name="q"]', 'Monitoro Herd automation');
console.log('Text entered into search box');

The `type` method finds the element using the CSS selector and simulates typing the specified text.

#### Clicking Elements

To click a button or link:

Code (javascript):
// Click a button
await page.click('input[type="submit"]');
console.log('Search button clicked');

By default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:

Code (javascript):
// Click and wait for navigation
await page.click('input[type="submit"]', { 
  waitForNavigation: 'networkidle2' 
});
console.log('Search button clicked and navigation completed');

The `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.

#### Waiting for Elements

Sometimes you need to wait for elements to appear on the page:

Code (javascript):
// Wait for an element to appear
await page.waitForSelector('#search');
console.log('Search results have loaded');

This is useful when dealing with dynamic content that loads after the initial page load.

#### Search Engine Example

Let's put these concepts together in a search engine example:

Code (javascript):
async function searchExample() {
  const client = new HerdClient('your-token');
  
  try {
    await client.initialize();
    const devices = await client.listDevices();
    const device = devices[0];
    const page = await device.newPage();
    
    // Navigate to a search engine
    console.log('Navigating to Google...');
    await page.goto('https://www.google.com');
    
    // Type in the search box
    console.log('Entering search query...');
    await page.type('input[name="q"]', 'Monitoro Herd automation');
    
    // Submit the search form and wait for results
    console.log('Submitting search...');
    await page.click('input[type="submit"]', { 
      waitForNavigation: 'networkidle2' 
    });
    
    // Wait for results to load completely
    console.log('Waiting for search results...');
    await page.waitForSelector('#search');
    
    // Extract search result titles
    console.log('Extracting search results...');
    const searchResults = await page.extract({
      titles: {
        _$r: '#search .g h3',  // _$r extracts multiple elements
        text: ':root'           // For each match, get its text
      }
    });
    
    // Display the search result titles
    console.log('\nSearch Results:');
    searchResults.titles.forEach((result, index) => {
      console.log(`${index + 1}. ${result.text}`);
    });
    
  } catch (error) {
    console.error('Error:', error);
  } finally {
    await client.close();
  }
}

## python

## Python SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your Python environment and install the Herd SDK:

1. Make sure you have Python 3.8+ installed
2. Create a virtual environment (recommended)
3. Install the SDK using pip:

Code (bash):
pip install monitoro-herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (python):
# Import the Herd client
from monitoro_herd import HerdClient

# Initialize the client with your API URL and token
client = HerdClient('your-token')

# Always initialize the client before using it
client.initialize()
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

Next, connect to a device that will run your automation:

Code (python):
# Get available devices
devices = await client.list_devices()

# Connect to the first device
device = devices[0]

print(f"Connected to device: {device.id}")

### Creating a Page and Navigating

Now create a browser page and navigate to a website:

Code (python):
# Create a new page
page = await device.new_page()

# Navigate to a website
await page.goto("https://example.com")

print("Successfully navigated to example.com")

### Extracting Basic Information

Extract information from the page using CSS selectors:

Code (python):
# Extract basic information
data = await page.extract({
    "title": "h1",          # Main heading
    "description": "p",     # First paragraph
    "link": "a"             # First link text
})

# Display the extracted data
print("Extracted data:")
print(f"Title: {data['title']}")
print(f"Description: {data['description']}")
print(f"Link: {data['link']}")

### Resource Management

Always close resources when you're done:

Code (python):
# Close the page
await page.close()

# Close the client
await client.close()

### Complete Basic Example

Here's a complete example putting all these concepts together:

Code (python):
import asyncio
from monitoro_herd import HerdClient

async def basic_extraction():
    # Initialize the client
    client = HerdClient("your-token")
    
    try:
        # Initialize the connection
        await client.initialize()
        print("Client initialized successfully")
        
        # Get the first available device
        devices = await client.list_devices()
        if not devices:
            raise Exception("No devices available")
        device = devices[0]
        print(f"Connected to device: {device.id}")
        
        # Create a new page
        page = await device.new_page()
        print("New page created")
        
        # Navigate to a website
        print("Navigating to example.com...")
        await page.goto("https://example.com")
        print("Navigation complete")
        
        # Extract data using simple selectors
        print("Extracting content...")
        data = await page.extract({
            "title": "h1",
            "description": "p",
            "link": "a"
        })
        
        # Display the extracted data
        print("\nExtracted data:")
        print(f"Title: {data['title']}")
        print(f"Description: {data['description']}")
        print(f"Link: {data['link']}")
        
    except Exception as e:
        print(f"Error during automation: {e}")
    finally:
        # Always close resources
        print("Closing client connection...")
        await client.close()
        print("Client connection closed")

# Run the async function
asyncio.run(basic_extraction())

### Working with Lists and Structured Data

One of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.

#### The `_$r` Selector

To extract multiple elements that match a pattern, use the `_$r` (repeat) selector:

Code (python):
# Extract a list of items
data = await page.extract({
    "items": {
        "_$r": ".item",       # Find all elements with class "item"
        "name": ".item-name", # For each item, get the name
        "price": ".price"     # For each item, get the price
    }
})

# Access the extracted items
for item in data["items"]:
    print(f"Name: {item['name']}, Price: {item['price']}")

The `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.

#### Extracting Attributes

Sometimes you need to extract an attribute rather than the text content:

Code (python):
# Extract links and their href attributes
data = await page.extract({
    "links": {
        "_$r": "a",              # Find all links
        "text": ":root",         # Get the link text
        "url": {
            "_
quot;: ":root", # Reference the same element "attribute": "href" # Get its href attribute } } }) # Display the links for link in data["links"]: print(f"Link: {link['text']} -> {link['url']}") #### Hacker News Example Let's put these concepts together to scrape stories from Hacker News: Code (python): import asyncio from monitoro_herd import HerdClient async def scrape_hacker_news(): client = HerdClient("your-token") try: await client.initialize() devices = await client.list_devices() device = devices[0] page = await device.new_page() # Navigate to Hacker News print("Navigating to Hacker News...") await page.goto("https://news.ycombinator.com") # Extract stories and their metadata print("Extracting stories...") data = await page.extract({ # Extract the story elements "stories": { "_$r": ".athing", # Each story row "title": ".titleline > a", # Story title "site": ".sitestr", # Source website "link": { "_
quot;: ".titleline > a", # Story link "attribute": "href" # Get the URL } }, # Extract the metadata (points, author, etc.) "metadata": { "_$r": ".subline", # Metadata rows "points": ".score", # Points count "author": ".hnuser", # Author username "time": ".age" # Submission time } }) # Combine stories with their metadata # (They're in separate lists but in the same order) combined_stories = list(zip(data["stories"], data["metadata"])) # Display the first 3 stories print(f"\nExtracted {len(combined_stories)} stories:") for i, (story, meta) in enumerate(combined_stories[:3]): print(f"\nStory {i+1}:") print(f"Title: {story['title']}") if "site" in story: print(f"Site: {story['site']}") print(f"Link: {story['link']}") if "points" in meta: print(f"Points: {meta['points']}") if "author" in meta: print(f"Author: {meta['author']}") if "time" in meta: print(f"Posted: {meta['time']}") finally: await page.close() await client.close() # Run the function asyncio.run(scrape_hacker_news()) ## Tips for Successful Automation 1. **Start Simple**: Begin with basic extractions before moving to complex interactions 2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely 3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks 4. **Close Resources**: Always close pages and clients when done to avoid resource leaks 5. **Test Incrementally**: Build your automation step by step, testing each part 6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods 7. **Debug with Screenshots**: Take screenshots during automation to see what's happening ## Next Steps Now that you've created your first automation, you can: - Explore more complex selectors and extraction patterns - Learn how to handle authentication and login flows - Set up scheduled automations for regular data collection - Integrate with your existing systems via APIs ================================================================================ Document: Connect Your Browser URL: https://herd.garden/docs/connect-your-browser # Connect your Browser to Herd After installing the Herd extension, you need to connect your browser to your account. This guide explains how to establish and manage connections between your browsers and the Herd platform. You can connect multiple browsers to the same account. Learn more about [managing multiple devices](/docs/device-management). ## Device Registration Before you can connect a browser, you need to register the device in your Herd dashboard: 1. Log in to your Herd account 2. Navigate to the "Devices" section 3. Click "Register New Device" 4. Enter a descriptive name for the device (e.g., "Work Laptop - Chrome") 5. Choose appropriate tags if you're organizing devices into groups 6. Click "Create Registration" 7. Copy the registration code that appears (you'll need this to connect the browser) ## Connecting Your Browser Once you have a registration code, follow these steps to connect your browser: 1. Make sure the Herd extension is installed in your browser 2. Click the Herd icon in your browser toolbar 3. Select "Connect Browser" or "Register Device" from the menu 4. Paste the registration code into the field 5. Click "Connect" 6. You should see a confirmation message indicating the browser is now connected ## Managing Active Connections You can view and manage all your connected browsers from the Herd dashboard: ### Viewing Connected Devices 1. Log in to your Herd account 2. Navigate to the "Devices" section 3. The "Active Connections" tab shows all currently connected browsers 4. Each connection displays information such as: - Device name - Browser type and version - Connection status - Last activity timestamp ### Remote Actions Once a browser is connected, you can perform various remote actions: 1. **Remote Control**: Initiate a remote control session to view and interact with the browser 2. **Capture Screenshot**: Take a snapshot of the current browser window 3. **Tab Management**: View, open, close, or navigate tabs 4. **Bookmark Management**: View or modify the browser's bookmarks 5. **History Access**: View browsing history (if permissions allow) ## Connection Troubleshooting If you're having trouble connecting your browser to Herd, try these solutions: ### Connection Failures * Verify that the registration code is correct and hasn't expired * Make sure the browser is online and has a stable internet connection * Check that the Herd extension is properly installed and enabled * Try restarting your browser ### Dropped Connections * Check your network stability * Ensure the browser hasn't entered sleep mode * Verify that the extension hasn't been disabled * Check if a browser update has affected the extension ### Reconnecting If a connection is lost, you can easily reconnect: 1. Click the Herd icon in your browser toolbar 2. If the connection status shows "Disconnected," click "Reconnect" 3. If prompted, enter your registration code again 4. Wait for the connection to be reestablished ## Connection Security All connections between your browser and the Herd platform are secured with end-to-end encryption. Your data remains private and protected throughout the connection process. For more information on security features, see our [Security & Privacy](security-privacy) documentation. ================================================================================ Document: Data Extraction URL: https://herd.garden/docs/data-extraction # Data Extraction Welcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines. ## Understanding Selectors Herd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system. ### Basic Extraction ## javascript The simplest form of extraction uses CSS selectors to target elements: Code (javascript): // Extract basic text content const data = await page.extract({ title: 'h1', // Extracts the main heading description: 'p', // Extracts the first paragraph link: 'a' // Extracts the first link text }); console.log(data.title); // "Welcome to Our Website" console.log(data.description); // "This is our homepage." ## python The simplest form of extraction uses CSS selectors to target elements: Code (python): # Extract basic text content data = await page.extract({ "title": "h1", # Extracts the main heading "description": "p", # Extracts the first paragraph "link": "a" # Extracts the first link text }) print(data["title"]) # "Welcome to Our Website" print(data["description"]) # "This is our homepage." ### Advanced Selector Syntax ## javascript For more complex extraction needs, use the expanded object syntax: Code (javascript): const data = await page.extract({ title: { _$: 'h1', // CSS selector attribute: 'id' // Extract the ID attribute instead of text }, price: { _$: '.price', // Target price element pipes: ['parseNumber'] // Apply transformation } }); ## python For more complex extraction needs, use the expanded object syntax: Code (python): data = await page.extract({ "title": { "_
quot;: "h1", # CSS selector "attribute": "id" # Extract the ID attribute instead of text }, "price": { "_
quot;: ".price", # Target price element "pipes": ["parseNumber"] # Apply transformation } }) ### Extracting Lists of Items ## javascript To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (javascript): const data = await page.extract({ items: { _$r: '.item', // Find all elements with class "item" title: 'h2', // For each item, get the title price: '.price', // For each item, get the price date: 'time' // For each item, get the date } }); // Access the extracted items data.items.forEach(item => { console.log(`${item.title}: ${item.price}, Posted: ${item.date}`); }); ## python To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (python): data = await page.extract({ "items": { "_$r": ".item", # Find all elements with class "item" "title": "h2", # For each item, get the title "price": ".price", # For each item, get the price "date": "time" # For each item, get the date } }) # Access the extracted items for item in data["items"]: print(f"{item['title']}: {item['price']}, Posted: {item['date']}") ### Nested Extraction ## javascript You can nest selectors to extract hierarchical data: Code (javascript): const data = await page.extract({ product: { name: '.product-name', details: { _$: '.product-details', specs: { _$r: '.spec-item', label: '.spec-label', value: '.spec-value' } } } }); ## python You can nest selectors to extract hierarchical data: Code (python): data = await page.extract({ "product": { "name": ".product-name", "details": { "_
quot;: ".product-details", "specs": { "_$r": ".spec-item", "label": ".spec-label", "value": ".spec-value" } } } }) ## Special Selectors Herd provides special selectors to handle various extraction scenarios: ### Root Selector (`:root`) The `:root` selector refers to the current element in context: ## javascript Code (javascript): const data = await page.extract({ items: { _$r: '.item', someElement: ':root', // Extract text of the .item element itself classes: { _$: ':root', attribute: 'class' // Extract class attribute of the same element } } }); ## python Code (python): data = await page.extract({ "items": { "_$r": ".item", "someElement": ":root", # Extract text of the .item element itself "classes": { "_
quot;: ":root", "attribute": "class" # Extract class attribute of the same element } } }) ### Property Extraction You can extract JavaScript properties from elements: ## javascript Code (javascript): const data = await page.extract({ dimensions: { _$: '.box', property: 'getBoundingClientRect' // Get element dimensions }, html: { _$: '.content', property: 'innerHTML' // Get inner HTML } }); ## python Code (python): data = await page.extract({ "dimensions": { "_
quot;: ".box", "property": "getBoundingClientRect" # Get element dimensions }, "html": { "_
quot;: ".content", "property": "innerHTML" # Get inner HTML } }) ## Transformation Pipelines Herd includes powerful transformation pipelines to process extracted data: ### Available Transformations | Pipe | Description | Example Input | Example Output | |------|-------------|--------------|----------------| | `trim` | Removes whitespace from start/end | `" Hello "` | `"Hello"` | | `toLowerCase` | Converts text to lowercase | `"HELLO"` | `"hello"` | | `toUpperCase` | Converts text to uppercase | `"hello"` | `"HELLO"` | | `parseNumber` | Extracts numbers from text | `"$1,2K.45"` | `1200.45` | | `parseDate` | Converts text to date | `"2024-01-15"` | `"2024-01-15T00:00:00.000Z"` | | `parseDateTime` | Converts text to datetime | `"2024-01-15T12:00:00Z"` | `"2024-01-15T12:00:00.000Z"` | ### Using Transformations Apply transformations using the `pipes` property: ## javascript Code (javascript): const data = await page.extract({ price: { _$: '.price', pipes: ['parseNumber'] // Convert "$1,234.56" to 1234.56 }, title: { _$: 'h1', pipes: ['trim', 'toLowerCase'] // Apply multiple transformations } }); ## python Code (python): data = await page.extract({ "price": { "_
quot;: ".price", "pipes": ["parseNumber"] # Convert "$1,234.56" to 1234.56 }, "title": { "_
quot;: "h1", "pipes": ["trim", "toLowerCase"] # Apply multiple transformations } }) ### Handling Currency and Large Numbers The `parseNumber` transformation handles various formats: ## javascript Code (javascript): const data = await page.extract({ price1: { _$: '.price-1', // Contains "$1,234.56" pipes: ['parseNumber'] // Result: 1234.56 }, price2: { _$: '.price-2', // Contains "$1.5M" pipes: ['parseNumber'] // Result: 1500000 }, price3: { _$: '.price-3', // Contains "1.5T€" pipes: ['parseNumber'] // Result: 1500000000000 } }); ## python Code (python): data = await page.extract({ "price1": { "_
quot;: ".price-1", # Contains "$1,234.56" "pipes": ["parseNumber"] # Result: 1234.56 }, "price2": { "_
quot;: ".price-2", # Contains "$1.5M" "pipes": ["parseNumber"] # Result: 1500000 }, "price3": { "_
quot;: ".price-3", # Contains "1.5T€" "pipes": ["parseNumber"] # Result: 1500000000000 } }) ## Real-World Examples Let's look at some practical examples of data extraction: ### E-commerce Product Listing Extract products from a search results page: ## javascript Code (javascript): const searchResults = await page.extract({ products: { _$r: '[data-component-type="s-search-result"]', title: { _$: 'h2 .a-link-normal', pipes: ['trim'] }, price: { _$: '.a-price .a-offscreen', pipes: ['parseNumber'] }, rating: { _$: '.a-icon-star-small .a-icon-alt', pipes: ['trim'] }, reviews: { _$: '.a-size-base.s-underline-text', pipes: ['trim'] } } }); ## python Code (python): searchResults = await page.extract({ "products": { "_$r": '[data-component-type="s-search-result"]', "title": { "_
quot;: "h2 .a-link-normal", "pipes": ["trim"] }, "price": { "_
quot;: ".a-price .a-offscreen", "pipes": ["parseNumber"] }, "rating": { "_
quot;: ".a-icon-star-small .a-icon-alt", "pipes": ["trim"] }, "reviews": { "_
quot;: ".a-size-base.s-underline-text", "pipes": ["trim"] } } }) ### News Article List Extract articles from a news site: ## javascript Code (javascript): const articles = await page.extract({ items: { _$r: '.item', title: { _$: 'h2', pipes: ['trim', 'toLowerCase'] }, price: { _$: '.price', pipes: ['parseNumber'] }, date: { _$: 'time', pipes: ['parseDate'] } } }); ## python Code (python): articles = await page.extract({ "items": { "_$r": ".item", "title": { "_
quot;: "h2", "pipes": ["trim", "toLowerCase"] }, "price": { "_
quot;: ".price", "pipes": ["parseNumber"] }, "date": { "_
quot;: "time", "pipes": ["parseDate"] } } }) ## Advanced Techniques ### Handling Dynamic Content For dynamic content that loads after the page is ready: ## javascript Code (javascript): // Wait for dynamic content to load await page.waitForElement('#dynamic span'); // Then extract the content const data = await page.extract({ content: '#dynamic span' }); ## python Code (python): # Wait for dynamic content to load await page.waitForElement('#dynamic span') # Then extract the content data = await page.extract({ "content": "#dynamic span" }) ### Extracting Page Metadata Extract information about the page itself: ## javascript Code (javascript): const pageInfo = await page.extract({ title: 'title', metaDescription: 'meta[name="description"]', canonicalUrl: { _$: 'link[rel="canonical"]', attribute: 'href' } }); ## python Code (python): pageInfo = await page.extract({ "title": "title", "metaDescription": 'meta[name="description"]', "canonicalUrl": { "_
quot;: 'link[rel="canonical"]', "attribute": "href" } }) ## Tips for Effective Extraction 1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction 2. **Test Incrementally**: Build your extraction schema step by step, testing each part 3. **Handle Missing Data**: Always account for elements that might not exist on the page 4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed 5. **Combine with Interactions**: For complex sites, interact with the page before extraction ## Next Steps Now that you understand Herd's data extraction system, you can: - Create complex extraction schemas for any website - Transform raw data into structured, usable formats - Build powerful automations that collect and process web data ================================================================================ Document: Device Management URL: https://herd.garden/docs/device-management # Device Management Managing your devices in Herd is simple and intuitive. This guide will walk you through the various actions you can perform on the Devices page. ## Understanding the Devices Page The Devices page is your central hub for managing all browsers and headless devices connected to your Herd account. Here you can: - View all your connected devices - Register new devices - Access device registration URLs - Delete devices you no longer need ## Viewing Your Devices When you visit the Devices page, you'll see a list of all your registered devices. For each device, you can view: - Device name - Status (active or inactive) - Device ID - Device type (browser or headless) - Last active timestamp Devices with an active status will display a pulsing green indicator, while inactive devices will show a gray status indicator. ## Registering a New Device To add a new device to your Herd account: 1. Click the **Register New Device** button at the top of the Devices page 2. Enter a name for your device (or use the suggested name) 3. Select the device type: - **Browser**: For devices with a visual interface such as your own browser - **Headless**: For devices running in headless mode (for docker and kubernetes deployments) 4. Click **Register Device** 5. A registration URL will be generated - use this URL to connect your device to Herd The registration URL will be stored locally in your browser, allowing you to access it again later if needed. ## Accessing Registration URLs If you need to access a previously generated registration URL: 1. Find the device in your devices list 2. Look for the "Registration URL available" indicator 3. Click the **View URL** button 4. The registration URL will be displayed in a modal window This is particularly useful if you need to reconnect a device or share the registration link with team members. ## Deleting a Device To remove a device from your Herd account: 1. Find the device you want to delete in your devices list 2. Click the **Delete** button for that device 3. Confirm the deletion in the confirmation dialog Please note that deleting a device is permanent and cannot be undone. The device will be removed from your account, and any stored registration URLs for that device will be cleared from your local storage. ## Device Status Devices in Herd can have different statuses: - **Active**: The device is currently connected and ready to use - **Inactive**: The device is registered but not currently connected An active device can be used immediately for automation tasks, while inactive devices need to be reconnected before use. ## Best Practices Here are some tips for effective device management: - Use descriptive names for your devices to easily identify them - Regularly clean up unused devices to keep your dashboard organized - Store registration URLs securely if you plan to share them with team members - Check the "Last Active" timestamp to identify devices that haven't been used recently By following these guidelines, you'll be able to maintain an organized and efficient device management system in Herd. ================================================================================ Document: Getting Started URL: https://herd.garden/docs/getting-started # Getting Started with Herd This guide will help you get up and running with Herd quickly to run your first trail. ## What is Herd? Herd connects AI Agents to websites using your own browser credentials. It enables you to: - **Run Trails** - pre-built automations for specific websites and tasks - **Extract data and interact with websites** using your logged-in browser sessions - **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude ## Quick Start ### 1. Install the Browser Extension Chrome Edge Brave ### 2. Register Your Browser After installing the extension: 1. Click the Herd icon in your browser toolbar 2. Sign in with your Herd account (or create one) 3. Name your device and register it ![Browser Registration](https://herd.garden/register-device.png) ### 3. Install the Herd SDK Install the Herd SDK using npm: ## npm Code (bash): npm install -g @monitoro/herd ## yarn Code (bash): yarn global add @monitoro/herd ## pnpm Code (bash): pnpm add -g @monitoro/herd ### 4. Run Your First Trail The browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out: Code (bash): herd trail run @herd/browser -a markdown -p '{"url": "https://example.com"}' That's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config: Code (json): { "mcpServers": { "browser": { "command": "herd", "args": [ "trail", "server", "@herd/browser" ] } } } ## For Developers You can also automate your browser with the Herd SDK. Connect to it with your AI agents or code: ## javascript Code (javascript): // Connect to your Herd device const client = new HerdClient('your-token'); await client.initialize(); const devices = await client.listDevices(); const device = devices[0]; // Create a new page and navigate const page = await device.newPage(); await page.goto("https://example.com"); // Extract data using simple selectors const data = await page.extract({ title: "h1", description: "p", link: "a" }); console.log("Extracted data:", data); ## python Code (python): from monitoro_herd import HerdClient # Connect to your Herd device client = HerdClient("your-token") await client.initialize() devices = await client.list_devices() device = devices[0] # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Extract data using simple selectors data = await page.extract({ "title": "h1", "description": "p", "link": "a" }) print("Extracted data:", data) ## What's Next? Now that you've run your first trail, you can: - [Explore available trails](/trails) - Browse pre-built trails for various websites - [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages - [Create your own trail](/docs/trails-automations) - Build and share your own custom trails ## Need Help? If you encounter any issues during setup: - Make sure your browser extension is correctly installed and you're signed in - Check that your device is registered in the [device dashboard](/devices) - Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions .browser-btn { display: inline-flex; align-items: center; padding: 0.2rem 1rem; background-color: #1f2937; color: white; border-radius: 0.375rem; font-size: 1.2rem; font-weight: 500; text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.1); } .browser-btn:hover { background-color: #374151; } ================================================================================ Document: Installation URL: https://herd.garden/docs/installation # Installing the Herd Extension The Herd extension is the client component that allows your browser to be remotely managed. This guide provides detailed instructions for installing the extension on different browsers. ## Chrome Installation The Herd extension is primarily designed for Google Chrome and Chromium-based browsers. Follow these steps to install: ### Standard Installation 1. Download the Herd extension from your dashboard by clicking "Download Herd" in the navigation bar 2. Open Chrome and navigate to `chrome://extensions` 3. Enable "Developer mode" by toggling the switch in the top-right corner 4. Drag and drop the downloaded `herd-latest.zip` file onto the extensions page 5. Chrome will automatically install the extension ### Verifying Installation After installation, you should see the Herd extension in your extensions list. To verify it's working correctly: 1. Look for the Herd icon in your browser toolbar 2. If it's not visible, click the puzzle piece icon to see all extensions and pin the Herd extension 3. The icon should be colored, indicating it's ready to be connected ## Installation on Other Browsers While Herd works best with Chrome, it's also compatible with other Chromium-based browsers: ### Microsoft Edge 1. Download the Herd extension zip file 2. Open Edge and navigate to `edge://extensions` 3. Enable "Developer mode" using the toggle in the left sidebar 4. Drag and drop the `herd-latest.zip` file onto the extensions page 5. Follow the prompts to complete installation ### Brave Browser 1. Download the Herd extension zip file 2. Open Brave and navigate to `brave://extensions` 3. Enable "Developer mode" in the top-right corner 4. Drag and drop the `herd-latest.zip` file onto the extensions page 5. Confirm the installation when prompted ## Enterprise Deployment For enterprise environments, you may want to deploy the Herd extension to multiple browsers. Here are some options: ### Chrome Enterprise Policy You can use Chrome Enterprise policies to automatically install and configure the Herd extension: 1. Extract the Herd extension zip file to a network location accessible to all users 2. Configure a policy to force-install extensions from a local path 3. Set up the appropriate extension settings via policy ### Manual Distribution For smaller teams, you can manually distribute the extension: 1. Download the extension once 2. Share the zip file with team members 3. Provide them with instructions for installation 4. Create device registrations for each team member in your Herd dashboard ## Troubleshooting Installation Issues If you encounter issues during installation, try these solutions: ### Extension Won't Install * Make sure Developer mode is enabled in your browser's extensions page * Check that you're using a supported browser (Chrome, Edge, Brave) * Verify that the zip file wasn't corrupted during download (try re-downloading) * Make sure you're dragging the zip file itself, not an extracted folder ### Extension Installed But Not Working * Check if the extension is enabled in your browser * Try restarting your browser * Verify that you've completed the device registration process * Check your browser's console for any error messages For more troubleshooting tips, see our [Troubleshooting](troubleshooting) guide. ================================================================================ Document: Reference Device URL: https://herd.garden/docs/reference-device # Device The Device class represents a connected browser or device in the Herd platform. It provides methods for managing pages, handling events, and controlling the device's lifecycle. Each Device instance gives you full control over a browser, allowing you to create and manage pages (tabs), handle various browser events, and automate browser interactions. ## javascript You can obtain a Device instance either by calling `client.listDevices()` to get all available devices, or `client.getDevice(deviceId)` to get a specific device by its ID. ## Properties ### deviceId The unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered. ### type The type of device, which indicates its capabilities and behavior. Currently supported types include: - 'browser': A browser instance that can be automated - 'headless': A headless browser instance running on docker or kubernetes ### name An optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard. ### status The current status of the device. Possible values include: - 'online': The device is connected and ready to receive commands - 'offline': The device is not currently connected - 'busy': The device is processing a command - 'error': The device encountered an error ### lastActive A timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a JavaScript Date object. ## Methods ### newPage() Creates a new page (tab) in the device. Code (javascript): // Create a new page const page = await device.newPage(); console.log('New page created:', page.id); ### listPages() Returns a list of all pages (tabs) currently open in the device. Code (javascript): // List all open pages const pages = await device.listPages(); pages.forEach(page => { console.log(`Page ${page.id}: ${page.url}`); }); ### getPage(pageId) Gets a specific page by ID. Code (javascript): // Get a specific page const page = await device.getPage(123); console.log('Current URL:', page.url); ### onEvent(callback) Subscribes to all events from the device. Returns an unsubscribe function. Code (javascript): // Subscribe to all device events const unsubscribe = device.onEvent((event) => { console.log('Device event:', event); }); // Later: stop listening to events unsubscribe(); ### on(eventName, callback) Subscribes to a specific event from the device. Returns the device instance for chaining. Code (javascript): // Subscribe to specific events device.on('navigation', (event) => { console.log('Navigation occurred:', event); }).on('console', (event) => { console.log('Console message:', event); }); ### close() Closes the device and cleans up resources. This will close all pages and remove event listeners. Code (javascript): // Close the device and cleanup await device.close(); ## Example Usage Here's a complete example showing how to use the Device class: Code (javascript): import { HerdClient } from '@monitoro/herd'; async function main() { const client = new HerdClient({ token: 'your-auth-token' }); await client.initialize(); // Get a device const device = await client.getDevice('my-browser'); // Create a new page and navigate const page = await device.newPage(); await page.goto('https://example.com'); // Listen for navigation events device.on('navigation', (event) => { console.log('Page navigated:', event.url); }); // List all pages const pages = await device.listPages(); console.log(`Device has ${pages.length} pages open`); // Cleanup when done await device.close(); await client.close(); } main().catch(console.error); ## python You can obtain a Device instance either by calling `client.list_devices()` to get all available devices, or `client.get_device(device_id)` to get a specific device by its ID. ## Properties ### device_id The unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered. ### type The type of device, which indicates its capabilities and behavior. Currently supported types include: - 'browser': A browser instance that can be automated - 'headless': A headless browser instance running on docker or kubernetes ### name An optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard. ### status The current status of the device. Possible values include: - 'online': The device is connected and ready to receive commands - 'offline': The device is not currently connected - 'busy': The device is processing a command - 'error': The device encountered an error ### last_active A timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a Python datetime object. ## Methods ### new_page() Creates a new page (tab) in the device. Code (python): # Create a new page page = await device.new_page() print(f"New page created: {page.id}") ### list_pages() Returns a list of all pages (tabs) currently open in the device. Code (python): # List all open pages pages = await device.list_pages() for page in pages: print(f"Page {page.id}: {page.url}") ### get_page(page_id) Gets a specific page by ID. Code (python): # Get a specific page page = await device.get_page(123) print(f"Current URL: {page.url}") ### on_event(callback) Subscribes to all events from the device. Returns an unsubscribe function. Code (python): # Subscribe to all device events def handle_event(event): print("Device event:", event) unsubscribe = device.on_event(handle_event) # Later: stop listening to events unsubscribe() ### on(event_name, callback) Subscribes to a specific event from the device. Returns the device instance for chaining. Code (python): # Subscribe to specific events def handle_navigation(event): print("Navigation occurred:", event) def handle_console(event): print("Console message:", event) device.on("navigation", handle_navigation)\ .on("console", handle_console) ### close() Closes the device and cleans up resources. This will close all pages and remove event listeners. Code (python): # Close the device and cleanup await device.close() ## Example Usage Here's a complete example showing how to use the Device class: Code (python): from monitoro_herd import HerdClient async def main(): client = HerdClient( token="your-auth-token" ) await client.initialize() # Get a device device = await client.get_device("my-browser") # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Listen for navigation events def handle_navigation(event): print("Page navigated:", event["url"]) device.on("navigation", handle_navigation) # List all pages pages = await device.list_pages() print(f"Device has {len(pages)} pages open") # Cleanup when done await device.close() await client.close() # Run the async function import asyncio asyncio.run(main()) ================================================================================ Document: Reference Herd Client URL: https://herd.garden/docs/reference-herd-client # HerdClient The HerdClient is the main entry point for interacting with the Herd platform. It provides methods for managing devices, pages, and executing browser automation commands. ## javascript ## Installation Code (bash): npm install @monitoro/herd # or yarn add @monitoro/herd ## Usage Code (javascript): import { HerdClient } from '@monitoro/herd'; // Create a client instance const client = new HerdClient({ token: 'your-auth-token' // Get your token at herd.garden }); // Initialize the client await client.initialize(); ## Methods ### initialize() Initializes the client by establishing connections to the Herd platform. Must be called before using other methods. Code (javascript): await client.initialize(); ### listDevices() Returns a list of all available devices. Code (javascript): const devices = await client.listDevices(); console.log('Available devices:', devices); ### getDevice(deviceId) Gets a specific device by ID. Code (javascript): const device = await client.getDevice('device-123'); ### registerDevice(options) Registers a new device with the platform. Code (javascript): const device = await client.registerDevice({ deviceId: 'my-device', type: 'browser', name: 'My Test Browser' }); ### sendCommand(deviceId, command, params) Sends a command to a specific device. This is a low-level method that allows you to send arbitrary commands to a device and is not recommended for most use cases. Code (javascript): const result = await client.sendCommand('device-123', 'Page.click', { selector: '#submit-button' }); ### subscribeToDeviceEvents(deviceId, callback) Subscribes to all events from a device. Code (javascript): const unsubscribe = client.subscribeToDeviceEvents('device-123', (event) => { console.log('Device event:', event); }); // Later: unsubscribe to stop receiving events unsubscribe(); ### subscribeToDeviceEvent(deviceId, eventName, callback) Subscribes to a specific event from a device. Code (javascript): const unsubscribe = client.subscribeToDeviceEvent('device-123', 'navigation', (event) => { console.log('Navigation event:', event); }); ### close() Closes the client and cleans up resources. Code (javascript): await client.close(); ## python ## Installation Code (bash): pip install monitoro-herd ## Usage Code (python): from monitoro_herd import HerdClient # Create a client instance client = HerdClient( token='your-auth-token' # Get your token at herd.garden ) # Initialize the client await client.initialize() ## Methods ### initialize() Initializes the client by establishing connections to the Herd platform. Must be called before using other methods. Code (python): await client.initialize() ### list_devices() Returns a list of all available devices. Code (python): devices = await client.list_devices() print('Available devices:', devices) ### get_device(device_id) Gets a specific device by ID. Code (python): device = await client.get_device('device-123') ### register_device(device_id, device_type, name) Registers a new device with the platform. Code (python): device = await client.register_device( device_id='my-device', device_type='browser', name='My Test Browser' ) ### send_command(device_id, command, payload) Sends a command to a specific device. Code (python): result = await client.send_command( 'device-123', 'Page.click', {'selector': '#submit-button'} ) ### subscribe_to_device_events(device_id, callback) Subscribes to all events from a device. Code (python): def handle_event(event): print('Device event:', event) unsubscribe = client.subscribe_to_device_events('device-123', handle_event) # Later: unsubscribe to stop receiving events unsubscribe() ### subscribe_to_device_event(device_id, event_name, callback) Subscribes to a specific event from a device. Code (python): def handle_navigation(event): print('Navigation event:', event) unsubscribe = client.subscribe_to_device_event('device-123', 'navigation', handle_navigation) ### close() Closes the client and cleans up resources. Code (python): await client.close() ================================================================================ Document: Reference Mcp Server URL: https://herd.garden/docs/reference-mcp-server # MCP Server Herd's MCP Server allows you to securely expose web applications to Large Language Models (LLMs) through local browser automation. Using the Model Context Protocol (MCP), you can create a secure bridge between AI models and your favorite websites without sharing credentials or running browsers in the cloud. ## Key Benefits - **Secure Access**: Your browser runs locally, keeping your credentials and cookies secure - **Privacy First**: No need to share sensitive data or tokens with third-party services - **Native Experience**: Interact with web apps through your actual browser, maintaining all your preferences and login state - **Universal Compatibility**: Works with any web application without needing API access - **Custom Tools**: Create tailored tools that encapsulate complex web interactions ## javascript ## Installation Code (bash): npm install @monitoro/herd ## Basic Setup Here's how to create an MCP server that exposes web application functionality: Code (javascript): import { HerdMcpServer } from '@monitoro/herd'; const server = new HerdMcpServer({ info: { name: "gmail-assistant", version: "1.0.0", description: "Gmail automation tools for LLMs" }, transport: { type: "sse", port: 3000 }, herd: { token: "your-herd-token" // Get from herd.garden } }); // Start the server await server.start(); ## Creating Web App Tools Tools encapsulate web application functionality for LLMs. Here are some examples: Code (javascript): // Gmail: Compose new email server.tool({ name: "composeEmail", description: "Compose and send a new email", schema: { to: z.string().email(), subject: z.string(), body: z.string() } }, async ({ to, subject, body }, devices) => { const device = devices[0]; const page = await device.newPage(); // Navigate to Gmail compose await page.goto('https://mail.google.com/mail/u/0/#compose'); // Fill out the email form await page.type('input[aria-label="To"]', to); await page.type('input[aria-label="Subject"]', subject); await page.type('div[aria-label="Message Body"]', body); // Send the email await page.click('div[aria-label="Send"]'); return { success: true }; }); // Twitter: Post a tweet server.tool({ name: "postTweet", description: "Post a new tweet", schema: { content: z.string().max(280) } }, async ({ content }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/compose/tweet'); await page.type('div[aria-label="Tweet text"]', content); await page.click('div[data-testid="tweetButton"]'); return { success: true }; }); ## Creating Web App Resources Resources provide structured data from web applications: Code (javascript): // Gmail: Unread emails server.resource({ name: "unreadEmails", uriOrTemplate: "gmail/unread", }, async (devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://mail.google.com/mail/u/0/#inbox'); // Extract unread email information const emails = await page.evaluate(() => { return Array.from(document.querySelectorAll('tr.unread')) .map(row => ({ sender: row.querySelector('.sender').textContent, subject: row.querySelector('.subject').textContent, date: row.querySelector('.date').textContent })); }); return { emails }; }); // LinkedIn: Profile Information server.resource({ name: "linkedinProfile", uriOrTemplate: "linkedin/profile/{username}", }, async ({ username }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto(`https://www.linkedin.com/in/${username}`); // Extract profile information return await page.extract({ name: 'h1', headline: '.headline', about: '.about-section p', experience: '.experience-section li' }); }); ## Complete Example: Twitter Assistant Here's a complete example showing how to create an MCP server that provides Twitter automation capabilities to LLMs: Code (javascript): import { HerdMcpServer } from '@monitoro/herd'; import { z } from 'zod'; const server = new HerdMcpServer({ info: { name: "twitter-assistant", version: "1.0.0", description: "Twitter automation for LLMs" }, transport: { type: "sse", port: 3000 }, herd: { token: process.env.HERD_TOKEN } }); // Post a tweet server.tool({ name: "postTweet", description: "Post a new tweet", schema: { content: z.string().max(280) } }, async ({ content }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/compose/tweet'); await page.type('div[aria-label="Tweet text"]', content); await page.click('div[data-testid="tweetButton"]'); return { success: true }; }); // Get timeline server.resource({ name: "timeline", uriOrTemplate: "twitter/timeline", }, async (devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/home'); return await page.extract({ tweets: { _$r: 'article[data-testid="tweet"]', author: '[data-testid="User-Name"]', content: '[data-testid="tweetText"]', stats: { likes: '[data-testid="like"]', retweets: '[data-testid="retweet"]' } } }); }); // Like a tweet server.tool({ name: "likeTweet", description: "Like a tweet by its URL", schema: { tweetUrl: z.string().url() } }, async ({ tweetUrl }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto(tweetUrl); await page.click('div[data-testid="like"]'); return { success: true }; }); // Start the server server.start().then(() => { console.log('Twitter Assistant ready!'); }).catch(console.error); This setup allows LLMs to: 1. Post tweets 2. Read the timeline 3. Like tweets 4. All through your local browser, maintaining your security and privacy ## python The MCP Server implementation is currently only available in JavaScript. Python support is coming soon! In the meantime, you can: 1. Use the JavaScript implementation to create your MCP server 2. Connect to it from Python using standard MCP client libraries 3. Use the Python Herd SDK for direct browser automation without MCP Example of direct web automation with Python: Code (python): from monitoro_herd import HerdClient async def main(): client = HerdClient(token="your-token") await client.initialize() device = await client.get_device("my-browser") page = await device.new_page() # Navigate to Twitter await page.goto("https://twitter.com") # Extract timeline content content = await page.extract({ "tweets": { "_$r": "article[data-testid='tweet']", "author": "[data-testid='User-Name']", "content": "[data-testid='tweetText']" } }) print("Timeline:", content) # Run the async function import asyncio asyncio.run(main()) Stay tuned for native Python MCP support! Read more about Model Context Protocol in the MCP official documentation. ================================================================================ Document: Reference Node URL: https://herd.garden/docs/reference-node # Node The Node class provides a DOM-like API for interacting with elements on a page. It allows you to inspect and manipulate elements using familiar DOM methods and properties. ## javascript You can obtain Node instances through Page query methods: - `page.querySelector(selector)` - Find first matching element - `page.querySelectorAll(selector)` - Find all matching elements - `node.querySelector(selector)` - Find first matching element within this node - `node.querySelectorAll(selector)` - Find all matching elements within this node ## Properties ### nodeType The type of node (1 for Element, 3 for Text). ### nodeName The name of the node (tag name for elements, '#text' for text nodes). ### nodeValue The text content for text nodes, null for elements. ### tagName The tag name of the element (empty string for non-elements). ### textContent The text content of the node and its descendants. ### innerHTML The HTML content inside the element. ### childNodes Array of child nodes. ### firstChild The first child node, or null if none exists. ### lastChild The last child node, or null if none exists. ## Methods ### getAttribute(name) Gets the value of an attribute. Code (javascript): const href = element.getAttribute('href'); ### hasAttribute(name) Checks if an attribute exists. Code (javascript): if (element.hasAttribute('disabled')) { console.log('Element is disabled'); } ### click([options]) Clicks the element. Code (javascript): // Simple click await element.click(); // Click with navigation wait await element.click({ waitForNavigation: 'networkidle2' }); ### type(text[, options]) Types text into the element. Code (javascript): await element.type('Hello world'); ### focus([options]) Focuses the element. Code (javascript): await element.focus(); ### blur([options]) Removes focus from the element. Code (javascript): await element.blur(); ### hover([options]) Hovers over the element. Code (javascript): await element.hover(); ### scrollIntoView([options]) Scrolls the element into view. Code (javascript): await element.scrollIntoView(); ### setValue(value[, options]) Sets the value of a form element. Code (javascript): // Set input value await element.setValue('test@example.com'); // Set checkbox await element.setValue(true); ### dispatchEvent(eventName[, detail, options]) Dispatches an event on the element. Code (javascript): await element.dispatchEvent('click'); ### dragTo(target[, options]) Drags this element to another element or selector. Code (javascript): // Drag to another element const target = await page.querySelector('.dropzone'); await element.dragTo(target); // Drag to selector await element.dragTo('.dropzone'); ### querySelector(selector) Finds the first matching element within this node. Code (javascript): const child = await element.querySelector('.child'); ### querySelectorAll(selector) Finds all matching elements within this node. Code (javascript): const children = await element.querySelectorAll('.child'); ### getBoundingClientRect() Gets the element's position and size. Code (javascript): const rect = element.getBoundingClientRect(); console.log(rect.x, rect.y, rect.width, rect.height); ## Example Usage Here's a complete example showing how to use the Node class: Code (javascript): // Get a form element const form = await page.querySelector('form'); // Fill out form fields const emailInput = await form.querySelector('input[type="email"]'); await emailInput.type('test@example.com'); // Check a checkbox const checkbox = await form.querySelector('.terms-checkbox'); await checkbox.setValue(true); // Get form dimensions const rect = form.getBoundingClientRect(); console.log('Form size:', rect.width, rect.height); // Submit the form const submitButton = await form.querySelector('button[type="submit"]'); await submitButton.click({ waitForNavigation: 'networkidle2' }); ## python The Node API is currently only available in JavaScript. In Python, you should use the Page methods directly with CSS selectors to interact with elements: Code (python): # Instead of: # element = await page.querySelector('.button') # await element.click() # Use: await page.click('.button') # Instead of: # element = await page.querySelector('input') # await element.type('Hello') # Use: await page.type('input', 'Hello') This provides the same functionality but with a slightly different API. The Node API will be available in Python in a future release. ================================================================================ Document: Reference Page URL: https://herd.garden/docs/reference-page # Page The Page class represents a browser tab or page in the Herd platform. It provides methods for navigating, interacting with elements, handling events, and automating browser actions. ## javascript You can obtain a Page instance using any of these Device methods: - `device.newPage()` - Create a new page - `device.listPages()` - Get all pages - `device.getPage(pageId)` - Get a specific page by ID ## Properties ### id The unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab. ### url The current URL of the page. Returns an empty string if the page hasn't loaded any URL yet. ### title The current title of the page. Returns an empty string if the page hasn't loaded or has no title. ### active Whether this page is currently the active tab in the browser window. ## Methods ### goto(url[, options]) Navigates the page to the specified URL. Code (javascript): // Navigate to a URL and wait for network to be idle await page.goto('https://example.com'); // Navigate with custom options await page.goto('https://example.com', { waitForNavigation: 'load' // Wait for load event instead of network idle }); Options: - `waitForNavigation`: When to consider navigation complete - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### querySelector(selector) Finds the first element matching the CSS selector. Returns a Node object that can be used for further interactions. Code (javascript): const element = await page.querySelector('.submit-button'); if (element) { console.log('Element found:', element.textContent); } ### querySelectorAll(selector) Finds all elements matching the CSS selector. Returns an array of Node objects. Code (javascript): const elements = await page.querySelectorAll('li.item'); for (const element of elements) { console.log('Item text:', element.textContent); } ### dom() Returns the DOM of the page as a JSDOM object for ultimate flexibility. This is useful for extracting data by walking the DOM and finding elements manually. Note: This is a read-only view of the DOM, so you cannot trigger events or modify the DOM this way. Code (javascript): const dom = await page.dom(); console.log(dom); ### waitForElement(selector[, options]) Waits for an element matching the selector to appear or disappear on the page. Code (javascript): // Wait for an element to be visible await page.waitForElement('#loading-indicator'); // or the following which is equivalent await page.waitForElement('#loading-indicator', { state: 'visible' }); // Wait for an element to be hidden await page.waitForElement('#loading-indicator', { state: 'hidden' }); // Wait for an element to be attached to DOM await page.waitForElement('.dynamic-content', { state: 'attached' }); // Wait for an element to be detached from DOM await page.waitForElement('.old-content', { state: 'detached' }); // Wait with timeout await page.waitForElement('.dynamic-content', { state: 'visible', timeout: 10000 // 10 seconds (default is 5 seconds) }); Options: - `state`: The state to wait for - `'visible'`: Wait for element to be visible (default) - `'hidden'`: Wait for element to be hidden - `'attached'`: Wait for element to be attached to DOM - `'detached'`: Wait for element to be detached from DOM - `timeout`: Maximum time to wait in milliseconds (default: 5000) ### waitForSelector(selector[, options]) Alias for waitForElement. Waits for an element matching the selector to appear or disappear. Code (javascript): // Wait for a selector to be visible await page.waitForSelector('.search-results', { state: 'visible' }); // Wait for a selector to be detached await page.waitForSelector('.loading-spinner', { state: 'detached', timeout: 5000 }); ### waitForNavigation(condition) Waits for navigation to complete based on the specified condition. Code (javascript): // Wait for page load event await page.waitForNavigation('load'); // Wait for network to be idle await page.waitForNavigation('networkidle0'); // Wait for URL change await page.waitForNavigation('change'); Conditions: - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'change'`: Wait for URL change - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### click(selector[, options]) Clicks an element that matches the selector. Code (javascript): // Simple click await page.click('#submit-button'); // Click with navigation wait await page.click('a.link', { waitForNavigation: 'networkidle2' }); ### type(selector, text[, options]) Types text into an input element. Code (javascript): // Type into an input field await page.type('#search-input', 'search query'); // Type with navigation wait (for auto-submit forms) await page.type('#search-input', 'search query', { waitForNavigation: 'networkidle2' }); ### focus(selector[, options]) Focuses an element on the page. Code (javascript): await page.focus('#email-input'); ### hover(selector[, options]) Hovers over an element. Code (javascript): await page.hover('.dropdown-trigger'); ### press(key[, options]) Presses a keyboard key. Code (javascript): await page.press('Enter'); ### scroll(x, y[, options]) Scrolls the page by the specified amount. Code (javascript): // Scroll down 500 pixels await page.scroll(0, 500); ### scrollIntoView(selector[, options]) Scrolls an element into view. Code (javascript): await page.scrollIntoView('#bottom-content'); ### back([options]) Navigates back in the browser history. Code (javascript): await page.back({ waitForNavigation: 'networkidle2' }); ### forward([options]) Navigates forward in the browser history. Code (javascript): await page.forward({ waitForNavigation: 'networkidle2' }); ### reload([options]) Reloads the current page. Code (javascript): await page.reload({ waitForNavigation: 'networkidle2' }); ### activate() Activates the page (makes it the active tab). Code (javascript): await page.activate(); ### close() Closes the page (tab). Code (javascript): await page.close(); ## Example Usage Here's a complete example showing how to use the Page class: Code (javascript): // Create a new page const page = await device.newPage(); // Navigate to a URL await page.goto('https://example.com'); // Fill out a form await page.type('#username', 'myuser'); await page.type('#password', 'mypass'); await page.click('#submit-button', { waitForNavigation: 'networkidle2' }); // Extract some data const title = await page.evaluate(() => document.title); console.log('Page title:', title); // Close the page when done await page.close(); ## python You can obtain a Page instance using any of these Device methods: - `device.new_page()` - Create a new page - `device.list_pages()` - Get all pages - `device.get_page(page_id)` - Get a specific page by ID ## Properties ### id The unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab. ### url The current URL of the page. Returns an empty string if the page hasn't loaded any URL yet. ### title The current title of the page. Returns an empty string if the page hasn't loaded or has no title. ### active Whether this page is currently the active tab in the browser window. ## Methods ### goto(url[, options]) Navigates the page to the specified URL. Code (python): # Navigate to a URL and wait for network to be idle await page.goto("https://example.com") # Navigate with custom options await page.goto("https://example.com", { "waitForNavigation": "load" # Wait for load event instead of network idle }) Options: - `waitForNavigation`: When to consider navigation complete - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### querySelector(selector) / Q(selector) Finds the first element matching the CSS selector. Returns a dictionary representing the element. Code (python): # Using querySelector (alias for Q) element = await page.querySelector(".submit-button") if element: print("Element found:", element) # Using Q directly element = await page.Q(".submit-button") ### querySelectorAll(selector) / QQ(selector) Finds all elements matching the CSS selector. Returns a list of dictionaries representing the elements. Code (python): # Using querySelectorAll (alias for QQ) elements = await page.querySelectorAll("li.item") for element in elements: print("Item:", element) # Using QQ directly elements = await page.QQ("li.item") ### click(selector[, options]) Clicks an element that matches the selector. Code (python): # Simple click await page.click("#submit-button") # Click with navigation wait await page.click("a.link", {"waitForNavigation": "networkidle2"}) ### type(selector, text[, options]) Types text into an input element. Code (python): # Type into an input field await page.type("#search-input", "search query") # Type with navigation wait (for auto-submit forms) await page.type("#search-input", "search query", { "waitForNavigation": "networkidle2" }) ### focus(selector[, options]) Focuses an element on the page. Code (python): await page.focus("#email-input") ### hover(selector[, options]) Hovers over an element. Code (python): await page.hover(".dropdown-trigger") ### scroll(x, y[, options]) Scrolls the page by the specified amount. Code (python): # Scroll down 500 pixels await page.scroll(0, 500) ### scroll_into_view(selector[, options]) Scrolls an element into view. Code (python): await page.scroll_into_view("#bottom-content") ### set_value(selector, value[, options]) Sets the value of a form element directly. Code (python): # Set input value await page.set_value("#quantity", "5") # Set checkbox await page.set_value("#agree", True) ### dispatch_event(selector, event_name[, detail, options]) Dispatches a DOM event on an element. Code (python): await page.dispatch_event("#my-button", "click") ### close() Closes the page (tab). Code (python): await page.close() ## Example Usage Here's a complete example showing how to use the Page class: Code (python): # Create a new page page = await device.new_page() # Navigate to a URL await page.goto("https://example.com") # Fill out a form await page.type("#username", "myuser") await page.type("#password", "mypass") await page.click("#submit-button", {"waitForNavigation": "networkidle2"}) # Extract some data using the extract method data = await page.extract({ "title": "h1", "description": ".description" }) print("Extracted data:", data) # Close the page when done await page.close() ================================================================================ Document: Security Privacy URL: https://herd.garden/docs/security-privacy # Security & Privacy in Herd At Herd, we take security and privacy seriously. This guide outlines the security features built into the platform and the privacy measures we take to protect your data. ## Security Architecture Herd is built with security at its core: ### End-to-End Encryption All communication between your browsers and the Herd platform is encrypted end-to-end: - **Transport Layer Security (TLS)**: All API requests and responses use TLS 1.3. - **WebRTC Encryption**: Remote control sessions use WebRTC with DTLS-SRTP encryption. - **Secure WebSockets**: Real-time communication uses encrypted WebSocket connections. - **NATS**: All communication between your browser and the code you run is encrypted end-to-end using a NATS-based PKI infrastructure and we do not intercept or inspect the content of the communication. ### Authentication & Authorization Multiple layers of security protect access to your account and devices: - **Multi-factor Authentication**: Optional 2FA for account access - **Device Registration Codes**: One-time codes for connecting browsers - **Session Management**: Automatic timeouts and the ability to revoke sessions - **Role-Based Access Control**: Granular permissions for team members ### Infrastructure Security Our platform infrastructure implements industry best practices: - **Regular Security Audits**: Third-party security audits of our systems - **Vulnerability Scanning**: Continuous monitoring for vulnerabilities - **Secure Development**: Strict coding practices and security reviews - **Cloud Security**: Leveraging secure cloud infrastructure with isolation between customers ## Privacy Features Herd includes several features to protect your privacy: ### Data Minimization We only collect the data necessary for the platform to function: - **Selective Access**: You control which browsers are connected and which data is shared - **No Unnecessary Telemetry**: Limited data collection focused on service performance - **Automatic Data Expiry**: Logs and temporary data are automatically purged after set periods ### User Control You maintain control over your data and connections: - **Connection Visibility**: Clear indicators when a browser is being monitored or controlled - **Permission Prompts**: Optional prompts before remote control is initiated - **Incognito Mode Handling**: Special handling of private browsing sessions - **Activity Logs**: Transparent logs of all remote control activities ### Compliance Features For organizations with specific compliance requirements: - **Data Residency Options**: Select where your data is stored (Enterprise plan) - **Compliance Reporting**: Generate reports for audit purposes - **Custom Retention Policies**: Set data retention periods to match your policies - **Privacy Mode**: Additional restrictions for sensitive environments ## Security Best Practices To maximize security when using Herd: ### Account Security - Use strong, unique passwords for your Herd account - Enable two-factor authentication - Regularly review active sessions and revoke any suspicious ones - Limit account access to necessary team members only ### Device Security - Register devices with descriptive names for easy identification - Regularly review connected devices and remove unused ones - Use device tagging to organize and manage access - Consider network-level restrictions for sensitive devices ### Remote Control Security - Always end remote control sessions when not in use - Use view-only mode when full control isn't necessary - Be cautious about what information is visible during remote sessions - Consider scheduling remote sessions in advance when possible ## Privacy Policy Herd's formal privacy policy can be found at [monitoro.co/privacy](https://monitoro.co/privacy). Key points include: - We do not sell your data to third parties - We only process your data to provide the Herd service - You retain ownership of all content viewed or managed through Herd - We implement strong security measures to protect your data - We are transparent about any data breaches or security incidents ## Security Updates We continuously improve our security and privacy features: - Security updates are automatically applied to the platform - Extension updates are released regularly with security improvements - Follow our blog for detailed information on security enhancements ## Reporting Security Issues If you discover a security vulnerability, please report it responsibly: 1. Email security@herd.garden with details of the vulnerability 2. Include steps to reproduce if possible 3. Allow time for us to address the issue before public disclosure Note: We unfortunately do not offer a bug bounty program as we are a small team and our resources are limited. We do appreciate your responsible disclosure and help keeping the internet a safer place. ================================================================================ Document: Trails Automations URL: https://herd.garden/docs/trails-automations # Trails Trails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process. ## javascript Trails are fully supported in the JavaScript SDK. ## Creating a Trail A trail defines the following components: - **urls.ts**: Exports an array of URL definitions - **selectors.ts**: Exports an array of selector configurations - **actions.ts**: Exports action classes that implement the `TrailAction` interface A trail at the minimum has the following structure: Code: google-search/ urls.ts selectors.ts actions.ts package.json The `package.json` file defines the trail and its dependencies: Code (json): { "name": "google-search", "description": "Search google for webpages.", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } You should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code. ## Trail Implementation Guide ### Step 1: Set up the trail structure Create a new directory for your trail with the following files: Code: my-trail/ urls.ts selectors.ts actions.ts package.json Add the basic package.json configuration: Code (json): { "name": "my-trail", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } ### Step 2: Define URLs In `urls.ts`, export an array of URL definitions that your trail will interact with: Code (typescript): export default [{ "id": "my-url", "template": "https://example.com/path?param1={param1}&param2={param2}", "description": "Description of what this URL represents", "examples": [ { "param1": "value1", "param2": "value2" } ], "params": { "param1": { "type": "string", "required": true, "description": "Description of param1" }, "param2": { "type": "string", "required": false, "default": "defaultValue", "description": "Description of param2" } } }]; ### Step 3: Define Selectors In `selectors.ts`, export an array of selector configurations that define how to extract data from web pages: Code (typescript): export default [{ "id": "my-selector", "value": { "dataKey": { "_$r": "#main-container", "title": { "_
quot;: ".title" }, "description": { "_
quot;: ".description" }, "link": { "_
quot;: "a.link", "attribute": "href" } } }, "description": "Selector for extracting specific data", "examples": [ { "urlId": "my-url", "urlParams": { "param1": "value1", "param2": "value2" } } ] }]; ### Step 4: Implement Actions In `actions.ts`, define one or more action classes that implement the `TrailAction` interface: Code (typescript): import type { Device, TrailAction, TrailActionManifest, TrailRunResources } from "@monitoro/herd"; export class MyTrailAction implements TrailAction { manifest: TrailActionManifest = { name: "my-action", description: "Description of what this action does", params: { param1: { type: "string", description: "Description of param1" }, param2: { type: "number", description: "Description of param2", default: 10 } }, result: { type: "array", description: "Description of the result", items: { type: "object", properties: { property1: { type: "string" }, property2: { type: "number" } } } }, examples: [ { "param1": "value1", "param2": 10 } ] } async test(device: Device, params: Record, resources: TrailRunResources) { try { const result = await this.run(device, params, resources); // Validate result if (!result || result.length === 0) { return { status: "error", message: "No results found", result: [] }; } return { status: "success", result }; } catch (e) { return { status: "error", message: `Error: ${e}`, result: null }; } } async run(device: Device, params: Record, resources: TrailRunResources) { const { param1, param2 } = params; const page = await device.newPage(); try { // Navigate to URL using the URL template from urls.ts await page.goto(resources.url('my-url', { param1, param2 })); // Extract data using selectors from selectors.ts const extracted = await page.extract(resources.selector('my-selector')); // Process extracted data const results = (extracted as any)?.dataKey || []; // Return processed results return results; } finally { await page.close(); } } } ### Step 5: Testing and debugging Use the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest): Code (bash): herd trail test --action my-trail You can also watch for changes in the trail and re-run tests: Code (bash): herd trail test --action my-trail --watch # or herd trail test -a my-trail -w And you can also test selectors only: Code (bash): herd trail test --selector my-selector And watch for changes in the selectors: Code (bash): herd trail test --selector my-selector --watch # or herd trail test -s my-selector -w ### Step 6: Publish your trail Publishing is coming soon! ### Best Practices 1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc. 2. **Performance**: Minimize page loads and extract as much data as possible from each page. 3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain. 4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios. 5. **Versioning**: Increment your trail's version in package.json when making changes. ## python Trails support for Python SDK is coming soon. Stay tuned for updates! In the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them. ================================================================================ Document: Troubleshooting URL: https://herd.garden/docs/troubleshooting # Troubleshooting Herd This guide provides solutions for common issues you might encounter when using the Herd platform. If you can't find a solution here, please contact our [support team](/docs/getting-started) for further assistance. ## Installation Issues ### Extension Won't Install **Problem**: You can't install the Herd extension in your browser. **Solutions**: - Verify Developer mode is enabled in your browser's extensions page - Make sure you're using a supported browser (Chrome, Edge, Brave) - Try downloading the extension file again as it might be corrupted - Check if your browser has restrictions on installing third-party extensions - Try installing from a different browser profile If all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share. ### Extension Shows as Corrupted **Problem**: Your browser shows the Herd extension as corrupted or invalid. **Solutions**: - Re-download the extension package - Clear your browser cache before installing - Try extracting the zip file and loading it as an unpacked extension - Verify that you have the latest version of the extension If all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share. ## Connection Issues ### Browser is disconnected or no browser registered **Problem**: Running a trail or calling any Herd command throws an exception "Browser is disconnected or no browser registered". This means that your browser is not connected to the Herd platform **Solutions**: - First ensure that you have installed Herd and registered your browser following our [Getting Started guide](/docs/getting-started). - Check the internet connection of the computer where you installed Herd extension - Go to `chrome://extensions` and click the reload icon next to Herd extension - If that doesn't work, delete the extension and reconnect it again from scratch, following our [Getting Started guide](/docs/getting-started). If nothing works, [contact](mailto:support@herd.garden) us for additional help with as much context about the issue as you can share. ### Can't Connect to Herd Server **Problem**: The extension is installed but can't connect to the Herd server. **Solutions**: - Check your internet connection - Verify that the registration code is correct and hasn't expired - Make sure your firewall isn't blocking the connection - Try disabling any VPN or proxy services temporarily - Check if your organization blocks WebSocket connections ### Connection Keeps Dropping **Problem**: The connection between your browser and Herd keeps disconnecting. **Solutions**: - Check for network stability issues - Make sure your computer isn't going to sleep - Verify that the browser is allowed to run in the background - Check if other extensions are conflicting with Herd - Try connecting using a wired network connection if possible ## Remote Control Issues ### Black Screen During Remote Control **Problem**: You see a black screen when trying to view a remote browser. **Solutions**: - Check if the remote device is in sleep mode or locked - Refresh the remote control session - Make sure the remote browser tab is active (not minimized) - Try restarting the remote browser - Verify that the remote device has granted screen sharing permissions ### High Latency in Remote Control **Problem**: There's significant lag when controlling a remote browser. **Solutions**: - Lower the streaming quality in the remote control settings - Check network conditions on both ends - Close unnecessary tabs and applications on both devices - Make sure no bandwidth-heavy activities are running (like video streaming) - Try using a wired connection if possible ### Input Not Registering **Problem**: Mouse clicks or keyboard input aren't registering on the remote browser. **Solutions**: - Check if you're in "View Only" mode and switch to "Control" mode - Try clicking on the remote view area to ensure it has focus - Refresh the remote control session - Check if the remote browser is responding to local inputs - Try restarting the remote control session ## Account and Management Issues ### Device Not Appearing in Dashboard **Problem**: A connected device isn't showing up in your Herd dashboard. **Solutions**: - Verify the device is properly connected - Refresh the dashboard page - Check if the device is registered under a different account - Make sure the extension is enabled and running - Try reconnecting the device using a new registration code ### Can't Create New Device Registration **Problem**: You're unable to create a new device registration. **Solutions**: - Check if you've reached your plan's device limit - Verify that you have the necessary permissions in your account - Try using a different browser to access the dashboard - Clear your browser cache and cookies - Check if your account has any restrictions ## System Requirements If you're experiencing persistent issues, verify that your system meets these minimum requirements: - **Browser**: Chrome 70+, Edge 79+, or Brave 1.0+ - **Operating System**: Windows 10+, macOS 10.14+, or Ubuntu 18.04+ - **RAM**: 4GB minimum (8GB recommended) - **Network**: Stable internet connection with at least 1Mbps upload/download - **Processor**: Dual-core processor at 2GHz or higher ## Contacting Support If you've tried the solutions above and are still experiencing issues, please contact our support team: 1. Email: support@herd.garden 2. In-app: Click the "Help" icon in the dashboard footer 3. Documentation: Check for updated troubleshooting guides on our website When contacting support, please include: - Your browser type and version - Your operating system - A description of the issue - Any error messages you've received - Steps you've already taken to resolve the issue ================================================================================

Top SitesHerd - Browser Superpowers & MCP Servers for AI Agents

Machine Readiness

Stored receipt and evidence

Overall

30

Readable

100

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

robots, llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Open robots.txt
User-agent: *
Allow: /

Sitemap: https://herd.garden/sitemap.xml

Document

llms.txt

Open llms.txt
Herd Documentation
==


Herd is a powerful platform and SDK for automating your own browser, ten or millions of them. Similar to Puppeteer but with support for multiple devices and real-time events, and no infrastructure to setup.


Document: Automation Basics
URL: https://herd.garden/docs/automation-basics

# Automation Basics

Welcome to Monitoro Herd! This guide will walk you through creating your first browser automation step-by-step. We'll start with the basics and gradually build up to more complex examples, explaining each concept along the way.

## javascript

## JavaScript SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your JavaScript environment and install the Herd SDK:

1. Make sure you have Node.js installed (version 14 or higher recommended)
2. Create a new project directory
3. Install the SDK using npm:

Code (bash):
npm install @monitoro/herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (javascript):
// Import the Herd client
import { HerdClient } from '@monitoro/herd';

// Initialize the client with your API URL and token
const client = new HerdClient('your-token');

// Always initialize the client before using it
await client.initialize();
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

After initializing the client, you need to connect to a device (browser) that will perform the automation:

Code (javascript):
// Get a list of available devices
const devices = await client.listDevices();

// Connect to the first available device
const device = devices[0];

console.log(`Connected to device: ${device.id}`);

This code retrieves all devices registered to your account and connects to the first one. In a production environment, you might want to select a specific device based on its properties or availability.

### Creating a Page and Navigating

Now that you're connected to a device, you can create a new browser page and navigate to a website:

Code (javascript):
// Create a new page in the browser
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com');

console.log('Successfully navigated to example.com');

The `goto` method loads the specified URL and waits for the page to load. By default, it waits until the page's `load` event is fired, but you can customize this behavior with options.

### Extracting Basic Information

One of the most common automation tasks is extracting information from web pages. Here's how to extract basic elements:

Code (javascript):
// Extract content using CSS selectors
const content = await page.extract({
  title: 'h1',           // Extracts the main heading
  description: 'p',      // Extracts the first paragraph
  link: 'a'              // Extracts the first link text
});

// Display the extracted content
console.log('Extracted content:');
console.log(`Title: ${content.title}`);
console.log(`Description: ${content.description}`);
console.log(`Link: ${content.link}`);

The `extract` method uses CSS selectors to find elements on the page and extract their text content. This is a powerful way to scrape structured data from websites.

### Proper Resource Management

Always remember to close resources when you're done with them to prevent memory leaks:

Code (javascript):
// Close the page when done
await page.close();

// Close the client connection
await client.close();

### Putting It All Together

Here's a complete example that combines all the steps above into a single function:

Code (javascript):
import { HerdClient } from '@monitoro/herd';

async function runBasicAutomation() {
  const client = new HerdClient('your-token');
  
  try {
    // Initialize the client
    await client.initialize();
    console.log('Client initialized successfully');
    
    // Get the first available device
    const devices = await client.listDevices();
    if (devices.length === 0) {
      throw new Error('No devices available');
    }
    const device = devices[0];
    console.log(`Connected to device: ${device.id}`);
    
    // Create a new page
    const page = await device.newPage();
    console.log('New page created');
    
    // Navigate to a website
    console.log('Navigating to example.com...');
    await page.goto('https://example.com');
    console.log('Navigation complete');
    
    // Extract content
    console.log('Extracting content...');
    const content = await page.extract({
      title: 'h1',
      description: 'p',
      link: 'a'
    });
    
    // Display the extracted content
    console.log('\nExtracted content:');
    console.log(`Title: ${content.title}`);
    console.log(`Description: ${content.description}`);
    console.log(`Link: ${content.link}`);
    
  } catch (error) {
    console.error('Error during automation:', error);
  } finally {
    // Always close the client when done
    console.log('Closing client connection...');
    await client.close();
    console.log('Client connection closed');
  }
}

// Run the automation
runBasicAutomation();

### Interacting with Web Pages

Now let's explore how to interact with elements on a page. This includes clicking buttons, typing text, and handling forms.

#### Finding Elements

Before interacting with an element, you need to find it on the page:

Code (javascript):
// Find an element using a CSS selector
const searchBox = await page.$('input[name="q"]');

// Check if the element was found
if (searchBox) {
  console.log('Search box found');
} else {
  console.log('Search box not found');
}

The `


  
  
  
  
  herd.garden | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   method returns the first element that matches the CSS selector, or `null` if no element is found.

#### Typing Text

To type text into an input field:

Code (javascript):
// Type text into an input field
await page.type('input[name="q"]', 'Monitoro Herd automation');
console.log('Text entered into search box');

The `type` method finds the element using the CSS selector and simulates typing the specified text.

#### Clicking Elements

To click a button or link:

Code (javascript):
// Click a button
await page.click('input[type="submit"]');
console.log('Search button clicked');

By default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:

Code (javascript):
// Click and wait for navigation
await page.click('input[type="submit"]', { 
  waitForNavigation: 'networkidle2' 
});
console.log('Search button clicked and navigation completed');

The `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.

#### Waiting for Elements

Sometimes you need to wait for elements to appear on the page:

Code (javascript):
// Wait for an element to appear
await page.waitForSelector('#search');
console.log('Search results have loaded');

This is useful when dealing with dynamic content that loads after the initial page load.

#### Search Engine Example

Let's put these concepts together in a search engine example:

Code (javascript):
async function searchExample() {
  const client = new HerdClient('your-token');
  
  try {
    await client.initialize();
    const devices = await client.listDevices();
    const device = devices[0];
    const page = await device.newPage();
    
    // Navigate to a search engine
    console.log('Navigating to Google...');
    await page.goto('https://www.google.com');
    
    // Type in the search box
    console.log('Entering search query...');
    await page.type('input[name="q"]', 'Monitoro Herd automation');
    
    // Submit the search form and wait for results
    console.log('Submitting search...');
    await page.click('input[type="submit"]', { 
      waitForNavigation: 'networkidle2' 
    });
    
    // Wait for results to load completely
    console.log('Waiting for search results...');
    await page.waitForSelector('#search');
    
    // Extract search result titles
    console.log('Extracting search results...');
    const searchResults = await page.extract({
      titles: {
        _$r: '#search .g h3',  // _$r extracts multiple elements
        text: ':root'           // For each match, get its text
      }
    });
    
    // Display the search result titles
    console.log('\nSearch Results:');
    searchResults.titles.forEach((result, index) => {
      console.log(`${index + 1}. ${result.text}`);
    });
    
  } catch (error) {
    console.error('Error:', error);
  } finally {
    await client.close();
  }
}

## python

## Python SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your Python environment and install the Herd SDK:

1. Make sure you have Python 3.8+ installed
2. Create a virtual environment (recommended)
3. Install the SDK using pip:

Code (bash):
pip install monitoro-herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (python):
# Import the Herd client
from monitoro_herd import HerdClient

# Initialize the client with your API URL and token
client = HerdClient('your-token')

# Always initialize the client before using it
client.initialize()
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

Next, connect to a device that will run your automation:

Code (python):
# Get available devices
devices = await client.list_devices()

# Connect to the first device
device = devices[0]

print(f"Connected to device: {device.id}")

### Creating a Page and Navigating

Now create a browser page and navigate to a website:

Code (python):
# Create a new page
page = await device.new_page()

# Navigate to a website
await page.goto("https://example.com")

print("Successfully navigated to example.com")

### Extracting Basic Information

Extract information from the page using CSS selectors:

Code (python):
# Extract basic information
data = await page.extract({
    "title": "h1",          # Main heading
    "description": "p",     # First paragraph
    "link": "a"             # First link text
})

# Display the extracted data
print("Extracted data:")
print(f"Title: {data['title']}")
print(f"Description: {data['description']}")
print(f"Link: {data['link']}")

### Resource Management

Always close resources when you're done:

Code (python):
# Close the page
await page.close()

# Close the client
await client.close()

### Complete Basic Example

Here's a complete example putting all these concepts together:

Code (python):
import asyncio
from monitoro_herd import HerdClient

async def basic_extraction():
    # Initialize the client
    client = HerdClient("your-token")
    
    try:
        # Initialize the connection
        await client.initialize()
        print("Client initialized successfully")
        
        # Get the first available device
        devices = await client.list_devices()
        if not devices:
            raise Exception("No devices available")
        device = devices[0]
        print(f"Connected to device: {device.id}")
        
        # Create a new page
        page = await device.new_page()
        print("New page created")
        
        # Navigate to a website
        print("Navigating to example.com...")
        await page.goto("https://example.com")
        print("Navigation complete")
        
        # Extract data using simple selectors
        print("Extracting content...")
        data = await page.extract({
            "title": "h1",
            "description": "p",
            "link": "a"
        })
        
        # Display the extracted data
        print("\nExtracted data:")
        print(f"Title: {data['title']}")
        print(f"Description: {data['description']}")
        print(f"Link: {data['link']}")
        
    except Exception as e:
        print(f"Error during automation: {e}")
    finally:
        # Always close resources
        print("Closing client connection...")
        await client.close()
        print("Client connection closed")

# Run the async function
asyncio.run(basic_extraction())

### Working with Lists and Structured Data

One of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.

#### The `_$r` Selector

To extract multiple elements that match a pattern, use the `_$r` (repeat) selector:

Code (python):
# Extract a list of items
data = await page.extract({
    "items": {
        "_$r": ".item",       # Find all elements with class "item"
        "name": ".item-name", # For each item, get the name
        "price": ".price"     # For each item, get the price
    }
})

# Access the extracted items
for item in data["items"]:
    print(f"Name: {item['name']}, Price: {item['price']}")

The `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.

#### Extracting Attributes

Sometimes you need to extract an attribute rather than the text content:

Code (python):
# Extract links and their href attributes
data = await page.extract({
    "links": {
        "_$r": "a",              # Find all links
        "text": ":root",         # Get the link text
        "url": {
            "_
quot;: ":root", # Reference the same element "attribute": "href" # Get its href attribute } } }) # Display the links for link in data["links"]: print(f"Link: {link['text']} -> {link['url']}") #### Hacker News Example Let's put these concepts together to scrape stories from Hacker News: Code (python): import asyncio from monitoro_herd import HerdClient async def scrape_hacker_news(): client = HerdClient("your-token") try: await client.initialize() devices = await client.list_devices() device = devices[0] page = await device.new_page() # Navigate to Hacker News print("Navigating to Hacker News...") await page.goto("https://news.ycombinator.com") # Extract stories and their metadata print("Extracting stories...") data = await page.extract({ # Extract the story elements "stories": { "_$r": ".athing", # Each story row "title": ".titleline > a", # Story title "site": ".sitestr", # Source website "link": { "_
quot;: ".titleline > a", # Story link "attribute": "href" # Get the URL } }, # Extract the metadata (points, author, etc.) "metadata": { "_$r": ".subline", # Metadata rows "points": ".score", # Points count "author": ".hnuser", # Author username "time": ".age" # Submission time } }) # Combine stories with their metadata # (They're in separate lists but in the same order) combined_stories = list(zip(data["stories"], data["metadata"])) # Display the first 3 stories print(f"\nExtracted {len(combined_stories)} stories:") for i, (story, meta) in enumerate(combined_stories[:3]): print(f"\nStory {i+1}:") print(f"Title: {story['title']}") if "site" in story: print(f"Site: {story['site']}") print(f"Link: {story['link']}") if "points" in meta: print(f"Points: {meta['points']}") if "author" in meta: print(f"Author: {meta['author']}") if "time" in meta: print(f"Posted: {meta['time']}") finally: await page.close() await client.close() # Run the function asyncio.run(scrape_hacker_news()) ## Tips for Successful Automation 1. **Start Simple**: Begin with basic extractions before moving to complex interactions 2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely 3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks 4. **Close Resources**: Always close pages and clients when done to avoid resource leaks 5. **Test Incrementally**: Build your automation step by step, testing each part 6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods 7. **Debug with Screenshots**: Take screenshots during automation to see what's happening ## Next Steps Now that you've created your first automation, you can: - Explore more complex selectors and extraction patterns - Learn how to handle authentication and login flows - Set up scheduled automations for regular data collection - Integrate with your existing systems via APIs == Document: Data Extraction URL: https://herd.garden/docs/data-extraction # Data Extraction Welcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines. ## Understanding Selectors Herd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system. ### Basic Extraction ## javascript The simplest form of extraction uses CSS selectors to target elements: Code (javascript): // Extract basic text content const data = await page.extract({ title: 'h1', // Extracts the main heading description: 'p', // Extracts the first paragraph link: 'a' // Extracts the first link text }); console.log(data.title); // "Welcome to Our Website" console.log(data.description); // "This is our homepage." ## python The simplest form of extraction uses CSS selectors to target elements: Code (python): # Extract basic text content data = await page.extract({ "title": "h1", # Extracts the main heading "description": "p", # Extracts the first paragraph "link": "a" # Extracts the first link text }) print(data["title"]) # "Welcome to Our Website" print(data["description"]) # "This is our homepage." ### Advanced Selector Syntax ## javascript For more complex extraction needs, use the expanded object syntax: Code (javascript): const data = await page.extract({ title: { _$: 'h1', // CSS selector attribute: 'id' // Extract the ID attribute instead of text }, price: { _$: '.price', // Target price element pipes: ['parseNumber'] // Apply transformation } }); ## python For more complex extraction needs, use the expanded object syntax: Code (python): data = await page.extract({ "title": { "_
quot;: "h1", # CSS selector "attribute": "id" # Extract the ID attribute instead of text }, "price": { "_
quot;: ".price", # Target price element "pipes": ["parseNumber"] # Apply transformation } }) ### Extracting Lists of Items ## javascript To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (javascript): const data = await page.extract({ items: { _$r: '.item', // Find all elements with class "item" title: 'h2', // For each item, get the title price: '.price', // For each item, get the price date: 'time' // For each item, get the date } }); // Access the extracted items data.items.forEach(item => { console.log(`${item.title}: ${item.price}, Posted: ${item.date}`); }); ## python To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (python): data = await page.extract({ "items": { "_$r": ".item", # Find all elements with class "item" "title": "h2", # For each item, get the title "price": ".price", # For each item, get the price "date": "time" # For each item, get the date } }) # Access the extracted items for item in data["items"]: print(f"{item['title']}: {item['price']}, Posted: {item['date']}") ### Nested Extraction ## javascript You can nest selectors to extract hierarchical data: Code (javascript): const data = await page.extract({ product: { name: '.product-name', details: { _$: '.product-details', specs: { _$r: '.spec-item', label: '.spec-label', value: '.spec-value' } } } }); ## python You can nest selectors to extract hierarchical data: Code (python): data = await page.extract({ "product": { "name": ".product-name", "details": { "_
quot;: ".product-details", "specs": { "_$r": ".spec-item", "label": ".spec-label", "value": ".spec-value" } } } }) ## Special Selectors Herd provides special selectors to handle various extraction scenarios: ### Root Selector (`:root`) The `:root` selector refers to the current element in context: ## javascript Code (javascript): const data = await page.extract({ items: { _$r: '.item', someElement: ':root', // Extract text of the .item element itself classes: { _$: ':root', attribute: 'class' // Extract class attribute of the same element } } }); ## python Code (python): data = await page.extract({ "items": { "_$r": ".item", "someElement": ":root", # Extract text of the .item element itself "classes": { "_
quot;: ":root", "attribute": "class" # Extract class attribute of the same element } } }) ### Property Extraction You can extract JavaScript properties from elements: ## javascript Code (javascript): const data = await page.extract({ dimensions: { _$: '.box', property: 'getBoundingClientRect' // Get element dimensions }, html: { _$: '.content', property: 'innerHTML' // Get inner HTML } }); ## python Code (python): data = await page.extract({ "dimensions": { "_
quot;: ".box", "property": "getBoundingClientRect" # Get element dimensions }, "html": { "_
quot;: ".content", "property": "innerHTML" # Get inner HTML } }) ## Transformation Pipelines Herd includes powerful transformation pipelines to process extracted data: ### Available Transformations | Pipe | Description | Example Input | Example Output | |------|-------------|--------------|----------------| | `trim` | Removes whitespace from start/end | `" Hello "` | `"Hello"` | | `toLowerCase` | Converts text to lowercase | `"HELLO"` | `"hello"` | | `toUpperCase` | Converts text to uppercase | `"hello"` | `"HELLO"` | | `parseNumber` | Extracts numbers from text | `"$1,2K.45"` | `1200.45` | | `parseDate` | Converts text to date | `"2024-01-15"` | `"2024-01-15T00:00:00.000Z"` | | `parseDateTime` | Converts text to datetime | `"2024-01-15T12:00:00Z"` | `"2024-01-15T12:00:00.000Z"` | ### Using Transformations Apply transformations using the `pipes` property: ## javascript Code (javascript): const data = await page.extract({ price: { _$: '.price', pipes: ['parseNumber'] // Convert "$1,234.56" to 1234.56 }, title: { _$: 'h1', pipes: ['trim', 'toLowerCase'] // Apply multiple transformations } }); ## python Code (python): data = await page.extract({ "price": { "_
quot;: ".price", "pipes": ["parseNumber"] # Convert "$1,234.56" to 1234.56 }, "title": { "_
quot;: "h1", "pipes": ["trim", "toLowerCase"] # Apply multiple transformations } }) ### Handling Currency and Large Numbers The `parseNumber` transformation handles various formats: ## javascript Code (javascript): const data = await page.extract({ price1: { _$: '.price-1', // Contains "$1,234.56" pipes: ['parseNumber'] // Result: 1234.56 }, price2: { _$: '.price-2', // Contains "$1.5M" pipes: ['parseNumber'] // Result: 1500000 }, price3: { _$: '.price-3', // Contains "1.5T€" pipes: ['parseNumber'] // Result: 1500000000000 } }); ## python Code (python): data = await page.extract({ "price1": { "_
quot;: ".price-1", # Contains "$1,234.56" "pipes": ["parseNumber"] # Result: 1234.56 }, "price2": { "_
quot;: ".price-2", # Contains "$1.5M" "pipes": ["parseNumber"] # Result: 1500000 }, "price3": { "_
quot;: ".price-3", # Contains "1.5T€" "pipes": ["parseNumber"] # Result: 1500000000000 } }) ## Real-World Examples Let's look at some practical examples of data extraction: ### E-commerce Product Listing Extract products from a search results page: ## javascript Code (javascript): const searchResults = await page.extract({ products: { _$r: '[data-component-type="s-search-result"]', title: { _$: 'h2 .a-link-normal', pipes: ['trim'] }, price: { _$: '.a-price .a-offscreen', pipes: ['parseNumber'] }, rating: { _$: '.a-icon-star-small .a-icon-alt', pipes: ['trim'] }, reviews: { _$: '.a-size-base.s-underline-text', pipes: ['trim'] } } }); ## python Code (python): searchResults = await page.extract({ "products": { "_$r": '[data-component-type="s-search-result"]', "title": { "_
quot;: "h2 .a-link-normal", "pipes": ["trim"] }, "price": { "_
quot;: ".a-price .a-offscreen", "pipes": ["parseNumber"] }, "rating": { "_
quot;: ".a-icon-star-small .a-icon-alt", "pipes": ["trim"] }, "reviews": { "_
quot;: ".a-size-base.s-underline-text", "pipes": ["trim"] } } }) ### News Article List Extract articles from a news site: ## javascript Code (javascript): const articles = await page.extract({ items: { _$r: '.item', title: { _$: 'h2', pipes: ['trim', 'toLowerCase'] }, price: { _$: '.price', pipes: ['parseNumber'] }, date: { _$: 'time', pipes: ['parseDate'] } } }); ## python Code (python): articles = await page.extract({ "items": { "_$r": ".item", "title": { "_
quot;: "h2", "pipes": ["trim", "toLowerCase"] }, "price": { "_
quot;: ".price", "pipes": ["parseNumber"] }, "date": { "_
quot;: "time", "pipes": ["parseDate"] } } }) ## Advanced Techniques ### Handling Dynamic Content For dynamic content that loads after the page is ready: ## javascript Code (javascript): // Wait for dynamic content to load await page.waitForElement('#dynamic span'); // Then extract the content const data = await page.extract({ content: '#dynamic span' }); ## python Code (python): # Wait for dynamic content to load await page.waitForElement('#dynamic span') # Then extract the content data = await page.extract({ "content": "#dynamic span" }) ### Extracting Page Metadata Extract information about the page itself: ## javascript Code (javascript): const pageInfo = await page.extract({ title: 'title', metaDescription: 'meta[name="description"]', canonicalUrl: { _$: 'link[rel="canonical"]', attribute: 'href' } }); ## python Code (python): pageInfo = await page.extract({ "title": "title", "metaDescription": 'meta[name="description"]', "canonicalUrl": { "_
quot;: 'link[rel="canonical"]', "attribute": "href" } }) ## Tips for Effective Extraction 1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction 2. **Test Incrementally**: Build your extraction schema step by step, testing each part 3. **Handle Missing Data**: Always account for elements that might not exist on the page 4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed 5. **Combine with Interactions**: For complex sites, interact with the page before extraction ## Next Steps Now that you understand Herd's data extraction system, you can: - Create complex extraction schemas for any website - Transform raw data into structured, usable formats - Build powerful automations that collect and process web data == Document: Getting Started URL: https://herd.garden/docs/getting-started # Getting Started with Herd This guide will help you get up and running with Herd quickly to run your first trail. ## What is Herd? Herd connects AI Agents to websites using your own browser credentials. It enables you to: - **Run Trails** - pre-built automations for specific websites and tasks - **Extract data and interact with websites** using your logged-in browser sessions - **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude ## Quick Start ### 1. Install the Browser Extension Chrome Edge Brave ### 2. Register Your Browser After installing the extension: 1. Click the Herd icon in your browser toolbar 2. Sign in with your Herd account (or create one) 3. Name your device and register it ![Browser Registration](https://herd.garden/register-device.png) ### 3. Install the Herd SDK Install the Herd SDK using npm: ## npm Code (bash): npm install -g @monitoro/herd ## yarn Code (bash): yarn global add @monitoro/herd ## pnpm Code (bash): pnpm add -g @monitoro/herd ### 4. Run Your First Trail The browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out: Code (bash): herd trail run @herd/browser -a markdown -p '{"url": "https://example.com"}' That's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config: Code (json): { "mcpServers": { "browser": { "command": "herd", "args": [ "trail", "server", "@herd/browser" ] } } } ## For Developers You can also automate your browser with the Herd SDK. Connect to it with your AI agents or code: ## javascript Code (javascript): // Connect to your Herd device const client = new HerdClient('your-token'); await client.initialize(); const devices = await client.listDevices(); const device = devices[0]; // Create a new page and navigate const page = await device.newPage(); await page.goto("https://example.com"); // Extract data using simple selectors const data = await page.extract({ title: "h1", description: "p", link: "a" }); console.log("Extracted data:", data); ## python Code (python): from monitoro_herd import HerdClient # Connect to your Herd device client = HerdClient("your-token") await client.initialize() devices = await client.list_devices() device = devices[0] # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Extract data using simple selectors data = await page.extract({ "title": "h1", "description": "p", "link": "a" }) print("Extracted data:", data) ## What's Next? Now that you've run your first trail, you can: - [Explore available trails](/trails) - Browse pre-built trails for various websites - [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages - [Create your own trail](/docs/trails-automations) - Build and share your own custom trails ## Need Help? If you encounter any issues during setup: - Make sure your browser extension is correctly installed and you're signed in - Check that your device is registered in the [device dashboard](/devices) - Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions .browser-btn { display: inline-flex; align-items: center; padding: 0.2rem 1rem; background-color: #1f2937; color: white; border-radius: 0.375rem; font-size: 1.2rem; font-weight: 500; text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.1); } .browser-btn:hover { background-color: #374151; } == Document: Trails Automations URL: https://herd.garden/docs/trails-automations # Trails Trails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process. ## javascript Trails are fully supported in the JavaScript SDK. ## Creating a Trail A trail defines the following components: - **urls.ts**: Exports an array of URL definitions - **selectors.ts**: Exports an array of selector configurations - **actions.ts**: Exports action classes that implement the `TrailAction` interface A trail at the minimum has the following structure: Code: google-search/ urls.ts selectors.ts actions.ts package.json The `package.json` file defines the trail and its dependencies: Code (json): { "name": "google-search", "description": "Search google for webpages.", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } You should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code. ## Trail Implementation Guide ### Step 1: Set up the trail structure Create a new directory for your trail with the following files: Code: my-trail/ urls.ts selectors.ts actions.ts package.json Add the basic package.json configuration: Code (json): { "name": "my-trail", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } ### Step 2: Define URLs In `urls.ts`, export an array of URL definitions that your trail will interact with: Code (typescript): export default [{ "id": "my-url", "template": "https://example.com/path?param1={param1}&param2={param2}", "description": "Description of what this URL represents", "examples": [ { "param1": "value1", "param2": "value2" } ], "params": { "param1": { "type": "string", "required": true, "description": "Description of param1" }, "param2": { "type": "string", "required": false, "default": "defaultValue", "description": "Description of param2" } } }]; ### Step 3: Define Selectors In `selectors.ts`, export an array of selector configurations that define how to extract data from web pages: Code (typescript): export default [{ "id": "my-selector", "value": { "dataKey": { "_$r": "#main-container", "title": { "_
quot;: ".title" }, "description": { "_
quot;: ".description" }, "link": { "_
quot;: "a.link", "attribute": "href" } } }, "description": "Selector for extracting specific data", "examples": [ { "urlId": "my-url", "urlParams": { "param1": "value1", "param2": "value2" } } ] }]; ### Step 4: Implement Actions In `actions.ts`, define one or more action classes that implement the `TrailAction` interface: Code (typescript): import type { Device, TrailAction, TrailActionManifest, TrailRunResources } from "@monitoro/herd"; export class MyTrailAction implements TrailAction { manifest: TrailActionManifest = { name: "my-action", description: "Description of what this action does", params: { param1: { type: "string", description: "Description of param1" }, param2: { type: "number", description: "Description of param2", default: 10 } }, result: { type: "array", description: "Description of the result", items: { type: "object", properties: { property1: { type: "string" }, property2: { type: "number" } } } }, examples: [ { "param1": "value1", "param2": 10 } ] } async test(device: Device, params: Record, resources: TrailRunResources) { try { const result = await this.run(device, params, resources); // Validate result if (!result || result.length === 0) { return { status: "error", message: "No results found", result: [] }; } return { status: "success", result }; } catch (e) { return { status: "error", message: `Error: ${e}`, result: null }; } } async run(device: Device, params: Record, resources: TrailRunResources) { const { param1, param2 } = params; const page = await device.newPage(); try { // Navigate to URL using the URL template from urls.ts await page.goto(resources.url('my-url', { param1, param2 })); // Extract data using selectors from selectors.ts const extracted = await page.extract(resources.selector('my-selector')); // Process extracted data const results = (extracted as any)?.dataKey || []; // Return processed results return results; } finally { await page.close(); } } } ### Step 5: Testing and debugging Use the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest): Code (bash): herd trail test --action my-trail You can also watch for changes in the trail and re-run tests: Code (bash): herd trail test --action my-trail --watch # or herd trail test -a my-trail -w And you can also test selectors only: Code (bash): herd trail test --selector my-selector And watch for changes in the selectors: Code (bash): herd trail test --selector my-selector --watch # or herd trail test -s my-selector -w ### Step 6: Publish your trail Publishing is coming soon! ### Best Practices 1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc. 2. **Performance**: Minimize page loads and extract as much data as possible from each page. 3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain. 4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios. 5. **Versioning**: Increment your trail's version in package.json when making changes. ## python Trails support for Python SDK is coming soon. Stay tuned for updates! In the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them. ==

Document

llms-full.txt

Open llms-full.txt
Herd Documentation
================================================================================

Document: Alternative Herd Vs Apify
URL: https://herd.garden/docs/alternative-herd-vs-apify

# Herd vs Apify: A Cost-Effective Alternative for Web Automation

Apify is a popular platform for web scraping and automation, but its cloud-based infrastructure can be costly and limiting. Herd offers a compelling alternative with similar capabilities but a fundamentally different approach that eliminates infrastructure costs and provides more control over your automation.

## Quick Comparison

| Feature | Herd | Apify |
| --- | --- | --- |
| **Primary Focus** | Browser automation & web scraping | Web scraping platform with cloud infrastructure |
| **Infrastructure** | Uses your existing browser | Cloud-based platform with managed instances |
| **Pricing Model** | Flat rate subscription | Usage-based pricing |
| **Browser Control** | Direct control of your browser | Remote control of cloud browsers |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome/Chromium in cloud |
| **Setup Required** | Simple browser extension | No browser setup (cloud-based) |
| **Authentication** | Uses existing browser sessions | Requires manual setup |
| **Data Extraction** | Built-in extraction tools | Various actor-based extraction tools |
| **Resource Usage** | Minimal (shared with browser) | Separate cloud resources (higher cost) |
| **Customization** | Full control of local environment | Limited to platform capabilities |

## Key Differences in Depth

### Infrastructure and Pricing Model

**Apify:**
- Cloud-based platform with usage-based pricing
- Costs scale with computation time and resource usage
- Requires paid proxy services for many use cases
- Monthly subscription plus usage-based fees

**Herd:**
- Uses your existing browser and computer
- No cloud infrastructure required
- Direct control of your local resources 
- Supports Chrome, Edge, Brave, Arc, Opera
- No additional infrastructure costs
- No separate compute units to pay for
- Simple and predictable pricing

### Browser Control and Authentication

**Apify:**
- Operates browsers in the cloud
- Must manually set up authentication flows
- Sessions are isolated and temporary
- Limited access to browser-specific features

**Herd:**
- Direct control of your own browser
- Uses your existing authenticated sessions
- Persistent cookies and storage between runs
- Full access to browser capabilities and extensions

### Setup and Customization

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Simple setup code
import { HerdClient } from '@monitoro/herd';

// Connect to your own browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

## apify

Code (javascript):
// Install the Apify SDK
npm install apify

// Create an actor
import { Actor } from 'apify';

// Run in Apify cloud environment
await Actor.init();

// Launch a browser in the cloud
const browser = await Actor.launchPuppeteer();
const page = await browser.newPage();
await page.goto('https://example.com');

// Must manually handle stopping the actor
await Actor.exit();

### Data Extraction Capabilities

**Apify:**
- Offers pre-built actors for common websites
- Large marketplace of ready-made solutions
- Extraction limited to what actors provide
- Can become expensive for large-scale extraction

**Herd:**
- Powerful built-in extraction API
- Simple selector-based data retrieval
- Access to authenticated content
- Extract data without usage limits

## Use Case Comparisons

### Web Scraping with Authentication

## herd-auth

Code (javascript):
// Using Herd with an already authenticated browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Access a site where you're already logged in
const page = await device.newPage();
await page.goto('https://account.example.com/dashboard');

// Extract authenticated data directly
const userData = await page.extract({
  username: '.user-profile .username',
  accountType: '.account-type',
  balance: '.account-balance',
  transactions: {
    _$r: '.transaction-item',
    date: '.transaction-date',
    amount: '.transaction-amount',
    description: '.transaction-description'
  }
});

console.log(userData);
await client.close();

## apify-auth

Code (javascript):
// Using Apify with manual authentication
import { Actor } from 'apify';

await Actor.init();
const browser = await Actor.launchPuppeteer();
const page = await browser.newPage();

// Need to manually log in first
await page.goto('https://example.com/login');
await page.type('#username', 'your-username');
await page.type('#password', 'your-password');
await page.click('.login-button');
await page.waitForNavigation();

// Now navigate to the dashboard
await page.goto('https://account.example.com/dashboard');

// Extract data with multiple evaluations
const username = await page.$eval('.user-profile .username', el => el.textContent);
const accountType = await page.$eval('.account-type', el => el.textContent);
const balanceText = await page.$eval('.account-balance', el => el.textContent);
const balance = parseFloat(balanceText.replace(/[^0-9.-]+/g, ''));

// Extract transaction data
const transactions = await page.$eval('.transaction-item', items => 
  items.map(item => ({
    date: item.querySelector('.transaction-date').textContent,
    amount: item.querySelector('.transaction-amount').textContent,
    description: item.querySelector('.transaction-description').textContent
  }))
);

const userData = {
  username,
  accountType,
  balance,
  transactions
};

console.log(userData);
await Actor.exit();

### Multi-Page Crawling

## herd-crawl

Code (javascript):
// Using Herd for multi-page crawling
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Collect all product links first
const productLinks = await page.extract({
  links: {
    _$r: '.product-card a',
    url: { attribute: 'href' }
  }
});

// Visit each product page and extract details
const products = [];
for (const { url } of productLinks.links) {
  await page.goto(url);
  
  const productData = await page.extract({
    name: '.product-name',
    price: '.product-price',
    description: '.product-description',
    specs: {
      _$r: '.spec-item',
      name: '.spec-name',
      value: '.spec-value'
    }
  });
  
  products.push(productData);
}

console.log(products);
await client.close();

## apify-crawl

Code (javascript):
// Using Apify for multi-page crawling
import { Actor, PuppeteerCrawler } from 'apify';

await Actor.init();

// Define the crawler
const crawler = new PuppeteerCrawler({
  async requestHandler({ request, page }) {
    console.log(`Processing ${request.url}...`);
    
    if (request.userData.detailPage) {
      // Extract product details
      const productData = {
        url: request.url,
        name: await page.$eval('.product-name', el => el.textContent),
        price: await page.$eval('.product-price', el => el.textContent),
        description: await page.$eval('.product-description', el => el.textContent),
        specs: await page.$eval('.spec-item', items => 
          items.map(item => ({
            name: item.querySelector('.spec-name').textContent,
            value: item.querySelector('.spec-value').textContent
          }))
        )
      };
      
      // Save the extracted data
      await Actor.pushData(productData);
    } else {
      // On the listing page, extract links to products
      const productLinks = await page.$eval('.product-card a', links => 
        links.map(link => link.href)
      );
      
      // Enqueue product detail pages
      for (const url of productLinks) {
        await crawler.requestQueue.addRequest({
          url,
          userData: { detailPage: true }
        });
      }
    }
  },
  maxRequestsPerCrawl: 100,
});

// Start with the product listing page
await crawler.run(['https://example.com/products']);

await Actor.exit();

## Migration Guide: From Apify to Herd

Transitioning from Apify to Herd is straightforward. Here's a guide to help you migrate:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   npm install @monitoro/herd

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Apify | Herd | Notes |
| --- | --- | --- |
| `Actor.init()` | `const client = new HerdClient(apiUrl, token)`  `await client.initialize()` | Herd uses a simple client-server model |
| `Actor.launchPuppeteer()` | `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `browser.newPage()` | `await device.newPage()` | Similar API |
| `page.goto(url)` | `await page.goto(url)` | Identical usage |
| `page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd has a more powerful extraction API |
| `Actor.pushData(data)` | Store data directly in your code | No platform-specific storage |
| `Actor.exit()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Handling Authentication

**Apify:**

Code (javascript):
// Manual login process
await page.goto('https://example.com/login');
await page.type('#username', 'user');
await page.type('#password', 'pass');
await page.click('#login-button');

**Herd:**

Code (javascript):
// Simply use your already authenticated browser
await page.goto('https://example.com/dashboard');  // Already logged in

## Why Choose Herd Over Apify?

### 1. Cost Efficiency

Herd eliminates the need for cloud infrastructure, resulting in:
- No usage-based computation costs
- No proxy costs for most use cases
- Significant cost savings for regular automation
- Predictable pricing independent of usage volume

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to handle authentication flows in code
- Access to sites with complex auth (2FA, CAPTCHA)
- Use existing cookies, local storage, and sessions

### 3. Local Control and Privacy

Herd provides:
- Full control over the automation environment
- Higher privacy (data stays on your machine)
- Direct access to local resources when needed
- No dependence on third-party cloud infrastructure

### 4. Simpler Development Experience

Herd offers:
- More intuitive APIs for common tasks
- Real-time debugging in your browser
- No need to deploy or manage cloud resources
- Faster iteration during development

## Get Started with Herd Today

Ready to try a more flexible alternative to Apify? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide all the capabilities you need for web automation and scraping at a fraction of the cost of cloud-based solutions like Apify.

================================================================================

Document: Alternative Herd Vs Browserbase
URL: https://herd.garden/docs/alternative-herd-vs-browserbase

# Herd vs Browserbase: No-Infrastructure Browser Automation

Browserbase provides cloud-based headless browsers for automation and AI applications. While it offers a reliable platform for running browser instances, Herd takes a fundamentally different approach by leveraging your existing browsers, eliminating infrastructure costs and complexity.

## Quick Comparison

| Feature | Herd | Browserbase |
| --- | --- | --- |
| **Browser Location** | Your local machine | Cloud-based infrastructure |
| **Infrastructure Needed** | None (uses your browser) | Managed cloud infrastructure |
| **Pricing Model** | Flat subscription | Usage-based pricing |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium in cloud |
| **Latency** | Minimal (1-hop) | Higher (multiple hops) |
| **Authentication** | Uses existing browser sessions | Requires manual setup |
| **Framework Support** | JavaScript/Python SDKs | Stagehand, Playwright, Puppeteer, Selenium |
| **Setup Required** | Browser extension installation | No installation (cloud-based) |
| **Resource Constraints** | Depends on local resources | Limited by pricing tier |

## Key Differences in Depth

### Infrastructure and Cost Model

**Browserbase:**
- Runs browsers on managed cloud infrastructure
- Costs scale with usage and session duration
- Requires networking between your code and cloud
- Additional costs for premium features like proxies

**Herd:**
- Uses browsers already installed on your machine
- No cloud infrastructure required
- Direct access to your local machine resources
- Supports Chrome, Edge, Brave, Arc, Opera
- Fixed, predictable pricing not tied to usage
- Local execution with minimal network overhead
- No additional infrastructure costs to manage

### Setup and Integration

## herd

Code (javascript):
// Simple installation - no code required
// 1. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox/Safari not supported)
// 2. Connect your browser to Herd

// Simple connection to your browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a new page
const page = await device.newPage();
await page.goto('https://example.com');

## browserbase

Code (javascript):
// Install the SDK
npm install browserbase

// Connect to cloud infrastructure
import { Browserbase } from 'browserbase';

const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create a session on cloud infrastructure
const session = await bb.sessions.create({
  timeout: 60, // Session timeout in seconds
});

// Create a page in the cloud browser
const page = await session.newPage();
await page.goto('https://example.com');

### Session Management and Performance

**Browserbase:**
- Cloud-based sessions with timeout limits
- Performance dependent on cloud resources and network
- Sessions isolated from local environment
- Must explicitly manage session lifecycle

**Herd:**
- Direct access to local browser sessions
- Local performance without network latency
- Integrated with your local environment
- Sessions persist with your browser

### Authentication and User Context

**Browserbase:**
- Requires implementing authentication for each session
- Isolated sessions without access to existing cookies
- Must manually handle login flows
- Credentials need to be stored and managed

**Herd:**
- Uses your browser's existing authenticated sessions
- Access to all cookies, local storage, and session data
- No need to implement authentication flows
- Use sites you're already logged into

## Use Case Comparisons

### Web Automation for Logged-in Services

## herd-auth

Code (javascript):
// Using Herd with pre-authenticated browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Directly access authenticated service
const page = await device.newPage();
await page.goto('https://app.example.com/dashboard');  // Already logged in

// Perform actions on authenticated page
await page.click('.create-new-button');
await page.type('#item-name', 'New Item');
await page.click('.save-button');

// Verify result
const confirmationText = await page.$eval('.confirmation', el => el.textContent);
console.log(confirmationText);

## browserbase-auth

Code (javascript):
// Using Browserbase with manual authentication
const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create cloud browser session
const session = await bb.sessions.create({
  timeout: 300,  // Longer timeout for auth flow
});

// Create page and handle login manually
const page = await session.newPage();

// Navigate to login page
await page.goto('https://app.example.com/login');

// Fill login form
await page.type('#email', 'user@example.com');
await page.type('#password', 'your-secure-password');
await page.click('#login-button');

// Wait for login to complete
await page.waitForNavigation();

// Now navigate to dashboard
await page.goto('https://app.example.com/dashboard');

// Perform actions on authenticated page
await page.click('.create-new-button');
await page.type('#item-name', 'New Item');
await page.click('.save-button');

// Verify result
const confirmationText = await page.$eval('.confirmation', el => el.textContent);
console.log(confirmationText);

// Must explicitly end session
await session.close();

### Data Extraction at Scale

## herd-extract

Code (javascript):
// Using Herd for data extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Open multiple pages for parallel extraction
const pages = await Promise.all([1, 2, 3].map(() => device.newPage()));

// Extract data from multiple sources in parallel
const results = await Promise.all(pages.map(async (page, index) => {
  await page.goto(`https://example.com/category/${index+1}`);
  
  // Use Herd's extraction API
  const data = await page.extract({
    categoryName: '.category-header h1',
    items: {
      _$r: '.product-item',
      title: '.product-title',
      price: '.product-price',
      rating: '.rating-value'
    }
  });
  
  return data;
}));

// Close pages when done
await Promise.all(pages.map(page => page.close()));
await client.close();

console.log(results);

## browserbase-extract

Code (javascript):
// Using Browserbase for data extraction
const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create separate sessions for parallel extraction
const sessions = await Promise.all([1, 2, 3].map(() => 
  bb.sessions.create({ timeout: 120 })
));

// Extract data from multiple sources
const results = await Promise.all(sessions.map(async (session, index) => {
  const page = await session.newPage();
  await page.goto(`https://example.com/category/${index+1}`);
  
  // Extract data using Puppeteer-style selectors
  const categoryName = await page.$eval('.category-header h1', el => el.textContent);
  
  const itemElements = await page.$('.product-item');
  const items = [];
  
  for (const element of itemElements) {
    const title = await element.$eval('.product-title', el => el.textContent);
    const price = await element.$eval('.product-price', el => el.textContent);
    
    let rating = null;
    try {
      rating = await element.$eval('.rating-value', el => el.textContent);
    } catch (e) {
      // Element might not exist
    }
    
    items.push({ title, price, rating });
  }
  
  // Must close session when done
  await session.close();
  
  return { categoryName, items };
}));

console.log(results);

## Migration Guide: From Browserbase to Herd

Transitioning from Browserbase to Herd is straightforward. Here's a guide to help you migrate:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Browserbase | Herd | Notes |
| --- | --- | --- |
| `new Browserbase({ api_key })` | `new HerdClient(apiUrl, token)`  `await client.initialize()` | Herd uses a client-server architecture |
| `bb.sessions.create()` | `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `session.newPage()` | `await device.newPage()` | Similar API |
| `await page.goto(url)` | `await page.goto(url)` | Identical usage |
| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |
| `await page.click(selector)` | `await page.click(selector)` | Identical usage |
| `await page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd offers a more powerful extraction API |
| `await session.close()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Framework Integration

**Browserbase:**

Code (javascript):
// Browserbase with Playwright
const { chromium } = require('playwright');
const browser = await chromium.connectOverCDP(session.wsEndpoint);
const page = await browser.newPage();

**Herd:**

Code (javascript):
// Herd uses its own API directly
const page = await device.newPage();
// Direct integrations with testing frameworks available

## Why Choose Herd Over Browserbase?

### 1. No Cloud Infrastructure Required

Herd eliminates the need for cloud infrastructure, providing:
- Zero dependency on remote browser instances
- No need to manage cloud resources
- Reduced latency with local execution
- Complete isolation from cloud service disruptions

### 2. Cost Predictability and Efficiency

Herd offers a more predictable and often lower cost:
- No usage-based billing surprises
- No charges based on session duration
- No additional costs for scaling automation
- Fixed costs regardless of automation volume

### 3. Use Existing Browser State and Auth

With Herd, you can leverage your browser's existing state:
- Use sites you're already logged into
- Access to all browser extensions
- Utilize stored passwords and authentication
- No need to manage credentials in code

### 4. Lower Latency and Higher Performance

Herd provides performance advantages with local execution:
- No network latency between code and browser
- Faster execution of automation tasks
- Direct access to local resources
- No timeout limitations on sessions

## Get Started with Herd Today

Ready to try a more flexible alternative to Browserbase? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide all the capabilities you need for web automation without the complexity and costs of cloud-based infrastructure.

================================================================================

Document: Alternative Herd Vs Firecrawl
URL: https://herd.garden/docs/alternative-herd-vs-firecrawl

# Herd vs Firecrawl: Flexible Browser Automation and Data Extraction

Firecrawl is a specialized web scraping and crawling tool designed primarily for extracting and cleaning web content, especially for use with LLMs. While Firecrawl offers powerful crawling capabilities, Herd provides a more comprehensive browser automation solution with greater flexibility and control over the browsing experience.

## Quick Comparison

| Feature | Herd | Firecrawl |
| --- | --- | --- |
| **Primary Focus** | Complete browser automation | Web crawling and content extraction |
| **Infrastructure** | Uses your existing browser | Cloud-based crawling infrastructure |
| **Pricing Model** | Flat subscription | Usage-based pricing |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Managed cloud browsers |
| **Browser Control** | Full interactive browser control | Limited to crawling and extraction |
| **Authentication** | Uses existing browser sessions | Limited authentication capabilities |
| **Content Processing** | Raw and structured data extraction | Optimized for clean text/markdown output |
| **Usage Flexibility** | General-purpose automation | Specialized for content crawling |
| **Interactive Workflows** | Supports complex interactions | Limited to extraction patterns |

## Key Differences in Depth

### Primary Focus and Capabilities

**Firecrawl:**
- Specialized in high-quality web content extraction
- Optimized for converting websites to clean markdown
- Focused on crawling through website links
- Built primarily for LLM data ingestion
- Limited interactive capabilities

**Herd:**
- Complete browser automation platform
- Full interactive control of browser actions
- Supports Chrome, Edge, Brave, Arc, Opera
- Supports both data extraction and automation workflows
- General-purpose browser control
- Rich interaction with web applications

### Infrastructure and Execution Model

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Connect to your existing browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Full browser automation capabilities
const page = await device.newPage();
await page.goto('https://example.com');

## firecrawl

Code (javascript):
// Install the Firecrawl SDK
npm install @mendable/firecrawl-js

// Connect to Firecrawl's cloud service
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Send request to cloud-based crawling service
const result = await app.scrapeUrl('example.com');
console.log(result.markdown);

### Data Extraction Approaches

**Firecrawl:**
- Specializes in converting HTML to clean markdown
- Automatically handles JavaScript rendering
- Built-in content cleaning and formatting
- Output optimized for LLM consumption
- Limited customization of extraction patterns

**Herd:**
- Flexible data extraction patterns
- CSS selector-based extraction
- Support for complex nested data structures
- Raw data access and custom transformations
- Complete control over extraction logic

## Use Case Comparisons

### Website Content Extraction

## herd-extract

Code (javascript):
// Using Herd for content extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/article');

// Extract structured content with control over the format
const articleData = await page.extract({
  title: '.article-title',
  author: '.author-name',
  published: {
    _$: '.publish-date',
    pipes: ['parseDate']
  },
  content: '.article-body',
  tags: {
    _$r: '.tag',
    text: ':root'
  }
});

console.log(articleData);
await client.close();

## firecrawl-extract

Code (javascript):
// Using Firecrawl for content extraction
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Simple URL-based extraction
const scrapeResult = await app.scrapeUrl('https://example.com/article');

if (scrapeResult.success) {
  // Get the clean markdown content
  console.log(scrapeResult.markdown);
  
  // Access metadata
  console.log(scrapeResult.metadata);
} else {
  console.error('Failed to scrape:', scrapeResult.error);
}

### Interactive Web Automation

## herd-automation

Code (javascript):
// Using Herd for interactive web automation
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();

// Navigate to a web application
await page.goto('https://app.example.com/dashboard');

// Fill out a form
await page.click('.create-new-button');
await page.type('#title-input', 'New Project');
await page.type('#description-input', 'This is a test project created by automation');
await page.select('#category-select', 'development');

// Upload a file
const fileInput = await page.$('input[type="file"]');
await fileInput.uploadFile('/path/to/local/file.pdf');

// Submit the form
await page.click('.submit-button');

// Wait for confirmation and extract result
await page.waitForSelector('.success-message');
const confirmationText = await page.$eval('.success-message', el => el.textContent);
console.log('Form submitted successfully:', confirmationText);

await client.close();

## firecrawl-automation

Code (javascript):
// Firecrawl has limited interactive capabilities
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// For interactive tasks like form submission, 
// Firecrawl has limited capabilities, primarily focused
// on crawling and content extraction.

// You could use the actions feature for limited interactions:
const result = await app.scrapeUrl('https://app.example.com', {
  actions: [
    { type: 'click', selector: '.login-button' },
    { type: 'wait', time: 2000 }
    // Limited set of basic actions available
  ]
});

// But complex workflows like file uploads or 
// multi-step interactions require a more 
// comprehensive automation tool like Herd

### Multi-Page Crawling

## herd-crawl

Code (javascript):
// Using Herd for custom crawling
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Extract all product links
const productLinks = await page.extract({
  links: {
    _$r: '.product-card a',
    url: { attribute: 'href' }
  }
});

// Custom crawling logic with full control
const productDetails = [];
for (const { url } of productLinks.links) {
  // Navigate to each product page
  await page.goto(url);
  
  // Extract detailed information
  const product = await page.extract({
    name: '.product-name',
    price: '.product-price',
    description: '.product-description',
    inStock: '.stock-status'
  });
  
  productDetails.push(product);
  
  // You can implement custom logic: only continue if conditions are met
  if (productDetails.length >= 10) break;
}

console.log(productDetails);
await client.close();

## firecrawl-crawl

Code (javascript):
// Using Firecrawl for website crawling
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Crawl an entire site
const crawlResult = await app.crawlWebsite('example.com', {
  maxPages: 10,  // Limit the crawl
  includeSitemap: true, // Use sitemap if available
  followExternalLinks: false // Stay on the same domain
});

if (crawlResult.success) {
  // Access all crawled pages
  for (const page of crawlResult.pages) {
    console.log(`Page: ${page.url}`);
    console.log(`Content: ${page.markdown}`);
  }
} else {
  console.error('Crawl failed:', crawlResult.error);
}

## Migration Guide: From Firecrawl to Herd

Transitioning from Firecrawl to Herd is straightforward. Here's a guide to help you migrate:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Firecrawl | Herd | Notes |
| --- | --- | --- |
| `new FirecrawlApp({ apiKey })` | `new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `app.scrapeUrl(url)` | `const page = await device.newPage()`  `await page.goto(url)`  `const data = await page.extract(...)` | More granular control in Herd |
| `result.markdown` | Custom extraction patterns with formatting | More flexible data extraction options |
| `app.crawlWebsite(domain)` | Custom crawling logic implemented with Herd's navigation and extraction APIs | Full control over crawling behavior |

### 3. Implementing Markdown Conversion

If you specifically need markdown output like Firecrawl provides:

Code (javascript):
// Helper function to convert extracted HTML to markdown
function htmlToMarkdown(html) {
  // Use a library like turndown
  const turndownService = new TurndownService();
  return turndownService.turndown(html);
}

// Extract with Herd and convert to markdown
const content = await page.extract({
  body: {
    _$: '.article-content',
    attribute: 'innerHTML'
  }
});

## Why Choose Herd Over Firecrawl?

### 1. Comprehensive Browser Control

Herd provides full browser automation capabilities:
- Complete interactive control beyond just crawling
- Support for complex user interactions
- Ability to automate any browser-based workflow
- Full access to browser APIs and capabilities

### 2. Flexible Authentication and Sessions

Herd's approach offers significant authentication advantages:
- Use your existing authenticated browser sessions
- No need to implement login flows
- Support for complex authentication scenarios
- Access to secure content without credential management

### 3. Customizable Extraction and Processing

Herd gives you complete control over data extraction:
- Custom extraction patterns for any website structure
- Flexible transformation of extracted data
- Support for complex nested data extraction
- Processing options beyond just markdown conversion

### 4. Broader Use Case Support

Herd supports a wider range of automation scenarios:
- Form submission and interactive workflows
- File uploads and downloads
- Conditional logic based on page content
- Testing and verification workflows

## Get Started with Herd Today

Ready to try a more flexible alternative to Firecrawl? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide enhanced capabilities for both content extraction and browser automation, giving you more control and flexibility than specialized crawling tools like Firecrawl.

================================================================================

Document: Alternative Herd Vs Mcp Sdk
URL: https://herd.garden/docs/alternative-herd-vs-mcp-sdk

# Herd vs MCP SDK: Streamlined Browser Automation

The Model Context Protocol (MCP) SDK provides browser automation capabilities primarily focused on AI agent integration. While MCP SDK offers powerful integration with Large Language Models, Herd provides a more accessible and straightforward approach to browser automation with simplified setup and direct browser control.

## Quick Comparison

| Feature | Herd | MCP SDK |
| --- | --- | --- |
| **Primary Focus** | General browser automation | AI agent browser automation |
| **Infrastructure** | Uses your existing browser | Requires separate browser setup |
| **API Design** | Simple, direct browser control | Protocol-oriented architecture |
| **Integration** | JavaScript/Python SDKs | Multiple languages supported |
| **Setup Complexity** | Simple browser extension | More complex server configuration |
| **Authentication** | Uses existing browser sessions | Requires manual configuration |
| **Learning Curve** | Shallow, familiar browser API | Steeper with protocol concepts |
| **Use Cases** | General automation and extraction | AI agent browsing tasks |

## Key Differences in Depth

### Focus and Architecture

**MCP SDK:**
- Designed primarily for AI model integration
- Protocol-based communication model
- Server-client architecture
- Focus on enabling AI agents to browse
- More complex protocol implementation

**Herd:**
- Direct browser automation focus
- Simple client-browser connection
- Intuitive API design
- Supports Chrome, Edge, Brave, Arc, Opera
- Streamlined API for common tasks
- Designed for developers first
- Lower implementation complexity

### Setup and Integration

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Simple direct connection to your browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

## mcp

Code (javascript):
// Install MCP SDK
npm install mcp-browser-automation

// Set up the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({
  port: 8000,
  // Additional configuration for the server
});

// Start the server
await server.start();

// Client side needs to implement MCP protocol
// to communicate with the server

// Then through MCP protocol interactions:
// 1. Create a browser session
// 2. Navigate to URL
// 3. Interact with page

### Integration with AI Systems

**MCP SDK:**
- Designed specifically for AI model integration
- Protocol-based approach for AI agents
- Built to enable AI systems to browse the web
- Complex implementation for general use cases
- Strong focus on AI agent capabilities

**Herd:**
- General-purpose browser automation
- Can be integrated with AI systems through standard APIs
- Simpler implementation for most use cases
- Direct browser control paradigm
- Focus on developer experience and simplicity

## Use Case Comparisons

### Basic Web Automation

## herd-auto

Code (javascript):
// Using Herd for basic web automation
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a new page
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com/login');

// Fill login form
await page.type('#username', 'test_user');
await page.type('#password', 'password123');
await page.click('.login-button');

// Wait for navigation and verify login
await page.waitForSelector('.dashboard');
const welcomeText = await page.$eval('.welcome-message', el => el.textContent);
console.log('Login successful:', welcomeText);

await client.close();

## mcp-auto

Code (javascript):
// Using MCP SDK for basic web automation
// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// For client-side interaction, implement the MCP protocol
// This is a simplified example showing the concept
const response = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'createSession',
    params: {}
  })
});
const { sessionId } = await response.json();

// Navigate to a website
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'navigate',
    sessionId,
    params: { url: 'https://example.com/login' }
  })
});

// Fill login form (multiple requests needed)
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'type',
    sessionId,
    params: { selector: '#username', text: 'test_user' }
  })
});

// Additional requests for password and clicking login button
// ...

// MCP SDK is more verbose for simple automation tasks
// and requires protocol knowledge

### Data Extraction Tasks

## herd-extract

Code (javascript):
// Using Herd for data extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Extract data using Herd's powerful extraction API
const productData = await page.extract({
  title: '.page-title',
  products: {
    _$r: '.product-item',  // Repeat for all products
    name: '.product-name',
    price: '.product-price',
    rating: '.rating-stars',
    available: '.stock-status'
  }
});

console.log(productData);
await client.close();

## mcp-extract

Code (javascript):
// Using MCP SDK for data extraction
// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// For client-side extraction, implement the MCP protocol
// This is a simplified example showing the concept
const response = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'createSession',
    params: {}
  })
});
const { sessionId } = await response.json();

// Navigate to the products page
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'navigate',
    sessionId,
    params: { url: 'https://example.com/products' }
  })
});

// Extract the page title
const titleResponse = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'evaluate',
    sessionId,
    params: { 
      script: "document.querySelector('.page-title').textContent" 
    }
  })
});
const { result: title } = await titleResponse.json();

// Extract product data would require more complex script execution
// or multiple requests to get all the product information
// ...

// MCP SDK requires more complex orchestration for data extraction
// compared to Herd's simplified extraction API

### AI Integration

## herd-ai

Code (javascript):
// Using Herd with AI integration
// First, set up Herd client as usual
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a function to handle AI requests for web content
async function fetchWebContentForAI(url, query) {
  const page = await device.newPage();
  await page.goto(url);
  
  // Extract relevant content based on the AI query
  const content = await page.extract({
    title: 'h1',
    mainContent: '.main-content',
    relevantSections: {
      _$r: '.content-section',
      heading: 'h2',
      text: 'p'
    }
  });
  
  // Close the page when done
  await page.close();
  
  // Return the content for AI processing
  return content;
}

// Example usage with an AI system
const aiPrompt = "Summarize the information about machine learning from example.com";
const url = "https://example.com/machine-learning";

// Get the content for the AI
const webContent = await fetchWebContentForAI(url, "machine learning");

// Feed the content to the AI system
const aiResponse = await callAISystem(aiPrompt, webContent);
console.log(aiResponse);

await client.close();

// This pattern keeps the AI integration simple and separate from
// the browser automation concerns

## mcp-ai

Code (javascript):
// Using MCP SDK with AI integration
// MCP is specifically designed for this use case

// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// This server can now be used by AI agents through the MCP protocol
console.log('MCP Browser Automation server is running on port 8000');

// When an AI system wants to browse, it would send requests like:
/*
{
  "action": "createSession",
  "params": {}
}
*/

// And receive responses like:
/*
{
  "sessionId": "session123",
  "status": "success"
}
*/

// The AI can then navigate, interact with pages, and extract content
// through the MCP protocol

// This architecture is optimized for AI systems that implement
// the MCP protocol, but requires more complex integration
// than direct SDK usage like Herd offers

## Migration Guide: From MCP SDK to Herd

Transitioning from MCP SDK to Herd simplifies your browser automation code. Here's a migration guide:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| MCP SDK | Herd | Notes |
| --- | --- | --- |
| MCP server setup | `new HerdClient(apiUrl, token)`  `await client.initialize()` | No server needed with Herd |
| Session creation via protocol | `const devices = await client.listDevices()`  `const device = devices[0]` | Simplified session management |
| Navigation requests | `const page = await device.newPage()`  `await page.goto(url)` | Direct browser control |
| Element interactions via protocol | `await page.click(selector)`  `await page.type(selector, text)` | Simpler interaction API |
| Data extraction with custom scripts | `await page.extract(selectors)` | Powerful extraction API |
| Session closing via protocol | `await client.close()` | Simple cleanup |

### 3. AI Integration Approach

**MCP SDK:**

Code (javascript):
// AI systems implement MCP protocol directly
// Complex integration but designed for AI

// AI system would send requests like:
const request = {
  action: "evaluateElement",
  params: { selector: ".content", attribute: "textContent" }
};
// And process responses

**Herd:**

Code (javascript):
// Build an adapter layer for AI integration
async function getWebContent(url, aiQuery) {
  // Use Herd to fetch and extract the content
  const page = await device.newPage();
  await page.goto(url);
  const content = await page.extract({ /* ... */ });
  await page.close();
  return content;
}

// Then use this in your AI system
const content = await getWebContent(url, query);
const aiResponse = await yourAISystem.process(content);

### 4. Simpler Setup

Herd simplifies your automation workflow:

- No need to run a server process
- Uses your existing browser
- Simple browser extension rather than complex setup
- Supports Chrome, Edge, Brave, Arc, Opera
- Works with browsers you're already using every day

## Why Choose Herd Over MCP SDK?

### 1. Simpler Developer Experience

Herd provides a more straightforward approach to browser automation:
- No complex protocol implementation
- Direct browser control API
- Familiar programming model
- Lower learning curve

### 2. Less Infrastructure to Manage

Herd eliminates the need for additional infrastructure:
- No server to set up and maintain
- Uses your existing browser
- Simpler deployment architecture
- Fewer moving parts

### 3. Powerful Built-in Capabilities

Herd includes powerful features out of the box:
- Sophisticated data extraction API
- Session and cookie management
- Authentication handling
- Browser state persistence

### 4. Broader Applicability

While MCP SDK focuses on AI integration, Herd supports:
- General browser automation
- Web scraping and data extraction
- Testing and monitoring
- Process automation

## Get Started with Herd

Ready to try a more straightforward alternative to MCP SDK? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation tasks with its intuitive API and direct browser control, providing a more accessible alternative to protocol-based approaches like MCP SDK.

================================================================================

Document: Alternative Herd Vs Monitoro
URL: https://herd.garden/docs/alternative-herd-vs-monitoro

# Herd vs Monitoro: Complementary Browser Tools

Herd and Monitoro are sister products created by the same team, designed to serve complementary but distinct purposes. While Herd provides programmatic browser control and multi-browser orchestration capabilities, Monitoro focuses on no-code monitoring and data extraction. Understanding their differences helps you choose the right tool for your specific needs.

## Quick Comparison

| Feature | Herd | Monitoro |
| --- | --- | --- |
| **Primary Focus** | Browser automation & orchestration | Website monitoring & data extraction |
| **Core Function** | Programmatic browser control | Monitoring webpages for changes |
| **Target User** | Developers & automation teams | Non-technical users & business teams |
| **Coding Required** | Yes (JavaScript/Python) | No (visual interface) |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Edge, Brave |
| **Browser Orchestration** | Multiple browsers and devices | Single-focus monitoring |
| **Implementation** | JavaScript/Python SDK | No-code browser extension |
| **Data Processing** | Programmatic data workflows | Automated alerts and integrations |
| **Best For** | Complex automation needs | Monitoring & simple data extraction |

## Understanding the Difference

### Herd

Herd is designed for **programmatic browser control and orchestration**, allowing developers to:
- Automate complex web tasks across multiple browsers
- Extract data from websites at scale
- Leverage their existing browsers for automation
- Build persistent automation workflows
- Orchestrate multiple browser instances simultaneously
- Create sophisticated data processing pipelines
- Works with Chrome, Edge, Brave, Arc, Opera

### Monitoro

Monitoro is designed for **no-code webpage monitoring and alerts**, allowing anyone to:
- Track changes on websites without coding
- Set up alerts when specific data changes
- Extract structured data from webpages
- Send notifications to various channels (Slack, Discord, etc.)
- Create automated workflows based on webpage changes
- Integrate with tools like Google Sheets and Airtable

## When to Use Each Tool

## herd-use

**Use Herd when you need to:**

- Create complex automation scripts
- Orchestrate multiple browsers
- Build sophisticated data extraction pipelines
- Integrate browser automation into your application
- Control browsers programmatically
- Run continuous automation jobs
- Implement advanced web interaction patterns
- Scale automation across multiple devices

**Example use cases:**
- Large-scale data extraction projects
- Multi-step workflow automation
- Integration testing across browsers
- Sophisticated web monitoring systems
- Building browser-based APIs
- Authentication-required data access

## monitoro-use

**Use Monitoro when you need to:**

- Monitor websites for changes without coding
- Get alerts when specific data changes
- Extract data and send it to other tools
- Create simple automations based on website changes
- Set up monitoring dashboards
- Share monitoring alerts with teams

**Example use cases:**
- Price monitoring on e-commerce sites
- Tracking product availability
- Monitoring competitor websites
- Setting up alerts for new content
- Syncing web data to spreadsheets
- Creating webhooks for website changes

## Implementation Comparison

### Herd Implementation

## herd-js

Code (javascript):
// Using Herd for browser automation
import { HerdClient } from '@monitoro/herd';

// Initialize the client
const client = new HerdClient('your-token');
await client.initialize();

// Get a device
const devices = await client.listDevices();
const device = devices[0];

// Create a new page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

// Interact with the page
await page.type('#search', 'automation');
await page.click('.search-button');

// Extract data
const results = await page.extract({
  titles: {
    _$r: '.result-item',
    title: '.item-title',
    description: '.item-description'
  }
});

console.log(results);
await client.close();

## herd-py

Code (python):
# Using Herd for browser automation
from monitoro_herd import HerdClient

# Initialize the client
client = HerdClient('your-token')
client.initialize()

# Get a device
devices = client.list_devices()
device = devices[0]

# Create a new page and automate it
page = device.new_page()
page.goto('https://example.com')

# Interact with the page
page.type('#search', 'automation')
page.click('.search-button')

# Extract data
results = page.extract({
  "titles": {
    "_$r": ".result-item",
    "title": ".item-title",
    "description": ".item-description"
  }
})

print(results)
client.close()

### Monitoro Implementation

Monitoro works through a no-code interface:

1. **Install the Monitoro browser extension**
2. **Create a monitor:**
   - Navigate to the webpage you want to monitor
   - Use the Monitoro interface to select elements to track
   - Set up conditions for when alerts should trigger
   - Configure how often the page should be checked

3. **Configure integrations:**
   - Connect to notification channels like Discord, Slack, or Telegram
   - Set up data destinations like Google Sheets or Airtable
   - Create webhooks for custom integrations

Code:
# No code required for Monitoro - it's all done through the visual interface

# Example monitoring workflow:
1. Set up a monitor for a product page on an e-commerce site
2. Configure it to check for price changes or "In Stock" status
3. Set up alerts to Discord when conditions are met
4. Configure Google Sheets integration to log all price changes

## Using Herd and Monitoro Together

These tools can work together in a complementary fashion:

1. **Use Monitoro for initial monitoring and alerts:**
   - Set up no-code monitors for important websites
   - Get alerted when specific changes occur
   - Collect initial data in spreadsheets

2. **Use Herd for advanced follow-up automation:**
   - Trigger Herd workflows based on Monitoro alerts
   - Perform complex interactions beyond Monitoro's capabilities
   - Extract deeper data that requires authentication or multiple steps
   - Orchestrate actions across multiple browsers

### Example workflow:

1. Monitoro monitors competitor pricing and alerts when prices change
2. A webhook from Monitoro triggers a Herd automation
3. Herd performs a deep analysis across multiple pages, including login-required areas
4. Herd generates a comprehensive report and updates internal systems

## When to Upgrade from Monitoro to Herd

Consider upgrading from Monitoro to Herd when:

1. You need to go beyond simple monitoring to complex automation
2. Your workflows require orchestration of multiple browsers
3. You need to access authenticated areas of websites
4. You require sophisticated data processing capabilities
5. You need programmatic control over browser behavior
6. Your team has development resources for coding solutions

## monitoro-simple

Code:
# Monitoro approach (no-code)

1. Set up a monitor for an e-commerce product page
2. Configure it to check price every hour
3. Send price alerts to Slack channel
4. Log all prices to Google Sheets

## herd-advanced

Code (javascript):
// Herd advanced solution

import { HerdClient } from '@monitoro/herd';

async function monitorPrices() {
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  // Open multiple pages for parallel extraction
  const productUrls = [
    'https://example.com/product/1',
    'https://example.com/product/2',
    'https://example.com/product/3'
  ];
  
  // Login first to access special pricing
  const page = await device.newPage();
  await page.goto('https://example.com/login');
  await page.type('#email', process.env.USERNAME);
  await page.type('#password', process.env.PASSWORD);
  await page.click('#login-button');
  await page.waitForNavigation();
  
  // Now check all products in parallel
  const priceData = [];
  for (const url of productUrls) {
    await page.goto(url);
    
    const data = await page.extract({
      productId: {
        _$: '.product-id',
        regex: 'ID: (.*)'
      },
      regularPrice: '.regular-price',
      salePrice: '.sale-price',
      memberPrice: '.member-price',
      availability: '.stock-status',
      shipping: '.shipping-info'
    });
    
    // Compare with historical data in database
    const priceChanged = await comparePriceWithHistory(data);
    if (priceChanged) {
      // Send custom notification with detailed info
      await sendDetailedAlert(data);
      // Update database with new price info
      await updatePriceDatabase(data);
    }
    
    priceData.push(data);
  }
  
  await client.close();
  return priceData;
}

// Run on schedule
setInterval(monitorPrices, 3600000); // Every hour

## Why Use Both Herd and Monitoro?

### 1. Complementary Capabilities

- **Monitoro:** Fast, no-code setup for basic monitoring needs
- **Herd:** Developer-focused tool for complex automation requirements

### 2. Different Team Members, Different Needs

- **Business Teams:** Can use Monitoro without technical skills
- **Developers:** Can use Herd for advanced customization
- **Operations:** Can set up Monitoro for quick insights
- **Engineering:** Can build on those insights with Herd

### 3. Staged Implementation

Monitoro and Herd support a natural progression:
- Start with simple Monitoro monitoring
- Identify areas that need deeper automation
- Implement targeted Herd solutions for those areas
- Maintain both for their distinct advantages

## Get Started with Herd and Monitoro

Ready to implement a complete browser automation and monitoring solution?

### For Herd:

1. [Create a Herd account](/register)
2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

### For Monitoro:

1. Visit [Monitoro.co](https://monitoro.co) to sign up
2. Install the Monitoro browser extension
3. Navigate to the website you want to monitor
4. Use the visual interface to set up your first monitor

Choose the right tool for each specific need, or use them together for a comprehensive web monitoring and automation solution.

================================================================================

Document: Alternative Herd Vs Puppeteer
URL: https://herd.garden/docs/alternative-herd-vs-puppeteer

# Herd vs Puppeteer: A Better Alternative for Browser Automation

In the world of browser automation and web scraping, Puppeteer has long been a popular choice for developers. However, Herd provides a compelling alternative that addresses many of Puppeteer's limitations while offering unique advantages for modern development workflows.

## Quick Comparison

| Feature | Herd | Puppeteer |
| --- | --- | --- |
| **Browser Type** | Your existing browser | Separate Chromium instance |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium, Chrome (limited Firefox) |
| **Infrastructure Requirements** | None (uses your browser) | Requires separate browser instances |
| **Authentication** | Uses existing sessions | Requires manual setup |
| **Setup Complexity** | Simple extension installation | More complex setup |
| **Programming Languages** | JavaScript, Python | JavaScript/TypeScript only |
| **Session Management** | Persistent across runs | Must be rebuilt each run |
| **Resource Usage** | Minimal (shared with browser) | High (separate processes) |

## Key Differences in Depth

### Infrastructure Requirements

**Puppeteer:**
- Requires installing and managing separate Chromium instances
- Needs dedicated resources for each browser instance
- Increases infrastructure costs in cloud environments
- Requires managing updates to the Chromium engine

**Herd:**
- Uses your existing browser installation
- No additional browser instances to manage
- Significantly lower resource utilization
- Leverages native browser capabilities

### Setup and Installation Process

## herd

Code (bash):
# Install the Herd SDK
npm install @monitoro/herd

# Then install the browser extension and connect your browser
# That's it! No browser installation or management needed

## puppeteer

Code (bash):
# Install Puppeteer
npm install puppeteer

# Puppeteer will download and manage its own Chromium instance
# You'll need to handle this in deployment environments
# Additional setup for proxies, authentication, etc.

### Browser Support

**Puppeteer:**
- Primarily designed for Chrome/Chromium browsers
- Limited experimental support for Firefox
- No support for Safari or Edge

**Herd:**
- Works with Chrome, Edge, Brave, Arc, Opera 
- Consistent experience across all supported Chromium-based browsers

### Authentication and Session Handling

**Puppeteer:**
- Sessions must be recreated for each new Puppeteer instance
- Requires manually handling cookies and authentication flows
- Accessing logged-in state requires additional code
- Difficult to use existing authenticated sessions

**Herd:**
- Uses your existing browser's authenticated sessions
- No need to handle authentication separately
- Persistent cookies and storage between sessions
- Access to browser extensions that manage authentication

## Use Case Comparisons

### Data Extraction

## herd-extract

Code (javascript):
// Initialize the client and connect to your browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Extract data using simple selectors
const page = await device.newPage();
await page.goto('https://example.com');
const data = await page.extract({
  title: 'h1',
  description: 'p',
  links: {
    _$r: 'a',  // Extract all links
    href: { attribute: 'href' },
    text: ':root'
  }
});

console.log(data);

## puppeteer-extract

Code (javascript):
// Launch a separate browser instance
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');

// Extract data with multiple evaluations
const data = {
  title: await page.$eval('h1', el => el.textContent),
  description: await page.$eval('p', el => el.textContent),
  links: await page.$eval('a', elements => 
    elements.map(el => ({
      href: el.getAttribute('href'),
      text: el.textContent
    }))
  )
};

console.log(data);
await browser.close();

### Web Automation

## herd-auto

Code (javascript):
// Initialize and connect to your browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Use the existing browser with current sessions
const page = await device.newPage();
await page.goto('https://myapp.com/dashboard'); // Already logged in

// Interact with the page
await page.click('.new-item-button');
await page.type('#item-name', 'New Task');
await page.click('.save-button');

// Process results
const notification = await page.waitForSelector('.success-message');
console.log(notification.textContent);

## puppeteer-auto

Code (javascript):
// Launch a separate browser instance
const browser = await puppeteer.launch();
const page = await browser.newPage();

// Need to handle login first
await page.goto('https://myapp.com/login');
await page.type('#username', 'user@example.com');
await page.type('#password', 'password');
await page.click('.login-button');
await page.waitForNavigation();

// Now navigate to dashboard after login
await page.goto('https://myapp.com/dashboard');

// Interact with the page
await page.click('.new-item-button');
await page.type('#item-name', 'New Task');
await page.click('.save-button');

// Process results
const notification = await page.waitForSelector('.success-message');
console.log(await notification.evaluate(el => el.textContent));
await browser.close();

## Migration Guide: From Puppeteer to Herd

Transitioning from Puppeteer to Herd is straightforward. Here's a simple migration guide:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   npm install @monitoro/herd

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Puppeteer | Herd | Notes |
| --- | --- | --- |
| `const browser = await puppeteer.launch()` | `const client = new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `const page = await browser.newPage()` | `const page = await device.newPage()` | Similar API, different source |
| `await page.goto(url)` | `await page.goto(url)` | Identical usage |
| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |
| `await page.click(selector)` | `await page.click(selector)` | Identical usage |
| `await page.$eval(selector, fn)` | `const element = await page.$(selector)`  `await element.evaluate(fn)` | Slightly different approach |
| `await page.screenshot()` | `await page.screenshot()` | Identical usage |
| `await browser.close()` | `await client.close()` | Browser stays open, just disconnects client |

## Why Choose Herd Over Puppeteer?

### 1. No Infrastructure Management

Herd eliminates the need to maintain separate browser instances, significantly reducing:
- Memory and CPU usage
- Infrastructure costs for cloud deployments
- Maintenance overhead for browser updates

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to handle authentication flows in code
- Access to sites that require complex authentication
- Use existing cookies, local storage, and sessions

### 3. Cross-Browser Compatibility

While Puppeteer is primarily focused on Chromium:
- Herd works across Chrome, Edge, and Brave
- Same code works on any supported browser
- Test on multiple browsers with minimal configuration changes

### 4. Simpler Development Experience

Herd provides:
- More intuitive APIs for common tasks
- Better debugging experience (view automation in real browser)
- Easier integration with existing workflows

## Get Started with Herd Today

Ready to try a better alternative to Puppeteer? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation workflows while reducing infrastructure costs and complexity.

================================================================================

Document: Alternative Herd Vs Selenium
URL: https://herd.garden/docs/alternative-herd-vs-selenium

# Herd vs Selenium: A More Efficient Browser Automation Alternative

Selenium has been the industry standard for browser automation for many years, but its architecture presents significant challenges for modern development workflows. Herd offers a compelling alternative that addresses many of Selenium's pain points while providing a more intuitive experience.

## Quick Comparison

| Feature | Herd | Selenium |
| --- | --- | --- |
| **Driver Requirements** | No drivers needed | Requires WebDriver for each browser |
| **Browser Type** | Your existing browser | Creates new browser instances |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Firefox, Edge, Safari, IE |
| **Infrastructure** | Uses your existing browser | Requires WebDriver servers |
| **Authentication** | Uses existing sessions | Requires manual setup |
| **Programming Languages** | JavaScript, Python | Java, Python, C#, Ruby, JavaScript |
| **Setup Complexity** | Simple browser extension | WebDriver setup for each browser |
| **Maintenance Required** | Minimal (browser updates only) | High (drivers must match browser versions) |
| **Session Management** | Persistent across runs | Must be rebuilt each run |

## Key Differences in Depth

### Driver and Infrastructure Requirements

**Selenium:**
- Requires installation and management of WebDrivers for each browser
- WebDrivers must be kept in sync with browser versions
- Separate browser instances for automation
- Complex setup in CI/CD environments
- High resource usage (separate process for each browser)

**Herd:**
- No WebDrivers or separate drivers needed
- Works directly with your installed browser
- No version synchronization issues
- Simple setup in any environment
- Low resource usage (shares existing browser process)

### Setup and Installation Process

## herd

Code (bash):
# JavaScript
npm install @monitoro/herd

# Python
pip install herd-client

# Then install the browser extension and connect your browser
# That's it! No WebDrivers or browser drivers to manage

## selenium

Code (bash):
# JavaScript
npm install selenium-webdriver

# Python
pip install selenium

# Additionally, you must:
# 1. Download the correct WebDriver for each browser
# 2. Ensure WebDriver versions match browser versions
# 3. Add WebDrivers to your PATH or specify their location
# 4. Update WebDrivers when browsers update

### Browser Support and Consistency

**Selenium:**
- Supports all major browsers including Chrome, Firefox, Safari, Edge, and IE
- Requires separate WebDriver configurations for each browser
- May exhibit inconsistent behavior across different browsers
- Requires updates when browsers update

**Herd:**
- Supports Chrome, Edge, Brave, Arc, Opera
- Uniform behavior across supported Chromium-based browsers
- No additional configuration needed for different browsers

### Authentication and Session Handling

**Selenium:**
- Sessions are isolated and temporary
- Requires manually handling authentication steps
- Session storage is cleared between runs
- Difficult to use existing authenticated sessions

**Herd:**
- Uses your browser's existing authenticated sessions
- Access sites you're already logged into
- Persistent cookies and storage
- Access to browser extensions that manage authentication

## Use Case Comparisons

### Web Testing

## herd-test

Code (javascript):
// JavaScript
import { HerdClient } from '@monitoro/herd';

async function runTest() {
  // Connect to your existing browser
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  // Create a new page for testing
  const page = await device.newPage();
  await page.goto('https://example.com');
  
  // Test interactions
  await page.click('.nav-item');
  await page.waitForSelector('.content-loaded');
  
  // Assert condition
  const header = await page.$('.header');
  const text = await header.getText();
  console.assert(text.includes('Expected Text'), 'Header text verification failed');
  
  // Cleanup
  await page.close();
  await client.close();
}

runTest();

## selenium-test

Code (javascript):
// JavaScript
import { Builder, By, until } from 'selenium-webdriver';

async function runTest() {
  // Launch a separate browser instance with WebDriver
  const driver = await new Builder()
    .forBrowser('chrome')
    .build();
  
  try {
    // Navigate to the test site
    await driver.get('https://example.com');
    
    // Test interactions
    await driver.findElement(By.css('.nav-item')).click();
    await driver.wait(until.elementLocated(By.css('.content-loaded')), 5000);
    
    // Assert condition
    const header = await driver.findElement(By.css('.header'));
    const text = await header.getText();
    console.assert(text.includes('Expected Text'), 'Header text verification failed');
  } finally {
    // Always close the browser
    await driver.quit();
  }
}

runTest();

### Data Extraction

## herd-extract

Code (javascript):
// JavaScript
import { HerdClient } from '@monitoro/herd';

async function extractData() {
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  const page = await device.newPage();
  await page.goto('https://example.com/products');
  
  // Extract product data with a single call
  const products = await page.extract({
    items: {
      _$r: '.product-card',  // Repeat for each product card
      name: '.product-name',
      price: '.product-price',
      rating: '.product-rating',
      inStock: '.stock-status'
    }
  });
  
  console.log(products.items);
  await client.close();
}

extractData();

## selenium-extract

Code (javascript):
// JavaScript
import { Builder, By } from 'selenium-webdriver';

async function extractData() {
  const driver = await new Builder()
    .forBrowser('chrome')
    .build();
  
  try {
    await driver.get('https://example.com/products');
    
    // Extract product data with multiple queries
    const productElements = await driver.findElements(By.css('.product-card'));
    
    const products = [];
    for (const element of productElements) {
      const name = await element.findElement(By.css('.product-name')).getText();
      const price = await element.findElement(By.css('.product-price')).getText();
      
      let rating = '';
      try {
        rating = await element.findElement(By.css('.product-rating')).getText();
      } catch (e) {
        // Element might not exist
        rating = 'N/A';
      }
      
      let inStock = false;
      try {
        const stockText = await element.findElement(By.css('.stock-status')).getText();
        inStock = stockText.includes('In Stock');
      } catch (e) {
        // Element might not exist
      }
      
      products.push({ name, price, rating, inStock });
    }
    
    console.log(products);
  } finally {
    await driver.quit();
  }
}

extractData();

## Migration Guide: From Selenium to Herd

Transitioning from Selenium to Herd is straightforward. Here's a guide to help you migrate your existing code:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   # JavaScript
   npm install @monitoro/herd
   
   # Python
   pip install herd-client

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Selenium | Herd | Notes |
| --- | --- | --- |
| `new Builder().forBrowser().build()` | `new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `driver.get(url)` | `await page.goto(url)` | Similar syntax |
| `driver.findElement(By.css(selector))` | `await page.$(selector)` | Herd uses CSS selectors directly |
| `element.sendKeys(text)` | `await element.type(text)` | Different method name |
| `element.click()` | `await element.click()` | Identical usage |
| `driver.wait(until.elementLocated())` | `await page.waitForSelector(selector)` | Similar functionality |
| `driver.quit()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Handling Multiple Browsers

**Selenium:**

Code (javascript):
const chrome = await new Builder().forBrowser('chrome').build();
const firefox = await new Builder().forBrowser('firefox').build();

**Herd:**

Code (javascript):
// Connect to different browsers that are registered as devices
const chromiumDevice = devices.find(d => d.name === 'Chrome Browser');

## Why Choose Herd Over Selenium?

### 1. No WebDriver Headaches

Herd eliminates the need for WebDrivers, solving the most common Selenium pain points:
- No driver version compatibility issues
- No driver installation or updates needed
- No broken tests due to browser updates

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to write and maintain authentication code
- Access to sites requiring complex authentication
- Use existing cookies, local storage, and sessions

### 3. Simplified Setup and Maintenance

Herd significantly reduces the overhead of browser automation:
- No complex CI/CD configuration
- No driver path management
- No browser version tracking

### 4. Intuitive API for Modern Development

Herd provides:
- Clean, Promise-based API
- Powerful data extraction capabilities
- Better debugging experience (view automation in your browser)

## Get Started with Herd Today

Ready to try a more efficient alternative to Selenium? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation workflows while eliminating the most common frustrations of working with Selenium.

================================================================================

Document: Automation Basics
URL: https://herd.garden/docs/automation-basics

# Automation Basics

Welcome to Monitoro Herd! This guide will walk you through creating your first browser automation step-by-step. We'll start with the basics and gradually build up to more complex examples, explaining each concept along the way.

## javascript

## JavaScript SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your JavaScript environment and install the Herd SDK:

1. Make sure you have Node.js installed (version 14 or higher recommended)
2. Create a new project directory
3. Install the SDK using npm:

Code (bash):
npm install @monitoro/herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (javascript):
// Import the Herd client
import { HerdClient } from '@monitoro/herd';

// Initialize the client with your API URL and token
const client = new HerdClient('your-token');

// Always initialize the client before using it
await client.initialize();
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

After initializing the client, you need to connect to a device (browser) that will perform the automation:

Code (javascript):
// Get a list of available devices
const devices = await client.listDevices();

// Connect to the first available device
const device = devices[0];

console.log(`Connected to device: ${device.id}`);

This code retrieves all devices registered to your account and connects to the first one. In a production environment, you might want to select a specific device based on its properties or availability.

### Creating a Page and Navigating

Now that you're connected to a device, you can create a new browser page and navigate to a website:

Code (javascript):
// Create a new page in the browser
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com');

console.log('Successfully navigated to example.com');

The `goto` method loads the specified URL and waits for the page to load. By default, it waits until the page's `load` event is fired, but you can customize this behavior with options.

### Extracting Basic Information

One of the most common automation tasks is extracting information from web pages. Here's how to extract basic elements:

Code (javascript):
// Extract content using CSS selectors
const content = await page.extract({
  title: 'h1',           // Extracts the main heading
  description: 'p',      // Extracts the first paragraph
  link: 'a'              // Extracts the first link text
});

// Display the extracted content
console.log('Extracted content:');
console.log(`Title: ${content.title}`);
console.log(`Description: ${content.description}`);
console.log(`Link: ${content.link}`);

The `extract` method uses CSS selectors to find elements on the page and extract their text content. This is a powerful way to scrape structured data from websites.

### Proper Resource Management

Always remember to close resources when you're done with them to prevent memory leaks:

Code (javascript):
// Close the page when done
await page.close();

// Close the client connection
await client.close();

### Putting It All Together

Here's a complete example that combines all the steps above into a single function:

Code (javascript):
import { HerdClient } from '@monitoro/herd';

async function runBasicAutomation() {
  const client = new HerdClient('your-token');
  
  try {
    // Initialize the client
    await client.initialize();
    console.log('Client initialized successfully');
    
    // Get the first available device
    const devices = await client.listDevices();
    if (devices.length === 0) {
      throw new Error('No devices available');
    }
    const device = devices[0];
    console.log(`Connected to device: ${device.id}`);
    
    // Create a new page
    const page = await device.newPage();
    console.log('New page created');
    
    // Navigate to a website
    console.log('Navigating to example.com...');
    await page.goto('https://example.com');
    console.log('Navigation complete');
    
    // Extract content
    console.log('Extracting content...');
    const content = await page.extract({
      title: 'h1',
      description: 'p',
      link: 'a'
    });
    
    // Display the extracted content
    console.log('\nExtracted content:');
    console.log(`Title: ${content.title}`);
    console.log(`Description: ${content.description}`);
    console.log(`Link: ${content.link}`);
    
  } catch (error) {
    console.error('Error during automation:', error);
  } finally {
    // Always close the client when done
    console.log('Closing client connection...');
    await client.close();
    console.log('Client connection closed');
  }
}

// Run the automation
runBasicAutomation();

### Interacting with Web Pages

Now let's explore how to interact with elements on a page. This includes clicking buttons, typing text, and handling forms.

#### Finding Elements

Before interacting with an element, you need to find it on the page:

Code (javascript):
// Find an element using a CSS selector
const searchBox = await page.$('input[name="q"]');

// Check if the element was found
if (searchBox) {
  console.log('Search box found');
} else {
  console.log('Search box not found');
}

The `


  
  
  
  
  herd.garden | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   method returns the first element that matches the CSS selector, or `null` if no element is found.

#### Typing Text

To type text into an input field:

Code (javascript):
// Type text into an input field
await page.type('input[name="q"]', 'Monitoro Herd automation');
console.log('Text entered into search box');

The `type` method finds the element using the CSS selector and simulates typing the specified text.

#### Clicking Elements

To click a button or link:

Code (javascript):
// Click a button
await page.click('input[type="submit"]');
console.log('Search button clicked');

By default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:

Code (javascript):
// Click and wait for navigation
await page.click('input[type="submit"]', { 
  waitForNavigation: 'networkidle2' 
});
console.log('Search button clicked and navigation completed');

The `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.

#### Waiting for Elements

Sometimes you need to wait for elements to appear on the page:

Code (javascript):
// Wait for an element to appear
await page.waitForSelector('#search');
console.log('Search results have loaded');

This is useful when dealing with dynamic content that loads after the initial page load.

#### Search Engine Example

Let's put these concepts together in a search engine example:

Code (javascript):
async function searchExample() {
  const client = new HerdClient('your-token');
  
  try {
    await client.initialize();
    const devices = await client.listDevices();
    const device = devices[0];
    const page = await device.newPage();
    
    // Navigate to a search engine
    console.log('Navigating to Google...');
    await page.goto('https://www.google.com');
    
    // Type in the search box
    console.log('Entering search query...');
    await page.type('input[name="q"]', 'Monitoro Herd automation');
    
    // Submit the search form and wait for results
    console.log('Submitting search...');
    await page.click('input[type="submit"]', { 
      waitForNavigation: 'networkidle2' 
    });
    
    // Wait for results to load completely
    console.log('Waiting for search results...');
    await page.waitForSelector('#search');
    
    // Extract search result titles
    console.log('Extracting search results...');
    const searchResults = await page.extract({
      titles: {
        _$r: '#search .g h3',  // _$r extracts multiple elements
        text: ':root'           // For each match, get its text
      }
    });
    
    // Display the search result titles
    console.log('\nSearch Results:');
    searchResults.titles.forEach((result, index) => {
      console.log(`${index + 1}. ${result.text}`);
    });
    
  } catch (error) {
    console.error('Error:', error);
  } finally {
    await client.close();
  }
}

## python

## Python SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your Python environment and install the Herd SDK:

1. Make sure you have Python 3.8+ installed
2. Create a virtual environment (recommended)
3. Install the SDK using pip:

Code (bash):
pip install monitoro-herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (python):
# Import the Herd client
from monitoro_herd import HerdClient

# Initialize the client with your API URL and token
client = HerdClient('your-token')

# Always initialize the client before using it
client.initialize()
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

Next, connect to a device that will run your automation:

Code (python):
# Get available devices
devices = await client.list_devices()

# Connect to the first device
device = devices[0]

print(f"Connected to device: {device.id}")

### Creating a Page and Navigating

Now create a browser page and navigate to a website:

Code (python):
# Create a new page
page = await device.new_page()

# Navigate to a website
await page.goto("https://example.com")

print("Successfully navigated to example.com")

### Extracting Basic Information

Extract information from the page using CSS selectors:

Code (python):
# Extract basic information
data = await page.extract({
    "title": "h1",          # Main heading
    "description": "p",     # First paragraph
    "link": "a"             # First link text
})

# Display the extracted data
print("Extracted data:")
print(f"Title: {data['title']}")
print(f"Description: {data['description']}")
print(f"Link: {data['link']}")

### Resource Management

Always close resources when you're done:

Code (python):
# Close the page
await page.close()

# Close the client
await client.close()

### Complete Basic Example

Here's a complete example putting all these concepts together:

Code (python):
import asyncio
from monitoro_herd import HerdClient

async def basic_extraction():
    # Initialize the client
    client = HerdClient("your-token")
    
    try:
        # Initialize the connection
        await client.initialize()
        print("Client initialized successfully")
        
        # Get the first available device
        devices = await client.list_devices()
        if not devices:
            raise Exception("No devices available")
        device = devices[0]
        print(f"Connected to device: {device.id}")
        
        # Create a new page
        page = await device.new_page()
        print("New page created")
        
        # Navigate to a website
        print("Navigating to example.com...")
        await page.goto("https://example.com")
        print("Navigation complete")
        
        # Extract data using simple selectors
        print("Extracting content...")
        data = await page.extract({
            "title": "h1",
            "description": "p",
            "link": "a"
        })
        
        # Display the extracted data
        print("\nExtracted data:")
        print(f"Title: {data['title']}")
        print(f"Description: {data['description']}")
        print(f"Link: {data['link']}")
        
    except Exception as e:
        print(f"Error during automation: {e}")
    finally:
        # Always close resources
        print("Closing client connection...")
        await client.close()
        print("Client connection closed")

# Run the async function
asyncio.run(basic_extraction())

### Working with Lists and Structured Data

One of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.

#### The `_$r` Selector

To extract multiple elements that match a pattern, use the `_$r` (repeat) selector:

Code (python):
# Extract a list of items
data = await page.extract({
    "items": {
        "_$r": ".item",       # Find all elements with class "item"
        "name": ".item-name", # For each item, get the name
        "price": ".price"     # For each item, get the price
    }
})

# Access the extracted items
for item in data["items"]:
    print(f"Name: {item['name']}, Price: {item['price']}")

The `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.

#### Extracting Attributes

Sometimes you need to extract an attribute rather than the text content:

Code (python):
# Extract links and their href attributes
data = await page.extract({
    "links": {
        "_$r": "a",              # Find all links
        "text": ":root",         # Get the link text
        "url": {
            "_
quot;: ":root", # Reference the same element "attribute": "href" # Get its href attribute } } }) # Display the links for link in data["links"]: print(f"Link: {link['text']} -> {link['url']}") #### Hacker News Example Let's put these concepts together to scrape stories from Hacker News: Code (python): import asyncio from monitoro_herd import HerdClient async def scrape_hacker_news(): client = HerdClient("your-token") try: await client.initialize() devices = await client.list_devices() device = devices[0] page = await device.new_page() # Navigate to Hacker News print("Navigating to Hacker News...") await page.goto("https://news.ycombinator.com") # Extract stories and their metadata print("Extracting stories...") data = await page.extract({ # Extract the story elements "stories": { "_$r": ".athing", # Each story row "title": ".titleline > a", # Story title "site": ".sitestr", # Source website "link": { "_
quot;: ".titleline > a", # Story link "attribute": "href" # Get the URL } }, # Extract the metadata (points, author, etc.) "metadata": { "_$r": ".subline", # Metadata rows "points": ".score", # Points count "author": ".hnuser", # Author username "time": ".age" # Submission time } }) # Combine stories with their metadata # (They're in separate lists but in the same order) combined_stories = list(zip(data["stories"], data["metadata"])) # Display the first 3 stories print(f"\nExtracted {len(combined_stories)} stories:") for i, (story, meta) in enumerate(combined_stories[:3]): print(f"\nStory {i+1}:") print(f"Title: {story['title']}") if "site" in story: print(f"Site: {story['site']}") print(f"Link: {story['link']}") if "points" in meta: print(f"Points: {meta['points']}") if "author" in meta: print(f"Author: {meta['author']}") if "time" in meta: print(f"Posted: {meta['time']}") finally: await page.close() await client.close() # Run the function asyncio.run(scrape_hacker_news()) ## Tips for Successful Automation 1. **Start Simple**: Begin with basic extractions before moving to complex interactions 2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely 3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks 4. **Close Resources**: Always close pages and clients when done to avoid resource leaks 5. **Test Incrementally**: Build your automation step by step, testing each part 6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods 7. **Debug with Screenshots**: Take screenshots during automation to see what's happening ## Next Steps Now that you've created your first automation, you can: - Explore more complex selectors and extraction patterns - Learn how to handle authentication and login flows - Set up scheduled automations for regular data collection - Integrate with your existing systems via APIs ================================================================================ Document: Connect Your Browser URL: https://herd.garden/docs/connect-your-browser # Connect your Browser to Herd After installing the Herd extension, you need to connect your browser to your account. This guide explains how to establish and manage connections between your browsers and the Herd platform. You can connect multiple browsers to the same account. Learn more about [managing multiple devices](/docs/device-management). ## Device Registration Before you can connect a browser, you need to register the device in your Herd dashboard: 1. Log in to your Herd account 2. Navigate to the "Devices" section 3. Click "Register New Device" 4. Enter a descriptive name for the device (e.g., "Work Laptop - Chrome") 5. Choose appropriate tags if you're organizing devices into groups 6. Click "Create Registration" 7. Copy the registration code that appears (you'll need this to connect the browser) ## Connecting Your Browser Once you have a registration code, follow these steps to connect your browser: 1. Make sure the Herd extension is installed in your browser 2. Click the Herd icon in your browser toolbar 3. Select "Connect Browser" or "Register Device" from the menu 4. Paste the registration code into the field 5. Click "Connect" 6. You should see a confirmation message indicating the browser is now connected ## Managing Active Connections You can view and manage all your connected browsers from the Herd dashboard: ### Viewing Connected Devices 1. Log in to your Herd account 2. Navigate to the "Devices" section 3. The "Active Connections" tab shows all currently connected browsers 4. Each connection displays information such as: - Device name - Browser type and version - Connection status - Last activity timestamp ### Remote Actions Once a browser is connected, you can perform various remote actions: 1. **Remote Control**: Initiate a remote control session to view and interact with the browser 2. **Capture Screenshot**: Take a snapshot of the current browser window 3. **Tab Management**: View, open, close, or navigate tabs 4. **Bookmark Management**: View or modify the browser's bookmarks 5. **History Access**: View browsing history (if permissions allow) ## Connection Troubleshooting If you're having trouble connecting your browser to Herd, try these solutions: ### Connection Failures * Verify that the registration code is correct and hasn't expired * Make sure the browser is online and has a stable internet connection * Check that the Herd extension is properly installed and enabled * Try restarting your browser ### Dropped Connections * Check your network stability * Ensure the browser hasn't entered sleep mode * Verify that the extension hasn't been disabled * Check if a browser update has affected the extension ### Reconnecting If a connection is lost, you can easily reconnect: 1. Click the Herd icon in your browser toolbar 2. If the connection status shows "Disconnected," click "Reconnect" 3. If prompted, enter your registration code again 4. Wait for the connection to be reestablished ## Connection Security All connections between your browser and the Herd platform are secured with end-to-end encryption. Your data remains private and protected throughout the connection process. For more information on security features, see our [Security & Privacy](security-privacy) documentation. ================================================================================ Document: Data Extraction URL: https://herd.garden/docs/data-extraction # Data Extraction Welcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines. ## Understanding Selectors Herd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system. ### Basic Extraction ## javascript The simplest form of extraction uses CSS selectors to target elements: Code (javascript): // Extract basic text content const data = await page.extract({ title: 'h1', // Extracts the main heading description: 'p', // Extracts the first paragraph link: 'a' // Extracts the first link text }); console.log(data.title); // "Welcome to Our Website" console.log(data.description); // "This is our homepage." ## python The simplest form of extraction uses CSS selectors to target elements: Code (python): # Extract basic text content data = await page.extract({ "title": "h1", # Extracts the main heading "description": "p", # Extracts the first paragraph "link": "a" # Extracts the first link text }) print(data["title"]) # "Welcome to Our Website" print(data["description"]) # "This is our homepage." ### Advanced Selector Syntax ## javascript For more complex extraction needs, use the expanded object syntax: Code (javascript): const data = await page.extract({ title: { _$: 'h1', // CSS selector attribute: 'id' // Extract the ID attribute instead of text }, price: { _$: '.price', // Target price element pipes: ['parseNumber'] // Apply transformation } }); ## python For more complex extraction needs, use the expanded object syntax: Code (python): data = await page.extract({ "title": { "_
quot;: "h1", # CSS selector "attribute": "id" # Extract the ID attribute instead of text }, "price": { "_
quot;: ".price", # Target price element "pipes": ["parseNumber"] # Apply transformation } }) ### Extracting Lists of Items ## javascript To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (javascript): const data = await page.extract({ items: { _$r: '.item', // Find all elements with class "item" title: 'h2', // For each item, get the title price: '.price', // For each item, get the price date: 'time' // For each item, get the date } }); // Access the extracted items data.items.forEach(item => { console.log(`${item.title}: ${item.price}, Posted: ${item.date}`); }); ## python To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (python): data = await page.extract({ "items": { "_$r": ".item", # Find all elements with class "item" "title": "h2", # For each item, get the title "price": ".price", # For each item, get the price "date": "time" # For each item, get the date } }) # Access the extracted items for item in data["items"]: print(f"{item['title']}: {item['price']}, Posted: {item['date']}") ### Nested Extraction ## javascript You can nest selectors to extract hierarchical data: Code (javascript): const data = await page.extract({ product: { name: '.product-name', details: { _$: '.product-details', specs: { _$r: '.spec-item', label: '.spec-label', value: '.spec-value' } } } }); ## python You can nest selectors to extract hierarchical data: Code (python): data = await page.extract({ "product": { "name": ".product-name", "details": { "_
quot;: ".product-details", "specs": { "_$r": ".spec-item", "label": ".spec-label", "value": ".spec-value" } } } }) ## Special Selectors Herd provides special selectors to handle various extraction scenarios: ### Root Selector (`:root`) The `:root` selector refers to the current element in context: ## javascript Code (javascript): const data = await page.extract({ items: { _$r: '.item', someElement: ':root', // Extract text of the .item element itself classes: { _$: ':root', attribute: 'class' // Extract class attribute of the same element } } }); ## python Code (python): data = await page.extract({ "items": { "_$r": ".item", "someElement": ":root", # Extract text of the .item element itself "classes": { "_
quot;: ":root", "attribute": "class" # Extract class attribute of the same element } } }) ### Property Extraction You can extract JavaScript properties from elements: ## javascript Code (javascript): const data = await page.extract({ dimensions: { _$: '.box', property: 'getBoundingClientRect' // Get element dimensions }, html: { _$: '.content', property: 'innerHTML' // Get inner HTML } }); ## python Code (python): data = await page.extract({ "dimensions": { "_
quot;: ".box", "property": "getBoundingClientRect" # Get element dimensions }, "html": { "_
quot;: ".content", "property": "innerHTML" # Get inner HTML } }) ## Transformation Pipelines Herd includes powerful transformation pipelines to process extracted data: ### Available Transformations | Pipe | Description | Example Input | Example Output | |------|-------------|--------------|----------------| | `trim` | Removes whitespace from start/end | `" Hello "` | `"Hello"` | | `toLowerCase` | Converts text to lowercase | `"HELLO"` | `"hello"` | | `toUpperCase` | Converts text to uppercase | `"hello"` | `"HELLO"` | | `parseNumber` | Extracts numbers from text | `"$1,2K.45"` | `1200.45` | | `parseDate` | Converts text to date | `"2024-01-15"` | `"2024-01-15T00:00:00.000Z"` | | `parseDateTime` | Converts text to datetime | `"2024-01-15T12:00:00Z"` | `"2024-01-15T12:00:00.000Z"` | ### Using Transformations Apply transformations using the `pipes` property: ## javascript Code (javascript): const data = await page.extract({ price: { _$: '.price', pipes: ['parseNumber'] // Convert "$1,234.56" to 1234.56 }, title: { _$: 'h1', pipes: ['trim', 'toLowerCase'] // Apply multiple transformations } }); ## python Code (python): data = await page.extract({ "price": { "_
quot;: ".price", "pipes": ["parseNumber"] # Convert "$1,234.56" to 1234.56 }, "title": { "_
quot;: "h1", "pipes": ["trim", "toLowerCase"] # Apply multiple transformations } }) ### Handling Currency and Large Numbers The `parseNumber` transformation handles various formats: ## javascript Code (javascript): const data = await page.extract({ price1: { _$: '.price-1', // Contains "$1,234.56" pipes: ['parseNumber'] // Result: 1234.56 }, price2: { _$: '.price-2', // Contains "$1.5M" pipes: ['parseNumber'] // Result: 1500000 }, price3: { _$: '.price-3', // Contains "1.5T€" pipes: ['parseNumber'] // Result: 1500000000000 } }); ## python Code (python): data = await page.extract({ "price1": { "_
quot;: ".price-1", # Contains "$1,234.56" "pipes": ["parseNumber"] # Result: 1234.56 }, "price2": { "_
quot;: ".price-2", # Contains "$1.5M" "pipes": ["parseNumber"] # Result: 1500000 }, "price3": { "_
quot;: ".price-3", # Contains "1.5T€" "pipes": ["parseNumber"] # Result: 1500000000000 } }) ## Real-World Examples Let's look at some practical examples of data extraction: ### E-commerce Product Listing Extract products from a search results page: ## javascript Code (javascript): const searchResults = await page.extract({ products: { _$r: '[data-component-type="s-search-result"]', title: { _$: 'h2 .a-link-normal', pipes: ['trim'] }, price: { _$: '.a-price .a-offscreen', pipes: ['parseNumber'] }, rating: { _$: '.a-icon-star-small .a-icon-alt', pipes: ['trim'] }, reviews: { _$: '.a-size-base.s-underline-text', pipes: ['trim'] } } }); ## python Code (python): searchResults = await page.extract({ "products": { "_$r": '[data-component-type="s-search-result"]', "title": { "_
quot;: "h2 .a-link-normal", "pipes": ["trim"] }, "price": { "_
quot;: ".a-price .a-offscreen", "pipes": ["parseNumber"] }, "rating": { "_
quot;: ".a-icon-star-small .a-icon-alt", "pipes": ["trim"] }, "reviews": { "_
quot;: ".a-size-base.s-underline-text", "pipes": ["trim"] } } }) ### News Article List Extract articles from a news site: ## javascript Code (javascript): const articles = await page.extract({ items: { _$r: '.item', title: { _$: 'h2', pipes: ['trim', 'toLowerCase'] }, price: { _$: '.price', pipes: ['parseNumber'] }, date: { _$: 'time', pipes: ['parseDate'] } } }); ## python Code (python): articles = await page.extract({ "items": { "_$r": ".item", "title": { "_
quot;: "h2", "pipes": ["trim", "toLowerCase"] }, "price": { "_
quot;: ".price", "pipes": ["parseNumber"] }, "date": { "_
quot;: "time", "pipes": ["parseDate"] } } }) ## Advanced Techniques ### Handling Dynamic Content For dynamic content that loads after the page is ready: ## javascript Code (javascript): // Wait for dynamic content to load await page.waitForElement('#dynamic span'); // Then extract the content const data = await page.extract({ content: '#dynamic span' }); ## python Code (python): # Wait for dynamic content to load await page.waitForElement('#dynamic span') # Then extract the content data = await page.extract({ "content": "#dynamic span" }) ### Extracting Page Metadata Extract information about the page itself: ## javascript Code (javascript): const pageInfo = await page.extract({ title: 'title', metaDescription: 'meta[name="description"]', canonicalUrl: { _$: 'link[rel="canonical"]', attribute: 'href' } }); ## python Code (python): pageInfo = await page.extract({ "title": "title", "metaDescription": 'meta[name="description"]', "canonicalUrl": { "_
quot;: 'link[rel="canonical"]', "attribute": "href" } }) ## Tips for Effective Extraction 1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction 2. **Test Incrementally**: Build your extraction schema step by step, testing each part 3. **Handle Missing Data**: Always account for elements that might not exist on the page 4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed 5. **Combine with Interactions**: For complex sites, interact with the page before extraction ## Next Steps Now that you understand Herd's data extraction system, you can: - Create complex extraction schemas for any website - Transform raw data into structured, usable formats - Build powerful automations that collect and process web data ================================================================================ Document: Device Management URL: https://herd.garden/docs/device-management # Device Management Managing your devices in Herd is simple and intuitive. This guide will walk you through the various actions you can perform on the Devices page. ## Understanding the Devices Page The Devices page is your central hub for managing all browsers and headless devices connected to your Herd account. Here you can: - View all your connected devices - Register new devices - Access device registration URLs - Delete devices you no longer need ## Viewing Your Devices When you visit the Devices page, you'll see a list of all your registered devices. For each device, you can view: - Device name - Status (active or inactive) - Device ID - Device type (browser or headless) - Last active timestamp Devices with an active status will display a pulsing green indicator, while inactive devices will show a gray status indicator. ## Registering a New Device To add a new device to your Herd account: 1. Click the **Register New Device** button at the top of the Devices page 2. Enter a name for your device (or use the suggested name) 3. Select the device type: - **Browser**: For devices with a visual interface such as your own browser - **Headless**: For devices running in headless mode (for docker and kubernetes deployments) 4. Click **Register Device** 5. A registration URL will be generated - use this URL to connect your device to Herd The registration URL will be stored locally in your browser, allowing you to access it again later if needed. ## Accessing Registration URLs If you need to access a previously generated registration URL: 1. Find the device in your devices list 2. Look for the "Registration URL available" indicator 3. Click the **View URL** button 4. The registration URL will be displayed in a modal window This is particularly useful if you need to reconnect a device or share the registration link with team members. ## Deleting a Device To remove a device from your Herd account: 1. Find the device you want to delete in your devices list 2. Click the **Delete** button for that device 3. Confirm the deletion in the confirmation dialog Please note that deleting a device is permanent and cannot be undone. The device will be removed from your account, and any stored registration URLs for that device will be cleared from your local storage. ## Device Status Devices in Herd can have different statuses: - **Active**: The device is currently connected and ready to use - **Inactive**: The device is registered but not currently connected An active device can be used immediately for automation tasks, while inactive devices need to be reconnected before use. ## Best Practices Here are some tips for effective device management: - Use descriptive names for your devices to easily identify them - Regularly clean up unused devices to keep your dashboard organized - Store registration URLs securely if you plan to share them with team members - Check the "Last Active" timestamp to identify devices that haven't been used recently By following these guidelines, you'll be able to maintain an organized and efficient device management system in Herd. ================================================================================ Document: Getting Started URL: https://herd.garden/docs/getting-started # Getting Started with Herd This guide will help you get up and running with Herd quickly to run your first trail. ## What is Herd? Herd connects AI Agents to websites using your own browser credentials. It enables you to: - **Run Trails** - pre-built automations for specific websites and tasks - **Extract data and interact with websites** using your logged-in browser sessions - **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude ## Quick Start ### 1. Install the Browser Extension Chrome Edge Brave ### 2. Register Your Browser After installing the extension: 1. Click the Herd icon in your browser toolbar 2. Sign in with your Herd account (or create one) 3. Name your device and register it ![Browser Registration](https://herd.garden/register-device.png) ### 3. Install the Herd SDK Install the Herd SDK using npm: ## npm Code (bash): npm install -g @monitoro/herd ## yarn Code (bash): yarn global add @monitoro/herd ## pnpm Code (bash): pnpm add -g @monitoro/herd ### 4. Run Your First Trail The browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out: Code (bash): herd trail run @herd/browser -a markdown -p '{"url": "https://example.com"}' That's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config: Code (json): { "mcpServers": { "browser": { "command": "herd", "args": [ "trail", "server", "@herd/browser" ] } } } ## For Developers You can also automate your browser with the Herd SDK. Connect to it with your AI agents or code: ## javascript Code (javascript): // Connect to your Herd device const client = new HerdClient('your-token'); await client.initialize(); const devices = await client.listDevices(); const device = devices[0]; // Create a new page and navigate const page = await device.newPage(); await page.goto("https://example.com"); // Extract data using simple selectors const data = await page.extract({ title: "h1", description: "p", link: "a" }); console.log("Extracted data:", data); ## python Code (python): from monitoro_herd import HerdClient # Connect to your Herd device client = HerdClient("your-token") await client.initialize() devices = await client.list_devices() device = devices[0] # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Extract data using simple selectors data = await page.extract({ "title": "h1", "description": "p", "link": "a" }) print("Extracted data:", data) ## What's Next? Now that you've run your first trail, you can: - [Explore available trails](/trails) - Browse pre-built trails for various websites - [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages - [Create your own trail](/docs/trails-automations) - Build and share your own custom trails ## Need Help? If you encounter any issues during setup: - Make sure your browser extension is correctly installed and you're signed in - Check that your device is registered in the [device dashboard](/devices) - Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions .browser-btn { display: inline-flex; align-items: center; padding: 0.2rem 1rem; background-color: #1f2937; color: white; border-radius: 0.375rem; font-size: 1.2rem; font-weight: 500; text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.1); } .browser-btn:hover { background-color: #374151; } ================================================================================ Document: Installation URL: https://herd.garden/docs/installation # Installing the Herd Extension The Herd extension is the client component that allows your browser to be remotely managed. This guide provides detailed instructions for installing the extension on different browsers. ## Chrome Installation The Herd extension is primarily designed for Google Chrome and Chromium-based browsers. Follow these steps to install: ### Standard Installation 1. Download the Herd extension from your dashboard by clicking "Download Herd" in the navigation bar 2. Open Chrome and navigate to `chrome://extensions` 3. Enable "Developer mode" by toggling the switch in the top-right corner 4. Drag and drop the downloaded `herd-latest.zip` file onto the extensions page 5. Chrome will automatically install the extension ### Verifying Installation After installation, you should see the Herd extension in your extensions list. To verify it's working correctly: 1. Look for the Herd icon in your browser toolbar 2. If it's not visible, click the puzzle piece icon to see all extensions and pin the Herd extension 3. The icon should be colored, indicating it's ready to be connected ## Installation on Other Browsers While Herd works best with Chrome, it's also compatible with other Chromium-based browsers: ### Microsoft Edge 1. Download the Herd extension zip file 2. Open Edge and navigate to `edge://extensions` 3. Enable "Developer mode" using the toggle in the left sidebar 4. Drag and drop the `herd-latest.zip` file onto the extensions page 5. Follow the prompts to complete installation ### Brave Browser 1. Download the Herd extension zip file 2. Open Brave and navigate to `brave://extensions` 3. Enable "Developer mode" in the top-right corner 4. Drag and drop the `herd-latest.zip` file onto the extensions page 5. Confirm the installation when prompted ## Enterprise Deployment For enterprise environments, you may want to deploy the Herd extension to multiple browsers. Here are some options: ### Chrome Enterprise Policy You can use Chrome Enterprise policies to automatically install and configure the Herd extension: 1. Extract the Herd extension zip file to a network location accessible to all users 2. Configure a policy to force-install extensions from a local path 3. Set up the appropriate extension settings via policy ### Manual Distribution For smaller teams, you can manually distribute the extension: 1. Download the extension once 2. Share the zip file with team members 3. Provide them with instructions for installation 4. Create device registrations for each team member in your Herd dashboard ## Troubleshooting Installation Issues If you encounter issues during installation, try these solutions: ### Extension Won't Install * Make sure Developer mode is enabled in your browser's extensions page * Check that you're using a supported browser (Chrome, Edge, Brave) * Verify that the zip file wasn't corrupted during download (try re-downloading) * Make sure you're dragging the zip file itself, not an extracted folder ### Extension Installed But Not Working * Check if the extension is enabled in your browser * Try restarting your browser * Verify that you've completed the device registration process * Check your browser's console for any error messages For more troubleshooting tips, see our [Troubleshooting](troubleshooting) guide. ================================================================================ Document: Reference Device URL: https://herd.garden/docs/reference-device # Device The Device class represents a connected browser or device in the Herd platform. It provides methods for managing pages, handling events, and controlling the device's lifecycle. Each Device instance gives you full control over a browser, allowing you to create and manage pages (tabs), handle various browser events, and automate browser interactions. ## javascript You can obtain a Device instance either by calling `client.listDevices()` to get all available devices, or `client.getDevice(deviceId)` to get a specific device by its ID. ## Properties ### deviceId The unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered. ### type The type of device, which indicates its capabilities and behavior. Currently supported types include: - 'browser': A browser instance that can be automated - 'headless': A headless browser instance running on docker or kubernetes ### name An optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard. ### status The current status of the device. Possible values include: - 'online': The device is connected and ready to receive commands - 'offline': The device is not currently connected - 'busy': The device is processing a command - 'error': The device encountered an error ### lastActive A timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a JavaScript Date object. ## Methods ### newPage() Creates a new page (tab) in the device. Code (javascript): // Create a new page const page = await device.newPage(); console.log('New page created:', page.id); ### listPages() Returns a list of all pages (tabs) currently open in the device. Code (javascript): // List all open pages const pages = await device.listPages(); pages.forEach(page => { console.log(`Page ${page.id}: ${page.url}`); }); ### getPage(pageId) Gets a specific page by ID. Code (javascript): // Get a specific page const page = await device.getPage(123); console.log('Current URL:', page.url); ### onEvent(callback) Subscribes to all events from the device. Returns an unsubscribe function. Code (javascript): // Subscribe to all device events const unsubscribe = device.onEvent((event) => { console.log('Device event:', event); }); // Later: stop listening to events unsubscribe(); ### on(eventName, callback) Subscribes to a specific event from the device. Returns the device instance for chaining. Code (javascript): // Subscribe to specific events device.on('navigation', (event) => { console.log('Navigation occurred:', event); }).on('console', (event) => { console.log('Console message:', event); }); ### close() Closes the device and cleans up resources. This will close all pages and remove event listeners. Code (javascript): // Close the device and cleanup await device.close(); ## Example Usage Here's a complete example showing how to use the Device class: Code (javascript): import { HerdClient } from '@monitoro/herd'; async function main() { const client = new HerdClient({ token: 'your-auth-token' }); await client.initialize(); // Get a device const device = await client.getDevice('my-browser'); // Create a new page and navigate const page = await device.newPage(); await page.goto('https://example.com'); // Listen for navigation events device.on('navigation', (event) => { console.log('Page navigated:', event.url); }); // List all pages const pages = await device.listPages(); console.log(`Device has ${pages.length} pages open`); // Cleanup when done await device.close(); await client.close(); } main().catch(console.error); ## python You can obtain a Device instance either by calling `client.list_devices()` to get all available devices, or `client.get_device(device_id)` to get a specific device by its ID. ## Properties ### device_id The unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered. ### type The type of device, which indicates its capabilities and behavior. Currently supported types include: - 'browser': A browser instance that can be automated - 'headless': A headless browser instance running on docker or kubernetes ### name An optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard. ### status The current status of the device. Possible values include: - 'online': The device is connected and ready to receive commands - 'offline': The device is not currently connected - 'busy': The device is processing a command - 'error': The device encountered an error ### last_active A timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a Python datetime object. ## Methods ### new_page() Creates a new page (tab) in the device. Code (python): # Create a new page page = await device.new_page() print(f"New page created: {page.id}") ### list_pages() Returns a list of all pages (tabs) currently open in the device. Code (python): # List all open pages pages = await device.list_pages() for page in pages: print(f"Page {page.id}: {page.url}") ### get_page(page_id) Gets a specific page by ID. Code (python): # Get a specific page page = await device.get_page(123) print(f"Current URL: {page.url}") ### on_event(callback) Subscribes to all events from the device. Returns an unsubscribe function. Code (python): # Subscribe to all device events def handle_event(event): print("Device event:", event) unsubscribe = device.on_event(handle_event) # Later: stop listening to events unsubscribe() ### on(event_name, callback) Subscribes to a specific event from the device. Returns the device instance for chaining. Code (python): # Subscribe to specific events def handle_navigation(event): print("Navigation occurred:", event) def handle_console(event): print("Console message:", event) device.on("navigation", handle_navigation)\ .on("console", handle_console) ### close() Closes the device and cleans up resources. This will close all pages and remove event listeners. Code (python): # Close the device and cleanup await device.close() ## Example Usage Here's a complete example showing how to use the Device class: Code (python): from monitoro_herd import HerdClient async def main(): client = HerdClient( token="your-auth-token" ) await client.initialize() # Get a device device = await client.get_device("my-browser") # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Listen for navigation events def handle_navigation(event): print("Page navigated:", event["url"]) device.on("navigation", handle_navigation) # List all pages pages = await device.list_pages() print(f"Device has {len(pages)} pages open") # Cleanup when done await device.close() await client.close() # Run the async function import asyncio asyncio.run(main()) ================================================================================ Document: Reference Herd Client URL: https://herd.garden/docs/reference-herd-client # HerdClient The HerdClient is the main entry point for interacting with the Herd platform. It provides methods for managing devices, pages, and executing browser automation commands. ## javascript ## Installation Code (bash): npm install @monitoro/herd # or yarn add @monitoro/herd ## Usage Code (javascript): import { HerdClient } from '@monitoro/herd'; // Create a client instance const client = new HerdClient({ token: 'your-auth-token' // Get your token at herd.garden }); // Initialize the client await client.initialize(); ## Methods ### initialize() Initializes the client by establishing connections to the Herd platform. Must be called before using other methods. Code (javascript): await client.initialize(); ### listDevices() Returns a list of all available devices. Code (javascript): const devices = await client.listDevices(); console.log('Available devices:', devices); ### getDevice(deviceId) Gets a specific device by ID. Code (javascript): const device = await client.getDevice('device-123'); ### registerDevice(options) Registers a new device with the platform. Code (javascript): const device = await client.registerDevice({ deviceId: 'my-device', type: 'browser', name: 'My Test Browser' }); ### sendCommand(deviceId, command, params) Sends a command to a specific device. This is a low-level method that allows you to send arbitrary commands to a device and is not recommended for most use cases. Code (javascript): const result = await client.sendCommand('device-123', 'Page.click', { selector: '#submit-button' }); ### subscribeToDeviceEvents(deviceId, callback) Subscribes to all events from a device. Code (javascript): const unsubscribe = client.subscribeToDeviceEvents('device-123', (event) => { console.log('Device event:', event); }); // Later: unsubscribe to stop receiving events unsubscribe(); ### subscribeToDeviceEvent(deviceId, eventName, callback) Subscribes to a specific event from a device. Code (javascript): const unsubscribe = client.subscribeToDeviceEvent('device-123', 'navigation', (event) => { console.log('Navigation event:', event); }); ### close() Closes the client and cleans up resources. Code (javascript): await client.close(); ## python ## Installation Code (bash): pip install monitoro-herd ## Usage Code (python): from monitoro_herd import HerdClient # Create a client instance client = HerdClient( token='your-auth-token' # Get your token at herd.garden ) # Initialize the client await client.initialize() ## Methods ### initialize() Initializes the client by establishing connections to the Herd platform. Must be called before using other methods. Code (python): await client.initialize() ### list_devices() Returns a list of all available devices. Code (python): devices = await client.list_devices() print('Available devices:', devices) ### get_device(device_id) Gets a specific device by ID. Code (python): device = await client.get_device('device-123') ### register_device(device_id, device_type, name) Registers a new device with the platform. Code (python): device = await client.register_device( device_id='my-device', device_type='browser', name='My Test Browser' ) ### send_command(device_id, command, payload) Sends a command to a specific device. Code (python): result = await client.send_command( 'device-123', 'Page.click', {'selector': '#submit-button'} ) ### subscribe_to_device_events(device_id, callback) Subscribes to all events from a device. Code (python): def handle_event(event): print('Device event:', event) unsubscribe = client.subscribe_to_device_events('device-123', handle_event) # Later: unsubscribe to stop receiving events unsubscribe() ### subscribe_to_device_event(device_id, event_name, callback) Subscribes to a specific event from a device. Code (python): def handle_navigation(event): print('Navigation event:', event) unsubscribe = client.subscribe_to_device_event('device-123', 'navigation', handle_navigation) ### close() Closes the client and cleans up resources. Code (python): await client.close() ================================================================================ Document: Reference Mcp Server URL: https://herd.garden/docs/reference-mcp-server # MCP Server Herd's MCP Server allows you to securely expose web applications to Large Language Models (LLMs) through local browser automation. Using the Model Context Protocol (MCP), you can create a secure bridge between AI models and your favorite websites without sharing credentials or running browsers in the cloud. ## Key Benefits - **Secure Access**: Your browser runs locally, keeping your credentials and cookies secure - **Privacy First**: No need to share sensitive data or tokens with third-party services - **Native Experience**: Interact with web apps through your actual browser, maintaining all your preferences and login state - **Universal Compatibility**: Works with any web application without needing API access - **Custom Tools**: Create tailored tools that encapsulate complex web interactions ## javascript ## Installation Code (bash): npm install @monitoro/herd ## Basic Setup Here's how to create an MCP server that exposes web application functionality: Code (javascript): import { HerdMcpServer } from '@monitoro/herd'; const server = new HerdMcpServer({ info: { name: "gmail-assistant", version: "1.0.0", description: "Gmail automation tools for LLMs" }, transport: { type: "sse", port: 3000 }, herd: { token: "your-herd-token" // Get from herd.garden } }); // Start the server await server.start(); ## Creating Web App Tools Tools encapsulate web application functionality for LLMs. Here are some examples: Code (javascript): // Gmail: Compose new email server.tool({ name: "composeEmail", description: "Compose and send a new email", schema: { to: z.string().email(), subject: z.string(), body: z.string() } }, async ({ to, subject, body }, devices) => { const device = devices[0]; const page = await device.newPage(); // Navigate to Gmail compose await page.goto('https://mail.google.com/mail/u/0/#compose'); // Fill out the email form await page.type('input[aria-label="To"]', to); await page.type('input[aria-label="Subject"]', subject); await page.type('div[aria-label="Message Body"]', body); // Send the email await page.click('div[aria-label="Send"]'); return { success: true }; }); // Twitter: Post a tweet server.tool({ name: "postTweet", description: "Post a new tweet", schema: { content: z.string().max(280) } }, async ({ content }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/compose/tweet'); await page.type('div[aria-label="Tweet text"]', content); await page.click('div[data-testid="tweetButton"]'); return { success: true }; }); ## Creating Web App Resources Resources provide structured data from web applications: Code (javascript): // Gmail: Unread emails server.resource({ name: "unreadEmails", uriOrTemplate: "gmail/unread", }, async (devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://mail.google.com/mail/u/0/#inbox'); // Extract unread email information const emails = await page.evaluate(() => { return Array.from(document.querySelectorAll('tr.unread')) .map(row => ({ sender: row.querySelector('.sender').textContent, subject: row.querySelector('.subject').textContent, date: row.querySelector('.date').textContent })); }); return { emails }; }); // LinkedIn: Profile Information server.resource({ name: "linkedinProfile", uriOrTemplate: "linkedin/profile/{username}", }, async ({ username }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto(`https://www.linkedin.com/in/${username}`); // Extract profile information return await page.extract({ name: 'h1', headline: '.headline', about: '.about-section p', experience: '.experience-section li' }); }); ## Complete Example: Twitter Assistant Here's a complete example showing how to create an MCP server that provides Twitter automation capabilities to LLMs: Code (javascript): import { HerdMcpServer } from '@monitoro/herd'; import { z } from 'zod'; const server = new HerdMcpServer({ info: { name: "twitter-assistant", version: "1.0.0", description: "Twitter automation for LLMs" }, transport: { type: "sse", port: 3000 }, herd: { token: process.env.HERD_TOKEN } }); // Post a tweet server.tool({ name: "postTweet", description: "Post a new tweet", schema: { content: z.string().max(280) } }, async ({ content }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/compose/tweet'); await page.type('div[aria-label="Tweet text"]', content); await page.click('div[data-testid="tweetButton"]'); return { success: true }; }); // Get timeline server.resource({ name: "timeline", uriOrTemplate: "twitter/timeline", }, async (devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/home'); return await page.extract({ tweets: { _$r: 'article[data-testid="tweet"]', author: '[data-testid="User-Name"]', content: '[data-testid="tweetText"]', stats: { likes: '[data-testid="like"]', retweets: '[data-testid="retweet"]' } } }); }); // Like a tweet server.tool({ name: "likeTweet", description: "Like a tweet by its URL", schema: { tweetUrl: z.string().url() } }, async ({ tweetUrl }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto(tweetUrl); await page.click('div[data-testid="like"]'); return { success: true }; }); // Start the server server.start().then(() => { console.log('Twitter Assistant ready!'); }).catch(console.error); This setup allows LLMs to: 1. Post tweets 2. Read the timeline 3. Like tweets 4. All through your local browser, maintaining your security and privacy ## python The MCP Server implementation is currently only available in JavaScript. Python support is coming soon! In the meantime, you can: 1. Use the JavaScript implementation to create your MCP server 2. Connect to it from Python using standard MCP client libraries 3. Use the Python Herd SDK for direct browser automation without MCP Example of direct web automation with Python: Code (python): from monitoro_herd import HerdClient async def main(): client = HerdClient(token="your-token") await client.initialize() device = await client.get_device("my-browser") page = await device.new_page() # Navigate to Twitter await page.goto("https://twitter.com") # Extract timeline content content = await page.extract({ "tweets": { "_$r": "article[data-testid='tweet']", "author": "[data-testid='User-Name']", "content": "[data-testid='tweetText']" } }) print("Timeline:", content) # Run the async function import asyncio asyncio.run(main()) Stay tuned for native Python MCP support! Read more about Model Context Protocol in the MCP official documentation. ================================================================================ Document: Reference Node URL: https://herd.garden/docs/reference-node # Node The Node class provides a DOM-like API for interacting with elements on a page. It allows you to inspect and manipulate elements using familiar DOM methods and properties. ## javascript You can obtain Node instances through Page query methods: - `page.querySelector(selector)` - Find first matching element - `page.querySelectorAll(selector)` - Find all matching elements - `node.querySelector(selector)` - Find first matching element within this node - `node.querySelectorAll(selector)` - Find all matching elements within this node ## Properties ### nodeType The type of node (1 for Element, 3 for Text). ### nodeName The name of the node (tag name for elements, '#text' for text nodes). ### nodeValue The text content for text nodes, null for elements. ### tagName The tag name of the element (empty string for non-elements). ### textContent The text content of the node and its descendants. ### innerHTML The HTML content inside the element. ### childNodes Array of child nodes. ### firstChild The first child node, or null if none exists. ### lastChild The last child node, or null if none exists. ## Methods ### getAttribute(name) Gets the value of an attribute. Code (javascript): const href = element.getAttribute('href'); ### hasAttribute(name) Checks if an attribute exists. Code (javascript): if (element.hasAttribute('disabled')) { console.log('Element is disabled'); } ### click([options]) Clicks the element. Code (javascript): // Simple click await element.click(); // Click with navigation wait await element.click({ waitForNavigation: 'networkidle2' }); ### type(text[, options]) Types text into the element. Code (javascript): await element.type('Hello world'); ### focus([options]) Focuses the element. Code (javascript): await element.focus(); ### blur([options]) Removes focus from the element. Code (javascript): await element.blur(); ### hover([options]) Hovers over the element. Code (javascript): await element.hover(); ### scrollIntoView([options]) Scrolls the element into view. Code (javascript): await element.scrollIntoView(); ### setValue(value[, options]) Sets the value of a form element. Code (javascript): // Set input value await element.setValue('test@example.com'); // Set checkbox await element.setValue(true); ### dispatchEvent(eventName[, detail, options]) Dispatches an event on the element. Code (javascript): await element.dispatchEvent('click'); ### dragTo(target[, options]) Drags this element to another element or selector. Code (javascript): // Drag to another element const target = await page.querySelector('.dropzone'); await element.dragTo(target); // Drag to selector await element.dragTo('.dropzone'); ### querySelector(selector) Finds the first matching element within this node. Code (javascript): const child = await element.querySelector('.child'); ### querySelectorAll(selector) Finds all matching elements within this node. Code (javascript): const children = await element.querySelectorAll('.child'); ### getBoundingClientRect() Gets the element's position and size. Code (javascript): const rect = element.getBoundingClientRect(); console.log(rect.x, rect.y, rect.width, rect.height); ## Example Usage Here's a complete example showing how to use the Node class: Code (javascript): // Get a form element const form = await page.querySelector('form'); // Fill out form fields const emailInput = await form.querySelector('input[type="email"]'); await emailInput.type('test@example.com'); // Check a checkbox const checkbox = await form.querySelector('.terms-checkbox'); await checkbox.setValue(true); // Get form dimensions const rect = form.getBoundingClientRect(); console.log('Form size:', rect.width, rect.height); // Submit the form const submitButton = await form.querySelector('button[type="submit"]'); await submitButton.click({ waitForNavigation: 'networkidle2' }); ## python The Node API is currently only available in JavaScript. In Python, you should use the Page methods directly with CSS selectors to interact with elements: Code (python): # Instead of: # element = await page.querySelector('.button') # await element.click() # Use: await page.click('.button') # Instead of: # element = await page.querySelector('input') # await element.type('Hello') # Use: await page.type('input', 'Hello') This provides the same functionality but with a slightly different API. The Node API will be available in Python in a future release. ================================================================================ Document: Reference Page URL: https://herd.garden/docs/reference-page # Page The Page class represents a browser tab or page in the Herd platform. It provides methods for navigating, interacting with elements, handling events, and automating browser actions. ## javascript You can obtain a Page instance using any of these Device methods: - `device.newPage()` - Create a new page - `device.listPages()` - Get all pages - `device.getPage(pageId)` - Get a specific page by ID ## Properties ### id The unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab. ### url The current URL of the page. Returns an empty string if the page hasn't loaded any URL yet. ### title The current title of the page. Returns an empty string if the page hasn't loaded or has no title. ### active Whether this page is currently the active tab in the browser window. ## Methods ### goto(url[, options]) Navigates the page to the specified URL. Code (javascript): // Navigate to a URL and wait for network to be idle await page.goto('https://example.com'); // Navigate with custom options await page.goto('https://example.com', { waitForNavigation: 'load' // Wait for load event instead of network idle }); Options: - `waitForNavigation`: When to consider navigation complete - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### querySelector(selector) Finds the first element matching the CSS selector. Returns a Node object that can be used for further interactions. Code (javascript): const element = await page.querySelector('.submit-button'); if (element) { console.log('Element found:', element.textContent); } ### querySelectorAll(selector) Finds all elements matching the CSS selector. Returns an array of Node objects. Code (javascript): const elements = await page.querySelectorAll('li.item'); for (const element of elements) { console.log('Item text:', element.textContent); } ### dom() Returns the DOM of the page as a JSDOM object for ultimate flexibility. This is useful for extracting data by walking the DOM and finding elements manually. Note: This is a read-only view of the DOM, so you cannot trigger events or modify the DOM this way. Code (javascript): const dom = await page.dom(); console.log(dom); ### waitForElement(selector[, options]) Waits for an element matching the selector to appear or disappear on the page. Code (javascript): // Wait for an element to be visible await page.waitForElement('#loading-indicator'); // or the following which is equivalent await page.waitForElement('#loading-indicator', { state: 'visible' }); // Wait for an element to be hidden await page.waitForElement('#loading-indicator', { state: 'hidden' }); // Wait for an element to be attached to DOM await page.waitForElement('.dynamic-content', { state: 'attached' }); // Wait for an element to be detached from DOM await page.waitForElement('.old-content', { state: 'detached' }); // Wait with timeout await page.waitForElement('.dynamic-content', { state: 'visible', timeout: 10000 // 10 seconds (default is 5 seconds) }); Options: - `state`: The state to wait for - `'visible'`: Wait for element to be visible (default) - `'hidden'`: Wait for element to be hidden - `'attached'`: Wait for element to be attached to DOM - `'detached'`: Wait for element to be detached from DOM - `timeout`: Maximum time to wait in milliseconds (default: 5000) ### waitForSelector(selector[, options]) Alias for waitForElement. Waits for an element matching the selector to appear or disappear. Code (javascript): // Wait for a selector to be visible await page.waitForSelector('.search-results', { state: 'visible' }); // Wait for a selector to be detached await page.waitForSelector('.loading-spinner', { state: 'detached', timeout: 5000 }); ### waitForNavigation(condition) Waits for navigation to complete based on the specified condition. Code (javascript): // Wait for page load event await page.waitForNavigation('load'); // Wait for network to be idle await page.waitForNavigation('networkidle0'); // Wait for URL change await page.waitForNavigation('change'); Conditions: - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'change'`: Wait for URL change - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### click(selector[, options]) Clicks an element that matches the selector. Code (javascript): // Simple click await page.click('#submit-button'); // Click with navigation wait await page.click('a.link', { waitForNavigation: 'networkidle2' }); ### type(selector, text[, options]) Types text into an input element. Code (javascript): // Type into an input field await page.type('#search-input', 'search query'); // Type with navigation wait (for auto-submit forms) await page.type('#search-input', 'search query', { waitForNavigation: 'networkidle2' }); ### focus(selector[, options]) Focuses an element on the page. Code (javascript): await page.focus('#email-input'); ### hover(selector[, options]) Hovers over an element. Code (javascript): await page.hover('.dropdown-trigger'); ### press(key[, options]) Presses a keyboard key. Code (javascript): await page.press('Enter'); ### scroll(x, y[, options]) Scrolls the page by the specified amount. Code (javascript): // Scroll down 500 pixels await page.scroll(0, 500); ### scrollIntoView(selector[, options]) Scrolls an element into view. Code (javascript): await page.scrollIntoView('#bottom-content'); ### back([options]) Navigates back in the browser history. Code (javascript): await page.back({ waitForNavigation: 'networkidle2' }); ### forward([options]) Navigates forward in the browser history. Code (javascript): await page.forward({ waitForNavigation: 'networkidle2' }); ### reload([options]) Reloads the current page. Code (javascript): await page.reload({ waitForNavigation: 'networkidle2' }); ### activate() Activates the page (makes it the active tab). Code (javascript): await page.activate(); ### close() Closes the page (tab). Code (javascript): await page.close(); ## Example Usage Here's a complete example showing how to use the Page class: Code (javascript): // Create a new page const page = await device.newPage(); // Navigate to a URL await page.goto('https://example.com'); // Fill out a form await page.type('#username', 'myuser'); await page.type('#password', 'mypass'); await page.click('#submit-button', { waitForNavigation: 'networkidle2' }); // Extract some data const title = await page.evaluate(() => document.title); console.log('Page title:', title); // Close the page when done await page.close(); ## python You can obtain a Page instance using any of these Device methods: - `device.new_page()` - Create a new page - `device.list_pages()` - Get all pages - `device.get_page(page_id)` - Get a specific page by ID ## Properties ### id The unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab. ### url The current URL of the page. Returns an empty string if the page hasn't loaded any URL yet. ### title The current title of the page. Returns an empty string if the page hasn't loaded or has no title. ### active Whether this page is currently the active tab in the browser window. ## Methods ### goto(url[, options]) Navigates the page to the specified URL. Code (python): # Navigate to a URL and wait for network to be idle await page.goto("https://example.com") # Navigate with custom options await page.goto("https://example.com", { "waitForNavigation": "load" # Wait for load event instead of network idle }) Options: - `waitForNavigation`: When to consider navigation complete - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### querySelector(selector) / Q(selector) Finds the first element matching the CSS selector. Returns a dictionary representing the element. Code (python): # Using querySelector (alias for Q) element = await page.querySelector(".submit-button") if element: print("Element found:", element) # Using Q directly element = await page.Q(".submit-button") ### querySelectorAll(selector) / QQ(selector) Finds all elements matching the CSS selector. Returns a list of dictionaries representing the elements. Code (python): # Using querySelectorAll (alias for QQ) elements = await page.querySelectorAll("li.item") for element in elements: print("Item:", element) # Using QQ directly elements = await page.QQ("li.item") ### click(selector[, options]) Clicks an element that matches the selector. Code (python): # Simple click await page.click("#submit-button") # Click with navigation wait await page.click("a.link", {"waitForNavigation": "networkidle2"}) ### type(selector, text[, options]) Types text into an input element. Code (python): # Type into an input field await page.type("#search-input", "search query") # Type with navigation wait (for auto-submit forms) await page.type("#search-input", "search query", { "waitForNavigation": "networkidle2" }) ### focus(selector[, options]) Focuses an element on the page. Code (python): await page.focus("#email-input") ### hover(selector[, options]) Hovers over an element. Code (python): await page.hover(".dropdown-trigger") ### scroll(x, y[, options]) Scrolls the page by the specified amount. Code (python): # Scroll down 500 pixels await page.scroll(0, 500) ### scroll_into_view(selector[, options]) Scrolls an element into view. Code (python): await page.scroll_into_view("#bottom-content") ### set_value(selector, value[, options]) Sets the value of a form element directly. Code (python): # Set input value await page.set_value("#quantity", "5") # Set checkbox await page.set_value("#agree", True) ### dispatch_event(selector, event_name[, detail, options]) Dispatches a DOM event on an element. Code (python): await page.dispatch_event("#my-button", "click") ### close() Closes the page (tab). Code (python): await page.close() ## Example Usage Here's a complete example showing how to use the Page class: Code (python): # Create a new page page = await device.new_page() # Navigate to a URL await page.goto("https://example.com") # Fill out a form await page.type("#username", "myuser") await page.type("#password", "mypass") await page.click("#submit-button", {"waitForNavigation": "networkidle2"}) # Extract some data using the extract method data = await page.extract({ "title": "h1", "description": ".description" }) print("Extracted data:", data) # Close the page when done await page.close() ================================================================================ Document: Security Privacy URL: https://herd.garden/docs/security-privacy # Security & Privacy in Herd At Herd, we take security and privacy seriously. This guide outlines the security features built into the platform and the privacy measures we take to protect your data. ## Security Architecture Herd is built with security at its core: ### End-to-End Encryption All communication between your browsers and the Herd platform is encrypted end-to-end: - **Transport Layer Security (TLS)**: All API requests and responses use TLS 1.3. - **WebRTC Encryption**: Remote control sessions use WebRTC with DTLS-SRTP encryption. - **Secure WebSockets**: Real-time communication uses encrypted WebSocket connections. - **NATS**: All communication between your browser and the code you run is encrypted end-to-end using a NATS-based PKI infrastructure and we do not intercept or inspect the content of the communication. ### Authentication & Authorization Multiple layers of security protect access to your account and devices: - **Multi-factor Authentication**: Optional 2FA for account access - **Device Registration Codes**: One-time codes for connecting browsers - **Session Management**: Automatic timeouts and the ability to revoke sessions - **Role-Based Access Control**: Granular permissions for team members ### Infrastructure Security Our platform infrastructure implements industry best practices: - **Regular Security Audits**: Third-party security audits of our systems - **Vulnerability Scanning**: Continuous monitoring for vulnerabilities - **Secure Development**: Strict coding practices and security reviews - **Cloud Security**: Leveraging secure cloud infrastructure with isolation between customers ## Privacy Features Herd includes several features to protect your privacy: ### Data Minimization We only collect the data necessary for the platform to function: - **Selective Access**: You control which browsers are connected and which data is shared - **No Unnecessary Telemetry**: Limited data collection focused on service performance - **Automatic Data Expiry**: Logs and temporary data are automatically purged after set periods ### User Control You maintain control over your data and connections: - **Connection Visibility**: Clear indicators when a browser is being monitored or controlled - **Permission Prompts**: Optional prompts before remote control is initiated - **Incognito Mode Handling**: Special handling of private browsing sessions - **Activity Logs**: Transparent logs of all remote control activities ### Compliance Features For organizations with specific compliance requirements: - **Data Residency Options**: Select where your data is stored (Enterprise plan) - **Compliance Reporting**: Generate reports for audit purposes - **Custom Retention Policies**: Set data retention periods to match your policies - **Privacy Mode**: Additional restrictions for sensitive environments ## Security Best Practices To maximize security when using Herd: ### Account Security - Use strong, unique passwords for your Herd account - Enable two-factor authentication - Regularly review active sessions and revoke any suspicious ones - Limit account access to necessary team members only ### Device Security - Register devices with descriptive names for easy identification - Regularly review connected devices and remove unused ones - Use device tagging to organize and manage access - Consider network-level restrictions for sensitive devices ### Remote Control Security - Always end remote control sessions when not in use - Use view-only mode when full control isn't necessary - Be cautious about what information is visible during remote sessions - Consider scheduling remote sessions in advance when possible ## Privacy Policy Herd's formal privacy policy can be found at [monitoro.co/privacy](https://monitoro.co/privacy). Key points include: - We do not sell your data to third parties - We only process your data to provide the Herd service - You retain ownership of all content viewed or managed through Herd - We implement strong security measures to protect your data - We are transparent about any data breaches or security incidents ## Security Updates We continuously improve our security and privacy features: - Security updates are automatically applied to the platform - Extension updates are released regularly with security improvements - Follow our blog for detailed information on security enhancements ## Reporting Security Issues If you discover a security vulnerability, please report it responsibly: 1. Email security@herd.garden with details of the vulnerability 2. Include steps to reproduce if possible 3. Allow time for us to address the issue before public disclosure Note: We unfortunately do not offer a bug bounty program as we are a small team and our resources are limited. We do appreciate your responsible disclosure and help keeping the internet a safer place. ================================================================================ Document: Trails Automations URL: https://herd.garden/docs/trails-automations # Trails Trails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process. ## javascript Trails are fully supported in the JavaScript SDK. ## Creating a Trail A trail defines the following components: - **urls.ts**: Exports an array of URL definitions - **selectors.ts**: Exports an array of selector configurations - **actions.ts**: Exports action classes that implement the `TrailAction` interface A trail at the minimum has the following structure: Code: google-search/ urls.ts selectors.ts actions.ts package.json The `package.json` file defines the trail and its dependencies: Code (json): { "name": "google-search", "description": "Search google for webpages.", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } You should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code. ## Trail Implementation Guide ### Step 1: Set up the trail structure Create a new directory for your trail with the following files: Code: my-trail/ urls.ts selectors.ts actions.ts package.json Add the basic package.json configuration: Code (json): { "name": "my-trail", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } ### Step 2: Define URLs In `urls.ts`, export an array of URL definitions that your trail will interact with: Code (typescript): export default [{ "id": "my-url", "template": "https://example.com/path?param1={param1}&param2={param2}", "description": "Description of what this URL represents", "examples": [ { "param1": "value1", "param2": "value2" } ], "params": { "param1": { "type": "string", "required": true, "description": "Description of param1" }, "param2": { "type": "string", "required": false, "default": "defaultValue", "description": "Description of param2" } } }]; ### Step 3: Define Selectors In `selectors.ts`, export an array of selector configurations that define how to extract data from web pages: Code (typescript): export default [{ "id": "my-selector", "value": { "dataKey": { "_$r": "#main-container", "title": { "_
quot;: ".title" }, "description": { "_
quot;: ".description" }, "link": { "_
quot;: "a.link", "attribute": "href" } } }, "description": "Selector for extracting specific data", "examples": [ { "urlId": "my-url", "urlParams": { "param1": "value1", "param2": "value2" } } ] }]; ### Step 4: Implement Actions In `actions.ts`, define one or more action classes that implement the `TrailAction` interface: Code (typescript): import type { Device, TrailAction, TrailActionManifest, TrailRunResources } from "@monitoro/herd"; export class MyTrailAction implements TrailAction { manifest: TrailActionManifest = { name: "my-action", description: "Description of what this action does", params: { param1: { type: "string", description: "Description of param1" }, param2: { type: "number", description: "Description of param2", default: 10 } }, result: { type: "array", description: "Description of the result", items: { type: "object", properties: { property1: { type: "string" }, property2: { type: "number" } } } }, examples: [ { "param1": "value1", "param2": 10 } ] } async test(device: Device, params: Record, resources: TrailRunResources) { try { const result = await this.run(device, params, resources); // Validate result if (!result || result.length === 0) { return { status: "error", message: "No results found", result: [] }; } return { status: "success", result }; } catch (e) { return { status: "error", message: `Error: ${e}`, result: null }; } } async run(device: Device, params: Record, resources: TrailRunResources) { const { param1, param2 } = params; const page = await device.newPage(); try { // Navigate to URL using the URL template from urls.ts await page.goto(resources.url('my-url', { param1, param2 })); // Extract data using selectors from selectors.ts const extracted = await page.extract(resources.selector('my-selector')); // Process extracted data const results = (extracted as any)?.dataKey || []; // Return processed results return results; } finally { await page.close(); } } } ### Step 5: Testing and debugging Use the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest): Code (bash): herd trail test --action my-trail You can also watch for changes in the trail and re-run tests: Code (bash): herd trail test --action my-trail --watch # or herd trail test -a my-trail -w And you can also test selectors only: Code (bash): herd trail test --selector my-selector And watch for changes in the selectors: Code (bash): herd trail test --selector my-selector --watch # or herd trail test -s my-selector -w ### Step 6: Publish your trail Publishing is coming soon! ### Best Practices 1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc. 2. **Performance**: Minimize page loads and extract as much data as possible from each page. 3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain. 4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios. 5. **Versioning**: Increment your trail's version in package.json when making changes. ## python Trails support for Python SDK is coming soon. Stay tuned for updates! In the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them. ================================================================================ Document: Troubleshooting URL: https://herd.garden/docs/troubleshooting # Troubleshooting Herd This guide provides solutions for common issues you might encounter when using the Herd platform. If you can't find a solution here, please contact our [support team](/docs/getting-started) for further assistance. ## Installation Issues ### Extension Won't Install **Problem**: You can't install the Herd extension in your browser. **Solutions**: - Verify Developer mode is enabled in your browser's extensions page - Make sure you're using a supported browser (Chrome, Edge, Brave) - Try downloading the extension file again as it might be corrupted - Check if your browser has restrictions on installing third-party extensions - Try installing from a different browser profile If all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share. ### Extension Shows as Corrupted **Problem**: Your browser shows the Herd extension as corrupted or invalid. **Solutions**: - Re-download the extension package - Clear your browser cache before installing - Try extracting the zip file and loading it as an unpacked extension - Verify that you have the latest version of the extension If all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share. ## Connection Issues ### Browser is disconnected or no browser registered **Problem**: Running a trail or calling any Herd command throws an exception "Browser is disconnected or no browser registered". This means that your browser is not connected to the Herd platform **Solutions**: - First ensure that you have installed Herd and registered your browser following our [Getting Started guide](/docs/getting-started). - Check the internet connection of the computer where you installed Herd extension - Go to `chrome://extensions` and click the reload icon next to Herd extension - If that doesn't work, delete the extension and reconnect it again from scratch, following our [Getting Started guide](/docs/getting-started). If nothing works, [contact](mailto:support@herd.garden) us for additional help with as much context about the issue as you can share. ### Can't Connect to Herd Server **Problem**: The extension is installed but can't connect to the Herd server. **Solutions**: - Check your internet connection - Verify that the registration code is correct and hasn't expired - Make sure your firewall isn't blocking the connection - Try disabling any VPN or proxy services temporarily - Check if your organization blocks WebSocket connections ### Connection Keeps Dropping **Problem**: The connection between your browser and Herd keeps disconnecting. **Solutions**: - Check for network stability issues - Make sure your computer isn't going to sleep - Verify that the browser is allowed to run in the background - Check if other extensions are conflicting with Herd - Try connecting using a wired network connection if possible ## Remote Control Issues ### Black Screen During Remote Control **Problem**: You see a black screen when trying to view a remote browser. **Solutions**: - Check if the remote device is in sleep mode or locked - Refresh the remote control session - Make sure the remote browser tab is active (not minimized) - Try restarting the remote browser - Verify that the remote device has granted screen sharing permissions ### High Latency in Remote Control **Problem**: There's significant lag when controlling a remote browser. **Solutions**: - Lower the streaming quality in the remote control settings - Check network conditions on both ends - Close unnecessary tabs and applications on both devices - Make sure no bandwidth-heavy activities are running (like video streaming) - Try using a wired connection if possible ### Input Not Registering **Problem**: Mouse clicks or keyboard input aren't registering on the remote browser. **Solutions**: - Check if you're in "View Only" mode and switch to "Control" mode - Try clicking on the remote view area to ensure it has focus - Refresh the remote control session - Check if the remote browser is responding to local inputs - Try restarting the remote control session ## Account and Management Issues ### Device Not Appearing in Dashboard **Problem**: A connected device isn't showing up in your Herd dashboard. **Solutions**: - Verify the device is properly connected - Refresh the dashboard page - Check if the device is registered under a different account - Make sure the extension is enabled and running - Try reconnecting the device using a new registration code ### Can't Create New Device Registration **Problem**: You're unable to create a new device registration. **Solutions**: - Check if you've reached your plan's device limit - Verify that you have the necessary permissions in your account - Try using a different browser to access the dashboard - Clear your browser cache and cookies - Check if your account has any restrictions ## System Requirements If you're experiencing persistent issues, verify that your system meets these minimum requirements: - **Browser**: Chrome 70+, Edge 79+, or Brave 1.0+ - **Operating System**: Windows 10+, macOS 10.14+, or Ubuntu 18.04+ - **RAM**: 4GB minimum (8GB recommended) - **Network**: Stable internet connection with at least 1Mbps upload/download - **Processor**: Dual-core processor at 2GHz or higher ## Contacting Support If you've tried the solutions above and are still experiencing issues, please contact our support team: 1. Email: support@herd.garden 2. In-app: Click the "Help" icon in the dashboard footer 3. Documentation: Check for updated troubleshooting guides on our website When contacting support, please include: - Your browser type and version - Your operating system - A description of the issue - Any error messages you've received - Steps you've already taken to resolve the issue ================================================================================
method returns the first element that matches the CSS selector, or `null` if no element is found.\n\n#### Typing Text\n\nTo type text into an input field:\n\nCode (javascript):\n// Type text into an input field\nawait page.type('input[name=\"q\"]', 'Monitoro Herd automation');\nconsole.log('Text entered into search box');\n\nThe `type` method finds the element using the CSS selector and simulates typing the specified text.\n\n#### Clicking Elements\n\nTo click a button or link:\n\nCode (javascript):\n// Click a button\nawait page.click('input[type=\"submit\"]');\nconsole.log('Search button clicked');\n\nBy default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:\n\nCode (javascript):\n// Click and wait for navigation\nawait page.click('input[type=\"submit\"]', { \n waitForNavigation: 'networkidle2' \n});\nconsole.log('Search button clicked and navigation completed');\n\nThe `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.\n\n#### Waiting for Elements\n\nSometimes you need to wait for elements to appear on the page:\n\nCode (javascript):\n// Wait for an element to appear\nawait page.waitForSelector('#search');\nconsole.log('Search results have loaded');\n\nThis is useful when dealing with dynamic content that loads after the initial page load.\n\n#### Search Engine Example\n\nLet's put these concepts together in a search engine example:\n\nCode (javascript):\nasync function searchExample() {\n const client = new HerdClient('your-token');\n \n try {\n await client.initialize();\n const devices = await client.listDevices();\n const device = devices[0];\n const page = await device.newPage();\n \n // Navigate to a search engine\n console.log('Navigating to Google...');\n await page.goto('https://www.google.com');\n \n // Type in the search box\n console.log('Entering search query...');\n await page.type('input[name=\"q\"]', 'Monitoro Herd automation');\n \n // Submit the search form and wait for results\n console.log('Submitting search...');\n await page.click('input[type=\"submit\"]', { \n waitForNavigation: 'networkidle2' \n });\n \n // Wait for results to load completely\n console.log('Waiting for search results...');\n await page.waitForSelector('#search');\n \n // Extract search result titles\n console.log('Extracting search results...');\n const searchResults = await page.extract({\n titles: {\n _$r: '#search .g h3', // _$r extracts multiple elements\n text: ':root' // For each match, get its text\n }\n });\n \n // Display the search result titles\n console.log('\\nSearch Results:');\n searchResults.titles.forEach((result, index) =\u003e {\n console.log(`${index + 1}. ${result.text}`);\n });\n \n } catch (error) {\n console.error('Error:', error);\n } finally {\n await client.close();\n }\n}\n\n## python\n\n## Python SDK\n\n### Setting Up Your Environment\n\nBefore writing any code, you'll need to set up your Python environment and install the Herd SDK:\n\n1. Make sure you have Python 3.8+ installed\n2. Create a virtual environment (recommended)\n3. Install the SDK using pip:\n\nCode (bash):\npip install monitoro-herd\n\n### Initializing the Client\n\nThe first step in any automation is to initialize the Herd client with your API credentials:\n\nCode (python):\n# Import the Herd client\nfrom monitoro_herd import HerdClient\n\n# Initialize the client with your API URL and token\nclient = HerdClient('your-token')\n\n# Always initialize the client before using it\nclient.initialize()\nNote: **Note:** Replace the token with your actual Herd API token from your dashboard.\n\n### Connecting to a Device\n\nNext, connect to a device that will run your automation:\n\nCode (python):\n# Get available devices\ndevices = await client.list_devices()\n\n# Connect to the first device\ndevice = devices[0]\n\nprint(f\"Connected to device: {device.id}\")\n\n### Creating a Page and Navigating\n\nNow create a browser page and navigate to a website:\n\nCode (python):\n# Create a new page\npage = await device.new_page()\n\n# Navigate to a website\nawait page.goto(\"https://example.com\")\n\nprint(\"Successfully navigated to example.com\")\n\n### Extracting Basic Information\n\nExtract information from the page using CSS selectors:\n\nCode (python):\n# Extract basic information\ndata = await page.extract({\n \"title\": \"h1\", # Main heading\n \"description\": \"p\", # First paragraph\n \"link\": \"a\" # First link text\n})\n\n# Display the extracted data\nprint(\"Extracted data:\")\nprint(f\"Title: {data['title']}\")\nprint(f\"Description: {data['description']}\")\nprint(f\"Link: {data['link']}\")\n\n### Resource Management\n\nAlways close resources when you're done:\n\nCode (python):\n# Close the page\nawait page.close()\n\n# Close the client\nawait client.close()\n\n### Complete Basic Example\n\nHere's a complete example putting all these concepts together:\n\nCode (python):\nimport asyncio\nfrom monitoro_herd import HerdClient\n\nasync def basic_extraction():\n # Initialize the client\n client = HerdClient(\"your-token\")\n \n try:\n # Initialize the connection\n await client.initialize()\n print(\"Client initialized successfully\")\n \n # Get the first available device\n devices = await client.list_devices()\n if not devices:\n raise Exception(\"No devices available\")\n device = devices[0]\n print(f\"Connected to device: {device.id}\")\n \n # Create a new page\n page = await device.new_page()\n print(\"New page created\")\n \n # Navigate to a website\n print(\"Navigating to example.com...\")\n await page.goto(\"https://example.com\")\n print(\"Navigation complete\")\n \n # Extract data using simple selectors\n print(\"Extracting content...\")\n data = await page.extract({\n \"title\": \"h1\",\n \"description\": \"p\",\n \"link\": \"a\"\n })\n \n # Display the extracted data\n print(\"\\nExtracted data:\")\n print(f\"Title: {data['title']}\")\n print(f\"Description: {data['description']}\")\n print(f\"Link: {data['link']}\")\n \n except Exception as e:\n print(f\"Error during automation: {e}\")\n finally:\n # Always close resources\n print(\"Closing client connection...\")\n await client.close()\n print(\"Client connection closed\")\n\n# Run the async function\nasyncio.run(basic_extraction())\n\n### Working with Lists and Structured Data\n\nOne of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.\n\n#### The `_$r` Selector\n\nTo extract multiple elements that match a pattern, use the `_$r` (repeat) selector:\n\nCode (python):\n# Extract a list of items\ndata = await page.extract({\n \"items\": {\n \"_$r\": \".item\", # Find all elements with class \"item\"\n \"name\": \".item-name\", # For each item, get the name\n \"price\": \".price\" # For each item, get the price\n }\n})\n\n# Access the extracted items\nfor item in data[\"items\"]:\n print(f\"Name: {item['name']}, Price: {item['price']}\")\n\nThe `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.\n\n#### Extracting Attributes\n\nSometimes you need to extract an attribute rather than the text content:\n\nCode (python):\n# Extract links and their href attributes\ndata = await page.extract({\n \"links\": {\n \"_$r\": \"a\", # Find all links\n \"text\": \":root\", # Get the link text\n \"url\": {\n \"_$\": \":root\", # Reference the same element\n \"attribute\": \"href\" # Get its href attribute\n }\n }\n})\n\n# Display the links\nfor link in data[\"links\"]:\n print(f\"Link: {link['text']} -\u003e {link['url']}\")\n\n#### Hacker News Example\n\nLet's put these concepts together to scrape stories from Hacker News:\n\nCode (python):\nimport asyncio\nfrom monitoro_herd import HerdClient\n\nasync def scrape_hacker_news():\n client = HerdClient(\"your-token\")\n \n try:\n await client.initialize()\n devices = await client.list_devices()\n device = devices[0]\n page = await device.new_page()\n \n # Navigate to Hacker News\n print(\"Navigating to Hacker News...\")\n await page.goto(\"https://news.ycombinator.com\")\n \n # Extract stories and their metadata\n print(\"Extracting stories...\")\n data = await page.extract({\n # Extract the story elements\n \"stories\": {\n \"_$r\": \".athing\", # Each story row\n \"title\": \".titleline \u003e a\", # Story title\n \"site\": \".sitestr\", # Source website\n \"link\": {\n \"_$\": \".titleline \u003e a\", # Story link\n \"attribute\": \"href\" # Get the URL\n }\n },\n # Extract the metadata (points, author, etc.)\n \"metadata\": {\n \"_$r\": \".subline\", # Metadata rows\n \"points\": \".score\", # Points count\n \"author\": \".hnuser\", # Author username\n \"time\": \".age\" # Submission time\n }\n })\n \n # Combine stories with their metadata\n # (They're in separate lists but in the same order)\n combined_stories = list(zip(data[\"stories\"], data[\"metadata\"]))\n \n # Display the first 3 stories\n print(f\"\\nExtracted {len(combined_stories)} stories:\")\n for i, (story, meta) in enumerate(combined_stories[:3]):\n print(f\"\\nStory {i+1}:\")\n print(f\"Title: {story['title']}\")\n if \"site\" in story:\n print(f\"Site: {story['site']}\")\n print(f\"Link: {story['link']}\")\n if \"points\" in meta:\n print(f\"Points: {meta['points']}\")\n if \"author\" in meta:\n print(f\"Author: {meta['author']}\")\n if \"time\" in meta:\n print(f\"Posted: {meta['time']}\")\n \n finally:\n await page.close()\n await client.close()\n\n# Run the function\nasyncio.run(scrape_hacker_news())\n\n## Tips for Successful Automation\n\n1. **Start Simple**: Begin with basic extractions before moving to complex interactions\n2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely\n3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks\n4. **Close Resources**: Always close pages and clients when done to avoid resource leaks\n5. **Test Incrementally**: Build your automation step by step, testing each part\n6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods\n7. **Debug with Screenshots**: Take screenshots during automation to see what's happening\n\n## Next Steps\n\nNow that you've created your first automation, you can:\n\n- Explore more complex selectors and extraction patterns\n- Learn how to handle authentication and login flows\n- Set up scheduled automations for regular data collection\n- Integrate with your existing systems via APIs\n\n==\n\nDocument: Data Extraction\nURL: https://herd.garden/docs/data-extraction\n\n# Data Extraction\n\nWelcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines.\n\n## Understanding Selectors\n\nHerd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system.\n\n### Basic Extraction\n\n## javascript\n\nThe simplest form of extraction uses CSS selectors to target elements:\n\nCode (javascript):\n// Extract basic text content\nconst data = await page.extract({\n title: 'h1', // Extracts the main heading\n description: 'p', // Extracts the first paragraph\n link: 'a' // Extracts the first link text\n});\n\nconsole.log(data.title); // \"Welcome to Our Website\"\nconsole.log(data.description); // \"This is our homepage.\"\n\n## python\n\nThe simplest form of extraction uses CSS selectors to target elements:\n\nCode (python):\n# Extract basic text content\ndata = await page.extract({\n \"title\": \"h1\", # Extracts the main heading\n \"description\": \"p\", # Extracts the first paragraph\n \"link\": \"a\" # Extracts the first link text\n})\n\nprint(data[\"title\"]) # \"Welcome to Our Website\"\nprint(data[\"description\"]) # \"This is our homepage.\"\n\n### Advanced Selector Syntax\n\n## javascript\n\nFor more complex extraction needs, use the expanded object syntax:\n\nCode (javascript):\nconst data = await page.extract({\n title: {\n _$: 'h1', // CSS selector\n attribute: 'id' // Extract the ID attribute instead of text\n },\n price: {\n _$: '.price', // Target price element\n pipes: ['parseNumber'] // Apply transformation\n }\n});\n\n## python\n\nFor more complex extraction needs, use the expanded object syntax:\n\nCode (python):\ndata = await page.extract({\n \"title\": {\n \"_$\": \"h1\", # CSS selector\n \"attribute\": \"id\" # Extract the ID attribute instead of text\n },\n \"price\": {\n \"_$\": \".price\", # Target price element\n \"pipes\": [\"parseNumber\"] # Apply transformation\n }\n})\n\n### Extracting Lists of Items\n\n## javascript\n\nTo extract multiple elements that match a pattern, use the `_$r` (repeat) selector:\n\nCode (javascript):\nconst data = await page.extract({\n items: {\n _$r: '.item', // Find all elements with class \"item\"\n title: 'h2', // For each item, get the title\n price: '.price', // For each item, get the price\n date: 'time' // For each item, get the date\n }\n});\n\n// Access the extracted items\ndata.items.forEach(item =\u003e {\n console.log(`${item.title}: ${item.price}, Posted: ${item.date}`);\n});\n\n## python\n\nTo extract multiple elements that match a pattern, use the `_$r` (repeat) selector:\n\nCode (python):\ndata = await page.extract({\n \"items\": {\n \"_$r\": \".item\", # Find all elements with class \"item\"\n \"title\": \"h2\", # For each item, get the title\n \"price\": \".price\", # For each item, get the price\n \"date\": \"time\" # For each item, get the date\n }\n})\n\n# Access the extracted items\nfor item in data[\"items\"]:\n print(f\"{item['title']}: {item['price']}, Posted: {item['date']}\")\n\n### Nested Extraction\n\n## javascript\n\nYou can nest selectors to extract hierarchical data:\n\nCode (javascript):\nconst data = await page.extract({\n product: {\n name: '.product-name',\n details: {\n _$: '.product-details',\n specs: {\n _$r: '.spec-item',\n label: '.spec-label',\n value: '.spec-value'\n }\n }\n }\n});\n\n## python\n\nYou can nest selectors to extract hierarchical data:\n\nCode (python):\ndata = await page.extract({\n \"product\": {\n \"name\": \".product-name\",\n \"details\": {\n \"_$\": \".product-details\",\n \"specs\": {\n \"_$r\": \".spec-item\",\n \"label\": \".spec-label\",\n \"value\": \".spec-value\"\n }\n }\n }\n})\n\n## Special Selectors\n\nHerd provides special selectors to handle various extraction scenarios:\n\n### Root Selector (`:root`)\n\nThe `:root` selector refers to the current element in context:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n items: {\n _$r: '.item',\n someElement: ':root', // Extract text of the .item element itself\n classes: {\n _$: ':root',\n attribute: 'class' // Extract class attribute of the same element\n }\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"items\": {\n \"_$r\": \".item\",\n \"someElement\": \":root\", # Extract text of the .item element itself\n \"classes\": {\n \"_$\": \":root\",\n \"attribute\": \"class\" # Extract class attribute of the same element\n }\n }\n})\n\n### Property Extraction\n\nYou can extract JavaScript properties from elements:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n dimensions: {\n _$: '.box',\n property: 'getBoundingClientRect' // Get element dimensions\n },\n html: {\n _$: '.content',\n property: 'innerHTML' // Get inner HTML\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"dimensions\": {\n \"_$\": \".box\",\n \"property\": \"getBoundingClientRect\" # Get element dimensions\n },\n \"html\": {\n \"_$\": \".content\",\n \"property\": \"innerHTML\" # Get inner HTML\n }\n})\n\n## Transformation Pipelines\n\nHerd includes powerful transformation pipelines to process extracted data:\n\n### Available Transformations\n\n| Pipe | Description | Example Input | Example Output |\n|------|-------------|--------------|----------------|\n| `trim` | Removes whitespace from start/end | `\" Hello \"` | `\"Hello\"` |\n| `toLowerCase` | Converts text to lowercase | `\"HELLO\"` | `\"hello\"` |\n| `toUpperCase` | Converts text to uppercase | `\"hello\"` | `\"HELLO\"` |\n| `parseNumber` | Extracts numbers from text | `\"$1,2K.45\"` | `1200.45` |\n| `parseDate` | Converts text to date | `\"2024-01-15\"` | `\"2024-01-15T00:00:00.000Z\"` |\n| `parseDateTime` | Converts text to datetime | `\"2024-01-15T12:00:00Z\"` | `\"2024-01-15T12:00:00.000Z\"` |\n\n### Using Transformations\n\nApply transformations using the `pipes` property:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n price: {\n _$: '.price',\n pipes: ['parseNumber'] // Convert \"$1,234.56\" to 1234.56\n },\n title: {\n _$: 'h1',\n pipes: ['trim', 'toLowerCase'] // Apply multiple transformations\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"price\": {\n \"_$\": \".price\",\n \"pipes\": [\"parseNumber\"] # Convert \"$1,234.56\" to 1234.56\n },\n \"title\": {\n \"_$\": \"h1\",\n \"pipes\": [\"trim\", \"toLowerCase\"] # Apply multiple transformations\n }\n})\n\n### Handling Currency and Large Numbers\n\nThe `parseNumber` transformation handles various formats:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n price1: {\n _$: '.price-1', // Contains \"$1,234.56\"\n pipes: ['parseNumber'] // Result: 1234.56\n },\n price2: {\n _$: '.price-2', // Contains \"$1.5M\"\n pipes: ['parseNumber'] // Result: 1500000\n },\n price3: {\n _$: '.price-3', // Contains \"1.5T€\"\n pipes: ['parseNumber'] // Result: 1500000000000\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"price1\": {\n \"_$\": \".price-1\", # Contains \"$1,234.56\"\n \"pipes\": [\"parseNumber\"] # Result: 1234.56\n },\n \"price2\": {\n \"_$\": \".price-2\", # Contains \"$1.5M\"\n \"pipes\": [\"parseNumber\"] # Result: 1500000\n },\n \"price3\": {\n \"_$\": \".price-3\", # Contains \"1.5T€\"\n \"pipes\": [\"parseNumber\"] # Result: 1500000000000\n }\n})\n\n## Real-World Examples\n\nLet's look at some practical examples of data extraction:\n\n### E-commerce Product Listing\n\nExtract products from a search results page:\n\n## javascript\n\nCode (javascript):\nconst searchResults = await page.extract({\n products: {\n _$r: '[data-component-type=\"s-search-result\"]',\n title: {\n _$: 'h2 .a-link-normal',\n pipes: ['trim']\n },\n price: {\n _$: '.a-price .a-offscreen',\n pipes: ['parseNumber']\n },\n rating: {\n _$: '.a-icon-star-small .a-icon-alt',\n pipes: ['trim']\n },\n reviews: {\n _$: '.a-size-base.s-underline-text',\n pipes: ['trim']\n }\n }\n});\n\n## python\n\nCode (python):\nsearchResults = await page.extract({\n \"products\": {\n \"_$r\": '[data-component-type=\"s-search-result\"]',\n \"title\": {\n \"_$\": \"h2 .a-link-normal\",\n \"pipes\": [\"trim\"]\n },\n \"price\": {\n \"_$\": \".a-price .a-offscreen\",\n \"pipes\": [\"parseNumber\"]\n },\n \"rating\": {\n \"_$\": \".a-icon-star-small .a-icon-alt\",\n \"pipes\": [\"trim\"]\n },\n \"reviews\": {\n \"_$\": \".a-size-base.s-underline-text\",\n \"pipes\": [\"trim\"]\n }\n }\n})\n\n### News Article List\n\nExtract articles from a news site:\n\n## javascript\n\nCode (javascript):\nconst articles = await page.extract({\n items: {\n _$r: '.item',\n title: {\n _$: 'h2',\n pipes: ['trim', 'toLowerCase']\n },\n price: {\n _$: '.price',\n pipes: ['parseNumber']\n },\n date: {\n _$: 'time',\n pipes: ['parseDate']\n }\n }\n});\n\n## python\n\nCode (python):\narticles = await page.extract({\n \"items\": {\n \"_$r\": \".item\",\n \"title\": {\n \"_$\": \"h2\",\n \"pipes\": [\"trim\", \"toLowerCase\"]\n },\n \"price\": {\n \"_$\": \".price\",\n \"pipes\": [\"parseNumber\"]\n },\n \"date\": {\n \"_$\": \"time\",\n \"pipes\": [\"parseDate\"]\n }\n }\n})\n\n## Advanced Techniques\n\n### Handling Dynamic Content\n\nFor dynamic content that loads after the page is ready:\n\n## javascript\n\nCode (javascript):\n// Wait for dynamic content to load\nawait page.waitForElement('#dynamic span');\n\n// Then extract the content\nconst data = await page.extract({\n content: '#dynamic span'\n});\n\n## python\n\nCode (python):\n# Wait for dynamic content to load\nawait page.waitForElement('#dynamic span')\n\n# Then extract the content\ndata = await page.extract({\n \"content\": \"#dynamic span\"\n})\n\n### Extracting Page Metadata\n\nExtract information about the page itself:\n\n## javascript\n\nCode (javascript):\nconst pageInfo = await page.extract({\n title: 'title',\n metaDescription: 'meta[name=\"description\"]',\n canonicalUrl: {\n _$: 'link[rel=\"canonical\"]',\n attribute: 'href'\n }\n});\n\n## python\n\nCode (python):\npageInfo = await page.extract({\n \"title\": \"title\",\n \"metaDescription\": 'meta[name=\"description\"]',\n \"canonicalUrl\": {\n \"_$\": 'link[rel=\"canonical\"]',\n \"attribute\": \"href\"\n }\n})\n\n## Tips for Effective Extraction\n\n1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction\n2. **Test Incrementally**: Build your extraction schema step by step, testing each part\n3. **Handle Missing Data**: Always account for elements that might not exist on the page\n4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed\n5. **Combine with Interactions**: For complex sites, interact with the page before extraction\n\n## Next Steps\n\nNow that you understand Herd's data extraction system, you can:\n\n- Create complex extraction schemas for any website\n- Transform raw data into structured, usable formats\n- Build powerful automations that collect and process web data\n\n==\n\nDocument: Getting Started\nURL: https://herd.garden/docs/getting-started\n\n# Getting Started with Herd\n\nThis guide will help you get up and running with Herd quickly to run your first trail.\n\n## What is Herd?\n\nHerd connects AI Agents to websites using your own browser credentials. It enables you to:\n\n- **Run Trails** - pre-built automations for specific websites and tasks\n- **Extract data and interact with websites** using your logged-in browser sessions\n- **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude\n\n## Quick Start\n\n### 1. Install the Browser Extension\n\n Chrome\n\n Edge\n\n Brave\n\n### 2. Register Your Browser\n\nAfter installing the extension:\n\n1. Click the Herd icon in your browser toolbar\n2. Sign in with your Herd account (or create one)\n3. Name your device and register it\n\n![Browser Registration](https://herd.garden/register-device.png)\n\n### 3. Install the Herd SDK\n\nInstall the Herd SDK using npm:\n\n## npm\n\nCode (bash):\nnpm install -g @monitoro/herd\n\n## yarn\n\nCode (bash):\nyarn global add @monitoro/herd\n\n## pnpm\n\nCode (bash):\npnpm add -g @monitoro/herd\n\n### 4. Run Your First Trail\n\nThe browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out:\n\nCode (bash):\nherd trail run @herd/browser -a markdown -p '{\"url\": \"https://example.com\"}'\n\nThat's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config:\n\nCode (json):\n{\n \"mcpServers\": {\n \"browser\": {\n \"command\": \"herd\",\n \"args\": [\n \"trail\",\n \"server\",\n \"@herd/browser\"\n ]\n }\n }\n}\n\n## For Developers\n\nYou can also automate your browser with the Herd SDK. Connect to it with your AI agents or code:\n\n## javascript\n\nCode (javascript):\n// Connect to your Herd device\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a new page and navigate\nconst page = await device.newPage();\nawait page.goto(\"https://example.com\");\n\n// Extract data using simple selectors\nconst data = await page.extract({\n title: \"h1\",\n description: \"p\",\n link: \"a\"\n});\n\nconsole.log(\"Extracted data:\", data);\n\n## python\n\nCode (python):\nfrom monitoro_herd import HerdClient\n\n# Connect to your Herd device\nclient = HerdClient(\"your-token\")\nawait client.initialize()\ndevices = await client.list_devices()\ndevice = devices[0]\n\n# Create a new page and navigate\npage = await device.new_page()\nawait page.goto(\"https://example.com\")\n\n# Extract data using simple selectors\ndata = await page.extract({\n \"title\": \"h1\",\n \"description\": \"p\",\n \"link\": \"a\"\n})\n\nprint(\"Extracted data:\", data)\n\n## What's Next?\n\nNow that you've run your first trail, you can:\n\n- [Explore available trails](/trails) - Browse pre-built trails for various websites\n- [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages\n- [Create your own trail](/docs/trails-automations) - Build and share your own custom trails\n\n## Need Help?\n\nIf you encounter any issues during setup:\n\n- Make sure your browser extension is correctly installed and you're signed in\n- Check that your device is registered in the [device dashboard](/devices)\n- Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions\n\n.browser-btn {\n display: inline-flex;\n align-items: center;\n padding: 0.2rem 1rem;\n background-color: #1f2937;\n color: white;\n border-radius: 0.375rem;\n font-size: 1.2rem;\n font-weight: 500;\n text-decoration: none;\n border: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.browser-btn:hover {\n background-color: #374151;\n}\n\n==\n\nDocument: Trails Automations\nURL: https://herd.garden/docs/trails-automations\n\n# Trails\n\nTrails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process.\n\n## javascript\n\nTrails are fully supported in the JavaScript SDK.\n\n## Creating a Trail\n\nA trail defines the following components:\n\n- **urls.ts**: Exports an array of URL definitions\n- **selectors.ts**: Exports an array of selector configurations\n- **actions.ts**: Exports action classes that implement the `TrailAction` interface\n\nA trail at the minimum has the following structure:\n\nCode:\ngoogle-search/\n urls.ts\n selectors.ts\n actions.ts\n package.json\n\nThe `package.json` file defines the trail and its dependencies:\n\nCode (json):\n{\n \"name\": \"google-search\",\n \"description\": \"Search google for webpages.\",\n \"version\": \"1.0.0\",\n \"dependencies\": {\n \"@monitoro/herd\": \"latest\"\n }\n}\n\nYou should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code.\n\n## Trail Implementation Guide\n\n### Step 1: Set up the trail structure\n\nCreate a new directory for your trail with the following files:\n\nCode:\nmy-trail/\n urls.ts\n selectors.ts\n actions.ts\n package.json\n\nAdd the basic package.json configuration:\n\nCode (json):\n{\n \"name\": \"my-trail\",\n \"version\": \"1.0.0\",\n \"dependencies\": {\n \"@monitoro/herd\": \"latest\"\n }\n}\n\n### Step 2: Define URLs\n\nIn `urls.ts`, export an array of URL definitions that your trail will interact with:\n\nCode (typescript):\nexport default [{\n \"id\": \"my-url\",\n \"template\": \"https://example.com/path?param1={param1}\u0026param2={param2}\",\n \"description\": \"Description of what this URL represents\",\n \"examples\": [\n { \"param1\": \"value1\", \"param2\": \"value2\" }\n ],\n \"params\": {\n \"param1\": {\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Description of param1\"\n },\n \"param2\": {\n \"type\": \"string\",\n \"required\": false,\n \"default\": \"defaultValue\",\n \"description\": \"Description of param2\"\n }\n }\n}];\n\n### Step 3: Define Selectors\n\nIn `selectors.ts`, export an array of selector configurations that define how to extract data from web pages:\n\nCode (typescript):\nexport default [{\n \"id\": \"my-selector\",\n \"value\": {\n \"dataKey\": {\n \"_$r\": \"#main-container\",\n \"title\": { \"_$\": \".title\" },\n \"description\": { \"_$\": \".description\" },\n \"link\": { \"_$\": \"a.link\", \"attribute\": \"href\" }\n }\n },\n \"description\": \"Selector for extracting specific data\",\n \"examples\": [\n {\n \"urlId\": \"my-url\",\n \"urlParams\": { \"param1\": \"value1\", \"param2\": \"value2\" }\n }\n ]\n}];\n\n### Step 4: Implement Actions\n\nIn `actions.ts`, define one or more action classes that implement the `TrailAction` interface:\n\nCode (typescript):\nimport type { Device, TrailAction, TrailActionManifest, TrailRunResources } from \"@monitoro/herd\";\n\nexport class MyTrailAction implements TrailAction {\n manifest: TrailActionManifest = {\n name: \"my-action\",\n description: \"Description of what this action does\",\n params: {\n param1: {\n type: \"string\",\n description: \"Description of param1\"\n },\n param2: {\n type: \"number\",\n description: \"Description of param2\",\n default: 10\n }\n },\n result: {\n type: \"array\",\n description: \"Description of the result\",\n items: {\n type: \"object\",\n properties: {\n property1: { type: \"string\" },\n property2: { type: \"number\" }\n }\n }\n },\n examples: [\n {\n \"param1\": \"value1\",\n \"param2\": 10\n }\n ]\n }\n\n async test(device: Device, params: Record, resources: TrailRunResources) {\n try {\n const result = await this.run(device, params, resources);\n // Validate result\n if (!result || result.length === 0) {\n return { status: \"error\", message: \"No results found\", result: [] };\n }\n return { status: \"success\", result };\n } catch (e) {\n return { status: \"error\", message: `Error: ${e}`, result: null };\n }\n }\n\n async run(device: Device, params: Record, resources: TrailRunResources) {\n const { param1, param2 } = params;\n const page = await device.newPage();\n \n try {\n // Navigate to URL using the URL template from urls.ts\n await page.goto(resources.url('my-url', { param1, param2 }));\n \n // Extract data using selectors from selectors.ts\n const extracted = await page.extract(resources.selector('my-selector'));\n \n // Process extracted data\n const results = (extracted as any)?.dataKey || [];\n \n // Return processed results\n return results;\n } finally {\n await page.close();\n }\n }\n}\n\n### Step 5: Testing and debugging\n\nUse the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest):\n\nCode (bash):\nherd trail test --action my-trail\n\nYou can also watch for changes in the trail and re-run tests:\n\nCode (bash):\nherd trail test --action my-trail --watch # or herd trail test -a my-trail -w\n\nAnd you can also test selectors only:\n\nCode (bash):\nherd trail test --selector my-selector\n\nAnd watch for changes in the selectors:\n\nCode (bash):\nherd trail test --selector my-selector --watch # or herd trail test -s my-selector -w\n\n### Step 6: Publish your trail\n\nPublishing is coming soon!\n\n### Best Practices\n\n1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc.\n2. **Performance**: Minimize page loads and extract as much data as possible from each page.\n3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain.\n4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios.\n5. **Versioning**: Increment your trail's version in package.json when making changes.\n\n## python\n\nTrails support for Python SDK is coming soon. Stay tuned for updates!\n\nIn the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them.\n\n==\n","llms_full":"Herd Documentation\n================================================================================\n\nDocument: Alternative Herd Vs Apify\nURL: https://herd.garden/docs/alternative-herd-vs-apify\n\n# Herd vs Apify: A Cost-Effective Alternative for Web Automation\n\nApify is a popular platform for web scraping and automation, but its cloud-based infrastructure can be costly and limiting. Herd offers a compelling alternative with similar capabilities but a fundamentally different approach that eliminates infrastructure costs and provides more control over your automation.\n\n## Quick Comparison\n\n| Feature | Herd | Apify |\n| --- | --- | --- |\n| **Primary Focus** | Browser automation \u0026 web scraping | Web scraping platform with cloud infrastructure |\n| **Infrastructure** | Uses your existing browser | Cloud-based platform with managed instances |\n| **Pricing Model** | Flat rate subscription | Usage-based pricing |\n| **Browser Control** | Direct control of your browser | Remote control of cloud browsers |\n| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome/Chromium in cloud |\n| **Setup Required** | Simple browser extension | No browser setup (cloud-based) |\n| **Authentication** | Uses existing browser sessions | Requires manual setup |\n| **Data Extraction** | Built-in extraction tools | Various actor-based extraction tools |\n| **Resource Usage** | Minimal (shared with browser) | Separate cloud resources (higher cost) |\n| **Customization** | Full control of local environment | Limited to platform capabilities |\n\n## Key Differences in Depth\n\n### Infrastructure and Pricing Model\n\n**Apify:**\n- Cloud-based platform with usage-based pricing\n- Costs scale with computation time and resource usage\n- Requires paid proxy services for many use cases\n- Monthly subscription plus usage-based fees\n\n**Herd:**\n- Uses your existing browser and computer\n- No cloud infrastructure required\n- Direct control of your local resources \n- Supports Chrome, Edge, Brave, Arc, Opera\n- No additional infrastructure costs\n- No separate compute units to pay for\n- Simple and predictable pricing\n\n### Browser Control and Authentication\n\n**Apify:**\n- Operates browsers in the cloud\n- Must manually set up authentication flows\n- Sessions are isolated and temporary\n- Limited access to browser-specific features\n\n**Herd:**\n- Direct control of your own browser\n- Uses your existing authenticated sessions\n- Persistent cookies and storage between runs\n- Full access to browser capabilities and extensions\n\n### Setup and Customization\n\n## herd\n\nCode (javascript):\n// Install the Herd SDK\nnpm install @monitoro/herd\n\n// Simple setup code\nimport { HerdClient } from '@monitoro/herd';\n\n// Connect to your own browser\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a page and automate it\nconst page = await device.newPage();\nawait page.goto('https://example.com');\n\n## apify\n\nCode (javascript):\n// Install the Apify SDK\nnpm install apify\n\n// Create an actor\nimport { Actor } from 'apify';\n\n// Run in Apify cloud environment\nawait Actor.init();\n\n// Launch a browser in the cloud\nconst browser = await Actor.launchPuppeteer();\nconst page = await browser.newPage();\nawait page.goto('https://example.com');\n\n// Must manually handle stopping the actor\nawait Actor.exit();\n\n### Data Extraction Capabilities\n\n**Apify:**\n- Offers pre-built actors for common websites\n- Large marketplace of ready-made solutions\n- Extraction limited to what actors provide\n- Can become expensive for large-scale extraction\n\n**Herd:**\n- Powerful built-in extraction API\n- Simple selector-based data retrieval\n- Access to authenticated content\n- Extract data without usage limits\n\n## Use Case Comparisons\n\n### Web Scraping with Authentication\n\n## herd-auth\n\nCode (javascript):\n// Using Herd with an already authenticated browser\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Access a site where you're already logged in\nconst page = await device.newPage();\nawait page.goto('https://account.example.com/dashboard');\n\n// Extract authenticated data directly\nconst userData = await page.extract({\n username: '.user-profile .username',\n accountType: '.account-type',\n balance: '.account-balance',\n transactions: {\n _$r: '.transaction-item',\n date: '.transaction-date',\n amount: '.transaction-amount',\n description: '.transaction-description'\n }\n});\n\nconsole.log(userData);\nawait client.close();\n\n## apify-auth\n\nCode (javascript):\n// Using Apify with manual authentication\nimport { Actor } from 'apify';\n\nawait Actor.init();\nconst browser = await Actor.launchPuppeteer();\nconst page = await browser.newPage();\n\n// Need to manually log in first\nawait page.goto('https://example.com/login');\nawait page.type('#username', 'your-username');\nawait page.type('#password', 'your-password');\nawait page.click('.login-button');\nawait page.waitForNavigation();\n\n// Now navigate to the dashboard\nawait page.goto('https://account.example.com/dashboard');\n\n// Extract data with multiple evaluations\nconst username = await page.$eval('.user-profile .username', el =\u003e el.textContent);\nconst accountType = await page.$eval('.account-type', el =\u003e el.textContent);\nconst balanceText = await page.$eval('.account-balance', el =\u003e el.textContent);\nconst balance = parseFloat(balanceText.replace(/[^0-9.-]+/g, ''));\n\n// Extract transaction data\nconst transactions = await page.$eval('.transaction-item', items =\u003e \n items.map(item =\u003e ({\n date: item.querySelector('.transaction-date').textContent,\n amount: item.querySelector('.transaction-amount').textContent,\n description: item.querySelector('.transaction-description').textContent\n }))\n);\n\nconst userData = {\n username,\n accountType,\n balance,\n transactions\n};\n\nconsole.log(userData);\nawait Actor.exit();\n\n### Multi-Page Crawling\n\n## herd-crawl\n\nCode (javascript):\n// Using Herd for multi-page crawling\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\nconst page = await device.newPage();\nawait page.goto('https://example.com/products');\n\n// Collect all product links first\nconst productLinks = await page.extract({\n links: {\n _$r: '.product-card a',\n url: { attribute: 'href' }\n }\n});\n\n// Visit each product page and extract details\nconst products = [];\nfor (const { url } of productLinks.links) {\n await page.goto(url);\n \n const productData = await page.extract({\n name: '.product-name',\n price: '.product-price',\n description: '.product-description',\n specs: {\n _$r: '.spec-item',\n name: '.spec-name',\n value: '.spec-value'\n }\n });\n \n products.push(productData);\n}\n\nconsole.log(products);\nawait client.close();\n\n## apify-crawl\n\nCode (javascript):\n// Using Apify for multi-page crawling\nimport { Actor, PuppeteerCrawler } from 'apify';\n\nawait Actor.init();\n\n// Define the crawler\nconst crawler = new PuppeteerCrawler({\n async requestHandler({ request, page }) {\n console.log(`Processing ${request.url}...`);\n \n if (request.userData.detailPage) {\n // Extract product details\n const productData = {\n url: request.url,\n name: await page.$eval('.product-name', el =\u003e el.textContent),\n price: await page.$eval('.product-price', el =\u003e el.textContent),\n description: await page.$eval('.product-description', el =\u003e el.textContent),\n specs: await page.$eval('.spec-item', items =\u003e \n items.map(item =\u003e ({\n name: item.querySelector('.spec-name').textContent,\n value: item.querySelector('.spec-value').textContent\n }))\n )\n };\n \n // Save the extracted data\n await Actor.pushData(productData);\n } else {\n // On the listing page, extract links to products\n const productLinks = await page.$eval('.product-card a', links =\u003e \n links.map(link =\u003e link.href)\n );\n \n // Enqueue product detail pages\n for (const url of productLinks) {\n await crawler.requestQueue.addRequest({\n url,\n userData: { detailPage: true }\n });\n }\n }\n },\n maxRequestsPerCrawl: 100,\n});\n\n// Start with the product listing page\nawait crawler.run(['https://example.com/products']);\n\nawait Actor.exit();\n\n## Migration Guide: From Apify to Herd\n\nTransitioning from Apify to Herd is straightforward. Here's a guide to help you migrate:\n\n### 1. Installation\n\n1. Install the Herd SDK:\n \nCode (bash):\n npm install @monitoro/herd\n\n2. Install the Herd browser extension in your preferred browser\n\n3. Register your browser as a device in the Herd dashboard\n\n### 2. Code Migration\n\n| Apify | Herd | Notes |\n| --- | --- | --- |\n| `Actor.init()` | `const client = new HerdClient(apiUrl, token)` `await client.initialize()` | Herd uses a simple client-server model |\n| `Actor.launchPuppeteer()` | `const devices = await client.listDevices()` `const device = devices[0]` | Herd connects to your existing browser |\n| `browser.newPage()` | `await device.newPage()` | Similar API |\n| `page.goto(url)` | `await page.goto(url)` | Identical usage |\n| `page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd has a more powerful extraction API |\n| `Actor.pushData(data)` | Store data directly in your code | No platform-specific storage |\n| `Actor.exit()` | `await client.close()` | Herd just disconnects, browser stays open |\n\n### 3. Handling Authentication\n\n**Apify:**\n\nCode (javascript):\n// Manual login process\nawait page.goto('https://example.com/login');\nawait page.type('#username', 'user');\nawait page.type('#password', 'pass');\nawait page.click('#login-button');\n\n**Herd:**\n\nCode (javascript):\n// Simply use your already authenticated browser\nawait page.goto('https://example.com/dashboard'); // Already logged in\n\n## Why Choose Herd Over Apify?\n\n### 1. Cost Efficiency\n\nHerd eliminates the need for cloud infrastructure, resulting in:\n- No usage-based computation costs\n- No proxy costs for most use cases\n- Significant cost savings for regular automation\n- Predictable pricing independent of usage volume\n\n### 2. Use Existing Authentication\n\nWith Herd, you can automate tasks in your already authenticated browser:\n- No need to handle authentication flows in code\n- Access to sites with complex auth (2FA, CAPTCHA)\n- Use existing cookies, local storage, and sessions\n\n### 3. Local Control and Privacy\n\nHerd provides:\n- Full control over the automation environment\n- Higher privacy (data stays on your machine)\n- Direct access to local resources when needed\n- No dependence on third-party cloud infrastructure\n\n### 4. Simpler Development Experience\n\nHerd offers:\n- More intuitive APIs for common tasks\n- Real-time debugging in your browser\n- No need to deploy or manage cloud resources\n- Faster iteration during development\n\n## Get Started with Herd Today\n\nReady to try a more flexible alternative to Apify? Get started with Herd:\n\n1. [Create a Herd account](/register)\n2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)\n3. [Connect your browser](/docs/connect-your-browser)\n4. [Run your first automation](/docs/automation-basics)\n\nDiscover how Herd can provide all the capabilities you need for web automation and scraping at a fraction of the cost of cloud-based solutions like Apify.\n\n================================================================================\n\nDocument: Alternative Herd Vs Browserbase\nURL: https://herd.garden/docs/alternative-herd-vs-browserbase\n\n# Herd vs Browserbase: No-Infrastructure Browser Automation\n\nBrowserbase provides cloud-based headless browsers for automation and AI applications. While it offers a reliable platform for running browser instances, Herd takes a fundamentally different approach by leveraging your existing browsers, eliminating infrastructure costs and complexity.\n\n## Quick Comparison\n\n| Feature | Herd | Browserbase |\n| --- | --- | --- |\n| **Browser Location** | Your local machine | Cloud-based infrastructure |\n| **Infrastructure Needed** | None (uses your browser) | Managed cloud infrastructure |\n| **Pricing Model** | Flat subscription | Usage-based pricing |\n| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium in cloud |\n| **Latency** | Minimal (1-hop) | Higher (multiple hops) |\n| **Authentication** | Uses existing browser sessions | Requires manual setup |\n| **Framework Support** | JavaScript/Python SDKs | Stagehand, Playwright, Puppeteer, Selenium |\n| **Setup Required** | Browser extension installation | No installation (cloud-based) |\n| **Resource Constraints** | Depends on local resources | Limited by pricing tier |\n\n## Key Differences in Depth\n\n### Infrastructure and Cost Model\n\n**Browserbase:**\n- Runs browsers on managed cloud infrastructure\n- Costs scale with usage and session duration\n- Requires networking between your code and cloud\n- Additional costs for premium features like proxies\n\n**Herd:**\n- Uses browsers already installed on your machine\n- No cloud infrastructure required\n- Direct access to your local machine resources\n- Supports Chrome, Edge, Brave, Arc, Opera\n- Fixed, predictable pricing not tied to usage\n- Local execution with minimal network overhead\n- No additional infrastructure costs to manage\n\n### Setup and Integration\n\n## herd\n\nCode (javascript):\n// Simple installation - no code required\n// 1. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox/Safari not supported)\n// 2. Connect your browser to Herd\n\n// Simple connection to your browser\nimport { HerdClient } from '@monitoro/herd';\n\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a new page\nconst page = await device.newPage();\nawait page.goto('https://example.com');\n\n## browserbase\n\nCode (javascript):\n// Install the SDK\nnpm install browserbase\n\n// Connect to cloud infrastructure\nimport { Browserbase } from 'browserbase';\n\nconst bb = new Browserbase({\n api_key: 'your-api-key'\n});\n\n// Create a session on cloud infrastructure\nconst session = await bb.sessions.create({\n timeout: 60, // Session timeout in seconds\n});\n\n// Create a page in the cloud browser\nconst page = await session.newPage();\nawait page.goto('https://example.com');\n\n### Session Management and Performance\n\n**Browserbase:**\n- Cloud-based sessions with timeout limits\n- Performance dependent on cloud resources and network\n- Sessions isolated from local environment\n- Must explicitly manage session lifecycle\n\n**Herd:**\n- Direct access to local browser sessions\n- Local performance without network latency\n- Integrated with your local environment\n- Sessions persist with your browser\n\n### Authentication and User Context\n\n**Browserbase:**\n- Requires implementing authentication for each session\n- Isolated sessions without access to existing cookies\n- Must manually handle login flows\n- Credentials need to be stored and managed\n\n**Herd:**\n- Uses your browser's existing authenticated sessions\n- Access to all cookies, local storage, and session data\n- No need to implement authentication flows\n- Use sites you're already logged into\n\n## Use Case Comparisons\n\n### Web Automation for Logged-in Services\n\n## herd-auth\n\nCode (javascript):\n// Using Herd with pre-authenticated browser\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Directly access authenticated service\nconst page = await device.newPage();\nawait page.goto('https://app.example.com/dashboard'); // Already logged in\n\n// Perform actions on authenticated page\nawait page.click('.create-new-button');\nawait page.type('#item-name', 'New Item');\nawait page.click('.save-button');\n\n// Verify result\nconst confirmationText = await page.$eval('.confirmation', el =\u003e el.textContent);\nconsole.log(confirmationText);\n\n## browserbase-auth\n\nCode (javascript):\n// Using Browserbase with manual authentication\nconst bb = new Browserbase({\n api_key: 'your-api-key'\n});\n\n// Create cloud browser session\nconst session = await bb.sessions.create({\n timeout: 300, // Longer timeout for auth flow\n});\n\n// Create page and handle login manually\nconst page = await session.newPage();\n\n// Navigate to login page\nawait page.goto('https://app.example.com/login');\n\n// Fill login form\nawait page.type('#email', 'user@example.com');\nawait page.type('#password', 'your-secure-password');\nawait page.click('#login-button');\n\n// Wait for login to complete\nawait page.waitForNavigation();\n\n// Now navigate to dashboard\nawait page.goto('https://app.example.com/dashboard');\n\n// Perform actions on authenticated page\nawait page.click('.create-new-button');\nawait page.type('#item-name', 'New Item');\nawait page.click('.save-button');\n\n// Verify result\nconst confirmationText = await page.$eval('.confirmation', el =\u003e el.textContent);\nconsole.log(confirmationText);\n\n// Must explicitly end session\nawait session.close();\n\n### Data Extraction at Scale\n\n## herd-extract\n\nCode (javascript):\n// Using Herd for data extraction\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Open multiple pages for parallel extraction\nconst pages = await Promise.all([1, 2, 3].map(() =\u003e device.newPage()));\n\n// Extract data from multiple sources in parallel\nconst results = await Promise.all(pages.map(async (page, index) =\u003e {\n await page.goto(`https://example.com/category/${index+1}`);\n \n // Use Herd's extraction API\n const data = await page.extract({\n categoryName: '.category-header h1',\n items: {\n _$r: '.product-item',\n title: '.product-title',\n price: '.product-price',\n rating: '.rating-value'\n }\n });\n \n return data;\n}));\n\n// Close pages when done\nawait Promise.all(pages.map(page =\u003e page.close()));\nawait client.close();\n\nconsole.log(results);\n\n## browserbase-extract\n\nCode (javascript):\n// Using Browserbase for data extraction\nconst bb = new Browserbase({\n api_key: 'your-api-key'\n});\n\n// Create separate sessions for parallel extraction\nconst sessions = await Promise.all([1, 2, 3].map(() =\u003e \n bb.sessions.create({ timeout: 120 })\n));\n\n// Extract data from multiple sources\nconst results = await Promise.all(sessions.map(async (session, index) =\u003e {\n const page = await session.newPage();\n await page.goto(`https://example.com/category/${index+1}`);\n \n // Extract data using Puppeteer-style selectors\n const categoryName = await page.$eval('.category-header h1', el =\u003e el.textContent);\n \n const itemElements = await page.$('.product-item');\n const items = [];\n \n for (const element of itemElements) {\n const title = await element.$eval('.product-title', el =\u003e el.textContent);\n const price = await element.$eval('.product-price', el =\u003e el.textContent);\n \n let rating = null;\n try {\n rating = await element.$eval('.rating-value', el =\u003e el.textContent);\n } catch (e) {\n // Element might not exist\n }\n \n items.push({ title, price, rating });\n }\n \n // Must close session when done\n await session.close();\n \n return { categoryName, items };\n}));\n\nconsole.log(results);\n\n## Migration Guide: From Browserbase to Herd\n\nTransitioning from Browserbase to Herd is straightforward. Here's a guide to help you migrate:\n\n### Installation Steps\n\n1. [Sign up for a Herd account](/register)\n2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)\n3. Register your browser as a device in the Herd dashboard\n\n### 2. Code Migration\n\n| Browserbase | Herd | Notes |\n| --- | --- | --- |\n| `new Browserbase({ api_key })` | `new HerdClient(apiUrl, token)` `await client.initialize()` | Herd uses a client-server architecture |\n| `bb.sessions.create()` | `const devices = await client.listDevices()` `const device = devices[0]` | Herd connects to your existing browser |\n| `session.newPage()` | `await device.newPage()` | Similar API |\n| `await page.goto(url)` | `await page.goto(url)` | Identical usage |\n| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |\n| `await page.click(selector)` | `await page.click(selector)` | Identical usage |\n| `await page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd offers a more powerful extraction API |\n| `await session.close()` | `await client.close()` | Herd just disconnects, browser stays open |\n\n### 3. Framework Integration\n\n**Browserbase:**\n\nCode (javascript):\n// Browserbase with Playwright\nconst { chromium } = require('playwright');\nconst browser = await chromium.connectOverCDP(session.wsEndpoint);\nconst page = await browser.newPage();\n\n**Herd:**\n\nCode (javascript):\n// Herd uses its own API directly\nconst page = await device.newPage();\n// Direct integrations with testing frameworks available\n\n## Why Choose Herd Over Browserbase?\n\n### 1. No Cloud Infrastructure Required\n\nHerd eliminates the need for cloud infrastructure, providing:\n- Zero dependency on remote browser instances\n- No need to manage cloud resources\n- Reduced latency with local execution\n- Complete isolation from cloud service disruptions\n\n### 2. Cost Predictability and Efficiency\n\nHerd offers a more predictable and often lower cost:\n- No usage-based billing surprises\n- No charges based on session duration\n- No additional costs for scaling automation\n- Fixed costs regardless of automation volume\n\n### 3. Use Existing Browser State and Auth\n\nWith Herd, you can leverage your browser's existing state:\n- Use sites you're already logged into\n- Access to all browser extensions\n- Utilize stored passwords and authentication\n- No need to manage credentials in code\n\n### 4. Lower Latency and Higher Performance\n\nHerd provides performance advantages with local execution:\n- No network latency between code and browser\n- Faster execution of automation tasks\n- Direct access to local resources\n- No timeout limitations on sessions\n\n## Get Started with Herd Today\n\nReady to try a more flexible alternative to Browserbase? Get started with Herd:\n\n1. [Create a Herd account](/register)\n2. [Install the browser extension](/docs/installation)\n3. [Connect your browser](/docs/connect-your-browser)\n4. [Run your first automation](/docs/automation-basics)\n\nDiscover how Herd can provide all the capabilities you need for web automation without the complexity and costs of cloud-based infrastructure.\n\n================================================================================\n\nDocument: Alternative Herd Vs Firecrawl\nURL: https://herd.garden/docs/alternative-herd-vs-firecrawl\n\n# Herd vs Firecrawl: Flexible Browser Automation and Data Extraction\n\nFirecrawl is a specialized web scraping and crawling tool designed primarily for extracting and cleaning web content, especially for use with LLMs. While Firecrawl offers powerful crawling capabilities, Herd provides a more comprehensive browser automation solution with greater flexibility and control over the browsing experience.\n\n## Quick Comparison\n\n| Feature | Herd | Firecrawl |\n| --- | --- | --- |\n| **Primary Focus** | Complete browser automation | Web crawling and content extraction |\n| **Infrastructure** | Uses your existing browser | Cloud-based crawling infrastructure |\n| **Pricing Model** | Flat subscription | Usage-based pricing |\n| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Managed cloud browsers |\n| **Browser Control** | Full interactive browser control | Limited to crawling and extraction |\n| **Authentication** | Uses existing browser sessions | Limited authentication capabilities |\n| **Content Processing** | Raw and structured data extraction | Optimized for clean text/markdown output |\n| **Usage Flexibility** | General-purpose automation | Specialized for content crawling |\n| **Interactive Workflows** | Supports complex interactions | Limited to extraction patterns |\n\n## Key Differences in Depth\n\n### Primary Focus and Capabilities\n\n**Firecrawl:**\n- Specialized in high-quality web content extraction\n- Optimized for converting websites to clean markdown\n- Focused on crawling through website links\n- Built primarily for LLM data ingestion\n- Limited interactive capabilities\n\n**Herd:**\n- Complete browser automation platform\n- Full interactive control of browser actions\n- Supports Chrome, Edge, Brave, Arc, Opera\n- Supports both data extraction and automation workflows\n- General-purpose browser control\n- Rich interaction with web applications\n\n### Infrastructure and Execution Model\n\n## herd\n\nCode (javascript):\n// Install the Herd SDK\nnpm install @monitoro/herd\n\n// Connect to your existing browser\nimport { HerdClient } from '@monitoro/herd';\n\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Full browser automation capabilities\nconst page = await device.newPage();\nawait page.goto('https://example.com');\n\n## firecrawl\n\nCode (javascript):\n// Install the Firecrawl SDK\nnpm install @mendable/firecrawl-js\n\n// Connect to Firecrawl's cloud service\nimport FirecrawlApp from '@mendable/firecrawl-js';\n\nconst app = new FirecrawlApp({ apiKey: \"fc-YOUR_API_KEY\" });\n\n// Send request to cloud-based crawling service\nconst result = await app.scrapeUrl('example.com');\nconsole.log(result.markdown);\n\n### Data Extraction Approaches\n\n**Firecrawl:**\n- Specializes in converting HTML to clean markdown\n- Automatically handles JavaScript rendering\n- Built-in content cleaning and formatting\n- Output optimized for LLM consumption\n- Limited customization of extraction patterns\n\n**Herd:**\n- Flexible data extraction patterns\n- CSS selector-based extraction\n- Support for complex nested data structures\n- Raw data access and custom transformations\n- Complete control over extraction logic\n\n## Use Case Comparisons\n\n### Website Content Extraction\n\n## herd-extract\n\nCode (javascript):\n// Using Herd for content extraction\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\nconst page = await device.newPage();\nawait page.goto('https://example.com/article');\n\n// Extract structured content with control over the format\nconst articleData = await page.extract({\n title: '.article-title',\n author: '.author-name',\n published: {\n _$: '.publish-date',\n pipes: ['parseDate']\n },\n content: '.article-body',\n tags: {\n _$r: '.tag',\n text: ':root'\n }\n});\n\nconsole.log(articleData);\nawait client.close();\n\n## firecrawl-extract\n\nCode (javascript):\n// Using Firecrawl for content extraction\nimport FirecrawlApp from '@mendable/firecrawl-js';\n\nconst app = new FirecrawlApp({ apiKey: \"fc-YOUR_API_KEY\" });\n\n// Simple URL-based extraction\nconst scrapeResult = await app.scrapeUrl('https://example.com/article');\n\nif (scrapeResult.success) {\n // Get the clean markdown content\n console.log(scrapeResult.markdown);\n \n // Access metadata\n console.log(scrapeResult.metadata);\n} else {\n console.error('Failed to scrape:', scrapeResult.error);\n}\n\n### Interactive Web Automation\n\n## herd-automation\n\nCode (javascript):\n// Using Herd for interactive web automation\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\nconst page = await device.newPage();\n\n// Navigate to a web application\nawait page.goto('https://app.example.com/dashboard');\n\n// Fill out a form\nawait page.click('.create-new-button');\nawait page.type('#title-input', 'New Project');\nawait page.type('#description-input', 'This is a test project created by automation');\nawait page.select('#category-select', 'development');\n\n// Upload a file\nconst fileInput = await page.$('input[type=\"file\"]');\nawait fileInput.uploadFile('/path/to/local/file.pdf');\n\n// Submit the form\nawait page.click('.submit-button');\n\n// Wait for confirmation and extract result\nawait page.waitForSelector('.success-message');\nconst confirmationText = await page.$eval('.success-message', el =\u003e el.textContent);\nconsole.log('Form submitted successfully:', confirmationText);\n\nawait client.close();\n\n## firecrawl-automation\n\nCode (javascript):\n// Firecrawl has limited interactive capabilities\nimport FirecrawlApp from '@mendable/firecrawl-js';\n\nconst app = new FirecrawlApp({ apiKey: \"fc-YOUR_API_KEY\" });\n\n// For interactive tasks like form submission, \n// Firecrawl has limited capabilities, primarily focused\n// on crawling and content extraction.\n\n// You could use the actions feature for limited interactions:\nconst result = await app.scrapeUrl('https://app.example.com', {\n actions: [\n { type: 'click', selector: '.login-button' },\n { type: 'wait', time: 2000 }\n // Limited set of basic actions available\n ]\n});\n\n// But complex workflows like file uploads or \n// multi-step interactions require a more \n// comprehensive automation tool like Herd\n\n### Multi-Page Crawling\n\n## herd-crawl\n\nCode (javascript):\n// Using Herd for custom crawling\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\nconst page = await device.newPage();\nawait page.goto('https://example.com/products');\n\n// Extract all product links\nconst productLinks = await page.extract({\n links: {\n _$r: '.product-card a',\n url: { attribute: 'href' }\n }\n});\n\n// Custom crawling logic with full control\nconst productDetails = [];\nfor (const { url } of productLinks.links) {\n // Navigate to each product page\n await page.goto(url);\n \n // Extract detailed information\n const product = await page.extract({\n name: '.product-name',\n price: '.product-price',\n description: '.product-description',\n inStock: '.stock-status'\n });\n \n productDetails.push(product);\n \n // You can implement custom logic: only continue if conditions are met\n if (productDetails.length \u003e= 10) break;\n}\n\nconsole.log(productDetails);\nawait client.close();\n\n## firecrawl-crawl\n\nCode (javascript):\n// Using Firecrawl for website crawling\nimport FirecrawlApp from '@mendable/firecrawl-js';\n\nconst app = new FirecrawlApp({ apiKey: \"fc-YOUR_API_KEY\" });\n\n// Crawl an entire site\nconst crawlResult = await app.crawlWebsite('example.com', {\n maxPages: 10, // Limit the crawl\n includeSitemap: true, // Use sitemap if available\n followExternalLinks: false // Stay on the same domain\n});\n\nif (crawlResult.success) {\n // Access all crawled pages\n for (const page of crawlResult.pages) {\n console.log(`Page: ${page.url}`);\n console.log(`Content: ${page.markdown}`);\n }\n} else {\n console.error('Crawl failed:', crawlResult.error);\n}\n\n## Migration Guide: From Firecrawl to Herd\n\nTransitioning from Firecrawl to Herd is straightforward. Here's a guide to help you migrate:\n\n### Installation Steps\n\n1. [Sign up for a Herd account](/register)\n2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)\n3. Register your browser as a device in the Herd dashboard\n\n### 2. Code Migration\n\n| Firecrawl | Herd | Notes |\n| --- | --- | --- |\n| `new FirecrawlApp({ apiKey })` | `new HerdClient(apiUrl, token)` `await client.initialize()` `const devices = await client.listDevices()` `const device = devices[0]` | Herd connects to your existing browser |\n| `app.scrapeUrl(url)` | `const page = await device.newPage()` `await page.goto(url)` `const data = await page.extract(...)` | More granular control in Herd |\n| `result.markdown` | Custom extraction patterns with formatting | More flexible data extraction options |\n| `app.crawlWebsite(domain)` | Custom crawling logic implemented with Herd's navigation and extraction APIs | Full control over crawling behavior |\n\n### 3. Implementing Markdown Conversion\n\nIf you specifically need markdown output like Firecrawl provides:\n\nCode (javascript):\n// Helper function to convert extracted HTML to markdown\nfunction htmlToMarkdown(html) {\n // Use a library like turndown\n const turndownService = new TurndownService();\n return turndownService.turndown(html);\n}\n\n// Extract with Herd and convert to markdown\nconst content = await page.extract({\n body: {\n _$: '.article-content',\n attribute: 'innerHTML'\n }\n});\n\n## Why Choose Herd Over Firecrawl?\n\n### 1. Comprehensive Browser Control\n\nHerd provides full browser automation capabilities:\n- Complete interactive control beyond just crawling\n- Support for complex user interactions\n- Ability to automate any browser-based workflow\n- Full access to browser APIs and capabilities\n\n### 2. Flexible Authentication and Sessions\n\nHerd's approach offers significant authentication advantages:\n- Use your existing authenticated browser sessions\n- No need to implement login flows\n- Support for complex authentication scenarios\n- Access to secure content without credential management\n\n### 3. Customizable Extraction and Processing\n\nHerd gives you complete control over data extraction:\n- Custom extraction patterns for any website structure\n- Flexible transformation of extracted data\n- Support for complex nested data extraction\n- Processing options beyond just markdown conversion\n\n### 4. Broader Use Case Support\n\nHerd supports a wider range of automation scenarios:\n- Form submission and interactive workflows\n- File uploads and downloads\n- Conditional logic based on page content\n- Testing and verification workflows\n\n## Get Started with Herd Today\n\nReady to try a more flexible alternative to Firecrawl? Get started with Herd:\n\n1. [Create a Herd account](/register)\n2. [Install the browser extension](/docs/installation)\n3. [Connect your browser](/docs/connect-your-browser)\n4. [Run your first automation](/docs/automation-basics)\n\nDiscover how Herd can provide enhanced capabilities for both content extraction and browser automation, giving you more control and flexibility than specialized crawling tools like Firecrawl.\n\n================================================================================\n\nDocument: Alternative Herd Vs Mcp Sdk\nURL: https://herd.garden/docs/alternative-herd-vs-mcp-sdk\n\n# Herd vs MCP SDK: Streamlined Browser Automation\n\nThe Model Context Protocol (MCP) SDK provides browser automation capabilities primarily focused on AI agent integration. While MCP SDK offers powerful integration with Large Language Models, Herd provides a more accessible and straightforward approach to browser automation with simplified setup and direct browser control.\n\n## Quick Comparison\n\n| Feature | Herd | MCP SDK |\n| --- | --- | --- |\n| **Primary Focus** | General browser automation | AI agent browser automation |\n| **Infrastructure** | Uses your existing browser | Requires separate browser setup |\n| **API Design** | Simple, direct browser control | Protocol-oriented architecture |\n| **Integration** | JavaScript/Python SDKs | Multiple languages supported |\n| **Setup Complexity** | Simple browser extension | More complex server configuration |\n| **Authentication** | Uses existing browser sessions | Requires manual configuration |\n| **Learning Curve** | Shallow, familiar browser API | Steeper with protocol concepts |\n| **Use Cases** | General automation and extraction | AI agent browsing tasks |\n\n## Key Differences in Depth\n\n### Focus and Architecture\n\n**MCP SDK:**\n- Designed primarily for AI model integration\n- Protocol-based communication model\n- Server-client architecture\n- Focus on enabling AI agents to browse\n- More complex protocol implementation\n\n**Herd:**\n- Direct browser automation focus\n- Simple client-browser connection\n- Intuitive API design\n- Supports Chrome, Edge, Brave, Arc, Opera\n- Streamlined API for common tasks\n- Designed for developers first\n- Lower implementation complexity\n\n### Setup and Integration\n\n## herd\n\nCode (javascript):\n// Install the Herd SDK\nnpm install @monitoro/herd\n\n// Simple direct connection to your browser\nimport { HerdClient } from '@monitoro/herd';\n\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a page and automate it\nconst page = await device.newPage();\nawait page.goto('https://example.com');\n\n## mcp\n\nCode (javascript):\n// Install MCP SDK\nnpm install mcp-browser-automation\n\n// Set up the MCP server\nconst { MCPServer } = require('mcp-browser-automation');\nconst server = new MCPServer({\n port: 8000,\n // Additional configuration for the server\n});\n\n// Start the server\nawait server.start();\n\n// Client side needs to implement MCP protocol\n// to communicate with the server\n\n// Then through MCP protocol interactions:\n// 1. Create a browser session\n// 2. Navigate to URL\n// 3. Interact with page\n\n### Integration with AI Systems\n\n**MCP SDK:**\n- Designed specifically for AI model integration\n- Protocol-based approach for AI agents\n- Built to enable AI systems to browse the web\n- Complex implementation for general use cases\n- Strong focus on AI agent capabilities\n\n**Herd:**\n- General-purpose browser automation\n- Can be integrated with AI systems through standard APIs\n- Simpler implementation for most use cases\n- Direct browser control paradigm\n- Focus on developer experience and simplicity\n\n## Use Case Comparisons\n\n### Basic Web Automation\n\n## herd-auto\n\nCode (javascript):\n// Using Herd for basic web automation\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a new page\nconst page = await device.newPage();\n\n// Navigate to a website\nawait page.goto('https://example.com/login');\n\n// Fill login form\nawait page.type('#username', 'test_user');\nawait page.type('#password', 'password123');\nawait page.click('.login-button');\n\n// Wait for navigation and verify login\nawait page.waitForSelector('.dashboard');\nconst welcomeText = await page.$eval('.welcome-message', el =\u003e el.textContent);\nconsole.log('Login successful:', welcomeText);\n\nawait client.close();\n\n## mcp-auto\n\nCode (javascript):\n// Using MCP SDK for basic web automation\n// First, set up and start the MCP server\nconst { MCPServer } = require('mcp-browser-automation');\nconst server = new MCPServer({ port: 8000 });\nawait server.start();\n\n// For client-side interaction, implement the MCP protocol\n// This is a simplified example showing the concept\nconst response = await fetch('http://localhost:8000/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'createSession',\n params: {}\n })\n});\nconst { sessionId } = await response.json();\n\n// Navigate to a website\nawait fetch('http://localhost:8000/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'navigate',\n sessionId,\n params: { url: 'https://example.com/login' }\n })\n});\n\n// Fill login form (multiple requests needed)\nawait fetch('http://localhost:8000/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'type',\n sessionId,\n params: { selector: '#username', text: 'test_user' }\n })\n});\n\n// Additional requests for password and clicking login button\n// ...\n\n// MCP SDK is more verbose for simple automation tasks\n// and requires protocol knowledge\n\n### Data Extraction Tasks\n\n## herd-extract\n\nCode (javascript):\n// Using Herd for data extraction\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\nconst page = await device.newPage();\nawait page.goto('https://example.com/products');\n\n// Extract data using Herd's powerful extraction API\nconst productData = await page.extract({\n title: '.page-title',\n products: {\n _$r: '.product-item', // Repeat for all products\n name: '.product-name',\n price: '.product-price',\n rating: '.rating-stars',\n available: '.stock-status'\n }\n});\n\nconsole.log(productData);\nawait client.close();\n\n## mcp-extract\n\nCode (javascript):\n// Using MCP SDK for data extraction\n// First, set up and start the MCP server\nconst { MCPServer } = require('mcp-browser-automation');\nconst server = new MCPServer({ port: 8000 });\nawait server.start();\n\n// For client-side extraction, implement the MCP protocol\n// This is a simplified example showing the concept\nconst response = await fetch('http://localhost:8000/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'createSession',\n params: {}\n })\n});\nconst { sessionId } = await response.json();\n\n// Navigate to the products page\nawait fetch('http://localhost:8000/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'navigate',\n sessionId,\n params: { url: 'https://example.com/products' }\n })\n});\n\n// Extract the page title\nconst titleResponse = await fetch('http://localhost:8000/mcp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'evaluate',\n sessionId,\n params: { \n script: \"document.querySelector('.page-title').textContent\" \n }\n })\n});\nconst { result: title } = await titleResponse.json();\n\n// Extract product data would require more complex script execution\n// or multiple requests to get all the product information\n// ...\n\n// MCP SDK requires more complex orchestration for data extraction\n// compared to Herd's simplified extraction API\n\n### AI Integration\n\n## herd-ai\n\nCode (javascript):\n// Using Herd with AI integration\n// First, set up Herd client as usual\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a function to handle AI requests for web content\nasync function fetchWebContentForAI(url, query) {\n const page = await device.newPage();\n await page.goto(url);\n \n // Extract relevant content based on the AI query\n const content = await page.extract({\n title: 'h1',\n mainContent: '.main-content',\n relevantSections: {\n _$r: '.content-section',\n heading: 'h2',\n text: 'p'\n }\n });\n \n // Close the page when done\n await page.close();\n \n // Return the content for AI processing\n return content;\n}\n\n// Example usage with an AI system\nconst aiPrompt = \"Summarize the information about machine learning from example.com\";\nconst url = \"https://example.com/machine-learning\";\n\n// Get the content for the AI\nconst webContent = await fetchWebContentForAI(url, \"machine learning\");\n\n// Feed the content to the AI system\nconst aiResponse = await callAISystem(aiPrompt, webContent);\nconsole.log(aiResponse);\n\nawait client.close();\n\n// This pattern keeps the AI integration simple and separate from\n// the browser automation concerns\n\n## mcp-ai\n\nCode (javascript):\n// Using MCP SDK with AI integration\n// MCP is specifically designed for this use case\n\n// First, set up and start the MCP server\nconst { MCPServer } = require('mcp-browser-automation');\nconst server = new MCPServer({ port: 8000 });\nawait server.start();\n\n// This server can now be used by AI agents through the MCP protocol\nconsole.log('MCP Browser Automation server is running on port 8000');\n\n// When an AI system wants to browse, it would send requests like:\n/*\n{\n \"action\": \"createSession\",\n \"params\": {}\n}\n*/\n\n// And receive responses like:\n/*\n{\n \"sessionId\": \"session123\",\n \"status\": \"success\"\n}\n*/\n\n// The AI can then navigate, interact with pages, and extract content\n// through the MCP protocol\n\n// This architecture is optimized for AI systems that implement\n// the MCP protocol, but requires more complex integration\n// than direct SDK usage like Herd offers\n\n## Migration Guide: From MCP SDK to Herd\n\nTransitioning from MCP SDK to Herd simplifies your browser automation code. Here's a migration guide:\n\n### Installation Steps\n\n1. [Sign up for a Herd account](/register)\n2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)\n3. Register your browser as a device in the Herd dashboard\n\n### 2. Code Migration\n\n| MCP SDK | Herd | Notes |\n| --- | --- | --- |\n| MCP server setup | `new HerdClient(apiUrl, token)` `await client.initialize()` | No server needed with Herd |\n| Session creation via protocol | `const devices = await client.listDevices()` `const device = devices[0]` | Simplified session management |\n| Navigation requests | `const page = await device.newPage()` `await page.goto(url)` | Direct browser control |\n| Element interactions via protocol | `await page.click(selector)` `await page.type(selector, text)` | Simpler interaction API |\n| Data extraction with custom scripts | `await page.extract(selectors)` | Powerful extraction API |\n| Session closing via protocol | `await client.close()` | Simple cleanup |\n\n### 3. AI Integration Approach\n\n**MCP SDK:**\n\nCode (javascript):\n// AI systems implement MCP protocol directly\n// Complex integration but designed for AI\n\n// AI system would send requests like:\nconst request = {\n action: \"evaluateElement\",\n params: { selector: \".content\", attribute: \"textContent\" }\n};\n// And process responses\n\n**Herd:**\n\nCode (javascript):\n// Build an adapter layer for AI integration\nasync function getWebContent(url, aiQuery) {\n // Use Herd to fetch and extract the content\n const page = await device.newPage();\n await page.goto(url);\n const content = await page.extract({ /* ... */ });\n await page.close();\n return content;\n}\n\n// Then use this in your AI system\nconst content = await getWebContent(url, query);\nconst aiResponse = await yourAISystem.process(content);\n\n### 4. Simpler Setup\n\nHerd simplifies your automation workflow:\n\n- No need to run a server process\n- Uses your existing browser\n- Simple browser extension rather than complex setup\n- Supports Chrome, Edge, Brave, Arc, Opera\n- Works with browsers you're already using every day\n\n## Why Choose Herd Over MCP SDK?\n\n### 1. Simpler Developer Experience\n\nHerd provides a more straightforward approach to browser automation:\n- No complex protocol implementation\n- Direct browser control API\n- Familiar programming model\n- Lower learning curve\n\n### 2. Less Infrastructure to Manage\n\nHerd eliminates the need for additional infrastructure:\n- No server to set up and maintain\n- Uses your existing browser\n- Simpler deployment architecture\n- Fewer moving parts\n\n### 3. Powerful Built-in Capabilities\n\nHerd includes powerful features out of the box:\n- Sophisticated data extraction API\n- Session and cookie management\n- Authentication handling\n- Browser state persistence\n\n### 4. Broader Applicability\n\nWhile MCP SDK focuses on AI integration, Herd supports:\n- General browser automation\n- Web scraping and data extraction\n- Testing and monitoring\n- Process automation\n\n## Get Started with Herd\n\nReady to try a more straightforward alternative to MCP SDK? Get started with Herd:\n\n1. [Create a Herd account](/register)\n2. [Install the browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)\n3. [Connect your browser](/docs/connect-your-browser)\n4. [Run your first automation](/docs/automation-basics)\n\nDiscover how Herd can simplify your browser automation tasks with its intuitive API and direct browser control, providing a more accessible alternative to protocol-based approaches like MCP SDK.\n\n================================================================================\n\nDocument: Alternative Herd Vs Monitoro\nURL: https://herd.garden/docs/alternative-herd-vs-monitoro\n\n# Herd vs Monitoro: Complementary Browser Tools\n\nHerd and Monitoro are sister products created by the same team, designed to serve complementary but distinct purposes. While Herd provides programmatic browser control and multi-browser orchestration capabilities, Monitoro focuses on no-code monitoring and data extraction. Understanding their differences helps you choose the right tool for your specific needs.\n\n## Quick Comparison\n\n| Feature | Herd | Monitoro |\n| --- | --- | --- |\n| **Primary Focus** | Browser automation \u0026 orchestration | Website monitoring \u0026 data extraction |\n| **Core Function** | Programmatic browser control | Monitoring webpages for changes |\n| **Target User** | Developers \u0026 automation teams | Non-technical users \u0026 business teams |\n| **Coding Required** | Yes (JavaScript/Python) | No (visual interface) |\n| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Edge, Brave |\n| **Browser Orchestration** | Multiple browsers and devices | Single-focus monitoring |\n| **Implementation** | JavaScript/Python SDK | No-code browser extension |\n| **Data Processing** | Programmatic data workflows | Automated alerts and integrations |\n| **Best For** | Complex automation needs | Monitoring \u0026 simple data extraction |\n\n## Understanding the Difference\n\n### Herd\n\nHerd is designed for **programmatic browser control and orchestration**, allowing developers to:\n- Automate complex web tasks across multiple browsers\n- Extract data from websites at scale\n- Leverage their existing browsers for automation\n- Build persistent automation workflows\n- Orchestrate multiple browser instances simultaneously\n- Create sophisticated data processing pipelines\n- Works with Chrome, Edge, Brave, Arc, Opera\n\n### Monitoro\n\nMonitoro is designed for **no-code webpage monitoring and alerts**, allowing anyone to:\n- Track changes on websites without coding\n- Set up alerts when specific data changes\n- Extract structured data from webpages\n- Send notifications to various channels (Slack, Discord, etc.)\n- Create automated workflows based on webpage changes\n- Integrate with tools like Google Sheets and Airtable\n\n## When to Use Each Tool\n\n## herd-use\n\n**Use Herd when you need to:**\n\n- Create complex automation scripts\n- Orchestrate multiple browsers\n- Build sophisticated data extraction pipelines\n- Integrate browser automation into your application\n- Control browsers programmatically\n- Run continuous automation jobs\n- Implement advanced web interaction patterns\n- Scale automation across multiple devices\n\n**Example use cases:**\n- Large-scale data extraction projects\n- Multi-step workflow automation\n- Integration testing across browsers\n- Sophisticated web monitoring systems\n- Building browser-based APIs\n- Authentication-required data access\n\n## monitoro-use\n\n**Use Monitoro when you need to:**\n\n- Monitor websites for changes without coding\n- Get alerts when specific data changes\n- Extract data and send it to other tools\n- Create simple automations based on website changes\n- Set up monitoring dashboards\n- Share monitoring alerts with teams\n\n**Example use cases:**\n- Price monitoring on e-commerce sites\n- Tracking product availability\n- Monitoring competitor websites\n- Setting up alerts for new content\n- Syncing web data to spreadsheets\n- Creating webhooks for website changes\n\n## Implementation Comparison\n\n### Herd Implementation\n\n## herd-js\n\nCode (javascript):\n// Using Herd for browser automation\nimport { HerdClient } from '@monitoro/herd';\n\n// Initialize the client\nconst client = new HerdClient('your-token');\nawait client.initialize();\n\n// Get a device\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a new page and automate it\nconst page = await device.newPage();\nawait page.goto('https://example.com');\n\n// Interact with the page\nawait page.type('#search', 'automation');\nawait page.click('.search-button');\n\n// Extract data\nconst results = await page.extract({\n titles: {\n _$r: '.result-item',\n title: '.item-title',\n description: '.item-description'\n }\n});\n\nconsole.log(results);\nawait client.close();\n\n## herd-py\n\nCode (python):\n# Using Herd for browser automation\nfrom monitoro_herd import HerdClient\n\n# Initialize the client\nclient = HerdClient('your-token')\nclient.initialize()\n\n# Get a device\ndevices = client.list_devices()\ndevice = devices[0]\n\n# Create a new page and automate it\npage = device.new_page()\npage.goto('https://example.com')\n\n# Interact with the page\npage.type('#search', 'automation')\npage.click('.search-button')\n\n# Extract data\nresults = page.extract({\n \"titles\": {\n \"_$r\": \".result-item\",\n \"title\": \".item-title\",\n \"description\": \".item-description\"\n }\n})\n\nprint(results)\nclient.close()\n\n### Monitoro Implementation\n\nMonitoro works through a no-code interface:\n\n1. **Install the Monitoro browser extension**\n2. **Create a monitor:**\n - Navigate to the webpage you want to monitor\n - Use the Monitoro interface to select elements to track\n - Set up conditions for when alerts should trigger\n - Configure how often the page should be checked\n\n3. **Configure integrations:**\n - Connect to notification channels like Discord, Slack, or Telegram\n - Set up data destinations like Google Sheets or Airtable\n - Create webhooks for custom integrations\n\nCode:\n# No code required for Monitoro - it's all done through the visual interface\n\n# Example monitoring workflow:\n1. Set up a monitor for a product page on an e-commerce site\n2. Configure it to check for price changes or \"In Stock\" status\n3. Set up alerts to Discord when conditions are met\n4. Configure Google Sheets integration to log all price changes\n\n## Using Herd and Monitoro Together\n\nThese tools can work together in a complementary fashion:\n\n1. **Use Monitoro for initial monitoring and alerts:**\n - Set up no-code monitors for important websites\n - Get alerted when specific changes occur\n - Collect initial data in spreadsheets\n\n2. **Use Herd for advanced follow-up automation:**\n - Trigger Herd workflows based on Monitoro alerts\n - Perform complex interactions beyond Monitoro's capabilities\n - Extract deeper data that requires authentication or multiple steps\n - Orchestrate actions across multiple browsers\n\n### Example workflow:\n\n1. Monitoro monitors competitor pricing and alerts when prices change\n2. A webhook from Monitoro triggers a Herd automation\n3. Herd performs a deep analysis across multiple pages, including login-required areas\n4. Herd generates a comprehensive report and updates internal systems\n\n## When to Upgrade from Monitoro to Herd\n\nConsider upgrading from Monitoro to Herd when:\n\n1. You need to go beyond simple monitoring to complex automation\n2. Your workflows require orchestration of multiple browsers\n3. You need to access authenticated areas of websites\n4. You require sophisticated data processing capabilities\n5. You need programmatic control over browser behavior\n6. Your team has development resources for coding solutions\n\n## monitoro-simple\n\nCode:\n# Monitoro approach (no-code)\n\n1. Set up a monitor for an e-commerce product page\n2. Configure it to check price every hour\n3. Send price alerts to Slack channel\n4. Log all prices to Google Sheets\n\n## herd-advanced\n\nCode (javascript):\n// Herd advanced solution\n\nimport { HerdClient } from '@monitoro/herd';\n\nasync function monitorPrices() {\n const client = new HerdClient('your-token');\n await client.initialize();\n const devices = await client.listDevices();\n const device = devices[0];\n \n // Open multiple pages for parallel extraction\n const productUrls = [\n 'https://example.com/product/1',\n 'https://example.com/product/2',\n 'https://example.com/product/3'\n ];\n \n // Login first to access special pricing\n const page = await device.newPage();\n await page.goto('https://example.com/login');\n await page.type('#email', process.env.USERNAME);\n await page.type('#password', process.env.PASSWORD);\n await page.click('#login-button');\n await page.waitForNavigation();\n \n // Now check all products in parallel\n const priceData = [];\n for (const url of productUrls) {\n await page.goto(url);\n \n const data = await page.extract({\n productId: {\n _$: '.product-id',\n regex: 'ID: (.*)'\n },\n regularPrice: '.regular-price',\n salePrice: '.sale-price',\n memberPrice: '.member-price',\n availability: '.stock-status',\n shipping: '.shipping-info'\n });\n \n // Compare with historical data in database\n const priceChanged = await comparePriceWithHistory(data);\n if (priceChanged) {\n // Send custom notification with detailed info\n await sendDetailedAlert(data);\n // Update database with new price info\n await updatePriceDatabase(data);\n }\n \n priceData.push(data);\n }\n \n await client.close();\n return priceData;\n}\n\n// Run on schedule\nsetInterval(monitorPrices, 3600000); // Every hour\n\n## Why Use Both Herd and Monitoro?\n\n### 1. Complementary Capabilities\n\n- **Monitoro:** Fast, no-code setup for basic monitoring needs\n- **Herd:** Developer-focused tool for complex automation requirements\n\n### 2. Different Team Members, Different Needs\n\n- **Business Teams:** Can use Monitoro without technical skills\n- **Developers:** Can use Herd for advanced customization\n- **Operations:** Can set up Monitoro for quick insights\n- **Engineering:** Can build on those insights with Herd\n\n### 3. Staged Implementation\n\nMonitoro and Herd support a natural progression:\n- Start with simple Monitoro monitoring\n- Identify areas that need deeper automation\n- Implement targeted Herd solutions for those areas\n- Maintain both for their distinct advantages\n\n## Get Started with Herd and Monitoro\n\nReady to implement a complete browser automation and monitoring solution?\n\n### For Herd:\n\n1. [Create a Herd account](/register)\n2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)\n3. [Connect your browser](/docs/connect-your-browser)\n4. [Run your first automation](/docs/automation-basics)\n\n### For Monitoro:\n\n1. Visit [Monitoro.co](https://monitoro.co) to sign up\n2. Install the Monitoro browser extension\n3. Navigate to the website you want to monitor\n4. Use the visual interface to set up your first monitor\n\nChoose the right tool for each specific need, or use them together for a comprehensive web monitoring and automation solution.\n\n================================================================================\n\nDocument: Alternative Herd Vs Puppeteer\nURL: https://herd.garden/docs/alternative-herd-vs-puppeteer\n\n# Herd vs Puppeteer: A Better Alternative for Browser Automation\n\nIn the world of browser automation and web scraping, Puppeteer has long been a popular choice for developers. However, Herd provides a compelling alternative that addresses many of Puppeteer's limitations while offering unique advantages for modern development workflows.\n\n## Quick Comparison\n\n| Feature | Herd | Puppeteer |\n| --- | --- | --- |\n| **Browser Type** | Your existing browser | Separate Chromium instance |\n| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium, Chrome (limited Firefox) |\n| **Infrastructure Requirements** | None (uses your browser) | Requires separate browser instances |\n| **Authentication** | Uses existing sessions | Requires manual setup |\n| **Setup Complexity** | Simple extension installation | More complex setup |\n| **Programming Languages** | JavaScript, Python | JavaScript/TypeScript only |\n| **Session Management** | Persistent across runs | Must be rebuilt each run |\n| **Resource Usage** | Minimal (shared with browser) | High (separate processes) |\n\n## Key Differences in Depth\n\n### Infrastructure Requirements\n\n**Puppeteer:**\n- Requires installing and managing separate Chromium instances\n- Needs dedicated resources for each browser instance\n- Increases infrastructure costs in cloud environments\n- Requires managing updates to the Chromium engine\n\n**Herd:**\n- Uses your existing browser installation\n- No additional browser instances to manage\n- Significantly lower resource utilization\n- Leverages native browser capabilities\n\n### Setup and Installation Process\n\n## herd\n\nCode (bash):\n# Install the Herd SDK\nnpm install @monitoro/herd\n\n# Then install the browser extension and connect your browser\n# That's it! No browser installation or management needed\n\n## puppeteer\n\nCode (bash):\n# Install Puppeteer\nnpm install puppeteer\n\n# Puppeteer will download and manage its own Chromium instance\n# You'll need to handle this in deployment environments\n# Additional setup for proxies, authentication, etc.\n\n### Browser Support\n\n**Puppeteer:**\n- Primarily designed for Chrome/Chromium browsers\n- Limited experimental support for Firefox\n- No support for Safari or Edge\n\n**Herd:**\n- Works with Chrome, Edge, Brave, Arc, Opera \n- Consistent experience across all supported Chromium-based browsers\n\n### Authentication and Session Handling\n\n**Puppeteer:**\n- Sessions must be recreated for each new Puppeteer instance\n- Requires manually handling cookies and authentication flows\n- Accessing logged-in state requires additional code\n- Difficult to use existing authenticated sessions\n\n**Herd:**\n- Uses your existing browser's authenticated sessions\n- No need to handle authentication separately\n- Persistent cookies and storage between sessions\n- Access to browser extensions that manage authentication\n\n## Use Case Comparisons\n\n### Data Extraction\n\n## herd-extract\n\nCode (javascript):\n// Initialize the client and connect to your browser\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Extract data using simple selectors\nconst page = await device.newPage();\nawait page.goto('https://example.com');\nconst data = await page.extract({\n title: 'h1',\n description: 'p',\n links: {\n _$r: 'a', // Extract all links\n href: { attribute: 'href' },\n text: ':root'\n }\n});\n\nconsole.log(data);\n\n## puppeteer-extract\n\nCode (javascript):\n// Launch a separate browser instance\nconst browser = await puppeteer.launch();\nconst page = await browser.newPage();\nawait page.goto('https://example.com');\n\n// Extract data with multiple evaluations\nconst data = {\n title: await page.$eval('h1', el =\u003e el.textContent),\n description: await page.$eval('p', el =\u003e el.textContent),\n links: await page.$eval('a', elements =\u003e \n elements.map(el =\u003e ({\n href: el.getAttribute('href'),\n text: el.textContent\n }))\n )\n};\n\nconsole.log(data);\nawait browser.close();\n\n### Web Automation\n\n## herd-auto\n\nCode (javascript):\n// Initialize and connect to your browser\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Use the existing browser with current sessions\nconst page = await device.newPage();\nawait page.goto('https://myapp.com/dashboard'); // Already logged in\n\n// Interact with the page\nawait page.click('.new-item-button');\nawait page.type('#item-name', 'New Task');\nawait page.click('.save-button');\n\n// Process results\nconst notification = await page.waitForSelector('.success-message');\nconsole.log(notification.textContent);\n\n## puppeteer-auto\n\nCode (javascript):\n// Launch a separate browser instance\nconst browser = await puppeteer.launch();\nconst page = await browser.newPage();\n\n// Need to handle login first\nawait page.goto('https://myapp.com/login');\nawait page.type('#username', 'user@example.com');\nawait page.type('#password', 'password');\nawait page.click('.login-button');\nawait page.waitForNavigation();\n\n// Now navigate to dashboard after login\nawait page.goto('https://myapp.com/dashboard');\n\n// Interact with the page\nawait page.click('.new-item-button');\nawait page.type('#item-name', 'New Task');\nawait page.click('.save-button');\n\n// Process results\nconst notification = await page.waitForSelector('.success-message');\nconsole.log(await notification.evaluate(el =\u003e el.textContent));\nawait browser.close();\n\n## Migration Guide: From Puppeteer to Herd\n\nTransitioning from Puppeteer to Herd is straightforward. Here's a simple migration guide:\n\n### 1. Installation\n\n1. Install the Herd SDK:\n \nCode (bash):\n npm install @monitoro/herd\n\n2. Install the Herd browser extension in your preferred browser\n\n3. Register your browser as a device in the Herd dashboard\n\n### 2. Code Migration\n\n| Puppeteer | Herd | Notes |\n| --- | --- | --- |\n| `const browser = await puppeteer.launch()` | `const client = new HerdClient(apiUrl, token)` `await client.initialize()` `const devices = await client.listDevices()` `const device = devices[0]` | Herd connects to your existing browser |\n| `const page = await browser.newPage()` | `const page = await device.newPage()` | Similar API, different source |\n| `await page.goto(url)` | `await page.goto(url)` | Identical usage |\n| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |\n| `await page.click(selector)` | `await page.click(selector)` | Identical usage |\n| `await page.$eval(selector, fn)` | `const element = await page.$(selector)` `await element.evaluate(fn)` | Slightly different approach |\n| `await page.screenshot()` | `await page.screenshot()` | Identical usage |\n| `await browser.close()` | `await client.close()` | Browser stays open, just disconnects client |\n\n## Why Choose Herd Over Puppeteer?\n\n### 1. No Infrastructure Management\n\nHerd eliminates the need to maintain separate browser instances, significantly reducing:\n- Memory and CPU usage\n- Infrastructure costs for cloud deployments\n- Maintenance overhead for browser updates\n\n### 2. Use Existing Authentication\n\nWith Herd, you can automate tasks in your already authenticated browser:\n- No need to handle authentication flows in code\n- Access to sites that require complex authentication\n- Use existing cookies, local storage, and sessions\n\n### 3. Cross-Browser Compatibility\n\nWhile Puppeteer is primarily focused on Chromium:\n- Herd works across Chrome, Edge, and Brave\n- Same code works on any supported browser\n- Test on multiple browsers with minimal configuration changes\n\n### 4. Simpler Development Experience\n\nHerd provides:\n- More intuitive APIs for common tasks\n- Better debugging experience (view automation in real browser)\n- Easier integration with existing workflows\n\n## Get Started with Herd Today\n\nReady to try a better alternative to Puppeteer? Get started with Herd:\n\n1. [Create a Herd account](/register)\n2. [Install the browser extension](/docs/installation)\n3. [Connect your browser](/docs/connect-your-browser)\n4. [Run your first automation](/docs/automation-basics)\n\nDiscover how Herd can simplify your browser automation workflows while reducing infrastructure costs and complexity.\n\n================================================================================\n\nDocument: Alternative Herd Vs Selenium\nURL: https://herd.garden/docs/alternative-herd-vs-selenium\n\n# Herd vs Selenium: A More Efficient Browser Automation Alternative\n\nSelenium has been the industry standard for browser automation for many years, but its architecture presents significant challenges for modern development workflows. Herd offers a compelling alternative that addresses many of Selenium's pain points while providing a more intuitive experience.\n\n## Quick Comparison\n\n| Feature | Herd | Selenium |\n| --- | --- | --- |\n| **Driver Requirements** | No drivers needed | Requires WebDriver for each browser |\n| **Browser Type** | Your existing browser | Creates new browser instances |\n| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Firefox, Edge, Safari, IE |\n| **Infrastructure** | Uses your existing browser | Requires WebDriver servers |\n| **Authentication** | Uses existing sessions | Requires manual setup |\n| **Programming Languages** | JavaScript, Python | Java, Python, C#, Ruby, JavaScript |\n| **Setup Complexity** | Simple browser extension | WebDriver setup for each browser |\n| **Maintenance Required** | Minimal (browser updates only) | High (drivers must match browser versions) |\n| **Session Management** | Persistent across runs | Must be rebuilt each run |\n\n## Key Differences in Depth\n\n### Driver and Infrastructure Requirements\n\n**Selenium:**\n- Requires installation and management of WebDrivers for each browser\n- WebDrivers must be kept in sync with browser versions\n- Separate browser instances for automation\n- Complex setup in CI/CD environments\n- High resource usage (separate process for each browser)\n\n**Herd:**\n- No WebDrivers or separate drivers needed\n- Works directly with your installed browser\n- No version synchronization issues\n- Simple setup in any environment\n- Low resource usage (shares existing browser process)\n\n### Setup and Installation Process\n\n## herd\n\nCode (bash):\n# JavaScript\nnpm install @monitoro/herd\n\n# Python\npip install herd-client\n\n# Then install the browser extension and connect your browser\n# That's it! No WebDrivers or browser drivers to manage\n\n## selenium\n\nCode (bash):\n# JavaScript\nnpm install selenium-webdriver\n\n# Python\npip install selenium\n\n# Additionally, you must:\n# 1. Download the correct WebDriver for each browser\n# 2. Ensure WebDriver versions match browser versions\n# 3. Add WebDrivers to your PATH or specify their location\n# 4. Update WebDrivers when browsers update\n\n### Browser Support and Consistency\n\n**Selenium:**\n- Supports all major browsers including Chrome, Firefox, Safari, Edge, and IE\n- Requires separate WebDriver configurations for each browser\n- May exhibit inconsistent behavior across different browsers\n- Requires updates when browsers update\n\n**Herd:**\n- Supports Chrome, Edge, Brave, Arc, Opera\n- Uniform behavior across supported Chromium-based browsers\n- No additional configuration needed for different browsers\n\n### Authentication and Session Handling\n\n**Selenium:**\n- Sessions are isolated and temporary\n- Requires manually handling authentication steps\n- Session storage is cleared between runs\n- Difficult to use existing authenticated sessions\n\n**Herd:**\n- Uses your browser's existing authenticated sessions\n- Access sites you're already logged into\n- Persistent cookies and storage\n- Access to browser extensions that manage authentication\n\n## Use Case Comparisons\n\n### Web Testing\n\n## herd-test\n\nCode (javascript):\n// JavaScript\nimport { HerdClient } from '@monitoro/herd';\n\nasync function runTest() {\n // Connect to your existing browser\n const client = new HerdClient('your-token');\n await client.initialize();\n const devices = await client.listDevices();\n const device = devices[0];\n \n // Create a new page for testing\n const page = await device.newPage();\n await page.goto('https://example.com');\n \n // Test interactions\n await page.click('.nav-item');\n await page.waitForSelector('.content-loaded');\n \n // Assert condition\n const header = await page.$('.header');\n const text = await header.getText();\n console.assert(text.includes('Expected Text'), 'Header text verification failed');\n \n // Cleanup\n await page.close();\n await client.close();\n}\n\nrunTest();\n\n## selenium-test\n\nCode (javascript):\n// JavaScript\nimport { Builder, By, until } from 'selenium-webdriver';\n\nasync function runTest() {\n // Launch a separate browser instance with WebDriver\n const driver = await new Builder()\n .forBrowser('chrome')\n .build();\n \n try {\n // Navigate to the test site\n await driver.get('https://example.com');\n \n // Test interactions\n await driver.findElement(By.css('.nav-item')).click();\n await driver.wait(until.elementLocated(By.css('.content-loaded')), 5000);\n \n // Assert condition\n const header = await driver.findElement(By.css('.header'));\n const text = await header.getText();\n console.assert(text.includes('Expected Text'), 'Header text verification failed');\n } finally {\n // Always close the browser\n await driver.quit();\n }\n}\n\nrunTest();\n\n### Data Extraction\n\n## herd-extract\n\nCode (javascript):\n// JavaScript\nimport { HerdClient } from '@monitoro/herd';\n\nasync function extractData() {\n const client = new HerdClient('your-token');\n await client.initialize();\n const devices = await client.listDevices();\n const device = devices[0];\n \n const page = await device.newPage();\n await page.goto('https://example.com/products');\n \n // Extract product data with a single call\n const products = await page.extract({\n items: {\n _$r: '.product-card', // Repeat for each product card\n name: '.product-name',\n price: '.product-price',\n rating: '.product-rating',\n inStock: '.stock-status'\n }\n });\n \n console.log(products.items);\n await client.close();\n}\n\nextractData();\n\n## selenium-extract\n\nCode (javascript):\n// JavaScript\nimport { Builder, By } from 'selenium-webdriver';\n\nasync function extractData() {\n const driver = await new Builder()\n .forBrowser('chrome')\n .build();\n \n try {\n await driver.get('https://example.com/products');\n \n // Extract product data with multiple queries\n const productElements = await driver.findElements(By.css('.product-card'));\n \n const products = [];\n for (const element of productElements) {\n const name = await element.findElement(By.css('.product-name')).getText();\n const price = await element.findElement(By.css('.product-price')).getText();\n \n let rating = '';\n try {\n rating = await element.findElement(By.css('.product-rating')).getText();\n } catch (e) {\n // Element might not exist\n rating = 'N/A';\n }\n \n let inStock = false;\n try {\n const stockText = await element.findElement(By.css('.stock-status')).getText();\n inStock = stockText.includes('In Stock');\n } catch (e) {\n // Element might not exist\n }\n \n products.push({ name, price, rating, inStock });\n }\n \n console.log(products);\n } finally {\n await driver.quit();\n }\n}\n\nextractData();\n\n## Migration Guide: From Selenium to Herd\n\nTransitioning from Selenium to Herd is straightforward. Here's a guide to help you migrate your existing code:\n\n### 1. Installation\n\n1. Install the Herd SDK:\n \nCode (bash):\n # JavaScript\n npm install @monitoro/herd\n \n # Python\n pip install herd-client\n\n2. Install the Herd browser extension in your preferred browser\n\n3. Register your browser as a device in the Herd dashboard\n\n### 2. Code Migration\n\n| Selenium | Herd | Notes |\n| --- | --- | --- |\n| `new Builder().forBrowser().build()` | `new HerdClient(apiUrl, token)` `await client.initialize()` `const devices = await client.listDevices()` `const device = devices[0]` | Herd connects to your existing browser |\n| `driver.get(url)` | `await page.goto(url)` | Similar syntax |\n| `driver.findElement(By.css(selector))` | `await page.$(selector)` | Herd uses CSS selectors directly |\n| `element.sendKeys(text)` | `await element.type(text)` | Different method name |\n| `element.click()` | `await element.click()` | Identical usage |\n| `driver.wait(until.elementLocated())` | `await page.waitForSelector(selector)` | Similar functionality |\n| `driver.quit()` | `await client.close()` | Herd just disconnects, browser stays open |\n\n### 3. Handling Multiple Browsers\n\n**Selenium:**\n\nCode (javascript):\nconst chrome = await new Builder().forBrowser('chrome').build();\nconst firefox = await new Builder().forBrowser('firefox').build();\n\n**Herd:**\n\nCode (javascript):\n// Connect to different browsers that are registered as devices\nconst chromiumDevice = devices.find(d =\u003e d.name === 'Chrome Browser');\n\n## Why Choose Herd Over Selenium?\n\n### 1. No WebDriver Headaches\n\nHerd eliminates the need for WebDrivers, solving the most common Selenium pain points:\n- No driver version compatibility issues\n- No driver installation or updates needed\n- No broken tests due to browser updates\n\n### 2. Use Existing Authentication\n\nWith Herd, you can automate tasks in your already authenticated browser:\n- No need to write and maintain authentication code\n- Access to sites requiring complex authentication\n- Use existing cookies, local storage, and sessions\n\n### 3. Simplified Setup and Maintenance\n\nHerd significantly reduces the overhead of browser automation:\n- No complex CI/CD configuration\n- No driver path management\n- No browser version tracking\n\n### 4. Intuitive API for Modern Development\n\nHerd provides:\n- Clean, Promise-based API\n- Powerful data extraction capabilities\n- Better debugging experience (view automation in your browser)\n\n## Get Started with Herd Today\n\nReady to try a more efficient alternative to Selenium? Get started with Herd:\n\n1. [Create a Herd account](/register)\n2. [Install the browser extension](/docs/installation)\n3. [Connect your browser](/docs/connect-your-browser)\n4. [Run your first automation](/docs/automation-basics)\n\nDiscover how Herd can simplify your browser automation workflows while eliminating the most common frustrations of working with Selenium.\n\n================================================================================\n\nDocument: Automation Basics\nURL: https://herd.garden/docs/automation-basics\n\n# Automation Basics\n\nWelcome to Monitoro Herd! This guide will walk you through creating your first browser automation step-by-step. We'll start with the basics and gradually build up to more complex examples, explaining each concept along the way.\n\n## javascript\n\n## JavaScript SDK\n\n### Setting Up Your Environment\n\nBefore writing any code, you'll need to set up your JavaScript environment and install the Herd SDK:\n\n1. Make sure you have Node.js installed (version 14 or higher recommended)\n2. Create a new project directory\n3. Install the SDK using npm:\n\nCode (bash):\nnpm install @monitoro/herd\n\n### Initializing the Client\n\nThe first step in any automation is to initialize the Herd client with your API credentials:\n\nCode (javascript):\n// Import the Herd client\nimport { HerdClient } from '@monitoro/herd';\n\n// Initialize the client with your API URL and token\nconst client = new HerdClient('your-token');\n\n// Always initialize the client before using it\nawait client.initialize();\nNote: **Note:** Replace the token with your actual Herd API token from your dashboard.\n\n### Connecting to a Device\n\nAfter initializing the client, you need to connect to a device (browser) that will perform the automation:\n\nCode (javascript):\n// Get a list of available devices\nconst devices = await client.listDevices();\n\n// Connect to the first available device\nconst device = devices[0];\n\nconsole.log(`Connected to device: ${device.id}`);\n\nThis code retrieves all devices registered to your account and connects to the first one. In a production environment, you might want to select a specific device based on its properties or availability.\n\n### Creating a Page and Navigating\n\nNow that you're connected to a device, you can create a new browser page and navigate to a website:\n\nCode (javascript):\n// Create a new page in the browser\nconst page = await device.newPage();\n\n// Navigate to a website\nawait page.goto('https://example.com');\n\nconsole.log('Successfully navigated to example.com');\n\nThe `goto` method loads the specified URL and waits for the page to load. By default, it waits until the page's `load` event is fired, but you can customize this behavior with options.\n\n### Extracting Basic Information\n\nOne of the most common automation tasks is extracting information from web pages. Here's how to extract basic elements:\n\nCode (javascript):\n// Extract content using CSS selectors\nconst content = await page.extract({\n title: 'h1', // Extracts the main heading\n description: 'p', // Extracts the first paragraph\n link: 'a' // Extracts the first link text\n});\n\n// Display the extracted content\nconsole.log('Extracted content:');\nconsole.log(`Title: ${content.title}`);\nconsole.log(`Description: ${content.description}`);\nconsole.log(`Link: ${content.link}`);\n\nThe `extract` method uses CSS selectors to find elements on the page and extract their text content. This is a powerful way to scrape structured data from websites.\n\n### Proper Resource Management\n\nAlways remember to close resources when you're done with them to prevent memory leaks:\n\nCode (javascript):\n// Close the page when done\nawait page.close();\n\n// Close the client connection\nawait client.close();\n\n### Putting It All Together\n\nHere's a complete example that combines all the steps above into a single function:\n\nCode (javascript):\nimport { HerdClient } from '@monitoro/herd';\n\nasync function runBasicAutomation() {\n const client = new HerdClient('your-token');\n \n try {\n // Initialize the client\n await client.initialize();\n console.log('Client initialized successfully');\n \n // Get the first available device\n const devices = await client.listDevices();\n if (devices.length === 0) {\n throw new Error('No devices available');\n }\n const device = devices[0];\n console.log(`Connected to device: ${device.id}`);\n \n // Create a new page\n const page = await device.newPage();\n console.log('New page created');\n \n // Navigate to a website\n console.log('Navigating to example.com...');\n await page.goto('https://example.com');\n console.log('Navigation complete');\n \n // Extract content\n console.log('Extracting content...');\n const content = await page.extract({\n title: 'h1',\n description: 'p',\n link: 'a'\n });\n \n // Display the extracted content\n console.log('\\nExtracted content:');\n console.log(`Title: ${content.title}`);\n console.log(`Description: ${content.description}`);\n console.log(`Link: ${content.link}`);\n \n } catch (error) {\n console.error('Error during automation:', error);\n } finally {\n // Always close the client when done\n console.log('Closing client connection...');\n await client.close();\n console.log('Client connection closed');\n }\n}\n\n// Run the automation\nrunBasicAutomation();\n\n### Interacting with Web Pages\n\nNow let's explore how to interact with elements on a page. This includes clicking buttons, typing text, and handling forms.\n\n#### Finding Elements\n\nBefore interacting with an element, you need to find it on the page:\n\nCode (javascript):\n// Find an element using a CSS selector\nconst searchBox = await page.$('input[name=\"q\"]');\n\n// Check if the element was found\nif (searchBox) {\n console.log('Search box found');\n} else {\n console.log('Search box not found');\n}\n\nThe ` herd.garden | Top Sites | DialtoneApp

Top SitesHerd - Browser Superpowers & MCP Servers for AI Agents

Machine Readiness

Stored receipt and evidence

Overall

30

Readable

100

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

robots, llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Open robots.txt
User-agent: *
Allow: /

Sitemap: https://herd.garden/sitemap.xml

Document

llms.txt

Open llms.txt
Herd Documentation
==


Herd is a powerful platform and SDK for automating your own browser, ten or millions of them. Similar to Puppeteer but with support for multiple devices and real-time events, and no infrastructure to setup.


Document: Automation Basics
URL: https://herd.garden/docs/automation-basics

# Automation Basics

Welcome to Monitoro Herd! This guide will walk you through creating your first browser automation step-by-step. We'll start with the basics and gradually build up to more complex examples, explaining each concept along the way.

## javascript

## JavaScript SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your JavaScript environment and install the Herd SDK:

1. Make sure you have Node.js installed (version 14 or higher recommended)
2. Create a new project directory
3. Install the SDK using npm:

Code (bash):
npm install @monitoro/herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (javascript):
// Import the Herd client
import { HerdClient } from '@monitoro/herd';

// Initialize the client with your API URL and token
const client = new HerdClient('your-token');

// Always initialize the client before using it
await client.initialize();
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

After initializing the client, you need to connect to a device (browser) that will perform the automation:

Code (javascript):
// Get a list of available devices
const devices = await client.listDevices();

// Connect to the first available device
const device = devices[0];

console.log(`Connected to device: ${device.id}`);

This code retrieves all devices registered to your account and connects to the first one. In a production environment, you might want to select a specific device based on its properties or availability.

### Creating a Page and Navigating

Now that you're connected to a device, you can create a new browser page and navigate to a website:

Code (javascript):
// Create a new page in the browser
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com');

console.log('Successfully navigated to example.com');

The `goto` method loads the specified URL and waits for the page to load. By default, it waits until the page's `load` event is fired, but you can customize this behavior with options.

### Extracting Basic Information

One of the most common automation tasks is extracting information from web pages. Here's how to extract basic elements:

Code (javascript):
// Extract content using CSS selectors
const content = await page.extract({
  title: 'h1',           // Extracts the main heading
  description: 'p',      // Extracts the first paragraph
  link: 'a'              // Extracts the first link text
});

// Display the extracted content
console.log('Extracted content:');
console.log(`Title: ${content.title}`);
console.log(`Description: ${content.description}`);
console.log(`Link: ${content.link}`);

The `extract` method uses CSS selectors to find elements on the page and extract their text content. This is a powerful way to scrape structured data from websites.

### Proper Resource Management

Always remember to close resources when you're done with them to prevent memory leaks:

Code (javascript):
// Close the page when done
await page.close();

// Close the client connection
await client.close();

### Putting It All Together

Here's a complete example that combines all the steps above into a single function:

Code (javascript):
import { HerdClient } from '@monitoro/herd';

async function runBasicAutomation() {
  const client = new HerdClient('your-token');
  
  try {
    // Initialize the client
    await client.initialize();
    console.log('Client initialized successfully');
    
    // Get the first available device
    const devices = await client.listDevices();
    if (devices.length === 0) {
      throw new Error('No devices available');
    }
    const device = devices[0];
    console.log(`Connected to device: ${device.id}`);
    
    // Create a new page
    const page = await device.newPage();
    console.log('New page created');
    
    // Navigate to a website
    console.log('Navigating to example.com...');
    await page.goto('https://example.com');
    console.log('Navigation complete');
    
    // Extract content
    console.log('Extracting content...');
    const content = await page.extract({
      title: 'h1',
      description: 'p',
      link: 'a'
    });
    
    // Display the extracted content
    console.log('\nExtracted content:');
    console.log(`Title: ${content.title}`);
    console.log(`Description: ${content.description}`);
    console.log(`Link: ${content.link}`);
    
  } catch (error) {
    console.error('Error during automation:', error);
  } finally {
    // Always close the client when done
    console.log('Closing client connection...');
    await client.close();
    console.log('Client connection closed');
  }
}

// Run the automation
runBasicAutomation();

### Interacting with Web Pages

Now let's explore how to interact with elements on a page. This includes clicking buttons, typing text, and handling forms.

#### Finding Elements

Before interacting with an element, you need to find it on the page:

Code (javascript):
// Find an element using a CSS selector
const searchBox = await page.$('input[name="q"]');

// Check if the element was found
if (searchBox) {
  console.log('Search box found');
} else {
  console.log('Search box not found');
}

The `


  
  
  
  
  herd.garden | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   method returns the first element that matches the CSS selector, or `null` if no element is found.

#### Typing Text

To type text into an input field:

Code (javascript):
// Type text into an input field
await page.type('input[name="q"]', 'Monitoro Herd automation');
console.log('Text entered into search box');

The `type` method finds the element using the CSS selector and simulates typing the specified text.

#### Clicking Elements

To click a button or link:

Code (javascript):
// Click a button
await page.click('input[type="submit"]');
console.log('Search button clicked');

By default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:

Code (javascript):
// Click and wait for navigation
await page.click('input[type="submit"]', { 
  waitForNavigation: 'networkidle2' 
});
console.log('Search button clicked and navigation completed');

The `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.

#### Waiting for Elements

Sometimes you need to wait for elements to appear on the page:

Code (javascript):
// Wait for an element to appear
await page.waitForSelector('#search');
console.log('Search results have loaded');

This is useful when dealing with dynamic content that loads after the initial page load.

#### Search Engine Example

Let's put these concepts together in a search engine example:

Code (javascript):
async function searchExample() {
  const client = new HerdClient('your-token');
  
  try {
    await client.initialize();
    const devices = await client.listDevices();
    const device = devices[0];
    const page = await device.newPage();
    
    // Navigate to a search engine
    console.log('Navigating to Google...');
    await page.goto('https://www.google.com');
    
    // Type in the search box
    console.log('Entering search query...');
    await page.type('input[name="q"]', 'Monitoro Herd automation');
    
    // Submit the search form and wait for results
    console.log('Submitting search...');
    await page.click('input[type="submit"]', { 
      waitForNavigation: 'networkidle2' 
    });
    
    // Wait for results to load completely
    console.log('Waiting for search results...');
    await page.waitForSelector('#search');
    
    // Extract search result titles
    console.log('Extracting search results...');
    const searchResults = await page.extract({
      titles: {
        _$r: '#search .g h3',  // _$r extracts multiple elements
        text: ':root'           // For each match, get its text
      }
    });
    
    // Display the search result titles
    console.log('\nSearch Results:');
    searchResults.titles.forEach((result, index) => {
      console.log(`${index + 1}. ${result.text}`);
    });
    
  } catch (error) {
    console.error('Error:', error);
  } finally {
    await client.close();
  }
}

## python

## Python SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your Python environment and install the Herd SDK:

1. Make sure you have Python 3.8+ installed
2. Create a virtual environment (recommended)
3. Install the SDK using pip:

Code (bash):
pip install monitoro-herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (python):
# Import the Herd client
from monitoro_herd import HerdClient

# Initialize the client with your API URL and token
client = HerdClient('your-token')

# Always initialize the client before using it
client.initialize()
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

Next, connect to a device that will run your automation:

Code (python):
# Get available devices
devices = await client.list_devices()

# Connect to the first device
device = devices[0]

print(f"Connected to device: {device.id}")

### Creating a Page and Navigating

Now create a browser page and navigate to a website:

Code (python):
# Create a new page
page = await device.new_page()

# Navigate to a website
await page.goto("https://example.com")

print("Successfully navigated to example.com")

### Extracting Basic Information

Extract information from the page using CSS selectors:

Code (python):
# Extract basic information
data = await page.extract({
    "title": "h1",          # Main heading
    "description": "p",     # First paragraph
    "link": "a"             # First link text
})

# Display the extracted data
print("Extracted data:")
print(f"Title: {data['title']}")
print(f"Description: {data['description']}")
print(f"Link: {data['link']}")

### Resource Management

Always close resources when you're done:

Code (python):
# Close the page
await page.close()

# Close the client
await client.close()

### Complete Basic Example

Here's a complete example putting all these concepts together:

Code (python):
import asyncio
from monitoro_herd import HerdClient

async def basic_extraction():
    # Initialize the client
    client = HerdClient("your-token")
    
    try:
        # Initialize the connection
        await client.initialize()
        print("Client initialized successfully")
        
        # Get the first available device
        devices = await client.list_devices()
        if not devices:
            raise Exception("No devices available")
        device = devices[0]
        print(f"Connected to device: {device.id}")
        
        # Create a new page
        page = await device.new_page()
        print("New page created")
        
        # Navigate to a website
        print("Navigating to example.com...")
        await page.goto("https://example.com")
        print("Navigation complete")
        
        # Extract data using simple selectors
        print("Extracting content...")
        data = await page.extract({
            "title": "h1",
            "description": "p",
            "link": "a"
        })
        
        # Display the extracted data
        print("\nExtracted data:")
        print(f"Title: {data['title']}")
        print(f"Description: {data['description']}")
        print(f"Link: {data['link']}")
        
    except Exception as e:
        print(f"Error during automation: {e}")
    finally:
        # Always close resources
        print("Closing client connection...")
        await client.close()
        print("Client connection closed")

# Run the async function
asyncio.run(basic_extraction())

### Working with Lists and Structured Data

One of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.

#### The `_$r` Selector

To extract multiple elements that match a pattern, use the `_$r` (repeat) selector:

Code (python):
# Extract a list of items
data = await page.extract({
    "items": {
        "_$r": ".item",       # Find all elements with class "item"
        "name": ".item-name", # For each item, get the name
        "price": ".price"     # For each item, get the price
    }
})

# Access the extracted items
for item in data["items"]:
    print(f"Name: {item['name']}, Price: {item['price']}")

The `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.

#### Extracting Attributes

Sometimes you need to extract an attribute rather than the text content:

Code (python):
# Extract links and their href attributes
data = await page.extract({
    "links": {
        "_$r": "a",              # Find all links
        "text": ":root",         # Get the link text
        "url": {
            "_
quot;: ":root", # Reference the same element "attribute": "href" # Get its href attribute } } }) # Display the links for link in data["links"]: print(f"Link: {link['text']} -> {link['url']}") #### Hacker News Example Let's put these concepts together to scrape stories from Hacker News: Code (python): import asyncio from monitoro_herd import HerdClient async def scrape_hacker_news(): client = HerdClient("your-token") try: await client.initialize() devices = await client.list_devices() device = devices[0] page = await device.new_page() # Navigate to Hacker News print("Navigating to Hacker News...") await page.goto("https://news.ycombinator.com") # Extract stories and their metadata print("Extracting stories...") data = await page.extract({ # Extract the story elements "stories": { "_$r": ".athing", # Each story row "title": ".titleline > a", # Story title "site": ".sitestr", # Source website "link": { "_
quot;: ".titleline > a", # Story link "attribute": "href" # Get the URL } }, # Extract the metadata (points, author, etc.) "metadata": { "_$r": ".subline", # Metadata rows "points": ".score", # Points count "author": ".hnuser", # Author username "time": ".age" # Submission time } }) # Combine stories with their metadata # (They're in separate lists but in the same order) combined_stories = list(zip(data["stories"], data["metadata"])) # Display the first 3 stories print(f"\nExtracted {len(combined_stories)} stories:") for i, (story, meta) in enumerate(combined_stories[:3]): print(f"\nStory {i+1}:") print(f"Title: {story['title']}") if "site" in story: print(f"Site: {story['site']}") print(f"Link: {story['link']}") if "points" in meta: print(f"Points: {meta['points']}") if "author" in meta: print(f"Author: {meta['author']}") if "time" in meta: print(f"Posted: {meta['time']}") finally: await page.close() await client.close() # Run the function asyncio.run(scrape_hacker_news()) ## Tips for Successful Automation 1. **Start Simple**: Begin with basic extractions before moving to complex interactions 2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely 3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks 4. **Close Resources**: Always close pages and clients when done to avoid resource leaks 5. **Test Incrementally**: Build your automation step by step, testing each part 6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods 7. **Debug with Screenshots**: Take screenshots during automation to see what's happening ## Next Steps Now that you've created your first automation, you can: - Explore more complex selectors and extraction patterns - Learn how to handle authentication and login flows - Set up scheduled automations for regular data collection - Integrate with your existing systems via APIs == Document: Data Extraction URL: https://herd.garden/docs/data-extraction # Data Extraction Welcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines. ## Understanding Selectors Herd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system. ### Basic Extraction ## javascript The simplest form of extraction uses CSS selectors to target elements: Code (javascript): // Extract basic text content const data = await page.extract({ title: 'h1', // Extracts the main heading description: 'p', // Extracts the first paragraph link: 'a' // Extracts the first link text }); console.log(data.title); // "Welcome to Our Website" console.log(data.description); // "This is our homepage." ## python The simplest form of extraction uses CSS selectors to target elements: Code (python): # Extract basic text content data = await page.extract({ "title": "h1", # Extracts the main heading "description": "p", # Extracts the first paragraph "link": "a" # Extracts the first link text }) print(data["title"]) # "Welcome to Our Website" print(data["description"]) # "This is our homepage." ### Advanced Selector Syntax ## javascript For more complex extraction needs, use the expanded object syntax: Code (javascript): const data = await page.extract({ title: { _$: 'h1', // CSS selector attribute: 'id' // Extract the ID attribute instead of text }, price: { _$: '.price', // Target price element pipes: ['parseNumber'] // Apply transformation } }); ## python For more complex extraction needs, use the expanded object syntax: Code (python): data = await page.extract({ "title": { "_
quot;: "h1", # CSS selector "attribute": "id" # Extract the ID attribute instead of text }, "price": { "_
quot;: ".price", # Target price element "pipes": ["parseNumber"] # Apply transformation } }) ### Extracting Lists of Items ## javascript To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (javascript): const data = await page.extract({ items: { _$r: '.item', // Find all elements with class "item" title: 'h2', // For each item, get the title price: '.price', // For each item, get the price date: 'time' // For each item, get the date } }); // Access the extracted items data.items.forEach(item => { console.log(`${item.title}: ${item.price}, Posted: ${item.date}`); }); ## python To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (python): data = await page.extract({ "items": { "_$r": ".item", # Find all elements with class "item" "title": "h2", # For each item, get the title "price": ".price", # For each item, get the price "date": "time" # For each item, get the date } }) # Access the extracted items for item in data["items"]: print(f"{item['title']}: {item['price']}, Posted: {item['date']}") ### Nested Extraction ## javascript You can nest selectors to extract hierarchical data: Code (javascript): const data = await page.extract({ product: { name: '.product-name', details: { _$: '.product-details', specs: { _$r: '.spec-item', label: '.spec-label', value: '.spec-value' } } } }); ## python You can nest selectors to extract hierarchical data: Code (python): data = await page.extract({ "product": { "name": ".product-name", "details": { "_
quot;: ".product-details", "specs": { "_$r": ".spec-item", "label": ".spec-label", "value": ".spec-value" } } } }) ## Special Selectors Herd provides special selectors to handle various extraction scenarios: ### Root Selector (`:root`) The `:root` selector refers to the current element in context: ## javascript Code (javascript): const data = await page.extract({ items: { _$r: '.item', someElement: ':root', // Extract text of the .item element itself classes: { _$: ':root', attribute: 'class' // Extract class attribute of the same element } } }); ## python Code (python): data = await page.extract({ "items": { "_$r": ".item", "someElement": ":root", # Extract text of the .item element itself "classes": { "_
quot;: ":root", "attribute": "class" # Extract class attribute of the same element } } }) ### Property Extraction You can extract JavaScript properties from elements: ## javascript Code (javascript): const data = await page.extract({ dimensions: { _$: '.box', property: 'getBoundingClientRect' // Get element dimensions }, html: { _$: '.content', property: 'innerHTML' // Get inner HTML } }); ## python Code (python): data = await page.extract({ "dimensions": { "_
quot;: ".box", "property": "getBoundingClientRect" # Get element dimensions }, "html": { "_
quot;: ".content", "property": "innerHTML" # Get inner HTML } }) ## Transformation Pipelines Herd includes powerful transformation pipelines to process extracted data: ### Available Transformations | Pipe | Description | Example Input | Example Output | |------|-------------|--------------|----------------| | `trim` | Removes whitespace from start/end | `" Hello "` | `"Hello"` | | `toLowerCase` | Converts text to lowercase | `"HELLO"` | `"hello"` | | `toUpperCase` | Converts text to uppercase | `"hello"` | `"HELLO"` | | `parseNumber` | Extracts numbers from text | `"$1,2K.45"` | `1200.45` | | `parseDate` | Converts text to date | `"2024-01-15"` | `"2024-01-15T00:00:00.000Z"` | | `parseDateTime` | Converts text to datetime | `"2024-01-15T12:00:00Z"` | `"2024-01-15T12:00:00.000Z"` | ### Using Transformations Apply transformations using the `pipes` property: ## javascript Code (javascript): const data = await page.extract({ price: { _$: '.price', pipes: ['parseNumber'] // Convert "$1,234.56" to 1234.56 }, title: { _$: 'h1', pipes: ['trim', 'toLowerCase'] // Apply multiple transformations } }); ## python Code (python): data = await page.extract({ "price": { "_
quot;: ".price", "pipes": ["parseNumber"] # Convert "$1,234.56" to 1234.56 }, "title": { "_
quot;: "h1", "pipes": ["trim", "toLowerCase"] # Apply multiple transformations } }) ### Handling Currency and Large Numbers The `parseNumber` transformation handles various formats: ## javascript Code (javascript): const data = await page.extract({ price1: { _$: '.price-1', // Contains "$1,234.56" pipes: ['parseNumber'] // Result: 1234.56 }, price2: { _$: '.price-2', // Contains "$1.5M" pipes: ['parseNumber'] // Result: 1500000 }, price3: { _$: '.price-3', // Contains "1.5T€" pipes: ['parseNumber'] // Result: 1500000000000 } }); ## python Code (python): data = await page.extract({ "price1": { "_
quot;: ".price-1", # Contains "$1,234.56" "pipes": ["parseNumber"] # Result: 1234.56 }, "price2": { "_
quot;: ".price-2", # Contains "$1.5M" "pipes": ["parseNumber"] # Result: 1500000 }, "price3": { "_
quot;: ".price-3", # Contains "1.5T€" "pipes": ["parseNumber"] # Result: 1500000000000 } }) ## Real-World Examples Let's look at some practical examples of data extraction: ### E-commerce Product Listing Extract products from a search results page: ## javascript Code (javascript): const searchResults = await page.extract({ products: { _$r: '[data-component-type="s-search-result"]', title: { _$: 'h2 .a-link-normal', pipes: ['trim'] }, price: { _$: '.a-price .a-offscreen', pipes: ['parseNumber'] }, rating: { _$: '.a-icon-star-small .a-icon-alt', pipes: ['trim'] }, reviews: { _$: '.a-size-base.s-underline-text', pipes: ['trim'] } } }); ## python Code (python): searchResults = await page.extract({ "products": { "_$r": '[data-component-type="s-search-result"]', "title": { "_
quot;: "h2 .a-link-normal", "pipes": ["trim"] }, "price": { "_
quot;: ".a-price .a-offscreen", "pipes": ["parseNumber"] }, "rating": { "_
quot;: ".a-icon-star-small .a-icon-alt", "pipes": ["trim"] }, "reviews": { "_
quot;: ".a-size-base.s-underline-text", "pipes": ["trim"] } } }) ### News Article List Extract articles from a news site: ## javascript Code (javascript): const articles = await page.extract({ items: { _$r: '.item', title: { _$: 'h2', pipes: ['trim', 'toLowerCase'] }, price: { _$: '.price', pipes: ['parseNumber'] }, date: { _$: 'time', pipes: ['parseDate'] } } }); ## python Code (python): articles = await page.extract({ "items": { "_$r": ".item", "title": { "_
quot;: "h2", "pipes": ["trim", "toLowerCase"] }, "price": { "_
quot;: ".price", "pipes": ["parseNumber"] }, "date": { "_
quot;: "time", "pipes": ["parseDate"] } } }) ## Advanced Techniques ### Handling Dynamic Content For dynamic content that loads after the page is ready: ## javascript Code (javascript): // Wait for dynamic content to load await page.waitForElement('#dynamic span'); // Then extract the content const data = await page.extract({ content: '#dynamic span' }); ## python Code (python): # Wait for dynamic content to load await page.waitForElement('#dynamic span') # Then extract the content data = await page.extract({ "content": "#dynamic span" }) ### Extracting Page Metadata Extract information about the page itself: ## javascript Code (javascript): const pageInfo = await page.extract({ title: 'title', metaDescription: 'meta[name="description"]', canonicalUrl: { _$: 'link[rel="canonical"]', attribute: 'href' } }); ## python Code (python): pageInfo = await page.extract({ "title": "title", "metaDescription": 'meta[name="description"]', "canonicalUrl": { "_
quot;: 'link[rel="canonical"]', "attribute": "href" } }) ## Tips for Effective Extraction 1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction 2. **Test Incrementally**: Build your extraction schema step by step, testing each part 3. **Handle Missing Data**: Always account for elements that might not exist on the page 4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed 5. **Combine with Interactions**: For complex sites, interact with the page before extraction ## Next Steps Now that you understand Herd's data extraction system, you can: - Create complex extraction schemas for any website - Transform raw data into structured, usable formats - Build powerful automations that collect and process web data == Document: Getting Started URL: https://herd.garden/docs/getting-started # Getting Started with Herd This guide will help you get up and running with Herd quickly to run your first trail. ## What is Herd? Herd connects AI Agents to websites using your own browser credentials. It enables you to: - **Run Trails** - pre-built automations for specific websites and tasks - **Extract data and interact with websites** using your logged-in browser sessions - **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude ## Quick Start ### 1. Install the Browser Extension Chrome Edge Brave ### 2. Register Your Browser After installing the extension: 1. Click the Herd icon in your browser toolbar 2. Sign in with your Herd account (or create one) 3. Name your device and register it ![Browser Registration](https://herd.garden/register-device.png) ### 3. Install the Herd SDK Install the Herd SDK using npm: ## npm Code (bash): npm install -g @monitoro/herd ## yarn Code (bash): yarn global add @monitoro/herd ## pnpm Code (bash): pnpm add -g @monitoro/herd ### 4. Run Your First Trail The browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out: Code (bash): herd trail run @herd/browser -a markdown -p '{"url": "https://example.com"}' That's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config: Code (json): { "mcpServers": { "browser": { "command": "herd", "args": [ "trail", "server", "@herd/browser" ] } } } ## For Developers You can also automate your browser with the Herd SDK. Connect to it with your AI agents or code: ## javascript Code (javascript): // Connect to your Herd device const client = new HerdClient('your-token'); await client.initialize(); const devices = await client.listDevices(); const device = devices[0]; // Create a new page and navigate const page = await device.newPage(); await page.goto("https://example.com"); // Extract data using simple selectors const data = await page.extract({ title: "h1", description: "p", link: "a" }); console.log("Extracted data:", data); ## python Code (python): from monitoro_herd import HerdClient # Connect to your Herd device client = HerdClient("your-token") await client.initialize() devices = await client.list_devices() device = devices[0] # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Extract data using simple selectors data = await page.extract({ "title": "h1", "description": "p", "link": "a" }) print("Extracted data:", data) ## What's Next? Now that you've run your first trail, you can: - [Explore available trails](/trails) - Browse pre-built trails for various websites - [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages - [Create your own trail](/docs/trails-automations) - Build and share your own custom trails ## Need Help? If you encounter any issues during setup: - Make sure your browser extension is correctly installed and you're signed in - Check that your device is registered in the [device dashboard](/devices) - Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions .browser-btn { display: inline-flex; align-items: center; padding: 0.2rem 1rem; background-color: #1f2937; color: white; border-radius: 0.375rem; font-size: 1.2rem; font-weight: 500; text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.1); } .browser-btn:hover { background-color: #374151; } == Document: Trails Automations URL: https://herd.garden/docs/trails-automations # Trails Trails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process. ## javascript Trails are fully supported in the JavaScript SDK. ## Creating a Trail A trail defines the following components: - **urls.ts**: Exports an array of URL definitions - **selectors.ts**: Exports an array of selector configurations - **actions.ts**: Exports action classes that implement the `TrailAction` interface A trail at the minimum has the following structure: Code: google-search/ urls.ts selectors.ts actions.ts package.json The `package.json` file defines the trail and its dependencies: Code (json): { "name": "google-search", "description": "Search google for webpages.", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } You should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code. ## Trail Implementation Guide ### Step 1: Set up the trail structure Create a new directory for your trail with the following files: Code: my-trail/ urls.ts selectors.ts actions.ts package.json Add the basic package.json configuration: Code (json): { "name": "my-trail", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } ### Step 2: Define URLs In `urls.ts`, export an array of URL definitions that your trail will interact with: Code (typescript): export default [{ "id": "my-url", "template": "https://example.com/path?param1={param1}&param2={param2}", "description": "Description of what this URL represents", "examples": [ { "param1": "value1", "param2": "value2" } ], "params": { "param1": { "type": "string", "required": true, "description": "Description of param1" }, "param2": { "type": "string", "required": false, "default": "defaultValue", "description": "Description of param2" } } }]; ### Step 3: Define Selectors In `selectors.ts`, export an array of selector configurations that define how to extract data from web pages: Code (typescript): export default [{ "id": "my-selector", "value": { "dataKey": { "_$r": "#main-container", "title": { "_
quot;: ".title" }, "description": { "_
quot;: ".description" }, "link": { "_
quot;: "a.link", "attribute": "href" } } }, "description": "Selector for extracting specific data", "examples": [ { "urlId": "my-url", "urlParams": { "param1": "value1", "param2": "value2" } } ] }]; ### Step 4: Implement Actions In `actions.ts`, define one or more action classes that implement the `TrailAction` interface: Code (typescript): import type { Device, TrailAction, TrailActionManifest, TrailRunResources } from "@monitoro/herd"; export class MyTrailAction implements TrailAction { manifest: TrailActionManifest = { name: "my-action", description: "Description of what this action does", params: { param1: { type: "string", description: "Description of param1" }, param2: { type: "number", description: "Description of param2", default: 10 } }, result: { type: "array", description: "Description of the result", items: { type: "object", properties: { property1: { type: "string" }, property2: { type: "number" } } } }, examples: [ { "param1": "value1", "param2": 10 } ] } async test(device: Device, params: Record, resources: TrailRunResources) { try { const result = await this.run(device, params, resources); // Validate result if (!result || result.length === 0) { return { status: "error", message: "No results found", result: [] }; } return { status: "success", result }; } catch (e) { return { status: "error", message: `Error: ${e}`, result: null }; } } async run(device: Device, params: Record, resources: TrailRunResources) { const { param1, param2 } = params; const page = await device.newPage(); try { // Navigate to URL using the URL template from urls.ts await page.goto(resources.url('my-url', { param1, param2 })); // Extract data using selectors from selectors.ts const extracted = await page.extract(resources.selector('my-selector')); // Process extracted data const results = (extracted as any)?.dataKey || []; // Return processed results return results; } finally { await page.close(); } } } ### Step 5: Testing and debugging Use the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest): Code (bash): herd trail test --action my-trail You can also watch for changes in the trail and re-run tests: Code (bash): herd trail test --action my-trail --watch # or herd trail test -a my-trail -w And you can also test selectors only: Code (bash): herd trail test --selector my-selector And watch for changes in the selectors: Code (bash): herd trail test --selector my-selector --watch # or herd trail test -s my-selector -w ### Step 6: Publish your trail Publishing is coming soon! ### Best Practices 1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc. 2. **Performance**: Minimize page loads and extract as much data as possible from each page. 3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain. 4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios. 5. **Versioning**: Increment your trail's version in package.json when making changes. ## python Trails support for Python SDK is coming soon. Stay tuned for updates! In the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them. ==

Document

llms-full.txt

Open llms-full.txt
Herd Documentation
================================================================================

Document: Alternative Herd Vs Apify
URL: https://herd.garden/docs/alternative-herd-vs-apify

# Herd vs Apify: A Cost-Effective Alternative for Web Automation

Apify is a popular platform for web scraping and automation, but its cloud-based infrastructure can be costly and limiting. Herd offers a compelling alternative with similar capabilities but a fundamentally different approach that eliminates infrastructure costs and provides more control over your automation.

## Quick Comparison

| Feature | Herd | Apify |
| --- | --- | --- |
| **Primary Focus** | Browser automation & web scraping | Web scraping platform with cloud infrastructure |
| **Infrastructure** | Uses your existing browser | Cloud-based platform with managed instances |
| **Pricing Model** | Flat rate subscription | Usage-based pricing |
| **Browser Control** | Direct control of your browser | Remote control of cloud browsers |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome/Chromium in cloud |
| **Setup Required** | Simple browser extension | No browser setup (cloud-based) |
| **Authentication** | Uses existing browser sessions | Requires manual setup |
| **Data Extraction** | Built-in extraction tools | Various actor-based extraction tools |
| **Resource Usage** | Minimal (shared with browser) | Separate cloud resources (higher cost) |
| **Customization** | Full control of local environment | Limited to platform capabilities |

## Key Differences in Depth

### Infrastructure and Pricing Model

**Apify:**
- Cloud-based platform with usage-based pricing
- Costs scale with computation time and resource usage
- Requires paid proxy services for many use cases
- Monthly subscription plus usage-based fees

**Herd:**
- Uses your existing browser and computer
- No cloud infrastructure required
- Direct control of your local resources 
- Supports Chrome, Edge, Brave, Arc, Opera
- No additional infrastructure costs
- No separate compute units to pay for
- Simple and predictable pricing

### Browser Control and Authentication

**Apify:**
- Operates browsers in the cloud
- Must manually set up authentication flows
- Sessions are isolated and temporary
- Limited access to browser-specific features

**Herd:**
- Direct control of your own browser
- Uses your existing authenticated sessions
- Persistent cookies and storage between runs
- Full access to browser capabilities and extensions

### Setup and Customization

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Simple setup code
import { HerdClient } from '@monitoro/herd';

// Connect to your own browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

## apify

Code (javascript):
// Install the Apify SDK
npm install apify

// Create an actor
import { Actor } from 'apify';

// Run in Apify cloud environment
await Actor.init();

// Launch a browser in the cloud
const browser = await Actor.launchPuppeteer();
const page = await browser.newPage();
await page.goto('https://example.com');

// Must manually handle stopping the actor
await Actor.exit();

### Data Extraction Capabilities

**Apify:**
- Offers pre-built actors for common websites
- Large marketplace of ready-made solutions
- Extraction limited to what actors provide
- Can become expensive for large-scale extraction

**Herd:**
- Powerful built-in extraction API
- Simple selector-based data retrieval
- Access to authenticated content
- Extract data without usage limits

## Use Case Comparisons

### Web Scraping with Authentication

## herd-auth

Code (javascript):
// Using Herd with an already authenticated browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Access a site where you're already logged in
const page = await device.newPage();
await page.goto('https://account.example.com/dashboard');

// Extract authenticated data directly
const userData = await page.extract({
  username: '.user-profile .username',
  accountType: '.account-type',
  balance: '.account-balance',
  transactions: {
    _$r: '.transaction-item',
    date: '.transaction-date',
    amount: '.transaction-amount',
    description: '.transaction-description'
  }
});

console.log(userData);
await client.close();

## apify-auth

Code (javascript):
// Using Apify with manual authentication
import { Actor } from 'apify';

await Actor.init();
const browser = await Actor.launchPuppeteer();
const page = await browser.newPage();

// Need to manually log in first
await page.goto('https://example.com/login');
await page.type('#username', 'your-username');
await page.type('#password', 'your-password');
await page.click('.login-button');
await page.waitForNavigation();

// Now navigate to the dashboard
await page.goto('https://account.example.com/dashboard');

// Extract data with multiple evaluations
const username = await page.$eval('.user-profile .username', el => el.textContent);
const accountType = await page.$eval('.account-type', el => el.textContent);
const balanceText = await page.$eval('.account-balance', el => el.textContent);
const balance = parseFloat(balanceText.replace(/[^0-9.-]+/g, ''));

// Extract transaction data
const transactions = await page.$eval('.transaction-item', items => 
  items.map(item => ({
    date: item.querySelector('.transaction-date').textContent,
    amount: item.querySelector('.transaction-amount').textContent,
    description: item.querySelector('.transaction-description').textContent
  }))
);

const userData = {
  username,
  accountType,
  balance,
  transactions
};

console.log(userData);
await Actor.exit();

### Multi-Page Crawling

## herd-crawl

Code (javascript):
// Using Herd for multi-page crawling
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Collect all product links first
const productLinks = await page.extract({
  links: {
    _$r: '.product-card a',
    url: { attribute: 'href' }
  }
});

// Visit each product page and extract details
const products = [];
for (const { url } of productLinks.links) {
  await page.goto(url);
  
  const productData = await page.extract({
    name: '.product-name',
    price: '.product-price',
    description: '.product-description',
    specs: {
      _$r: '.spec-item',
      name: '.spec-name',
      value: '.spec-value'
    }
  });
  
  products.push(productData);
}

console.log(products);
await client.close();

## apify-crawl

Code (javascript):
// Using Apify for multi-page crawling
import { Actor, PuppeteerCrawler } from 'apify';

await Actor.init();

// Define the crawler
const crawler = new PuppeteerCrawler({
  async requestHandler({ request, page }) {
    console.log(`Processing ${request.url}...`);
    
    if (request.userData.detailPage) {
      // Extract product details
      const productData = {
        url: request.url,
        name: await page.$eval('.product-name', el => el.textContent),
        price: await page.$eval('.product-price', el => el.textContent),
        description: await page.$eval('.product-description', el => el.textContent),
        specs: await page.$eval('.spec-item', items => 
          items.map(item => ({
            name: item.querySelector('.spec-name').textContent,
            value: item.querySelector('.spec-value').textContent
          }))
        )
      };
      
      // Save the extracted data
      await Actor.pushData(productData);
    } else {
      // On the listing page, extract links to products
      const productLinks = await page.$eval('.product-card a', links => 
        links.map(link => link.href)
      );
      
      // Enqueue product detail pages
      for (const url of productLinks) {
        await crawler.requestQueue.addRequest({
          url,
          userData: { detailPage: true }
        });
      }
    }
  },
  maxRequestsPerCrawl: 100,
});

// Start with the product listing page
await crawler.run(['https://example.com/products']);

await Actor.exit();

## Migration Guide: From Apify to Herd

Transitioning from Apify to Herd is straightforward. Here's a guide to help you migrate:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   npm install @monitoro/herd

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Apify | Herd | Notes |
| --- | --- | --- |
| `Actor.init()` | `const client = new HerdClient(apiUrl, token)`  `await client.initialize()` | Herd uses a simple client-server model |
| `Actor.launchPuppeteer()` | `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `browser.newPage()` | `await device.newPage()` | Similar API |
| `page.goto(url)` | `await page.goto(url)` | Identical usage |
| `page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd has a more powerful extraction API |
| `Actor.pushData(data)` | Store data directly in your code | No platform-specific storage |
| `Actor.exit()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Handling Authentication

**Apify:**

Code (javascript):
// Manual login process
await page.goto('https://example.com/login');
await page.type('#username', 'user');
await page.type('#password', 'pass');
await page.click('#login-button');

**Herd:**

Code (javascript):
// Simply use your already authenticated browser
await page.goto('https://example.com/dashboard');  // Already logged in

## Why Choose Herd Over Apify?

### 1. Cost Efficiency

Herd eliminates the need for cloud infrastructure, resulting in:
- No usage-based computation costs
- No proxy costs for most use cases
- Significant cost savings for regular automation
- Predictable pricing independent of usage volume

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to handle authentication flows in code
- Access to sites with complex auth (2FA, CAPTCHA)
- Use existing cookies, local storage, and sessions

### 3. Local Control and Privacy

Herd provides:
- Full control over the automation environment
- Higher privacy (data stays on your machine)
- Direct access to local resources when needed
- No dependence on third-party cloud infrastructure

### 4. Simpler Development Experience

Herd offers:
- More intuitive APIs for common tasks
- Real-time debugging in your browser
- No need to deploy or manage cloud resources
- Faster iteration during development

## Get Started with Herd Today

Ready to try a more flexible alternative to Apify? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide all the capabilities you need for web automation and scraping at a fraction of the cost of cloud-based solutions like Apify.

================================================================================

Document: Alternative Herd Vs Browserbase
URL: https://herd.garden/docs/alternative-herd-vs-browserbase

# Herd vs Browserbase: No-Infrastructure Browser Automation

Browserbase provides cloud-based headless browsers for automation and AI applications. While it offers a reliable platform for running browser instances, Herd takes a fundamentally different approach by leveraging your existing browsers, eliminating infrastructure costs and complexity.

## Quick Comparison

| Feature | Herd | Browserbase |
| --- | --- | --- |
| **Browser Location** | Your local machine | Cloud-based infrastructure |
| **Infrastructure Needed** | None (uses your browser) | Managed cloud infrastructure |
| **Pricing Model** | Flat subscription | Usage-based pricing |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium in cloud |
| **Latency** | Minimal (1-hop) | Higher (multiple hops) |
| **Authentication** | Uses existing browser sessions | Requires manual setup |
| **Framework Support** | JavaScript/Python SDKs | Stagehand, Playwright, Puppeteer, Selenium |
| **Setup Required** | Browser extension installation | No installation (cloud-based) |
| **Resource Constraints** | Depends on local resources | Limited by pricing tier |

## Key Differences in Depth

### Infrastructure and Cost Model

**Browserbase:**
- Runs browsers on managed cloud infrastructure
- Costs scale with usage and session duration
- Requires networking between your code and cloud
- Additional costs for premium features like proxies

**Herd:**
- Uses browsers already installed on your machine
- No cloud infrastructure required
- Direct access to your local machine resources
- Supports Chrome, Edge, Brave, Arc, Opera
- Fixed, predictable pricing not tied to usage
- Local execution with minimal network overhead
- No additional infrastructure costs to manage

### Setup and Integration

## herd

Code (javascript):
// Simple installation - no code required
// 1. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox/Safari not supported)
// 2. Connect your browser to Herd

// Simple connection to your browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a new page
const page = await device.newPage();
await page.goto('https://example.com');

## browserbase

Code (javascript):
// Install the SDK
npm install browserbase

// Connect to cloud infrastructure
import { Browserbase } from 'browserbase';

const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create a session on cloud infrastructure
const session = await bb.sessions.create({
  timeout: 60, // Session timeout in seconds
});

// Create a page in the cloud browser
const page = await session.newPage();
await page.goto('https://example.com');

### Session Management and Performance

**Browserbase:**
- Cloud-based sessions with timeout limits
- Performance dependent on cloud resources and network
- Sessions isolated from local environment
- Must explicitly manage session lifecycle

**Herd:**
- Direct access to local browser sessions
- Local performance without network latency
- Integrated with your local environment
- Sessions persist with your browser

### Authentication and User Context

**Browserbase:**
- Requires implementing authentication for each session
- Isolated sessions without access to existing cookies
- Must manually handle login flows
- Credentials need to be stored and managed

**Herd:**
- Uses your browser's existing authenticated sessions
- Access to all cookies, local storage, and session data
- No need to implement authentication flows
- Use sites you're already logged into

## Use Case Comparisons

### Web Automation for Logged-in Services

## herd-auth

Code (javascript):
// Using Herd with pre-authenticated browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Directly access authenticated service
const page = await device.newPage();
await page.goto('https://app.example.com/dashboard');  // Already logged in

// Perform actions on authenticated page
await page.click('.create-new-button');
await page.type('#item-name', 'New Item');
await page.click('.save-button');

// Verify result
const confirmationText = await page.$eval('.confirmation', el => el.textContent);
console.log(confirmationText);

## browserbase-auth

Code (javascript):
// Using Browserbase with manual authentication
const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create cloud browser session
const session = await bb.sessions.create({
  timeout: 300,  // Longer timeout for auth flow
});

// Create page and handle login manually
const page = await session.newPage();

// Navigate to login page
await page.goto('https://app.example.com/login');

// Fill login form
await page.type('#email', 'user@example.com');
await page.type('#password', 'your-secure-password');
await page.click('#login-button');

// Wait for login to complete
await page.waitForNavigation();

// Now navigate to dashboard
await page.goto('https://app.example.com/dashboard');

// Perform actions on authenticated page
await page.click('.create-new-button');
await page.type('#item-name', 'New Item');
await page.click('.save-button');

// Verify result
const confirmationText = await page.$eval('.confirmation', el => el.textContent);
console.log(confirmationText);

// Must explicitly end session
await session.close();

### Data Extraction at Scale

## herd-extract

Code (javascript):
// Using Herd for data extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Open multiple pages for parallel extraction
const pages = await Promise.all([1, 2, 3].map(() => device.newPage()));

// Extract data from multiple sources in parallel
const results = await Promise.all(pages.map(async (page, index) => {
  await page.goto(`https://example.com/category/${index+1}`);
  
  // Use Herd's extraction API
  const data = await page.extract({
    categoryName: '.category-header h1',
    items: {
      _$r: '.product-item',
      title: '.product-title',
      price: '.product-price',
      rating: '.rating-value'
    }
  });
  
  return data;
}));

// Close pages when done
await Promise.all(pages.map(page => page.close()));
await client.close();

console.log(results);

## browserbase-extract

Code (javascript):
// Using Browserbase for data extraction
const bb = new Browserbase({
  api_key: 'your-api-key'
});

// Create separate sessions for parallel extraction
const sessions = await Promise.all([1, 2, 3].map(() => 
  bb.sessions.create({ timeout: 120 })
));

// Extract data from multiple sources
const results = await Promise.all(sessions.map(async (session, index) => {
  const page = await session.newPage();
  await page.goto(`https://example.com/category/${index+1}`);
  
  // Extract data using Puppeteer-style selectors
  const categoryName = await page.$eval('.category-header h1', el => el.textContent);
  
  const itemElements = await page.$('.product-item');
  const items = [];
  
  for (const element of itemElements) {
    const title = await element.$eval('.product-title', el => el.textContent);
    const price = await element.$eval('.product-price', el => el.textContent);
    
    let rating = null;
    try {
      rating = await element.$eval('.rating-value', el => el.textContent);
    } catch (e) {
      // Element might not exist
    }
    
    items.push({ title, price, rating });
  }
  
  // Must close session when done
  await session.close();
  
  return { categoryName, items };
}));

console.log(results);

## Migration Guide: From Browserbase to Herd

Transitioning from Browserbase to Herd is straightforward. Here's a guide to help you migrate:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Browserbase | Herd | Notes |
| --- | --- | --- |
| `new Browserbase({ api_key })` | `new HerdClient(apiUrl, token)`  `await client.initialize()` | Herd uses a client-server architecture |
| `bb.sessions.create()` | `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `session.newPage()` | `await device.newPage()` | Similar API |
| `await page.goto(url)` | `await page.goto(url)` | Identical usage |
| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |
| `await page.click(selector)` | `await page.click(selector)` | Identical usage |
| `await page.$eval(selector, fn)` | `await page.extract({ key: selector })` | Herd offers a more powerful extraction API |
| `await session.close()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Framework Integration

**Browserbase:**

Code (javascript):
// Browserbase with Playwright
const { chromium } = require('playwright');
const browser = await chromium.connectOverCDP(session.wsEndpoint);
const page = await browser.newPage();

**Herd:**

Code (javascript):
// Herd uses its own API directly
const page = await device.newPage();
// Direct integrations with testing frameworks available

## Why Choose Herd Over Browserbase?

### 1. No Cloud Infrastructure Required

Herd eliminates the need for cloud infrastructure, providing:
- Zero dependency on remote browser instances
- No need to manage cloud resources
- Reduced latency with local execution
- Complete isolation from cloud service disruptions

### 2. Cost Predictability and Efficiency

Herd offers a more predictable and often lower cost:
- No usage-based billing surprises
- No charges based on session duration
- No additional costs for scaling automation
- Fixed costs regardless of automation volume

### 3. Use Existing Browser State and Auth

With Herd, you can leverage your browser's existing state:
- Use sites you're already logged into
- Access to all browser extensions
- Utilize stored passwords and authentication
- No need to manage credentials in code

### 4. Lower Latency and Higher Performance

Herd provides performance advantages with local execution:
- No network latency between code and browser
- Faster execution of automation tasks
- Direct access to local resources
- No timeout limitations on sessions

## Get Started with Herd Today

Ready to try a more flexible alternative to Browserbase? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide all the capabilities you need for web automation without the complexity and costs of cloud-based infrastructure.

================================================================================

Document: Alternative Herd Vs Firecrawl
URL: https://herd.garden/docs/alternative-herd-vs-firecrawl

# Herd vs Firecrawl: Flexible Browser Automation and Data Extraction

Firecrawl is a specialized web scraping and crawling tool designed primarily for extracting and cleaning web content, especially for use with LLMs. While Firecrawl offers powerful crawling capabilities, Herd provides a more comprehensive browser automation solution with greater flexibility and control over the browsing experience.

## Quick Comparison

| Feature | Herd | Firecrawl |
| --- | --- | --- |
| **Primary Focus** | Complete browser automation | Web crawling and content extraction |
| **Infrastructure** | Uses your existing browser | Cloud-based crawling infrastructure |
| **Pricing Model** | Flat subscription | Usage-based pricing |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Managed cloud browsers |
| **Browser Control** | Full interactive browser control | Limited to crawling and extraction |
| **Authentication** | Uses existing browser sessions | Limited authentication capabilities |
| **Content Processing** | Raw and structured data extraction | Optimized for clean text/markdown output |
| **Usage Flexibility** | General-purpose automation | Specialized for content crawling |
| **Interactive Workflows** | Supports complex interactions | Limited to extraction patterns |

## Key Differences in Depth

### Primary Focus and Capabilities

**Firecrawl:**
- Specialized in high-quality web content extraction
- Optimized for converting websites to clean markdown
- Focused on crawling through website links
- Built primarily for LLM data ingestion
- Limited interactive capabilities

**Herd:**
- Complete browser automation platform
- Full interactive control of browser actions
- Supports Chrome, Edge, Brave, Arc, Opera
- Supports both data extraction and automation workflows
- General-purpose browser control
- Rich interaction with web applications

### Infrastructure and Execution Model

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Connect to your existing browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Full browser automation capabilities
const page = await device.newPage();
await page.goto('https://example.com');

## firecrawl

Code (javascript):
// Install the Firecrawl SDK
npm install @mendable/firecrawl-js

// Connect to Firecrawl's cloud service
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Send request to cloud-based crawling service
const result = await app.scrapeUrl('example.com');
console.log(result.markdown);

### Data Extraction Approaches

**Firecrawl:**
- Specializes in converting HTML to clean markdown
- Automatically handles JavaScript rendering
- Built-in content cleaning and formatting
- Output optimized for LLM consumption
- Limited customization of extraction patterns

**Herd:**
- Flexible data extraction patterns
- CSS selector-based extraction
- Support for complex nested data structures
- Raw data access and custom transformations
- Complete control over extraction logic

## Use Case Comparisons

### Website Content Extraction

## herd-extract

Code (javascript):
// Using Herd for content extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/article');

// Extract structured content with control over the format
const articleData = await page.extract({
  title: '.article-title',
  author: '.author-name',
  published: {
    _$: '.publish-date',
    pipes: ['parseDate']
  },
  content: '.article-body',
  tags: {
    _$r: '.tag',
    text: ':root'
  }
});

console.log(articleData);
await client.close();

## firecrawl-extract

Code (javascript):
// Using Firecrawl for content extraction
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Simple URL-based extraction
const scrapeResult = await app.scrapeUrl('https://example.com/article');

if (scrapeResult.success) {
  // Get the clean markdown content
  console.log(scrapeResult.markdown);
  
  // Access metadata
  console.log(scrapeResult.metadata);
} else {
  console.error('Failed to scrape:', scrapeResult.error);
}

### Interactive Web Automation

## herd-automation

Code (javascript):
// Using Herd for interactive web automation
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();

// Navigate to a web application
await page.goto('https://app.example.com/dashboard');

// Fill out a form
await page.click('.create-new-button');
await page.type('#title-input', 'New Project');
await page.type('#description-input', 'This is a test project created by automation');
await page.select('#category-select', 'development');

// Upload a file
const fileInput = await page.$('input[type="file"]');
await fileInput.uploadFile('/path/to/local/file.pdf');

// Submit the form
await page.click('.submit-button');

// Wait for confirmation and extract result
await page.waitForSelector('.success-message');
const confirmationText = await page.$eval('.success-message', el => el.textContent);
console.log('Form submitted successfully:', confirmationText);

await client.close();

## firecrawl-automation

Code (javascript):
// Firecrawl has limited interactive capabilities
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// For interactive tasks like form submission, 
// Firecrawl has limited capabilities, primarily focused
// on crawling and content extraction.

// You could use the actions feature for limited interactions:
const result = await app.scrapeUrl('https://app.example.com', {
  actions: [
    { type: 'click', selector: '.login-button' },
    { type: 'wait', time: 2000 }
    // Limited set of basic actions available
  ]
});

// But complex workflows like file uploads or 
// multi-step interactions require a more 
// comprehensive automation tool like Herd

### Multi-Page Crawling

## herd-crawl

Code (javascript):
// Using Herd for custom crawling
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Extract all product links
const productLinks = await page.extract({
  links: {
    _$r: '.product-card a',
    url: { attribute: 'href' }
  }
});

// Custom crawling logic with full control
const productDetails = [];
for (const { url } of productLinks.links) {
  // Navigate to each product page
  await page.goto(url);
  
  // Extract detailed information
  const product = await page.extract({
    name: '.product-name',
    price: '.product-price',
    description: '.product-description',
    inStock: '.stock-status'
  });
  
  productDetails.push(product);
  
  // You can implement custom logic: only continue if conditions are met
  if (productDetails.length >= 10) break;
}

console.log(productDetails);
await client.close();

## firecrawl-crawl

Code (javascript):
// Using Firecrawl for website crawling
import FirecrawlApp from '@mendable/firecrawl-js';

const app = new FirecrawlApp({ apiKey: "fc-YOUR_API_KEY" });

// Crawl an entire site
const crawlResult = await app.crawlWebsite('example.com', {
  maxPages: 10,  // Limit the crawl
  includeSitemap: true, // Use sitemap if available
  followExternalLinks: false // Stay on the same domain
});

if (crawlResult.success) {
  // Access all crawled pages
  for (const page of crawlResult.pages) {
    console.log(`Page: ${page.url}`);
    console.log(`Content: ${page.markdown}`);
  }
} else {
  console.error('Crawl failed:', crawlResult.error);
}

## Migration Guide: From Firecrawl to Herd

Transitioning from Firecrawl to Herd is straightforward. Here's a guide to help you migrate:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Firecrawl | Herd | Notes |
| --- | --- | --- |
| `new FirecrawlApp({ apiKey })` | `new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `app.scrapeUrl(url)` | `const page = await device.newPage()`  `await page.goto(url)`  `const data = await page.extract(...)` | More granular control in Herd |
| `result.markdown` | Custom extraction patterns with formatting | More flexible data extraction options |
| `app.crawlWebsite(domain)` | Custom crawling logic implemented with Herd's navigation and extraction APIs | Full control over crawling behavior |

### 3. Implementing Markdown Conversion

If you specifically need markdown output like Firecrawl provides:

Code (javascript):
// Helper function to convert extracted HTML to markdown
function htmlToMarkdown(html) {
  // Use a library like turndown
  const turndownService = new TurndownService();
  return turndownService.turndown(html);
}

// Extract with Herd and convert to markdown
const content = await page.extract({
  body: {
    _$: '.article-content',
    attribute: 'innerHTML'
  }
});

## Why Choose Herd Over Firecrawl?

### 1. Comprehensive Browser Control

Herd provides full browser automation capabilities:
- Complete interactive control beyond just crawling
- Support for complex user interactions
- Ability to automate any browser-based workflow
- Full access to browser APIs and capabilities

### 2. Flexible Authentication and Sessions

Herd's approach offers significant authentication advantages:
- Use your existing authenticated browser sessions
- No need to implement login flows
- Support for complex authentication scenarios
- Access to secure content without credential management

### 3. Customizable Extraction and Processing

Herd gives you complete control over data extraction:
- Custom extraction patterns for any website structure
- Flexible transformation of extracted data
- Support for complex nested data extraction
- Processing options beyond just markdown conversion

### 4. Broader Use Case Support

Herd supports a wider range of automation scenarios:
- Form submission and interactive workflows
- File uploads and downloads
- Conditional logic based on page content
- Testing and verification workflows

## Get Started with Herd Today

Ready to try a more flexible alternative to Firecrawl? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can provide enhanced capabilities for both content extraction and browser automation, giving you more control and flexibility than specialized crawling tools like Firecrawl.

================================================================================

Document: Alternative Herd Vs Mcp Sdk
URL: https://herd.garden/docs/alternative-herd-vs-mcp-sdk

# Herd vs MCP SDK: Streamlined Browser Automation

The Model Context Protocol (MCP) SDK provides browser automation capabilities primarily focused on AI agent integration. While MCP SDK offers powerful integration with Large Language Models, Herd provides a more accessible and straightforward approach to browser automation with simplified setup and direct browser control.

## Quick Comparison

| Feature | Herd | MCP SDK |
| --- | --- | --- |
| **Primary Focus** | General browser automation | AI agent browser automation |
| **Infrastructure** | Uses your existing browser | Requires separate browser setup |
| **API Design** | Simple, direct browser control | Protocol-oriented architecture |
| **Integration** | JavaScript/Python SDKs | Multiple languages supported |
| **Setup Complexity** | Simple browser extension | More complex server configuration |
| **Authentication** | Uses existing browser sessions | Requires manual configuration |
| **Learning Curve** | Shallow, familiar browser API | Steeper with protocol concepts |
| **Use Cases** | General automation and extraction | AI agent browsing tasks |

## Key Differences in Depth

### Focus and Architecture

**MCP SDK:**
- Designed primarily for AI model integration
- Protocol-based communication model
- Server-client architecture
- Focus on enabling AI agents to browse
- More complex protocol implementation

**Herd:**
- Direct browser automation focus
- Simple client-browser connection
- Intuitive API design
- Supports Chrome, Edge, Brave, Arc, Opera
- Streamlined API for common tasks
- Designed for developers first
- Lower implementation complexity

### Setup and Integration

## herd

Code (javascript):
// Install the Herd SDK
npm install @monitoro/herd

// Simple direct connection to your browser
import { HerdClient } from '@monitoro/herd';

const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

## mcp

Code (javascript):
// Install MCP SDK
npm install mcp-browser-automation

// Set up the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({
  port: 8000,
  // Additional configuration for the server
});

// Start the server
await server.start();

// Client side needs to implement MCP protocol
// to communicate with the server

// Then through MCP protocol interactions:
// 1. Create a browser session
// 2. Navigate to URL
// 3. Interact with page

### Integration with AI Systems

**MCP SDK:**
- Designed specifically for AI model integration
- Protocol-based approach for AI agents
- Built to enable AI systems to browse the web
- Complex implementation for general use cases
- Strong focus on AI agent capabilities

**Herd:**
- General-purpose browser automation
- Can be integrated with AI systems through standard APIs
- Simpler implementation for most use cases
- Direct browser control paradigm
- Focus on developer experience and simplicity

## Use Case Comparisons

### Basic Web Automation

## herd-auto

Code (javascript):
// Using Herd for basic web automation
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a new page
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com/login');

// Fill login form
await page.type('#username', 'test_user');
await page.type('#password', 'password123');
await page.click('.login-button');

// Wait for navigation and verify login
await page.waitForSelector('.dashboard');
const welcomeText = await page.$eval('.welcome-message', el => el.textContent);
console.log('Login successful:', welcomeText);

await client.close();

## mcp-auto

Code (javascript):
// Using MCP SDK for basic web automation
// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// For client-side interaction, implement the MCP protocol
// This is a simplified example showing the concept
const response = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'createSession',
    params: {}
  })
});
const { sessionId } = await response.json();

// Navigate to a website
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'navigate',
    sessionId,
    params: { url: 'https://example.com/login' }
  })
});

// Fill login form (multiple requests needed)
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'type',
    sessionId,
    params: { selector: '#username', text: 'test_user' }
  })
});

// Additional requests for password and clicking login button
// ...

// MCP SDK is more verbose for simple automation tasks
// and requires protocol knowledge

### Data Extraction Tasks

## herd-extract

Code (javascript):
// Using Herd for data extraction
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

const page = await device.newPage();
await page.goto('https://example.com/products');

// Extract data using Herd's powerful extraction API
const productData = await page.extract({
  title: '.page-title',
  products: {
    _$r: '.product-item',  // Repeat for all products
    name: '.product-name',
    price: '.product-price',
    rating: '.rating-stars',
    available: '.stock-status'
  }
});

console.log(productData);
await client.close();

## mcp-extract

Code (javascript):
// Using MCP SDK for data extraction
// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// For client-side extraction, implement the MCP protocol
// This is a simplified example showing the concept
const response = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'createSession',
    params: {}
  })
});
const { sessionId } = await response.json();

// Navigate to the products page
await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'navigate',
    sessionId,
    params: { url: 'https://example.com/products' }
  })
});

// Extract the page title
const titleResponse = await fetch('http://localhost:8000/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    action: 'evaluate',
    sessionId,
    params: { 
      script: "document.querySelector('.page-title').textContent" 
    }
  })
});
const { result: title } = await titleResponse.json();

// Extract product data would require more complex script execution
// or multiple requests to get all the product information
// ...

// MCP SDK requires more complex orchestration for data extraction
// compared to Herd's simplified extraction API

### AI Integration

## herd-ai

Code (javascript):
// Using Herd with AI integration
// First, set up Herd client as usual
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Create a function to handle AI requests for web content
async function fetchWebContentForAI(url, query) {
  const page = await device.newPage();
  await page.goto(url);
  
  // Extract relevant content based on the AI query
  const content = await page.extract({
    title: 'h1',
    mainContent: '.main-content',
    relevantSections: {
      _$r: '.content-section',
      heading: 'h2',
      text: 'p'
    }
  });
  
  // Close the page when done
  await page.close();
  
  // Return the content for AI processing
  return content;
}

// Example usage with an AI system
const aiPrompt = "Summarize the information about machine learning from example.com";
const url = "https://example.com/machine-learning";

// Get the content for the AI
const webContent = await fetchWebContentForAI(url, "machine learning");

// Feed the content to the AI system
const aiResponse = await callAISystem(aiPrompt, webContent);
console.log(aiResponse);

await client.close();

// This pattern keeps the AI integration simple and separate from
// the browser automation concerns

## mcp-ai

Code (javascript):
// Using MCP SDK with AI integration
// MCP is specifically designed for this use case

// First, set up and start the MCP server
const { MCPServer } = require('mcp-browser-automation');
const server = new MCPServer({ port: 8000 });
await server.start();

// This server can now be used by AI agents through the MCP protocol
console.log('MCP Browser Automation server is running on port 8000');

// When an AI system wants to browse, it would send requests like:
/*
{
  "action": "createSession",
  "params": {}
}
*/

// And receive responses like:
/*
{
  "sessionId": "session123",
  "status": "success"
}
*/

// The AI can then navigate, interact with pages, and extract content
// through the MCP protocol

// This architecture is optimized for AI systems that implement
// the MCP protocol, but requires more complex integration
// than direct SDK usage like Herd offers

## Migration Guide: From MCP SDK to Herd

Transitioning from MCP SDK to Herd simplifies your browser automation code. Here's a migration guide:

### Installation Steps

1. [Sign up for a Herd account](/register)
2. Install the Herd browser extension in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| MCP SDK | Herd | Notes |
| --- | --- | --- |
| MCP server setup | `new HerdClient(apiUrl, token)`  `await client.initialize()` | No server needed with Herd |
| Session creation via protocol | `const devices = await client.listDevices()`  `const device = devices[0]` | Simplified session management |
| Navigation requests | `const page = await device.newPage()`  `await page.goto(url)` | Direct browser control |
| Element interactions via protocol | `await page.click(selector)`  `await page.type(selector, text)` | Simpler interaction API |
| Data extraction with custom scripts | `await page.extract(selectors)` | Powerful extraction API |
| Session closing via protocol | `await client.close()` | Simple cleanup |

### 3. AI Integration Approach

**MCP SDK:**

Code (javascript):
// AI systems implement MCP protocol directly
// Complex integration but designed for AI

// AI system would send requests like:
const request = {
  action: "evaluateElement",
  params: { selector: ".content", attribute: "textContent" }
};
// And process responses

**Herd:**

Code (javascript):
// Build an adapter layer for AI integration
async function getWebContent(url, aiQuery) {
  // Use Herd to fetch and extract the content
  const page = await device.newPage();
  await page.goto(url);
  const content = await page.extract({ /* ... */ });
  await page.close();
  return content;
}

// Then use this in your AI system
const content = await getWebContent(url, query);
const aiResponse = await yourAISystem.process(content);

### 4. Simpler Setup

Herd simplifies your automation workflow:

- No need to run a server process
- Uses your existing browser
- Simple browser extension rather than complex setup
- Supports Chrome, Edge, Brave, Arc, Opera
- Works with browsers you're already using every day

## Why Choose Herd Over MCP SDK?

### 1. Simpler Developer Experience

Herd provides a more straightforward approach to browser automation:
- No complex protocol implementation
- Direct browser control API
- Familiar programming model
- Lower learning curve

### 2. Less Infrastructure to Manage

Herd eliminates the need for additional infrastructure:
- No server to set up and maintain
- Uses your existing browser
- Simpler deployment architecture
- Fewer moving parts

### 3. Powerful Built-in Capabilities

Herd includes powerful features out of the box:
- Sophisticated data extraction API
- Session and cookie management
- Authentication handling
- Browser state persistence

### 4. Broader Applicability

While MCP SDK focuses on AI integration, Herd supports:
- General browser automation
- Web scraping and data extraction
- Testing and monitoring
- Process automation

## Get Started with Herd

Ready to try a more straightforward alternative to MCP SDK? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation tasks with its intuitive API and direct browser control, providing a more accessible alternative to protocol-based approaches like MCP SDK.

================================================================================

Document: Alternative Herd Vs Monitoro
URL: https://herd.garden/docs/alternative-herd-vs-monitoro

# Herd vs Monitoro: Complementary Browser Tools

Herd and Monitoro are sister products created by the same team, designed to serve complementary but distinct purposes. While Herd provides programmatic browser control and multi-browser orchestration capabilities, Monitoro focuses on no-code monitoring and data extraction. Understanding their differences helps you choose the right tool for your specific needs.

## Quick Comparison

| Feature | Herd | Monitoro |
| --- | --- | --- |
| **Primary Focus** | Browser automation & orchestration | Website monitoring & data extraction |
| **Core Function** | Programmatic browser control | Monitoring webpages for changes |
| **Target User** | Developers & automation teams | Non-technical users & business teams |
| **Coding Required** | Yes (JavaScript/Python) | No (visual interface) |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Edge, Brave |
| **Browser Orchestration** | Multiple browsers and devices | Single-focus monitoring |
| **Implementation** | JavaScript/Python SDK | No-code browser extension |
| **Data Processing** | Programmatic data workflows | Automated alerts and integrations |
| **Best For** | Complex automation needs | Monitoring & simple data extraction |

## Understanding the Difference

### Herd

Herd is designed for **programmatic browser control and orchestration**, allowing developers to:
- Automate complex web tasks across multiple browsers
- Extract data from websites at scale
- Leverage their existing browsers for automation
- Build persistent automation workflows
- Orchestrate multiple browser instances simultaneously
- Create sophisticated data processing pipelines
- Works with Chrome, Edge, Brave, Arc, Opera

### Monitoro

Monitoro is designed for **no-code webpage monitoring and alerts**, allowing anyone to:
- Track changes on websites without coding
- Set up alerts when specific data changes
- Extract structured data from webpages
- Send notifications to various channels (Slack, Discord, etc.)
- Create automated workflows based on webpage changes
- Integrate with tools like Google Sheets and Airtable

## When to Use Each Tool

## herd-use

**Use Herd when you need to:**

- Create complex automation scripts
- Orchestrate multiple browsers
- Build sophisticated data extraction pipelines
- Integrate browser automation into your application
- Control browsers programmatically
- Run continuous automation jobs
- Implement advanced web interaction patterns
- Scale automation across multiple devices

**Example use cases:**
- Large-scale data extraction projects
- Multi-step workflow automation
- Integration testing across browsers
- Sophisticated web monitoring systems
- Building browser-based APIs
- Authentication-required data access

## monitoro-use

**Use Monitoro when you need to:**

- Monitor websites for changes without coding
- Get alerts when specific data changes
- Extract data and send it to other tools
- Create simple automations based on website changes
- Set up monitoring dashboards
- Share monitoring alerts with teams

**Example use cases:**
- Price monitoring on e-commerce sites
- Tracking product availability
- Monitoring competitor websites
- Setting up alerts for new content
- Syncing web data to spreadsheets
- Creating webhooks for website changes

## Implementation Comparison

### Herd Implementation

## herd-js

Code (javascript):
// Using Herd for browser automation
import { HerdClient } from '@monitoro/herd';

// Initialize the client
const client = new HerdClient('your-token');
await client.initialize();

// Get a device
const devices = await client.listDevices();
const device = devices[0];

// Create a new page and automate it
const page = await device.newPage();
await page.goto('https://example.com');

// Interact with the page
await page.type('#search', 'automation');
await page.click('.search-button');

// Extract data
const results = await page.extract({
  titles: {
    _$r: '.result-item',
    title: '.item-title',
    description: '.item-description'
  }
});

console.log(results);
await client.close();

## herd-py

Code (python):
# Using Herd for browser automation
from monitoro_herd import HerdClient

# Initialize the client
client = HerdClient('your-token')
client.initialize()

# Get a device
devices = client.list_devices()
device = devices[0]

# Create a new page and automate it
page = device.new_page()
page.goto('https://example.com')

# Interact with the page
page.type('#search', 'automation')
page.click('.search-button')

# Extract data
results = page.extract({
  "titles": {
    "_$r": ".result-item",
    "title": ".item-title",
    "description": ".item-description"
  }
})

print(results)
client.close()

### Monitoro Implementation

Monitoro works through a no-code interface:

1. **Install the Monitoro browser extension**
2. **Create a monitor:**
   - Navigate to the webpage you want to monitor
   - Use the Monitoro interface to select elements to track
   - Set up conditions for when alerts should trigger
   - Configure how often the page should be checked

3. **Configure integrations:**
   - Connect to notification channels like Discord, Slack, or Telegram
   - Set up data destinations like Google Sheets or Airtable
   - Create webhooks for custom integrations

Code:
# No code required for Monitoro - it's all done through the visual interface

# Example monitoring workflow:
1. Set up a monitor for a product page on an e-commerce site
2. Configure it to check for price changes or "In Stock" status
3. Set up alerts to Discord when conditions are met
4. Configure Google Sheets integration to log all price changes

## Using Herd and Monitoro Together

These tools can work together in a complementary fashion:

1. **Use Monitoro for initial monitoring and alerts:**
   - Set up no-code monitors for important websites
   - Get alerted when specific changes occur
   - Collect initial data in spreadsheets

2. **Use Herd for advanced follow-up automation:**
   - Trigger Herd workflows based on Monitoro alerts
   - Perform complex interactions beyond Monitoro's capabilities
   - Extract deeper data that requires authentication or multiple steps
   - Orchestrate actions across multiple browsers

### Example workflow:

1. Monitoro monitors competitor pricing and alerts when prices change
2. A webhook from Monitoro triggers a Herd automation
3. Herd performs a deep analysis across multiple pages, including login-required areas
4. Herd generates a comprehensive report and updates internal systems

## When to Upgrade from Monitoro to Herd

Consider upgrading from Monitoro to Herd when:

1. You need to go beyond simple monitoring to complex automation
2. Your workflows require orchestration of multiple browsers
3. You need to access authenticated areas of websites
4. You require sophisticated data processing capabilities
5. You need programmatic control over browser behavior
6. Your team has development resources for coding solutions

## monitoro-simple

Code:
# Monitoro approach (no-code)

1. Set up a monitor for an e-commerce product page
2. Configure it to check price every hour
3. Send price alerts to Slack channel
4. Log all prices to Google Sheets

## herd-advanced

Code (javascript):
// Herd advanced solution

import { HerdClient } from '@monitoro/herd';

async function monitorPrices() {
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  // Open multiple pages for parallel extraction
  const productUrls = [
    'https://example.com/product/1',
    'https://example.com/product/2',
    'https://example.com/product/3'
  ];
  
  // Login first to access special pricing
  const page = await device.newPage();
  await page.goto('https://example.com/login');
  await page.type('#email', process.env.USERNAME);
  await page.type('#password', process.env.PASSWORD);
  await page.click('#login-button');
  await page.waitForNavigation();
  
  // Now check all products in parallel
  const priceData = [];
  for (const url of productUrls) {
    await page.goto(url);
    
    const data = await page.extract({
      productId: {
        _$: '.product-id',
        regex: 'ID: (.*)'
      },
      regularPrice: '.regular-price',
      salePrice: '.sale-price',
      memberPrice: '.member-price',
      availability: '.stock-status',
      shipping: '.shipping-info'
    });
    
    // Compare with historical data in database
    const priceChanged = await comparePriceWithHistory(data);
    if (priceChanged) {
      // Send custom notification with detailed info
      await sendDetailedAlert(data);
      // Update database with new price info
      await updatePriceDatabase(data);
    }
    
    priceData.push(data);
  }
  
  await client.close();
  return priceData;
}

// Run on schedule
setInterval(monitorPrices, 3600000); // Every hour

## Why Use Both Herd and Monitoro?

### 1. Complementary Capabilities

- **Monitoro:** Fast, no-code setup for basic monitoring needs
- **Herd:** Developer-focused tool for complex automation requirements

### 2. Different Team Members, Different Needs

- **Business Teams:** Can use Monitoro without technical skills
- **Developers:** Can use Herd for advanced customization
- **Operations:** Can set up Monitoro for quick insights
- **Engineering:** Can build on those insights with Herd

### 3. Staged Implementation

Monitoro and Herd support a natural progression:
- Start with simple Monitoro monitoring
- Identify areas that need deeper automation
- Implement targeted Herd solutions for those areas
- Maintain both for their distinct advantages

## Get Started with Herd and Monitoro

Ready to implement a complete browser automation and monitoring solution?

### For Herd:

1. [Create a Herd account](/register)
2. [Install the Herd browser extension](/docs/installation) in Chrome, Edge, or Brave (Firefox and Safari not supported)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

### For Monitoro:

1. Visit [Monitoro.co](https://monitoro.co) to sign up
2. Install the Monitoro browser extension
3. Navigate to the website you want to monitor
4. Use the visual interface to set up your first monitor

Choose the right tool for each specific need, or use them together for a comprehensive web monitoring and automation solution.

================================================================================

Document: Alternative Herd Vs Puppeteer
URL: https://herd.garden/docs/alternative-herd-vs-puppeteer

# Herd vs Puppeteer: A Better Alternative for Browser Automation

In the world of browser automation and web scraping, Puppeteer has long been a popular choice for developers. However, Herd provides a compelling alternative that addresses many of Puppeteer's limitations while offering unique advantages for modern development workflows.

## Quick Comparison

| Feature | Herd | Puppeteer |
| --- | --- | --- |
| **Browser Type** | Your existing browser | Separate Chromium instance |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chromium, Chrome (limited Firefox) |
| **Infrastructure Requirements** | None (uses your browser) | Requires separate browser instances |
| **Authentication** | Uses existing sessions | Requires manual setup |
| **Setup Complexity** | Simple extension installation | More complex setup |
| **Programming Languages** | JavaScript, Python | JavaScript/TypeScript only |
| **Session Management** | Persistent across runs | Must be rebuilt each run |
| **Resource Usage** | Minimal (shared with browser) | High (separate processes) |

## Key Differences in Depth

### Infrastructure Requirements

**Puppeteer:**
- Requires installing and managing separate Chromium instances
- Needs dedicated resources for each browser instance
- Increases infrastructure costs in cloud environments
- Requires managing updates to the Chromium engine

**Herd:**
- Uses your existing browser installation
- No additional browser instances to manage
- Significantly lower resource utilization
- Leverages native browser capabilities

### Setup and Installation Process

## herd

Code (bash):
# Install the Herd SDK
npm install @monitoro/herd

# Then install the browser extension and connect your browser
# That's it! No browser installation or management needed

## puppeteer

Code (bash):
# Install Puppeteer
npm install puppeteer

# Puppeteer will download and manage its own Chromium instance
# You'll need to handle this in deployment environments
# Additional setup for proxies, authentication, etc.

### Browser Support

**Puppeteer:**
- Primarily designed for Chrome/Chromium browsers
- Limited experimental support for Firefox
- No support for Safari or Edge

**Herd:**
- Works with Chrome, Edge, Brave, Arc, Opera 
- Consistent experience across all supported Chromium-based browsers

### Authentication and Session Handling

**Puppeteer:**
- Sessions must be recreated for each new Puppeteer instance
- Requires manually handling cookies and authentication flows
- Accessing logged-in state requires additional code
- Difficult to use existing authenticated sessions

**Herd:**
- Uses your existing browser's authenticated sessions
- No need to handle authentication separately
- Persistent cookies and storage between sessions
- Access to browser extensions that manage authentication

## Use Case Comparisons

### Data Extraction

## herd-extract

Code (javascript):
// Initialize the client and connect to your browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Extract data using simple selectors
const page = await device.newPage();
await page.goto('https://example.com');
const data = await page.extract({
  title: 'h1',
  description: 'p',
  links: {
    _$r: 'a',  // Extract all links
    href: { attribute: 'href' },
    text: ':root'
  }
});

console.log(data);

## puppeteer-extract

Code (javascript):
// Launch a separate browser instance
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');

// Extract data with multiple evaluations
const data = {
  title: await page.$eval('h1', el => el.textContent),
  description: await page.$eval('p', el => el.textContent),
  links: await page.$eval('a', elements => 
    elements.map(el => ({
      href: el.getAttribute('href'),
      text: el.textContent
    }))
  )
};

console.log(data);
await browser.close();

### Web Automation

## herd-auto

Code (javascript):
// Initialize and connect to your browser
const client = new HerdClient('your-token');
await client.initialize();
const devices = await client.listDevices();
const device = devices[0];

// Use the existing browser with current sessions
const page = await device.newPage();
await page.goto('https://myapp.com/dashboard'); // Already logged in

// Interact with the page
await page.click('.new-item-button');
await page.type('#item-name', 'New Task');
await page.click('.save-button');

// Process results
const notification = await page.waitForSelector('.success-message');
console.log(notification.textContent);

## puppeteer-auto

Code (javascript):
// Launch a separate browser instance
const browser = await puppeteer.launch();
const page = await browser.newPage();

// Need to handle login first
await page.goto('https://myapp.com/login');
await page.type('#username', 'user@example.com');
await page.type('#password', 'password');
await page.click('.login-button');
await page.waitForNavigation();

// Now navigate to dashboard after login
await page.goto('https://myapp.com/dashboard');

// Interact with the page
await page.click('.new-item-button');
await page.type('#item-name', 'New Task');
await page.click('.save-button');

// Process results
const notification = await page.waitForSelector('.success-message');
console.log(await notification.evaluate(el => el.textContent));
await browser.close();

## Migration Guide: From Puppeteer to Herd

Transitioning from Puppeteer to Herd is straightforward. Here's a simple migration guide:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   npm install @monitoro/herd

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Puppeteer | Herd | Notes |
| --- | --- | --- |
| `const browser = await puppeteer.launch()` | `const client = new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `const page = await browser.newPage()` | `const page = await device.newPage()` | Similar API, different source |
| `await page.goto(url)` | `await page.goto(url)` | Identical usage |
| `await page.type(selector, text)` | `await page.type(selector, text)` | Identical usage |
| `await page.click(selector)` | `await page.click(selector)` | Identical usage |
| `await page.$eval(selector, fn)` | `const element = await page.$(selector)`  `await element.evaluate(fn)` | Slightly different approach |
| `await page.screenshot()` | `await page.screenshot()` | Identical usage |
| `await browser.close()` | `await client.close()` | Browser stays open, just disconnects client |

## Why Choose Herd Over Puppeteer?

### 1. No Infrastructure Management

Herd eliminates the need to maintain separate browser instances, significantly reducing:
- Memory and CPU usage
- Infrastructure costs for cloud deployments
- Maintenance overhead for browser updates

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to handle authentication flows in code
- Access to sites that require complex authentication
- Use existing cookies, local storage, and sessions

### 3. Cross-Browser Compatibility

While Puppeteer is primarily focused on Chromium:
- Herd works across Chrome, Edge, and Brave
- Same code works on any supported browser
- Test on multiple browsers with minimal configuration changes

### 4. Simpler Development Experience

Herd provides:
- More intuitive APIs for common tasks
- Better debugging experience (view automation in real browser)
- Easier integration with existing workflows

## Get Started with Herd Today

Ready to try a better alternative to Puppeteer? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation workflows while reducing infrastructure costs and complexity.

================================================================================

Document: Alternative Herd Vs Selenium
URL: https://herd.garden/docs/alternative-herd-vs-selenium

# Herd vs Selenium: A More Efficient Browser Automation Alternative

Selenium has been the industry standard for browser automation for many years, but its architecture presents significant challenges for modern development workflows. Herd offers a compelling alternative that addresses many of Selenium's pain points while providing a more intuitive experience.

## Quick Comparison

| Feature | Herd | Selenium |
| --- | --- | --- |
| **Driver Requirements** | No drivers needed | Requires WebDriver for each browser |
| **Browser Type** | Your existing browser | Creates new browser instances |
| **Browser Support** | Chrome, Edge, Brave, Arc, Opera | Chrome, Firefox, Edge, Safari, IE |
| **Infrastructure** | Uses your existing browser | Requires WebDriver servers |
| **Authentication** | Uses existing sessions | Requires manual setup |
| **Programming Languages** | JavaScript, Python | Java, Python, C#, Ruby, JavaScript |
| **Setup Complexity** | Simple browser extension | WebDriver setup for each browser |
| **Maintenance Required** | Minimal (browser updates only) | High (drivers must match browser versions) |
| **Session Management** | Persistent across runs | Must be rebuilt each run |

## Key Differences in Depth

### Driver and Infrastructure Requirements

**Selenium:**
- Requires installation and management of WebDrivers for each browser
- WebDrivers must be kept in sync with browser versions
- Separate browser instances for automation
- Complex setup in CI/CD environments
- High resource usage (separate process for each browser)

**Herd:**
- No WebDrivers or separate drivers needed
- Works directly with your installed browser
- No version synchronization issues
- Simple setup in any environment
- Low resource usage (shares existing browser process)

### Setup and Installation Process

## herd

Code (bash):
# JavaScript
npm install @monitoro/herd

# Python
pip install herd-client

# Then install the browser extension and connect your browser
# That's it! No WebDrivers or browser drivers to manage

## selenium

Code (bash):
# JavaScript
npm install selenium-webdriver

# Python
pip install selenium

# Additionally, you must:
# 1. Download the correct WebDriver for each browser
# 2. Ensure WebDriver versions match browser versions
# 3. Add WebDrivers to your PATH or specify their location
# 4. Update WebDrivers when browsers update

### Browser Support and Consistency

**Selenium:**
- Supports all major browsers including Chrome, Firefox, Safari, Edge, and IE
- Requires separate WebDriver configurations for each browser
- May exhibit inconsistent behavior across different browsers
- Requires updates when browsers update

**Herd:**
- Supports Chrome, Edge, Brave, Arc, Opera
- Uniform behavior across supported Chromium-based browsers
- No additional configuration needed for different browsers

### Authentication and Session Handling

**Selenium:**
- Sessions are isolated and temporary
- Requires manually handling authentication steps
- Session storage is cleared between runs
- Difficult to use existing authenticated sessions

**Herd:**
- Uses your browser's existing authenticated sessions
- Access sites you're already logged into
- Persistent cookies and storage
- Access to browser extensions that manage authentication

## Use Case Comparisons

### Web Testing

## herd-test

Code (javascript):
// JavaScript
import { HerdClient } from '@monitoro/herd';

async function runTest() {
  // Connect to your existing browser
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  // Create a new page for testing
  const page = await device.newPage();
  await page.goto('https://example.com');
  
  // Test interactions
  await page.click('.nav-item');
  await page.waitForSelector('.content-loaded');
  
  // Assert condition
  const header = await page.$('.header');
  const text = await header.getText();
  console.assert(text.includes('Expected Text'), 'Header text verification failed');
  
  // Cleanup
  await page.close();
  await client.close();
}

runTest();

## selenium-test

Code (javascript):
// JavaScript
import { Builder, By, until } from 'selenium-webdriver';

async function runTest() {
  // Launch a separate browser instance with WebDriver
  const driver = await new Builder()
    .forBrowser('chrome')
    .build();
  
  try {
    // Navigate to the test site
    await driver.get('https://example.com');
    
    // Test interactions
    await driver.findElement(By.css('.nav-item')).click();
    await driver.wait(until.elementLocated(By.css('.content-loaded')), 5000);
    
    // Assert condition
    const header = await driver.findElement(By.css('.header'));
    const text = await header.getText();
    console.assert(text.includes('Expected Text'), 'Header text verification failed');
  } finally {
    // Always close the browser
    await driver.quit();
  }
}

runTest();

### Data Extraction

## herd-extract

Code (javascript):
// JavaScript
import { HerdClient } from '@monitoro/herd';

async function extractData() {
  const client = new HerdClient('your-token');
  await client.initialize();
  const devices = await client.listDevices();
  const device = devices[0];
  
  const page = await device.newPage();
  await page.goto('https://example.com/products');
  
  // Extract product data with a single call
  const products = await page.extract({
    items: {
      _$r: '.product-card',  // Repeat for each product card
      name: '.product-name',
      price: '.product-price',
      rating: '.product-rating',
      inStock: '.stock-status'
    }
  });
  
  console.log(products.items);
  await client.close();
}

extractData();

## selenium-extract

Code (javascript):
// JavaScript
import { Builder, By } from 'selenium-webdriver';

async function extractData() {
  const driver = await new Builder()
    .forBrowser('chrome')
    .build();
  
  try {
    await driver.get('https://example.com/products');
    
    // Extract product data with multiple queries
    const productElements = await driver.findElements(By.css('.product-card'));
    
    const products = [];
    for (const element of productElements) {
      const name = await element.findElement(By.css('.product-name')).getText();
      const price = await element.findElement(By.css('.product-price')).getText();
      
      let rating = '';
      try {
        rating = await element.findElement(By.css('.product-rating')).getText();
      } catch (e) {
        // Element might not exist
        rating = 'N/A';
      }
      
      let inStock = false;
      try {
        const stockText = await element.findElement(By.css('.stock-status')).getText();
        inStock = stockText.includes('In Stock');
      } catch (e) {
        // Element might not exist
      }
      
      products.push({ name, price, rating, inStock });
    }
    
    console.log(products);
  } finally {
    await driver.quit();
  }
}

extractData();

## Migration Guide: From Selenium to Herd

Transitioning from Selenium to Herd is straightforward. Here's a guide to help you migrate your existing code:

### 1. Installation

1. Install the Herd SDK:
   
Code (bash):
   # JavaScript
   npm install @monitoro/herd
   
   # Python
   pip install herd-client

2. Install the Herd browser extension in your preferred browser

3. Register your browser as a device in the Herd dashboard

### 2. Code Migration

| Selenium | Herd | Notes |
| --- | --- | --- |
| `new Builder().forBrowser().build()` | `new HerdClient(apiUrl, token)`  `await client.initialize()`  `const devices = await client.listDevices()`  `const device = devices[0]` | Herd connects to your existing browser |
| `driver.get(url)` | `await page.goto(url)` | Similar syntax |
| `driver.findElement(By.css(selector))` | `await page.$(selector)` | Herd uses CSS selectors directly |
| `element.sendKeys(text)` | `await element.type(text)` | Different method name |
| `element.click()` | `await element.click()` | Identical usage |
| `driver.wait(until.elementLocated())` | `await page.waitForSelector(selector)` | Similar functionality |
| `driver.quit()` | `await client.close()` | Herd just disconnects, browser stays open |

### 3. Handling Multiple Browsers

**Selenium:**

Code (javascript):
const chrome = await new Builder().forBrowser('chrome').build();
const firefox = await new Builder().forBrowser('firefox').build();

**Herd:**

Code (javascript):
// Connect to different browsers that are registered as devices
const chromiumDevice = devices.find(d => d.name === 'Chrome Browser');

## Why Choose Herd Over Selenium?

### 1. No WebDriver Headaches

Herd eliminates the need for WebDrivers, solving the most common Selenium pain points:
- No driver version compatibility issues
- No driver installation or updates needed
- No broken tests due to browser updates

### 2. Use Existing Authentication

With Herd, you can automate tasks in your already authenticated browser:
- No need to write and maintain authentication code
- Access to sites requiring complex authentication
- Use existing cookies, local storage, and sessions

### 3. Simplified Setup and Maintenance

Herd significantly reduces the overhead of browser automation:
- No complex CI/CD configuration
- No driver path management
- No browser version tracking

### 4. Intuitive API for Modern Development

Herd provides:
- Clean, Promise-based API
- Powerful data extraction capabilities
- Better debugging experience (view automation in your browser)

## Get Started with Herd Today

Ready to try a more efficient alternative to Selenium? Get started with Herd:

1. [Create a Herd account](/register)
2. [Install the browser extension](/docs/installation)
3. [Connect your browser](/docs/connect-your-browser)
4. [Run your first automation](/docs/automation-basics)

Discover how Herd can simplify your browser automation workflows while eliminating the most common frustrations of working with Selenium.

================================================================================

Document: Automation Basics
URL: https://herd.garden/docs/automation-basics

# Automation Basics

Welcome to Monitoro Herd! This guide will walk you through creating your first browser automation step-by-step. We'll start with the basics and gradually build up to more complex examples, explaining each concept along the way.

## javascript

## JavaScript SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your JavaScript environment and install the Herd SDK:

1. Make sure you have Node.js installed (version 14 or higher recommended)
2. Create a new project directory
3. Install the SDK using npm:

Code (bash):
npm install @monitoro/herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (javascript):
// Import the Herd client
import { HerdClient } from '@monitoro/herd';

// Initialize the client with your API URL and token
const client = new HerdClient('your-token');

// Always initialize the client before using it
await client.initialize();
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

After initializing the client, you need to connect to a device (browser) that will perform the automation:

Code (javascript):
// Get a list of available devices
const devices = await client.listDevices();

// Connect to the first available device
const device = devices[0];

console.log(`Connected to device: ${device.id}`);

This code retrieves all devices registered to your account and connects to the first one. In a production environment, you might want to select a specific device based on its properties or availability.

### Creating a Page and Navigating

Now that you're connected to a device, you can create a new browser page and navigate to a website:

Code (javascript):
// Create a new page in the browser
const page = await device.newPage();

// Navigate to a website
await page.goto('https://example.com');

console.log('Successfully navigated to example.com');

The `goto` method loads the specified URL and waits for the page to load. By default, it waits until the page's `load` event is fired, but you can customize this behavior with options.

### Extracting Basic Information

One of the most common automation tasks is extracting information from web pages. Here's how to extract basic elements:

Code (javascript):
// Extract content using CSS selectors
const content = await page.extract({
  title: 'h1',           // Extracts the main heading
  description: 'p',      // Extracts the first paragraph
  link: 'a'              // Extracts the first link text
});

// Display the extracted content
console.log('Extracted content:');
console.log(`Title: ${content.title}`);
console.log(`Description: ${content.description}`);
console.log(`Link: ${content.link}`);

The `extract` method uses CSS selectors to find elements on the page and extract their text content. This is a powerful way to scrape structured data from websites.

### Proper Resource Management

Always remember to close resources when you're done with them to prevent memory leaks:

Code (javascript):
// Close the page when done
await page.close();

// Close the client connection
await client.close();

### Putting It All Together

Here's a complete example that combines all the steps above into a single function:

Code (javascript):
import { HerdClient } from '@monitoro/herd';

async function runBasicAutomation() {
  const client = new HerdClient('your-token');
  
  try {
    // Initialize the client
    await client.initialize();
    console.log('Client initialized successfully');
    
    // Get the first available device
    const devices = await client.listDevices();
    if (devices.length === 0) {
      throw new Error('No devices available');
    }
    const device = devices[0];
    console.log(`Connected to device: ${device.id}`);
    
    // Create a new page
    const page = await device.newPage();
    console.log('New page created');
    
    // Navigate to a website
    console.log('Navigating to example.com...');
    await page.goto('https://example.com');
    console.log('Navigation complete');
    
    // Extract content
    console.log('Extracting content...');
    const content = await page.extract({
      title: 'h1',
      description: 'p',
      link: 'a'
    });
    
    // Display the extracted content
    console.log('\nExtracted content:');
    console.log(`Title: ${content.title}`);
    console.log(`Description: ${content.description}`);
    console.log(`Link: ${content.link}`);
    
  } catch (error) {
    console.error('Error during automation:', error);
  } finally {
    // Always close the client when done
    console.log('Closing client connection...');
    await client.close();
    console.log('Client connection closed');
  }
}

// Run the automation
runBasicAutomation();

### Interacting with Web Pages

Now let's explore how to interact with elements on a page. This includes clicking buttons, typing text, and handling forms.

#### Finding Elements

Before interacting with an element, you need to find it on the page:

Code (javascript):
// Find an element using a CSS selector
const searchBox = await page.$('input[name="q"]');

// Check if the element was found
if (searchBox) {
  console.log('Search box found');
} else {
  console.log('Search box not found');
}

The `


  
  
  
  
  herd.garden | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   method returns the first element that matches the CSS selector, or `null` if no element is found.

#### Typing Text

To type text into an input field:

Code (javascript):
// Type text into an input field
await page.type('input[name="q"]', 'Monitoro Herd automation');
console.log('Text entered into search box');

The `type` method finds the element using the CSS selector and simulates typing the specified text.

#### Clicking Elements

To click a button or link:

Code (javascript):
// Click a button
await page.click('input[type="submit"]');
console.log('Search button clicked');

By default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:

Code (javascript):
// Click and wait for navigation
await page.click('input[type="submit"]', { 
  waitForNavigation: 'networkidle2' 
});
console.log('Search button clicked and navigation completed');

The `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.

#### Waiting for Elements

Sometimes you need to wait for elements to appear on the page:

Code (javascript):
// Wait for an element to appear
await page.waitForSelector('#search');
console.log('Search results have loaded');

This is useful when dealing with dynamic content that loads after the initial page load.

#### Search Engine Example

Let's put these concepts together in a search engine example:

Code (javascript):
async function searchExample() {
  const client = new HerdClient('your-token');
  
  try {
    await client.initialize();
    const devices = await client.listDevices();
    const device = devices[0];
    const page = await device.newPage();
    
    // Navigate to a search engine
    console.log('Navigating to Google...');
    await page.goto('https://www.google.com');
    
    // Type in the search box
    console.log('Entering search query...');
    await page.type('input[name="q"]', 'Monitoro Herd automation');
    
    // Submit the search form and wait for results
    console.log('Submitting search...');
    await page.click('input[type="submit"]', { 
      waitForNavigation: 'networkidle2' 
    });
    
    // Wait for results to load completely
    console.log('Waiting for search results...');
    await page.waitForSelector('#search');
    
    // Extract search result titles
    console.log('Extracting search results...');
    const searchResults = await page.extract({
      titles: {
        _$r: '#search .g h3',  // _$r extracts multiple elements
        text: ':root'           // For each match, get its text
      }
    });
    
    // Display the search result titles
    console.log('\nSearch Results:');
    searchResults.titles.forEach((result, index) => {
      console.log(`${index + 1}. ${result.text}`);
    });
    
  } catch (error) {
    console.error('Error:', error);
  } finally {
    await client.close();
  }
}

## python

## Python SDK

### Setting Up Your Environment

Before writing any code, you'll need to set up your Python environment and install the Herd SDK:

1. Make sure you have Python 3.8+ installed
2. Create a virtual environment (recommended)
3. Install the SDK using pip:

Code (bash):
pip install monitoro-herd

### Initializing the Client

The first step in any automation is to initialize the Herd client with your API credentials:

Code (python):
# Import the Herd client
from monitoro_herd import HerdClient

# Initialize the client with your API URL and token
client = HerdClient('your-token')

# Always initialize the client before using it
client.initialize()
Note: **Note:** Replace the token with your actual Herd API token from your dashboard.

### Connecting to a Device

Next, connect to a device that will run your automation:

Code (python):
# Get available devices
devices = await client.list_devices()

# Connect to the first device
device = devices[0]

print(f"Connected to device: {device.id}")

### Creating a Page and Navigating

Now create a browser page and navigate to a website:

Code (python):
# Create a new page
page = await device.new_page()

# Navigate to a website
await page.goto("https://example.com")

print("Successfully navigated to example.com")

### Extracting Basic Information

Extract information from the page using CSS selectors:

Code (python):
# Extract basic information
data = await page.extract({
    "title": "h1",          # Main heading
    "description": "p",     # First paragraph
    "link": "a"             # First link text
})

# Display the extracted data
print("Extracted data:")
print(f"Title: {data['title']}")
print(f"Description: {data['description']}")
print(f"Link: {data['link']}")

### Resource Management

Always close resources when you're done:

Code (python):
# Close the page
await page.close()

# Close the client
await client.close()

### Complete Basic Example

Here's a complete example putting all these concepts together:

Code (python):
import asyncio
from monitoro_herd import HerdClient

async def basic_extraction():
    # Initialize the client
    client = HerdClient("your-token")
    
    try:
        # Initialize the connection
        await client.initialize()
        print("Client initialized successfully")
        
        # Get the first available device
        devices = await client.list_devices()
        if not devices:
            raise Exception("No devices available")
        device = devices[0]
        print(f"Connected to device: {device.id}")
        
        # Create a new page
        page = await device.new_page()
        print("New page created")
        
        # Navigate to a website
        print("Navigating to example.com...")
        await page.goto("https://example.com")
        print("Navigation complete")
        
        # Extract data using simple selectors
        print("Extracting content...")
        data = await page.extract({
            "title": "h1",
            "description": "p",
            "link": "a"
        })
        
        # Display the extracted data
        print("\nExtracted data:")
        print(f"Title: {data['title']}")
        print(f"Description: {data['description']}")
        print(f"Link: {data['link']}")
        
    except Exception as e:
        print(f"Error during automation: {e}")
    finally:
        # Always close resources
        print("Closing client connection...")
        await client.close()
        print("Client connection closed")

# Run the async function
asyncio.run(basic_extraction())

### Working with Lists and Structured Data

One of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.

#### The `_$r` Selector

To extract multiple elements that match a pattern, use the `_$r` (repeat) selector:

Code (python):
# Extract a list of items
data = await page.extract({
    "items": {
        "_$r": ".item",       # Find all elements with class "item"
        "name": ".item-name", # For each item, get the name
        "price": ".price"     # For each item, get the price
    }
})

# Access the extracted items
for item in data["items"]:
    print(f"Name: {item['name']}, Price: {item['price']}")

The `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.

#### Extracting Attributes

Sometimes you need to extract an attribute rather than the text content:

Code (python):
# Extract links and their href attributes
data = await page.extract({
    "links": {
        "_$r": "a",              # Find all links
        "text": ":root",         # Get the link text
        "url": {
            "_
quot;: ":root", # Reference the same element "attribute": "href" # Get its href attribute } } }) # Display the links for link in data["links"]: print(f"Link: {link['text']} -> {link['url']}") #### Hacker News Example Let's put these concepts together to scrape stories from Hacker News: Code (python): import asyncio from monitoro_herd import HerdClient async def scrape_hacker_news(): client = HerdClient("your-token") try: await client.initialize() devices = await client.list_devices() device = devices[0] page = await device.new_page() # Navigate to Hacker News print("Navigating to Hacker News...") await page.goto("https://news.ycombinator.com") # Extract stories and their metadata print("Extracting stories...") data = await page.extract({ # Extract the story elements "stories": { "_$r": ".athing", # Each story row "title": ".titleline > a", # Story title "site": ".sitestr", # Source website "link": { "_
quot;: ".titleline > a", # Story link "attribute": "href" # Get the URL } }, # Extract the metadata (points, author, etc.) "metadata": { "_$r": ".subline", # Metadata rows "points": ".score", # Points count "author": ".hnuser", # Author username "time": ".age" # Submission time } }) # Combine stories with their metadata # (They're in separate lists but in the same order) combined_stories = list(zip(data["stories"], data["metadata"])) # Display the first 3 stories print(f"\nExtracted {len(combined_stories)} stories:") for i, (story, meta) in enumerate(combined_stories[:3]): print(f"\nStory {i+1}:") print(f"Title: {story['title']}") if "site" in story: print(f"Site: {story['site']}") print(f"Link: {story['link']}") if "points" in meta: print(f"Points: {meta['points']}") if "author" in meta: print(f"Author: {meta['author']}") if "time" in meta: print(f"Posted: {meta['time']}") finally: await page.close() await client.close() # Run the function asyncio.run(scrape_hacker_news()) ## Tips for Successful Automation 1. **Start Simple**: Begin with basic extractions before moving to complex interactions 2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely 3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks 4. **Close Resources**: Always close pages and clients when done to avoid resource leaks 5. **Test Incrementally**: Build your automation step by step, testing each part 6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods 7. **Debug with Screenshots**: Take screenshots during automation to see what's happening ## Next Steps Now that you've created your first automation, you can: - Explore more complex selectors and extraction patterns - Learn how to handle authentication and login flows - Set up scheduled automations for regular data collection - Integrate with your existing systems via APIs ================================================================================ Document: Connect Your Browser URL: https://herd.garden/docs/connect-your-browser # Connect your Browser to Herd After installing the Herd extension, you need to connect your browser to your account. This guide explains how to establish and manage connections between your browsers and the Herd platform. You can connect multiple browsers to the same account. Learn more about [managing multiple devices](/docs/device-management). ## Device Registration Before you can connect a browser, you need to register the device in your Herd dashboard: 1. Log in to your Herd account 2. Navigate to the "Devices" section 3. Click "Register New Device" 4. Enter a descriptive name for the device (e.g., "Work Laptop - Chrome") 5. Choose appropriate tags if you're organizing devices into groups 6. Click "Create Registration" 7. Copy the registration code that appears (you'll need this to connect the browser) ## Connecting Your Browser Once you have a registration code, follow these steps to connect your browser: 1. Make sure the Herd extension is installed in your browser 2. Click the Herd icon in your browser toolbar 3. Select "Connect Browser" or "Register Device" from the menu 4. Paste the registration code into the field 5. Click "Connect" 6. You should see a confirmation message indicating the browser is now connected ## Managing Active Connections You can view and manage all your connected browsers from the Herd dashboard: ### Viewing Connected Devices 1. Log in to your Herd account 2. Navigate to the "Devices" section 3. The "Active Connections" tab shows all currently connected browsers 4. Each connection displays information such as: - Device name - Browser type and version - Connection status - Last activity timestamp ### Remote Actions Once a browser is connected, you can perform various remote actions: 1. **Remote Control**: Initiate a remote control session to view and interact with the browser 2. **Capture Screenshot**: Take a snapshot of the current browser window 3. **Tab Management**: View, open, close, or navigate tabs 4. **Bookmark Management**: View or modify the browser's bookmarks 5. **History Access**: View browsing history (if permissions allow) ## Connection Troubleshooting If you're having trouble connecting your browser to Herd, try these solutions: ### Connection Failures * Verify that the registration code is correct and hasn't expired * Make sure the browser is online and has a stable internet connection * Check that the Herd extension is properly installed and enabled * Try restarting your browser ### Dropped Connections * Check your network stability * Ensure the browser hasn't entered sleep mode * Verify that the extension hasn't been disabled * Check if a browser update has affected the extension ### Reconnecting If a connection is lost, you can easily reconnect: 1. Click the Herd icon in your browser toolbar 2. If the connection status shows "Disconnected," click "Reconnect" 3. If prompted, enter your registration code again 4. Wait for the connection to be reestablished ## Connection Security All connections between your browser and the Herd platform are secured with end-to-end encryption. Your data remains private and protected throughout the connection process. For more information on security features, see our [Security & Privacy](security-privacy) documentation. ================================================================================ Document: Data Extraction URL: https://herd.garden/docs/data-extraction # Data Extraction Welcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines. ## Understanding Selectors Herd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system. ### Basic Extraction ## javascript The simplest form of extraction uses CSS selectors to target elements: Code (javascript): // Extract basic text content const data = await page.extract({ title: 'h1', // Extracts the main heading description: 'p', // Extracts the first paragraph link: 'a' // Extracts the first link text }); console.log(data.title); // "Welcome to Our Website" console.log(data.description); // "This is our homepage." ## python The simplest form of extraction uses CSS selectors to target elements: Code (python): # Extract basic text content data = await page.extract({ "title": "h1", # Extracts the main heading "description": "p", # Extracts the first paragraph "link": "a" # Extracts the first link text }) print(data["title"]) # "Welcome to Our Website" print(data["description"]) # "This is our homepage." ### Advanced Selector Syntax ## javascript For more complex extraction needs, use the expanded object syntax: Code (javascript): const data = await page.extract({ title: { _$: 'h1', // CSS selector attribute: 'id' // Extract the ID attribute instead of text }, price: { _$: '.price', // Target price element pipes: ['parseNumber'] // Apply transformation } }); ## python For more complex extraction needs, use the expanded object syntax: Code (python): data = await page.extract({ "title": { "_
quot;: "h1", # CSS selector "attribute": "id" # Extract the ID attribute instead of text }, "price": { "_
quot;: ".price", # Target price element "pipes": ["parseNumber"] # Apply transformation } }) ### Extracting Lists of Items ## javascript To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (javascript): const data = await page.extract({ items: { _$r: '.item', // Find all elements with class "item" title: 'h2', // For each item, get the title price: '.price', // For each item, get the price date: 'time' // For each item, get the date } }); // Access the extracted items data.items.forEach(item => { console.log(`${item.title}: ${item.price}, Posted: ${item.date}`); }); ## python To extract multiple elements that match a pattern, use the `_$r` (repeat) selector: Code (python): data = await page.extract({ "items": { "_$r": ".item", # Find all elements with class "item" "title": "h2", # For each item, get the title "price": ".price", # For each item, get the price "date": "time" # For each item, get the date } }) # Access the extracted items for item in data["items"]: print(f"{item['title']}: {item['price']}, Posted: {item['date']}") ### Nested Extraction ## javascript You can nest selectors to extract hierarchical data: Code (javascript): const data = await page.extract({ product: { name: '.product-name', details: { _$: '.product-details', specs: { _$r: '.spec-item', label: '.spec-label', value: '.spec-value' } } } }); ## python You can nest selectors to extract hierarchical data: Code (python): data = await page.extract({ "product": { "name": ".product-name", "details": { "_
quot;: ".product-details", "specs": { "_$r": ".spec-item", "label": ".spec-label", "value": ".spec-value" } } } }) ## Special Selectors Herd provides special selectors to handle various extraction scenarios: ### Root Selector (`:root`) The `:root` selector refers to the current element in context: ## javascript Code (javascript): const data = await page.extract({ items: { _$r: '.item', someElement: ':root', // Extract text of the .item element itself classes: { _$: ':root', attribute: 'class' // Extract class attribute of the same element } } }); ## python Code (python): data = await page.extract({ "items": { "_$r": ".item", "someElement": ":root", # Extract text of the .item element itself "classes": { "_
quot;: ":root", "attribute": "class" # Extract class attribute of the same element } } }) ### Property Extraction You can extract JavaScript properties from elements: ## javascript Code (javascript): const data = await page.extract({ dimensions: { _$: '.box', property: 'getBoundingClientRect' // Get element dimensions }, html: { _$: '.content', property: 'innerHTML' // Get inner HTML } }); ## python Code (python): data = await page.extract({ "dimensions": { "_
quot;: ".box", "property": "getBoundingClientRect" # Get element dimensions }, "html": { "_
quot;: ".content", "property": "innerHTML" # Get inner HTML } }) ## Transformation Pipelines Herd includes powerful transformation pipelines to process extracted data: ### Available Transformations | Pipe | Description | Example Input | Example Output | |------|-------------|--------------|----------------| | `trim` | Removes whitespace from start/end | `" Hello "` | `"Hello"` | | `toLowerCase` | Converts text to lowercase | `"HELLO"` | `"hello"` | | `toUpperCase` | Converts text to uppercase | `"hello"` | `"HELLO"` | | `parseNumber` | Extracts numbers from text | `"$1,2K.45"` | `1200.45` | | `parseDate` | Converts text to date | `"2024-01-15"` | `"2024-01-15T00:00:00.000Z"` | | `parseDateTime` | Converts text to datetime | `"2024-01-15T12:00:00Z"` | `"2024-01-15T12:00:00.000Z"` | ### Using Transformations Apply transformations using the `pipes` property: ## javascript Code (javascript): const data = await page.extract({ price: { _$: '.price', pipes: ['parseNumber'] // Convert "$1,234.56" to 1234.56 }, title: { _$: 'h1', pipes: ['trim', 'toLowerCase'] // Apply multiple transformations } }); ## python Code (python): data = await page.extract({ "price": { "_
quot;: ".price", "pipes": ["parseNumber"] # Convert "$1,234.56" to 1234.56 }, "title": { "_
quot;: "h1", "pipes": ["trim", "toLowerCase"] # Apply multiple transformations } }) ### Handling Currency and Large Numbers The `parseNumber` transformation handles various formats: ## javascript Code (javascript): const data = await page.extract({ price1: { _$: '.price-1', // Contains "$1,234.56" pipes: ['parseNumber'] // Result: 1234.56 }, price2: { _$: '.price-2', // Contains "$1.5M" pipes: ['parseNumber'] // Result: 1500000 }, price3: { _$: '.price-3', // Contains "1.5T€" pipes: ['parseNumber'] // Result: 1500000000000 } }); ## python Code (python): data = await page.extract({ "price1": { "_
quot;: ".price-1", # Contains "$1,234.56" "pipes": ["parseNumber"] # Result: 1234.56 }, "price2": { "_
quot;: ".price-2", # Contains "$1.5M" "pipes": ["parseNumber"] # Result: 1500000 }, "price3": { "_
quot;: ".price-3", # Contains "1.5T€" "pipes": ["parseNumber"] # Result: 1500000000000 } }) ## Real-World Examples Let's look at some practical examples of data extraction: ### E-commerce Product Listing Extract products from a search results page: ## javascript Code (javascript): const searchResults = await page.extract({ products: { _$r: '[data-component-type="s-search-result"]', title: { _$: 'h2 .a-link-normal', pipes: ['trim'] }, price: { _$: '.a-price .a-offscreen', pipes: ['parseNumber'] }, rating: { _$: '.a-icon-star-small .a-icon-alt', pipes: ['trim'] }, reviews: { _$: '.a-size-base.s-underline-text', pipes: ['trim'] } } }); ## python Code (python): searchResults = await page.extract({ "products": { "_$r": '[data-component-type="s-search-result"]', "title": { "_
quot;: "h2 .a-link-normal", "pipes": ["trim"] }, "price": { "_
quot;: ".a-price .a-offscreen", "pipes": ["parseNumber"] }, "rating": { "_
quot;: ".a-icon-star-small .a-icon-alt", "pipes": ["trim"] }, "reviews": { "_
quot;: ".a-size-base.s-underline-text", "pipes": ["trim"] } } }) ### News Article List Extract articles from a news site: ## javascript Code (javascript): const articles = await page.extract({ items: { _$r: '.item', title: { _$: 'h2', pipes: ['trim', 'toLowerCase'] }, price: { _$: '.price', pipes: ['parseNumber'] }, date: { _$: 'time', pipes: ['parseDate'] } } }); ## python Code (python): articles = await page.extract({ "items": { "_$r": ".item", "title": { "_
quot;: "h2", "pipes": ["trim", "toLowerCase"] }, "price": { "_
quot;: ".price", "pipes": ["parseNumber"] }, "date": { "_
quot;: "time", "pipes": ["parseDate"] } } }) ## Advanced Techniques ### Handling Dynamic Content For dynamic content that loads after the page is ready: ## javascript Code (javascript): // Wait for dynamic content to load await page.waitForElement('#dynamic span'); // Then extract the content const data = await page.extract({ content: '#dynamic span' }); ## python Code (python): # Wait for dynamic content to load await page.waitForElement('#dynamic span') # Then extract the content data = await page.extract({ "content": "#dynamic span" }) ### Extracting Page Metadata Extract information about the page itself: ## javascript Code (javascript): const pageInfo = await page.extract({ title: 'title', metaDescription: 'meta[name="description"]', canonicalUrl: { _$: 'link[rel="canonical"]', attribute: 'href' } }); ## python Code (python): pageInfo = await page.extract({ "title": "title", "metaDescription": 'meta[name="description"]', "canonicalUrl": { "_
quot;: 'link[rel="canonical"]', "attribute": "href" } }) ## Tips for Effective Extraction 1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction 2. **Test Incrementally**: Build your extraction schema step by step, testing each part 3. **Handle Missing Data**: Always account for elements that might not exist on the page 4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed 5. **Combine with Interactions**: For complex sites, interact with the page before extraction ## Next Steps Now that you understand Herd's data extraction system, you can: - Create complex extraction schemas for any website - Transform raw data into structured, usable formats - Build powerful automations that collect and process web data ================================================================================ Document: Device Management URL: https://herd.garden/docs/device-management # Device Management Managing your devices in Herd is simple and intuitive. This guide will walk you through the various actions you can perform on the Devices page. ## Understanding the Devices Page The Devices page is your central hub for managing all browsers and headless devices connected to your Herd account. Here you can: - View all your connected devices - Register new devices - Access device registration URLs - Delete devices you no longer need ## Viewing Your Devices When you visit the Devices page, you'll see a list of all your registered devices. For each device, you can view: - Device name - Status (active or inactive) - Device ID - Device type (browser or headless) - Last active timestamp Devices with an active status will display a pulsing green indicator, while inactive devices will show a gray status indicator. ## Registering a New Device To add a new device to your Herd account: 1. Click the **Register New Device** button at the top of the Devices page 2. Enter a name for your device (or use the suggested name) 3. Select the device type: - **Browser**: For devices with a visual interface such as your own browser - **Headless**: For devices running in headless mode (for docker and kubernetes deployments) 4. Click **Register Device** 5. A registration URL will be generated - use this URL to connect your device to Herd The registration URL will be stored locally in your browser, allowing you to access it again later if needed. ## Accessing Registration URLs If you need to access a previously generated registration URL: 1. Find the device in your devices list 2. Look for the "Registration URL available" indicator 3. Click the **View URL** button 4. The registration URL will be displayed in a modal window This is particularly useful if you need to reconnect a device or share the registration link with team members. ## Deleting a Device To remove a device from your Herd account: 1. Find the device you want to delete in your devices list 2. Click the **Delete** button for that device 3. Confirm the deletion in the confirmation dialog Please note that deleting a device is permanent and cannot be undone. The device will be removed from your account, and any stored registration URLs for that device will be cleared from your local storage. ## Device Status Devices in Herd can have different statuses: - **Active**: The device is currently connected and ready to use - **Inactive**: The device is registered but not currently connected An active device can be used immediately for automation tasks, while inactive devices need to be reconnected before use. ## Best Practices Here are some tips for effective device management: - Use descriptive names for your devices to easily identify them - Regularly clean up unused devices to keep your dashboard organized - Store registration URLs securely if you plan to share them with team members - Check the "Last Active" timestamp to identify devices that haven't been used recently By following these guidelines, you'll be able to maintain an organized and efficient device management system in Herd. ================================================================================ Document: Getting Started URL: https://herd.garden/docs/getting-started # Getting Started with Herd This guide will help you get up and running with Herd quickly to run your first trail. ## What is Herd? Herd connects AI Agents to websites using your own browser credentials. It enables you to: - **Run Trails** - pre-built automations for specific websites and tasks - **Extract data and interact with websites** using your logged-in browser sessions - **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude ## Quick Start ### 1. Install the Browser Extension Chrome Edge Brave ### 2. Register Your Browser After installing the extension: 1. Click the Herd icon in your browser toolbar 2. Sign in with your Herd account (or create one) 3. Name your device and register it ![Browser Registration](https://herd.garden/register-device.png) ### 3. Install the Herd SDK Install the Herd SDK using npm: ## npm Code (bash): npm install -g @monitoro/herd ## yarn Code (bash): yarn global add @monitoro/herd ## pnpm Code (bash): pnpm add -g @monitoro/herd ### 4. Run Your First Trail The browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out: Code (bash): herd trail run @herd/browser -a markdown -p '{"url": "https://example.com"}' That's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config: Code (json): { "mcpServers": { "browser": { "command": "herd", "args": [ "trail", "server", "@herd/browser" ] } } } ## For Developers You can also automate your browser with the Herd SDK. Connect to it with your AI agents or code: ## javascript Code (javascript): // Connect to your Herd device const client = new HerdClient('your-token'); await client.initialize(); const devices = await client.listDevices(); const device = devices[0]; // Create a new page and navigate const page = await device.newPage(); await page.goto("https://example.com"); // Extract data using simple selectors const data = await page.extract({ title: "h1", description: "p", link: "a" }); console.log("Extracted data:", data); ## python Code (python): from monitoro_herd import HerdClient # Connect to your Herd device client = HerdClient("your-token") await client.initialize() devices = await client.list_devices() device = devices[0] # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Extract data using simple selectors data = await page.extract({ "title": "h1", "description": "p", "link": "a" }) print("Extracted data:", data) ## What's Next? Now that you've run your first trail, you can: - [Explore available trails](/trails) - Browse pre-built trails for various websites - [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages - [Create your own trail](/docs/trails-automations) - Build and share your own custom trails ## Need Help? If you encounter any issues during setup: - Make sure your browser extension is correctly installed and you're signed in - Check that your device is registered in the [device dashboard](/devices) - Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions .browser-btn { display: inline-flex; align-items: center; padding: 0.2rem 1rem; background-color: #1f2937; color: white; border-radius: 0.375rem; font-size: 1.2rem; font-weight: 500; text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.1); } .browser-btn:hover { background-color: #374151; } ================================================================================ Document: Installation URL: https://herd.garden/docs/installation # Installing the Herd Extension The Herd extension is the client component that allows your browser to be remotely managed. This guide provides detailed instructions for installing the extension on different browsers. ## Chrome Installation The Herd extension is primarily designed for Google Chrome and Chromium-based browsers. Follow these steps to install: ### Standard Installation 1. Download the Herd extension from your dashboard by clicking "Download Herd" in the navigation bar 2. Open Chrome and navigate to `chrome://extensions` 3. Enable "Developer mode" by toggling the switch in the top-right corner 4. Drag and drop the downloaded `herd-latest.zip` file onto the extensions page 5. Chrome will automatically install the extension ### Verifying Installation After installation, you should see the Herd extension in your extensions list. To verify it's working correctly: 1. Look for the Herd icon in your browser toolbar 2. If it's not visible, click the puzzle piece icon to see all extensions and pin the Herd extension 3. The icon should be colored, indicating it's ready to be connected ## Installation on Other Browsers While Herd works best with Chrome, it's also compatible with other Chromium-based browsers: ### Microsoft Edge 1. Download the Herd extension zip file 2. Open Edge and navigate to `edge://extensions` 3. Enable "Developer mode" using the toggle in the left sidebar 4. Drag and drop the `herd-latest.zip` file onto the extensions page 5. Follow the prompts to complete installation ### Brave Browser 1. Download the Herd extension zip file 2. Open Brave and navigate to `brave://extensions` 3. Enable "Developer mode" in the top-right corner 4. Drag and drop the `herd-latest.zip` file onto the extensions page 5. Confirm the installation when prompted ## Enterprise Deployment For enterprise environments, you may want to deploy the Herd extension to multiple browsers. Here are some options: ### Chrome Enterprise Policy You can use Chrome Enterprise policies to automatically install and configure the Herd extension: 1. Extract the Herd extension zip file to a network location accessible to all users 2. Configure a policy to force-install extensions from a local path 3. Set up the appropriate extension settings via policy ### Manual Distribution For smaller teams, you can manually distribute the extension: 1. Download the extension once 2. Share the zip file with team members 3. Provide them with instructions for installation 4. Create device registrations for each team member in your Herd dashboard ## Troubleshooting Installation Issues If you encounter issues during installation, try these solutions: ### Extension Won't Install * Make sure Developer mode is enabled in your browser's extensions page * Check that you're using a supported browser (Chrome, Edge, Brave) * Verify that the zip file wasn't corrupted during download (try re-downloading) * Make sure you're dragging the zip file itself, not an extracted folder ### Extension Installed But Not Working * Check if the extension is enabled in your browser * Try restarting your browser * Verify that you've completed the device registration process * Check your browser's console for any error messages For more troubleshooting tips, see our [Troubleshooting](troubleshooting) guide. ================================================================================ Document: Reference Device URL: https://herd.garden/docs/reference-device # Device The Device class represents a connected browser or device in the Herd platform. It provides methods for managing pages, handling events, and controlling the device's lifecycle. Each Device instance gives you full control over a browser, allowing you to create and manage pages (tabs), handle various browser events, and automate browser interactions. ## javascript You can obtain a Device instance either by calling `client.listDevices()` to get all available devices, or `client.getDevice(deviceId)` to get a specific device by its ID. ## Properties ### deviceId The unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered. ### type The type of device, which indicates its capabilities and behavior. Currently supported types include: - 'browser': A browser instance that can be automated - 'headless': A headless browser instance running on docker or kubernetes ### name An optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard. ### status The current status of the device. Possible values include: - 'online': The device is connected and ready to receive commands - 'offline': The device is not currently connected - 'busy': The device is processing a command - 'error': The device encountered an error ### lastActive A timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a JavaScript Date object. ## Methods ### newPage() Creates a new page (tab) in the device. Code (javascript): // Create a new page const page = await device.newPage(); console.log('New page created:', page.id); ### listPages() Returns a list of all pages (tabs) currently open in the device. Code (javascript): // List all open pages const pages = await device.listPages(); pages.forEach(page => { console.log(`Page ${page.id}: ${page.url}`); }); ### getPage(pageId) Gets a specific page by ID. Code (javascript): // Get a specific page const page = await device.getPage(123); console.log('Current URL:', page.url); ### onEvent(callback) Subscribes to all events from the device. Returns an unsubscribe function. Code (javascript): // Subscribe to all device events const unsubscribe = device.onEvent((event) => { console.log('Device event:', event); }); // Later: stop listening to events unsubscribe(); ### on(eventName, callback) Subscribes to a specific event from the device. Returns the device instance for chaining. Code (javascript): // Subscribe to specific events device.on('navigation', (event) => { console.log('Navigation occurred:', event); }).on('console', (event) => { console.log('Console message:', event); }); ### close() Closes the device and cleans up resources. This will close all pages and remove event listeners. Code (javascript): // Close the device and cleanup await device.close(); ## Example Usage Here's a complete example showing how to use the Device class: Code (javascript): import { HerdClient } from '@monitoro/herd'; async function main() { const client = new HerdClient({ token: 'your-auth-token' }); await client.initialize(); // Get a device const device = await client.getDevice('my-browser'); // Create a new page and navigate const page = await device.newPage(); await page.goto('https://example.com'); // Listen for navigation events device.on('navigation', (event) => { console.log('Page navigated:', event.url); }); // List all pages const pages = await device.listPages(); console.log(`Device has ${pages.length} pages open`); // Cleanup when done await device.close(); await client.close(); } main().catch(console.error); ## python You can obtain a Device instance either by calling `client.list_devices()` to get all available devices, or `client.get_device(device_id)` to get a specific device by its ID. ## Properties ### device_id The unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered. ### type The type of device, which indicates its capabilities and behavior. Currently supported types include: - 'browser': A browser instance that can be automated - 'headless': A headless browser instance running on docker or kubernetes ### name An optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard. ### status The current status of the device. Possible values include: - 'online': The device is connected and ready to receive commands - 'offline': The device is not currently connected - 'busy': The device is processing a command - 'error': The device encountered an error ### last_active A timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a Python datetime object. ## Methods ### new_page() Creates a new page (tab) in the device. Code (python): # Create a new page page = await device.new_page() print(f"New page created: {page.id}") ### list_pages() Returns a list of all pages (tabs) currently open in the device. Code (python): # List all open pages pages = await device.list_pages() for page in pages: print(f"Page {page.id}: {page.url}") ### get_page(page_id) Gets a specific page by ID. Code (python): # Get a specific page page = await device.get_page(123) print(f"Current URL: {page.url}") ### on_event(callback) Subscribes to all events from the device. Returns an unsubscribe function. Code (python): # Subscribe to all device events def handle_event(event): print("Device event:", event) unsubscribe = device.on_event(handle_event) # Later: stop listening to events unsubscribe() ### on(event_name, callback) Subscribes to a specific event from the device. Returns the device instance for chaining. Code (python): # Subscribe to specific events def handle_navigation(event): print("Navigation occurred:", event) def handle_console(event): print("Console message:", event) device.on("navigation", handle_navigation)\ .on("console", handle_console) ### close() Closes the device and cleans up resources. This will close all pages and remove event listeners. Code (python): # Close the device and cleanup await device.close() ## Example Usage Here's a complete example showing how to use the Device class: Code (python): from monitoro_herd import HerdClient async def main(): client = HerdClient( token="your-auth-token" ) await client.initialize() # Get a device device = await client.get_device("my-browser") # Create a new page and navigate page = await device.new_page() await page.goto("https://example.com") # Listen for navigation events def handle_navigation(event): print("Page navigated:", event["url"]) device.on("navigation", handle_navigation) # List all pages pages = await device.list_pages() print(f"Device has {len(pages)} pages open") # Cleanup when done await device.close() await client.close() # Run the async function import asyncio asyncio.run(main()) ================================================================================ Document: Reference Herd Client URL: https://herd.garden/docs/reference-herd-client # HerdClient The HerdClient is the main entry point for interacting with the Herd platform. It provides methods for managing devices, pages, and executing browser automation commands. ## javascript ## Installation Code (bash): npm install @monitoro/herd # or yarn add @monitoro/herd ## Usage Code (javascript): import { HerdClient } from '@monitoro/herd'; // Create a client instance const client = new HerdClient({ token: 'your-auth-token' // Get your token at herd.garden }); // Initialize the client await client.initialize(); ## Methods ### initialize() Initializes the client by establishing connections to the Herd platform. Must be called before using other methods. Code (javascript): await client.initialize(); ### listDevices() Returns a list of all available devices. Code (javascript): const devices = await client.listDevices(); console.log('Available devices:', devices); ### getDevice(deviceId) Gets a specific device by ID. Code (javascript): const device = await client.getDevice('device-123'); ### registerDevice(options) Registers a new device with the platform. Code (javascript): const device = await client.registerDevice({ deviceId: 'my-device', type: 'browser', name: 'My Test Browser' }); ### sendCommand(deviceId, command, params) Sends a command to a specific device. This is a low-level method that allows you to send arbitrary commands to a device and is not recommended for most use cases. Code (javascript): const result = await client.sendCommand('device-123', 'Page.click', { selector: '#submit-button' }); ### subscribeToDeviceEvents(deviceId, callback) Subscribes to all events from a device. Code (javascript): const unsubscribe = client.subscribeToDeviceEvents('device-123', (event) => { console.log('Device event:', event); }); // Later: unsubscribe to stop receiving events unsubscribe(); ### subscribeToDeviceEvent(deviceId, eventName, callback) Subscribes to a specific event from a device. Code (javascript): const unsubscribe = client.subscribeToDeviceEvent('device-123', 'navigation', (event) => { console.log('Navigation event:', event); }); ### close() Closes the client and cleans up resources. Code (javascript): await client.close(); ## python ## Installation Code (bash): pip install monitoro-herd ## Usage Code (python): from monitoro_herd import HerdClient # Create a client instance client = HerdClient( token='your-auth-token' # Get your token at herd.garden ) # Initialize the client await client.initialize() ## Methods ### initialize() Initializes the client by establishing connections to the Herd platform. Must be called before using other methods. Code (python): await client.initialize() ### list_devices() Returns a list of all available devices. Code (python): devices = await client.list_devices() print('Available devices:', devices) ### get_device(device_id) Gets a specific device by ID. Code (python): device = await client.get_device('device-123') ### register_device(device_id, device_type, name) Registers a new device with the platform. Code (python): device = await client.register_device( device_id='my-device', device_type='browser', name='My Test Browser' ) ### send_command(device_id, command, payload) Sends a command to a specific device. Code (python): result = await client.send_command( 'device-123', 'Page.click', {'selector': '#submit-button'} ) ### subscribe_to_device_events(device_id, callback) Subscribes to all events from a device. Code (python): def handle_event(event): print('Device event:', event) unsubscribe = client.subscribe_to_device_events('device-123', handle_event) # Later: unsubscribe to stop receiving events unsubscribe() ### subscribe_to_device_event(device_id, event_name, callback) Subscribes to a specific event from a device. Code (python): def handle_navigation(event): print('Navigation event:', event) unsubscribe = client.subscribe_to_device_event('device-123', 'navigation', handle_navigation) ### close() Closes the client and cleans up resources. Code (python): await client.close() ================================================================================ Document: Reference Mcp Server URL: https://herd.garden/docs/reference-mcp-server # MCP Server Herd's MCP Server allows you to securely expose web applications to Large Language Models (LLMs) through local browser automation. Using the Model Context Protocol (MCP), you can create a secure bridge between AI models and your favorite websites without sharing credentials or running browsers in the cloud. ## Key Benefits - **Secure Access**: Your browser runs locally, keeping your credentials and cookies secure - **Privacy First**: No need to share sensitive data or tokens with third-party services - **Native Experience**: Interact with web apps through your actual browser, maintaining all your preferences and login state - **Universal Compatibility**: Works with any web application without needing API access - **Custom Tools**: Create tailored tools that encapsulate complex web interactions ## javascript ## Installation Code (bash): npm install @monitoro/herd ## Basic Setup Here's how to create an MCP server that exposes web application functionality: Code (javascript): import { HerdMcpServer } from '@monitoro/herd'; const server = new HerdMcpServer({ info: { name: "gmail-assistant", version: "1.0.0", description: "Gmail automation tools for LLMs" }, transport: { type: "sse", port: 3000 }, herd: { token: "your-herd-token" // Get from herd.garden } }); // Start the server await server.start(); ## Creating Web App Tools Tools encapsulate web application functionality for LLMs. Here are some examples: Code (javascript): // Gmail: Compose new email server.tool({ name: "composeEmail", description: "Compose and send a new email", schema: { to: z.string().email(), subject: z.string(), body: z.string() } }, async ({ to, subject, body }, devices) => { const device = devices[0]; const page = await device.newPage(); // Navigate to Gmail compose await page.goto('https://mail.google.com/mail/u/0/#compose'); // Fill out the email form await page.type('input[aria-label="To"]', to); await page.type('input[aria-label="Subject"]', subject); await page.type('div[aria-label="Message Body"]', body); // Send the email await page.click('div[aria-label="Send"]'); return { success: true }; }); // Twitter: Post a tweet server.tool({ name: "postTweet", description: "Post a new tweet", schema: { content: z.string().max(280) } }, async ({ content }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/compose/tweet'); await page.type('div[aria-label="Tweet text"]', content); await page.click('div[data-testid="tweetButton"]'); return { success: true }; }); ## Creating Web App Resources Resources provide structured data from web applications: Code (javascript): // Gmail: Unread emails server.resource({ name: "unreadEmails", uriOrTemplate: "gmail/unread", }, async (devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://mail.google.com/mail/u/0/#inbox'); // Extract unread email information const emails = await page.evaluate(() => { return Array.from(document.querySelectorAll('tr.unread')) .map(row => ({ sender: row.querySelector('.sender').textContent, subject: row.querySelector('.subject').textContent, date: row.querySelector('.date').textContent })); }); return { emails }; }); // LinkedIn: Profile Information server.resource({ name: "linkedinProfile", uriOrTemplate: "linkedin/profile/{username}", }, async ({ username }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto(`https://www.linkedin.com/in/${username}`); // Extract profile information return await page.extract({ name: 'h1', headline: '.headline', about: '.about-section p', experience: '.experience-section li' }); }); ## Complete Example: Twitter Assistant Here's a complete example showing how to create an MCP server that provides Twitter automation capabilities to LLMs: Code (javascript): import { HerdMcpServer } from '@monitoro/herd'; import { z } from 'zod'; const server = new HerdMcpServer({ info: { name: "twitter-assistant", version: "1.0.0", description: "Twitter automation for LLMs" }, transport: { type: "sse", port: 3000 }, herd: { token: process.env.HERD_TOKEN } }); // Post a tweet server.tool({ name: "postTweet", description: "Post a new tweet", schema: { content: z.string().max(280) } }, async ({ content }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/compose/tweet'); await page.type('div[aria-label="Tweet text"]', content); await page.click('div[data-testid="tweetButton"]'); return { success: true }; }); // Get timeline server.resource({ name: "timeline", uriOrTemplate: "twitter/timeline", }, async (devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto('https://twitter.com/home'); return await page.extract({ tweets: { _$r: 'article[data-testid="tweet"]', author: '[data-testid="User-Name"]', content: '[data-testid="tweetText"]', stats: { likes: '[data-testid="like"]', retweets: '[data-testid="retweet"]' } } }); }); // Like a tweet server.tool({ name: "likeTweet", description: "Like a tweet by its URL", schema: { tweetUrl: z.string().url() } }, async ({ tweetUrl }, devices) => { const device = devices[0]; const page = await device.newPage(); await page.goto(tweetUrl); await page.click('div[data-testid="like"]'); return { success: true }; }); // Start the server server.start().then(() => { console.log('Twitter Assistant ready!'); }).catch(console.error); This setup allows LLMs to: 1. Post tweets 2. Read the timeline 3. Like tweets 4. All through your local browser, maintaining your security and privacy ## python The MCP Server implementation is currently only available in JavaScript. Python support is coming soon! In the meantime, you can: 1. Use the JavaScript implementation to create your MCP server 2. Connect to it from Python using standard MCP client libraries 3. Use the Python Herd SDK for direct browser automation without MCP Example of direct web automation with Python: Code (python): from monitoro_herd import HerdClient async def main(): client = HerdClient(token="your-token") await client.initialize() device = await client.get_device("my-browser") page = await device.new_page() # Navigate to Twitter await page.goto("https://twitter.com") # Extract timeline content content = await page.extract({ "tweets": { "_$r": "article[data-testid='tweet']", "author": "[data-testid='User-Name']", "content": "[data-testid='tweetText']" } }) print("Timeline:", content) # Run the async function import asyncio asyncio.run(main()) Stay tuned for native Python MCP support! Read more about Model Context Protocol in the MCP official documentation. ================================================================================ Document: Reference Node URL: https://herd.garden/docs/reference-node # Node The Node class provides a DOM-like API for interacting with elements on a page. It allows you to inspect and manipulate elements using familiar DOM methods and properties. ## javascript You can obtain Node instances through Page query methods: - `page.querySelector(selector)` - Find first matching element - `page.querySelectorAll(selector)` - Find all matching elements - `node.querySelector(selector)` - Find first matching element within this node - `node.querySelectorAll(selector)` - Find all matching elements within this node ## Properties ### nodeType The type of node (1 for Element, 3 for Text). ### nodeName The name of the node (tag name for elements, '#text' for text nodes). ### nodeValue The text content for text nodes, null for elements. ### tagName The tag name of the element (empty string for non-elements). ### textContent The text content of the node and its descendants. ### innerHTML The HTML content inside the element. ### childNodes Array of child nodes. ### firstChild The first child node, or null if none exists. ### lastChild The last child node, or null if none exists. ## Methods ### getAttribute(name) Gets the value of an attribute. Code (javascript): const href = element.getAttribute('href'); ### hasAttribute(name) Checks if an attribute exists. Code (javascript): if (element.hasAttribute('disabled')) { console.log('Element is disabled'); } ### click([options]) Clicks the element. Code (javascript): // Simple click await element.click(); // Click with navigation wait await element.click({ waitForNavigation: 'networkidle2' }); ### type(text[, options]) Types text into the element. Code (javascript): await element.type('Hello world'); ### focus([options]) Focuses the element. Code (javascript): await element.focus(); ### blur([options]) Removes focus from the element. Code (javascript): await element.blur(); ### hover([options]) Hovers over the element. Code (javascript): await element.hover(); ### scrollIntoView([options]) Scrolls the element into view. Code (javascript): await element.scrollIntoView(); ### setValue(value[, options]) Sets the value of a form element. Code (javascript): // Set input value await element.setValue('test@example.com'); // Set checkbox await element.setValue(true); ### dispatchEvent(eventName[, detail, options]) Dispatches an event on the element. Code (javascript): await element.dispatchEvent('click'); ### dragTo(target[, options]) Drags this element to another element or selector. Code (javascript): // Drag to another element const target = await page.querySelector('.dropzone'); await element.dragTo(target); // Drag to selector await element.dragTo('.dropzone'); ### querySelector(selector) Finds the first matching element within this node. Code (javascript): const child = await element.querySelector('.child'); ### querySelectorAll(selector) Finds all matching elements within this node. Code (javascript): const children = await element.querySelectorAll('.child'); ### getBoundingClientRect() Gets the element's position and size. Code (javascript): const rect = element.getBoundingClientRect(); console.log(rect.x, rect.y, rect.width, rect.height); ## Example Usage Here's a complete example showing how to use the Node class: Code (javascript): // Get a form element const form = await page.querySelector('form'); // Fill out form fields const emailInput = await form.querySelector('input[type="email"]'); await emailInput.type('test@example.com'); // Check a checkbox const checkbox = await form.querySelector('.terms-checkbox'); await checkbox.setValue(true); // Get form dimensions const rect = form.getBoundingClientRect(); console.log('Form size:', rect.width, rect.height); // Submit the form const submitButton = await form.querySelector('button[type="submit"]'); await submitButton.click({ waitForNavigation: 'networkidle2' }); ## python The Node API is currently only available in JavaScript. In Python, you should use the Page methods directly with CSS selectors to interact with elements: Code (python): # Instead of: # element = await page.querySelector('.button') # await element.click() # Use: await page.click('.button') # Instead of: # element = await page.querySelector('input') # await element.type('Hello') # Use: await page.type('input', 'Hello') This provides the same functionality but with a slightly different API. The Node API will be available in Python in a future release. ================================================================================ Document: Reference Page URL: https://herd.garden/docs/reference-page # Page The Page class represents a browser tab or page in the Herd platform. It provides methods for navigating, interacting with elements, handling events, and automating browser actions. ## javascript You can obtain a Page instance using any of these Device methods: - `device.newPage()` - Create a new page - `device.listPages()` - Get all pages - `device.getPage(pageId)` - Get a specific page by ID ## Properties ### id The unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab. ### url The current URL of the page. Returns an empty string if the page hasn't loaded any URL yet. ### title The current title of the page. Returns an empty string if the page hasn't loaded or has no title. ### active Whether this page is currently the active tab in the browser window. ## Methods ### goto(url[, options]) Navigates the page to the specified URL. Code (javascript): // Navigate to a URL and wait for network to be idle await page.goto('https://example.com'); // Navigate with custom options await page.goto('https://example.com', { waitForNavigation: 'load' // Wait for load event instead of network idle }); Options: - `waitForNavigation`: When to consider navigation complete - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### querySelector(selector) Finds the first element matching the CSS selector. Returns a Node object that can be used for further interactions. Code (javascript): const element = await page.querySelector('.submit-button'); if (element) { console.log('Element found:', element.textContent); } ### querySelectorAll(selector) Finds all elements matching the CSS selector. Returns an array of Node objects. Code (javascript): const elements = await page.querySelectorAll('li.item'); for (const element of elements) { console.log('Item text:', element.textContent); } ### dom() Returns the DOM of the page as a JSDOM object for ultimate flexibility. This is useful for extracting data by walking the DOM and finding elements manually. Note: This is a read-only view of the DOM, so you cannot trigger events or modify the DOM this way. Code (javascript): const dom = await page.dom(); console.log(dom); ### waitForElement(selector[, options]) Waits for an element matching the selector to appear or disappear on the page. Code (javascript): // Wait for an element to be visible await page.waitForElement('#loading-indicator'); // or the following which is equivalent await page.waitForElement('#loading-indicator', { state: 'visible' }); // Wait for an element to be hidden await page.waitForElement('#loading-indicator', { state: 'hidden' }); // Wait for an element to be attached to DOM await page.waitForElement('.dynamic-content', { state: 'attached' }); // Wait for an element to be detached from DOM await page.waitForElement('.old-content', { state: 'detached' }); // Wait with timeout await page.waitForElement('.dynamic-content', { state: 'visible', timeout: 10000 // 10 seconds (default is 5 seconds) }); Options: - `state`: The state to wait for - `'visible'`: Wait for element to be visible (default) - `'hidden'`: Wait for element to be hidden - `'attached'`: Wait for element to be attached to DOM - `'detached'`: Wait for element to be detached from DOM - `timeout`: Maximum time to wait in milliseconds (default: 5000) ### waitForSelector(selector[, options]) Alias for waitForElement. Waits for an element matching the selector to appear or disappear. Code (javascript): // Wait for a selector to be visible await page.waitForSelector('.search-results', { state: 'visible' }); // Wait for a selector to be detached await page.waitForSelector('.loading-spinner', { state: 'detached', timeout: 5000 }); ### waitForNavigation(condition) Waits for navigation to complete based on the specified condition. Code (javascript): // Wait for page load event await page.waitForNavigation('load'); // Wait for network to be idle await page.waitForNavigation('networkidle0'); // Wait for URL change await page.waitForNavigation('change'); Conditions: - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'change'`: Wait for URL change - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### click(selector[, options]) Clicks an element that matches the selector. Code (javascript): // Simple click await page.click('#submit-button'); // Click with navigation wait await page.click('a.link', { waitForNavigation: 'networkidle2' }); ### type(selector, text[, options]) Types text into an input element. Code (javascript): // Type into an input field await page.type('#search-input', 'search query'); // Type with navigation wait (for auto-submit forms) await page.type('#search-input', 'search query', { waitForNavigation: 'networkidle2' }); ### focus(selector[, options]) Focuses an element on the page. Code (javascript): await page.focus('#email-input'); ### hover(selector[, options]) Hovers over an element. Code (javascript): await page.hover('.dropdown-trigger'); ### press(key[, options]) Presses a keyboard key. Code (javascript): await page.press('Enter'); ### scroll(x, y[, options]) Scrolls the page by the specified amount. Code (javascript): // Scroll down 500 pixels await page.scroll(0, 500); ### scrollIntoView(selector[, options]) Scrolls an element into view. Code (javascript): await page.scrollIntoView('#bottom-content'); ### back([options]) Navigates back in the browser history. Code (javascript): await page.back({ waitForNavigation: 'networkidle2' }); ### forward([options]) Navigates forward in the browser history. Code (javascript): await page.forward({ waitForNavigation: 'networkidle2' }); ### reload([options]) Reloads the current page. Code (javascript): await page.reload({ waitForNavigation: 'networkidle2' }); ### activate() Activates the page (makes it the active tab). Code (javascript): await page.activate(); ### close() Closes the page (tab). Code (javascript): await page.close(); ## Example Usage Here's a complete example showing how to use the Page class: Code (javascript): // Create a new page const page = await device.newPage(); // Navigate to a URL await page.goto('https://example.com'); // Fill out a form await page.type('#username', 'myuser'); await page.type('#password', 'mypass'); await page.click('#submit-button', { waitForNavigation: 'networkidle2' }); // Extract some data const title = await page.evaluate(() => document.title); console.log('Page title:', title); // Close the page when done await page.close(); ## python You can obtain a Page instance using any of these Device methods: - `device.new_page()` - Create a new page - `device.list_pages()` - Get all pages - `device.get_page(page_id)` - Get a specific page by ID ## Properties ### id The unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab. ### url The current URL of the page. Returns an empty string if the page hasn't loaded any URL yet. ### title The current title of the page. Returns an empty string if the page hasn't loaded or has no title. ### active Whether this page is currently the active tab in the browser window. ## Methods ### goto(url[, options]) Navigates the page to the specified URL. Code (python): # Navigate to a URL and wait for network to be idle await page.goto("https://example.com") # Navigate with custom options await page.goto("https://example.com", { "waitForNavigation": "load" # Wait for load event instead of network idle }) Options: - `waitForNavigation`: When to consider navigation complete - `'load'`: Wait for load event - `'domcontentloaded'`: Wait for DOMContentLoaded event - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms) - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms) ### querySelector(selector) / Q(selector) Finds the first element matching the CSS selector. Returns a dictionary representing the element. Code (python): # Using querySelector (alias for Q) element = await page.querySelector(".submit-button") if element: print("Element found:", element) # Using Q directly element = await page.Q(".submit-button") ### querySelectorAll(selector) / QQ(selector) Finds all elements matching the CSS selector. Returns a list of dictionaries representing the elements. Code (python): # Using querySelectorAll (alias for QQ) elements = await page.querySelectorAll("li.item") for element in elements: print("Item:", element) # Using QQ directly elements = await page.QQ("li.item") ### click(selector[, options]) Clicks an element that matches the selector. Code (python): # Simple click await page.click("#submit-button") # Click with navigation wait await page.click("a.link", {"waitForNavigation": "networkidle2"}) ### type(selector, text[, options]) Types text into an input element. Code (python): # Type into an input field await page.type("#search-input", "search query") # Type with navigation wait (for auto-submit forms) await page.type("#search-input", "search query", { "waitForNavigation": "networkidle2" }) ### focus(selector[, options]) Focuses an element on the page. Code (python): await page.focus("#email-input") ### hover(selector[, options]) Hovers over an element. Code (python): await page.hover(".dropdown-trigger") ### scroll(x, y[, options]) Scrolls the page by the specified amount. Code (python): # Scroll down 500 pixels await page.scroll(0, 500) ### scroll_into_view(selector[, options]) Scrolls an element into view. Code (python): await page.scroll_into_view("#bottom-content") ### set_value(selector, value[, options]) Sets the value of a form element directly. Code (python): # Set input value await page.set_value("#quantity", "5") # Set checkbox await page.set_value("#agree", True) ### dispatch_event(selector, event_name[, detail, options]) Dispatches a DOM event on an element. Code (python): await page.dispatch_event("#my-button", "click") ### close() Closes the page (tab). Code (python): await page.close() ## Example Usage Here's a complete example showing how to use the Page class: Code (python): # Create a new page page = await device.new_page() # Navigate to a URL await page.goto("https://example.com") # Fill out a form await page.type("#username", "myuser") await page.type("#password", "mypass") await page.click("#submit-button", {"waitForNavigation": "networkidle2"}) # Extract some data using the extract method data = await page.extract({ "title": "h1", "description": ".description" }) print("Extracted data:", data) # Close the page when done await page.close() ================================================================================ Document: Security Privacy URL: https://herd.garden/docs/security-privacy # Security & Privacy in Herd At Herd, we take security and privacy seriously. This guide outlines the security features built into the platform and the privacy measures we take to protect your data. ## Security Architecture Herd is built with security at its core: ### End-to-End Encryption All communication between your browsers and the Herd platform is encrypted end-to-end: - **Transport Layer Security (TLS)**: All API requests and responses use TLS 1.3. - **WebRTC Encryption**: Remote control sessions use WebRTC with DTLS-SRTP encryption. - **Secure WebSockets**: Real-time communication uses encrypted WebSocket connections. - **NATS**: All communication between your browser and the code you run is encrypted end-to-end using a NATS-based PKI infrastructure and we do not intercept or inspect the content of the communication. ### Authentication & Authorization Multiple layers of security protect access to your account and devices: - **Multi-factor Authentication**: Optional 2FA for account access - **Device Registration Codes**: One-time codes for connecting browsers - **Session Management**: Automatic timeouts and the ability to revoke sessions - **Role-Based Access Control**: Granular permissions for team members ### Infrastructure Security Our platform infrastructure implements industry best practices: - **Regular Security Audits**: Third-party security audits of our systems - **Vulnerability Scanning**: Continuous monitoring for vulnerabilities - **Secure Development**: Strict coding practices and security reviews - **Cloud Security**: Leveraging secure cloud infrastructure with isolation between customers ## Privacy Features Herd includes several features to protect your privacy: ### Data Minimization We only collect the data necessary for the platform to function: - **Selective Access**: You control which browsers are connected and which data is shared - **No Unnecessary Telemetry**: Limited data collection focused on service performance - **Automatic Data Expiry**: Logs and temporary data are automatically purged after set periods ### User Control You maintain control over your data and connections: - **Connection Visibility**: Clear indicators when a browser is being monitored or controlled - **Permission Prompts**: Optional prompts before remote control is initiated - **Incognito Mode Handling**: Special handling of private browsing sessions - **Activity Logs**: Transparent logs of all remote control activities ### Compliance Features For organizations with specific compliance requirements: - **Data Residency Options**: Select where your data is stored (Enterprise plan) - **Compliance Reporting**: Generate reports for audit purposes - **Custom Retention Policies**: Set data retention periods to match your policies - **Privacy Mode**: Additional restrictions for sensitive environments ## Security Best Practices To maximize security when using Herd: ### Account Security - Use strong, unique passwords for your Herd account - Enable two-factor authentication - Regularly review active sessions and revoke any suspicious ones - Limit account access to necessary team members only ### Device Security - Register devices with descriptive names for easy identification - Regularly review connected devices and remove unused ones - Use device tagging to organize and manage access - Consider network-level restrictions for sensitive devices ### Remote Control Security - Always end remote control sessions when not in use - Use view-only mode when full control isn't necessary - Be cautious about what information is visible during remote sessions - Consider scheduling remote sessions in advance when possible ## Privacy Policy Herd's formal privacy policy can be found at [monitoro.co/privacy](https://monitoro.co/privacy). Key points include: - We do not sell your data to third parties - We only process your data to provide the Herd service - You retain ownership of all content viewed or managed through Herd - We implement strong security measures to protect your data - We are transparent about any data breaches or security incidents ## Security Updates We continuously improve our security and privacy features: - Security updates are automatically applied to the platform - Extension updates are released regularly with security improvements - Follow our blog for detailed information on security enhancements ## Reporting Security Issues If you discover a security vulnerability, please report it responsibly: 1. Email security@herd.garden with details of the vulnerability 2. Include steps to reproduce if possible 3. Allow time for us to address the issue before public disclosure Note: We unfortunately do not offer a bug bounty program as we are a small team and our resources are limited. We do appreciate your responsible disclosure and help keeping the internet a safer place. ================================================================================ Document: Trails Automations URL: https://herd.garden/docs/trails-automations # Trails Trails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process. ## javascript Trails are fully supported in the JavaScript SDK. ## Creating a Trail A trail defines the following components: - **urls.ts**: Exports an array of URL definitions - **selectors.ts**: Exports an array of selector configurations - **actions.ts**: Exports action classes that implement the `TrailAction` interface A trail at the minimum has the following structure: Code: google-search/ urls.ts selectors.ts actions.ts package.json The `package.json` file defines the trail and its dependencies: Code (json): { "name": "google-search", "description": "Search google for webpages.", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } You should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code. ## Trail Implementation Guide ### Step 1: Set up the trail structure Create a new directory for your trail with the following files: Code: my-trail/ urls.ts selectors.ts actions.ts package.json Add the basic package.json configuration: Code (json): { "name": "my-trail", "version": "1.0.0", "dependencies": { "@monitoro/herd": "latest" } } ### Step 2: Define URLs In `urls.ts`, export an array of URL definitions that your trail will interact with: Code (typescript): export default [{ "id": "my-url", "template": "https://example.com/path?param1={param1}&param2={param2}", "description": "Description of what this URL represents", "examples": [ { "param1": "value1", "param2": "value2" } ], "params": { "param1": { "type": "string", "required": true, "description": "Description of param1" }, "param2": { "type": "string", "required": false, "default": "defaultValue", "description": "Description of param2" } } }]; ### Step 3: Define Selectors In `selectors.ts`, export an array of selector configurations that define how to extract data from web pages: Code (typescript): export default [{ "id": "my-selector", "value": { "dataKey": { "_$r": "#main-container", "title": { "_
quot;: ".title" }, "description": { "_
quot;: ".description" }, "link": { "_
quot;: "a.link", "attribute": "href" } } }, "description": "Selector for extracting specific data", "examples": [ { "urlId": "my-url", "urlParams": { "param1": "value1", "param2": "value2" } } ] }]; ### Step 4: Implement Actions In `actions.ts`, define one or more action classes that implement the `TrailAction` interface: Code (typescript): import type { Device, TrailAction, TrailActionManifest, TrailRunResources } from "@monitoro/herd"; export class MyTrailAction implements TrailAction { manifest: TrailActionManifest = { name: "my-action", description: "Description of what this action does", params: { param1: { type: "string", description: "Description of param1" }, param2: { type: "number", description: "Description of param2", default: 10 } }, result: { type: "array", description: "Description of the result", items: { type: "object", properties: { property1: { type: "string" }, property2: { type: "number" } } } }, examples: [ { "param1": "value1", "param2": 10 } ] } async test(device: Device, params: Record, resources: TrailRunResources) { try { const result = await this.run(device, params, resources); // Validate result if (!result || result.length === 0) { return { status: "error", message: "No results found", result: [] }; } return { status: "success", result }; } catch (e) { return { status: "error", message: `Error: ${e}`, result: null }; } } async run(device: Device, params: Record, resources: TrailRunResources) { const { param1, param2 } = params; const page = await device.newPage(); try { // Navigate to URL using the URL template from urls.ts await page.goto(resources.url('my-url', { param1, param2 })); // Extract data using selectors from selectors.ts const extracted = await page.extract(resources.selector('my-selector')); // Process extracted data const results = (extracted as any)?.dataKey || []; // Return processed results return results; } finally { await page.close(); } } } ### Step 5: Testing and debugging Use the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest): Code (bash): herd trail test --action my-trail You can also watch for changes in the trail and re-run tests: Code (bash): herd trail test --action my-trail --watch # or herd trail test -a my-trail -w And you can also test selectors only: Code (bash): herd trail test --selector my-selector And watch for changes in the selectors: Code (bash): herd trail test --selector my-selector --watch # or herd trail test -s my-selector -w ### Step 6: Publish your trail Publishing is coming soon! ### Best Practices 1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc. 2. **Performance**: Minimize page loads and extract as much data as possible from each page. 3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain. 4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios. 5. **Versioning**: Increment your trail's version in package.json when making changes. ## python Trails support for Python SDK is coming soon. Stay tuned for updates! In the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them. ================================================================================ Document: Troubleshooting URL: https://herd.garden/docs/troubleshooting # Troubleshooting Herd This guide provides solutions for common issues you might encounter when using the Herd platform. If you can't find a solution here, please contact our [support team](/docs/getting-started) for further assistance. ## Installation Issues ### Extension Won't Install **Problem**: You can't install the Herd extension in your browser. **Solutions**: - Verify Developer mode is enabled in your browser's extensions page - Make sure you're using a supported browser (Chrome, Edge, Brave) - Try downloading the extension file again as it might be corrupted - Check if your browser has restrictions on installing third-party extensions - Try installing from a different browser profile If all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share. ### Extension Shows as Corrupted **Problem**: Your browser shows the Herd extension as corrupted or invalid. **Solutions**: - Re-download the extension package - Clear your browser cache before installing - Try extracting the zip file and loading it as an unpacked extension - Verify that you have the latest version of the extension If all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share. ## Connection Issues ### Browser is disconnected or no browser registered **Problem**: Running a trail or calling any Herd command throws an exception "Browser is disconnected or no browser registered". This means that your browser is not connected to the Herd platform **Solutions**: - First ensure that you have installed Herd and registered your browser following our [Getting Started guide](/docs/getting-started). - Check the internet connection of the computer where you installed Herd extension - Go to `chrome://extensions` and click the reload icon next to Herd extension - If that doesn't work, delete the extension and reconnect it again from scratch, following our [Getting Started guide](/docs/getting-started). If nothing works, [contact](mailto:support@herd.garden) us for additional help with as much context about the issue as you can share. ### Can't Connect to Herd Server **Problem**: The extension is installed but can't connect to the Herd server. **Solutions**: - Check your internet connection - Verify that the registration code is correct and hasn't expired - Make sure your firewall isn't blocking the connection - Try disabling any VPN or proxy services temporarily - Check if your organization blocks WebSocket connections ### Connection Keeps Dropping **Problem**: The connection between your browser and Herd keeps disconnecting. **Solutions**: - Check for network stability issues - Make sure your computer isn't going to sleep - Verify that the browser is allowed to run in the background - Check if other extensions are conflicting with Herd - Try connecting using a wired network connection if possible ## Remote Control Issues ### Black Screen During Remote Control **Problem**: You see a black screen when trying to view a remote browser. **Solutions**: - Check if the remote device is in sleep mode or locked - Refresh the remote control session - Make sure the remote browser tab is active (not minimized) - Try restarting the remote browser - Verify that the remote device has granted screen sharing permissions ### High Latency in Remote Control **Problem**: There's significant lag when controlling a remote browser. **Solutions**: - Lower the streaming quality in the remote control settings - Check network conditions on both ends - Close unnecessary tabs and applications on both devices - Make sure no bandwidth-heavy activities are running (like video streaming) - Try using a wired connection if possible ### Input Not Registering **Problem**: Mouse clicks or keyboard input aren't registering on the remote browser. **Solutions**: - Check if you're in "View Only" mode and switch to "Control" mode - Try clicking on the remote view area to ensure it has focus - Refresh the remote control session - Check if the remote browser is responding to local inputs - Try restarting the remote control session ## Account and Management Issues ### Device Not Appearing in Dashboard **Problem**: A connected device isn't showing up in your Herd dashboard. **Solutions**: - Verify the device is properly connected - Refresh the dashboard page - Check if the device is registered under a different account - Make sure the extension is enabled and running - Try reconnecting the device using a new registration code ### Can't Create New Device Registration **Problem**: You're unable to create a new device registration. **Solutions**: - Check if you've reached your plan's device limit - Verify that you have the necessary permissions in your account - Try using a different browser to access the dashboard - Clear your browser cache and cookies - Check if your account has any restrictions ## System Requirements If you're experiencing persistent issues, verify that your system meets these minimum requirements: - **Browser**: Chrome 70+, Edge 79+, or Brave 1.0+ - **Operating System**: Windows 10+, macOS 10.14+, or Ubuntu 18.04+ - **RAM**: 4GB minimum (8GB recommended) - **Network**: Stable internet connection with at least 1Mbps upload/download - **Processor**: Dual-core processor at 2GHz or higher ## Contacting Support If you've tried the solutions above and are still experiencing issues, please contact our support team: 1. Email: support@herd.garden 2. In-app: Click the "Help" icon in the dashboard footer 3. Documentation: Check for updated troubleshooting guides on our website When contacting support, please include: - Your browser type and version - Your operating system - A description of the issue - Any error messages you've received - Steps you've already taken to resolve the issue ================================================================================
method returns the first element that matches the CSS selector, or `null` if no element is found.\n\n#### Typing Text\n\nTo type text into an input field:\n\nCode (javascript):\n// Type text into an input field\nawait page.type('input[name=\"q\"]', 'Monitoro Herd automation');\nconsole.log('Text entered into search box');\n\nThe `type` method finds the element using the CSS selector and simulates typing the specified text.\n\n#### Clicking Elements\n\nTo click a button or link:\n\nCode (javascript):\n// Click a button\nawait page.click('input[type=\"submit\"]');\nconsole.log('Search button clicked');\n\nBy default, the `click` method just clicks the element. If you want to wait for navigation to complete after clicking:\n\nCode (javascript):\n// Click and wait for navigation\nawait page.click('input[type=\"submit\"]', { \n waitForNavigation: 'networkidle2' \n});\nconsole.log('Search button clicked and navigation completed');\n\nThe `networkidle2` option waits until there are no more than 2 network connections for at least 500ms.\n\n#### Waiting for Elements\n\nSometimes you need to wait for elements to appear on the page:\n\nCode (javascript):\n// Wait for an element to appear\nawait page.waitForSelector('#search');\nconsole.log('Search results have loaded');\n\nThis is useful when dealing with dynamic content that loads after the initial page load.\n\n#### Search Engine Example\n\nLet's put these concepts together in a search engine example:\n\nCode (javascript):\nasync function searchExample() {\n const client = new HerdClient('your-token');\n \n try {\n await client.initialize();\n const devices = await client.listDevices();\n const device = devices[0];\n const page = await device.newPage();\n \n // Navigate to a search engine\n console.log('Navigating to Google...');\n await page.goto('https://www.google.com');\n \n // Type in the search box\n console.log('Entering search query...');\n await page.type('input[name=\"q\"]', 'Monitoro Herd automation');\n \n // Submit the search form and wait for results\n console.log('Submitting search...');\n await page.click('input[type=\"submit\"]', { \n waitForNavigation: 'networkidle2' \n });\n \n // Wait for results to load completely\n console.log('Waiting for search results...');\n await page.waitForSelector('#search');\n \n // Extract search result titles\n console.log('Extracting search results...');\n const searchResults = await page.extract({\n titles: {\n _$r: '#search .g h3', // _$r extracts multiple elements\n text: ':root' // For each match, get its text\n }\n });\n \n // Display the search result titles\n console.log('\\nSearch Results:');\n searchResults.titles.forEach((result, index) =\u003e {\n console.log(`${index + 1}. ${result.text}`);\n });\n \n } catch (error) {\n console.error('Error:', error);\n } finally {\n await client.close();\n }\n}\n\n## python\n\n## Python SDK\n\n### Setting Up Your Environment\n\nBefore writing any code, you'll need to set up your Python environment and install the Herd SDK:\n\n1. Make sure you have Python 3.8+ installed\n2. Create a virtual environment (recommended)\n3. Install the SDK using pip:\n\nCode (bash):\npip install monitoro-herd\n\n### Initializing the Client\n\nThe first step in any automation is to initialize the Herd client with your API credentials:\n\nCode (python):\n# Import the Herd client\nfrom monitoro_herd import HerdClient\n\n# Initialize the client with your API URL and token\nclient = HerdClient('your-token')\n\n# Always initialize the client before using it\nclient.initialize()\nNote: **Note:** Replace the token with your actual Herd API token from your dashboard.\n\n### Connecting to a Device\n\nNext, connect to a device that will run your automation:\n\nCode (python):\n# Get available devices\ndevices = await client.list_devices()\n\n# Connect to the first device\ndevice = devices[0]\n\nprint(f\"Connected to device: {device.id}\")\n\n### Creating a Page and Navigating\n\nNow create a browser page and navigate to a website:\n\nCode (python):\n# Create a new page\npage = await device.new_page()\n\n# Navigate to a website\nawait page.goto(\"https://example.com\")\n\nprint(\"Successfully navigated to example.com\")\n\n### Extracting Basic Information\n\nExtract information from the page using CSS selectors:\n\nCode (python):\n# Extract basic information\ndata = await page.extract({\n \"title\": \"h1\", # Main heading\n \"description\": \"p\", # First paragraph\n \"link\": \"a\" # First link text\n})\n\n# Display the extracted data\nprint(\"Extracted data:\")\nprint(f\"Title: {data['title']}\")\nprint(f\"Description: {data['description']}\")\nprint(f\"Link: {data['link']}\")\n\n### Resource Management\n\nAlways close resources when you're done:\n\nCode (python):\n# Close the page\nawait page.close()\n\n# Close the client\nawait client.close()\n\n### Complete Basic Example\n\nHere's a complete example putting all these concepts together:\n\nCode (python):\nimport asyncio\nfrom monitoro_herd import HerdClient\n\nasync def basic_extraction():\n # Initialize the client\n client = HerdClient(\"your-token\")\n \n try:\n # Initialize the connection\n await client.initialize()\n print(\"Client initialized successfully\")\n \n # Get the first available device\n devices = await client.list_devices()\n if not devices:\n raise Exception(\"No devices available\")\n device = devices[0]\n print(f\"Connected to device: {device.id}\")\n \n # Create a new page\n page = await device.new_page()\n print(\"New page created\")\n \n # Navigate to a website\n print(\"Navigating to example.com...\")\n await page.goto(\"https://example.com\")\n print(\"Navigation complete\")\n \n # Extract data using simple selectors\n print(\"Extracting content...\")\n data = await page.extract({\n \"title\": \"h1\",\n \"description\": \"p\",\n \"link\": \"a\"\n })\n \n # Display the extracted data\n print(\"\\nExtracted data:\")\n print(f\"Title: {data['title']}\")\n print(f\"Description: {data['description']}\")\n print(f\"Link: {data['link']}\")\n \n except Exception as e:\n print(f\"Error during automation: {e}\")\n finally:\n # Always close resources\n print(\"Closing client connection...\")\n await client.close()\n print(\"Client connection closed\")\n\n# Run the async function\nasyncio.run(basic_extraction())\n\n### Working with Lists and Structured Data\n\nOne of the most powerful features of Herd is the ability to extract structured data from lists of elements. This is perfect for scraping search results, product listings, or article collections.\n\n#### The `_$r` Selector\n\nTo extract multiple elements that match a pattern, use the `_$r` (repeat) selector:\n\nCode (python):\n# Extract a list of items\ndata = await page.extract({\n \"items\": {\n \"_$r\": \".item\", # Find all elements with class \"item\"\n \"name\": \".item-name\", # For each item, get the name\n \"price\": \".price\" # For each item, get the price\n }\n})\n\n# Access the extracted items\nfor item in data[\"items\"]:\n print(f\"Name: {item['name']}, Price: {item['price']}\")\n\nThe `_$r` selector tells Herd to find all elements matching the selector and extract the specified properties for each one.\n\n#### Extracting Attributes\n\nSometimes you need to extract an attribute rather than the text content:\n\nCode (python):\n# Extract links and their href attributes\ndata = await page.extract({\n \"links\": {\n \"_$r\": \"a\", # Find all links\n \"text\": \":root\", # Get the link text\n \"url\": {\n \"_$\": \":root\", # Reference the same element\n \"attribute\": \"href\" # Get its href attribute\n }\n }\n})\n\n# Display the links\nfor link in data[\"links\"]:\n print(f\"Link: {link['text']} -\u003e {link['url']}\")\n\n#### Hacker News Example\n\nLet's put these concepts together to scrape stories from Hacker News:\n\nCode (python):\nimport asyncio\nfrom monitoro_herd import HerdClient\n\nasync def scrape_hacker_news():\n client = HerdClient(\"your-token\")\n \n try:\n await client.initialize()\n devices = await client.list_devices()\n device = devices[0]\n page = await device.new_page()\n \n # Navigate to Hacker News\n print(\"Navigating to Hacker News...\")\n await page.goto(\"https://news.ycombinator.com\")\n \n # Extract stories and their metadata\n print(\"Extracting stories...\")\n data = await page.extract({\n # Extract the story elements\n \"stories\": {\n \"_$r\": \".athing\", # Each story row\n \"title\": \".titleline \u003e a\", # Story title\n \"site\": \".sitestr\", # Source website\n \"link\": {\n \"_$\": \".titleline \u003e a\", # Story link\n \"attribute\": \"href\" # Get the URL\n }\n },\n # Extract the metadata (points, author, etc.)\n \"metadata\": {\n \"_$r\": \".subline\", # Metadata rows\n \"points\": \".score\", # Points count\n \"author\": \".hnuser\", # Author username\n \"time\": \".age\" # Submission time\n }\n })\n \n # Combine stories with their metadata\n # (They're in separate lists but in the same order)\n combined_stories = list(zip(data[\"stories\"], data[\"metadata\"]))\n \n # Display the first 3 stories\n print(f\"\\nExtracted {len(combined_stories)} stories:\")\n for i, (story, meta) in enumerate(combined_stories[:3]):\n print(f\"\\nStory {i+1}:\")\n print(f\"Title: {story['title']}\")\n if \"site\" in story:\n print(f\"Site: {story['site']}\")\n print(f\"Link: {story['link']}\")\n if \"points\" in meta:\n print(f\"Points: {meta['points']}\")\n if \"author\" in meta:\n print(f\"Author: {meta['author']}\")\n if \"time\" in meta:\n print(f\"Posted: {meta['time']}\")\n \n finally:\n await page.close()\n await client.close()\n\n# Run the function\nasyncio.run(scrape_hacker_news())\n\n## Tips for Successful Automation\n\n1. **Start Simple**: Begin with basic extractions before moving to complex interactions\n2. **Use Appropriate Selectors**: Learn CSS selectors to target elements precisely\n3. **Handle Errors**: Always include try/catch (JavaScript) or try/except (Python) blocks\n4. **Close Resources**: Always close pages and clients when done to avoid resource leaks\n5. **Test Incrementally**: Build your automation step by step, testing each part\n6. **Add Delays When Needed**: For dynamic content, use `waitForSelector` or similar methods\n7. **Debug with Screenshots**: Take screenshots during automation to see what's happening\n\n## Next Steps\n\nNow that you've created your first automation, you can:\n\n- Explore more complex selectors and extraction patterns\n- Learn how to handle authentication and login flows\n- Set up scheduled automations for regular data collection\n- Integrate with your existing systems via APIs\n\n================================================================================\n\nDocument: Connect Your Browser\nURL: https://herd.garden/docs/connect-your-browser\n\n# Connect your Browser to Herd\n\nAfter installing the Herd extension, you need to connect your browser to your account. This guide explains how to establish and manage connections between your browsers and the Herd platform. You can connect multiple browsers to the same account. Learn more about [managing multiple devices](/docs/device-management).\n\n## Device Registration\n\nBefore you can connect a browser, you need to register the device in your Herd dashboard:\n\n1. Log in to your Herd account\n2. Navigate to the \"Devices\" section\n3. Click \"Register New Device\" \n4. Enter a descriptive name for the device (e.g., \"Work Laptop - Chrome\")\n5. Choose appropriate tags if you're organizing devices into groups\n6. Click \"Create Registration\"\n7. Copy the registration code that appears (you'll need this to connect the browser)\n\n## Connecting Your Browser\n\nOnce you have a registration code, follow these steps to connect your browser:\n\n1. Make sure the Herd extension is installed in your browser\n2. Click the Herd icon in your browser toolbar\n3. Select \"Connect Browser\" or \"Register Device\" from the menu\n4. Paste the registration code into the field\n5. Click \"Connect\"\n6. You should see a confirmation message indicating the browser is now connected\n\n## Managing Active Connections\n\nYou can view and manage all your connected browsers from the Herd dashboard:\n\n### Viewing Connected Devices\n\n1. Log in to your Herd account\n2. Navigate to the \"Devices\" section\n3. The \"Active Connections\" tab shows all currently connected browsers\n4. Each connection displays information such as:\n - Device name\n - Browser type and version\n - Connection status\n - Last activity timestamp\n\n### Remote Actions\n\nOnce a browser is connected, you can perform various remote actions:\n\n1. **Remote Control**: Initiate a remote control session to view and interact with the browser\n2. **Capture Screenshot**: Take a snapshot of the current browser window\n3. **Tab Management**: View, open, close, or navigate tabs\n4. **Bookmark Management**: View or modify the browser's bookmarks\n5. **History Access**: View browsing history (if permissions allow)\n\n## Connection Troubleshooting\n\nIf you're having trouble connecting your browser to Herd, try these solutions:\n\n### Connection Failures\n\n* Verify that the registration code is correct and hasn't expired\n* Make sure the browser is online and has a stable internet connection\n* Check that the Herd extension is properly installed and enabled\n* Try restarting your browser\n\n### Dropped Connections\n\n* Check your network stability\n* Ensure the browser hasn't entered sleep mode\n* Verify that the extension hasn't been disabled\n* Check if a browser update has affected the extension\n\n### Reconnecting\n\nIf a connection is lost, you can easily reconnect:\n\n1. Click the Herd icon in your browser toolbar\n2. If the connection status shows \"Disconnected,\" click \"Reconnect\"\n3. If prompted, enter your registration code again\n4. Wait for the connection to be reestablished\n\n## Connection Security\n\nAll connections between your browser and the Herd platform are secured with end-to-end encryption. Your data remains private and protected throughout the connection process.\n\nFor more information on security features, see our [Security \u0026 Privacy](security-privacy) documentation.\n\n================================================================================\n\nDocument: Data Extraction\nURL: https://herd.garden/docs/data-extraction\n\n# Data Extraction\n\nWelcome to Monitoro Herd's powerful data extraction system! This guide will walk you through how to extract structured data from web pages using our intuitive selector system and transformation pipelines.\n\n## Understanding Selectors\n\nHerd provides a flexible and powerful way to extract data from web pages using a declarative JSON-based selector system.\n\n### Basic Extraction\n\n## javascript\n\nThe simplest form of extraction uses CSS selectors to target elements:\n\nCode (javascript):\n// Extract basic text content\nconst data = await page.extract({\n title: 'h1', // Extracts the main heading\n description: 'p', // Extracts the first paragraph\n link: 'a' // Extracts the first link text\n});\n\nconsole.log(data.title); // \"Welcome to Our Website\"\nconsole.log(data.description); // \"This is our homepage.\"\n\n## python\n\nThe simplest form of extraction uses CSS selectors to target elements:\n\nCode (python):\n# Extract basic text content\ndata = await page.extract({\n \"title\": \"h1\", # Extracts the main heading\n \"description\": \"p\", # Extracts the first paragraph\n \"link\": \"a\" # Extracts the first link text\n})\n\nprint(data[\"title\"]) # \"Welcome to Our Website\"\nprint(data[\"description\"]) # \"This is our homepage.\"\n\n### Advanced Selector Syntax\n\n## javascript\n\nFor more complex extraction needs, use the expanded object syntax:\n\nCode (javascript):\nconst data = await page.extract({\n title: {\n _$: 'h1', // CSS selector\n attribute: 'id' // Extract the ID attribute instead of text\n },\n price: {\n _$: '.price', // Target price element\n pipes: ['parseNumber'] // Apply transformation\n }\n});\n\n## python\n\nFor more complex extraction needs, use the expanded object syntax:\n\nCode (python):\ndata = await page.extract({\n \"title\": {\n \"_$\": \"h1\", # CSS selector\n \"attribute\": \"id\" # Extract the ID attribute instead of text\n },\n \"price\": {\n \"_$\": \".price\", # Target price element\n \"pipes\": [\"parseNumber\"] # Apply transformation\n }\n})\n\n### Extracting Lists of Items\n\n## javascript\n\nTo extract multiple elements that match a pattern, use the `_$r` (repeat) selector:\n\nCode (javascript):\nconst data = await page.extract({\n items: {\n _$r: '.item', // Find all elements with class \"item\"\n title: 'h2', // For each item, get the title\n price: '.price', // For each item, get the price\n date: 'time' // For each item, get the date\n }\n});\n\n// Access the extracted items\ndata.items.forEach(item =\u003e {\n console.log(`${item.title}: ${item.price}, Posted: ${item.date}`);\n});\n\n## python\n\nTo extract multiple elements that match a pattern, use the `_$r` (repeat) selector:\n\nCode (python):\ndata = await page.extract({\n \"items\": {\n \"_$r\": \".item\", # Find all elements with class \"item\"\n \"title\": \"h2\", # For each item, get the title\n \"price\": \".price\", # For each item, get the price\n \"date\": \"time\" # For each item, get the date\n }\n})\n\n# Access the extracted items\nfor item in data[\"items\"]:\n print(f\"{item['title']}: {item['price']}, Posted: {item['date']}\")\n\n### Nested Extraction\n\n## javascript\n\nYou can nest selectors to extract hierarchical data:\n\nCode (javascript):\nconst data = await page.extract({\n product: {\n name: '.product-name',\n details: {\n _$: '.product-details',\n specs: {\n _$r: '.spec-item',\n label: '.spec-label',\n value: '.spec-value'\n }\n }\n }\n});\n\n## python\n\nYou can nest selectors to extract hierarchical data:\n\nCode (python):\ndata = await page.extract({\n \"product\": {\n \"name\": \".product-name\",\n \"details\": {\n \"_$\": \".product-details\",\n \"specs\": {\n \"_$r\": \".spec-item\",\n \"label\": \".spec-label\",\n \"value\": \".spec-value\"\n }\n }\n }\n})\n\n## Special Selectors\n\nHerd provides special selectors to handle various extraction scenarios:\n\n### Root Selector (`:root`)\n\nThe `:root` selector refers to the current element in context:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n items: {\n _$r: '.item',\n someElement: ':root', // Extract text of the .item element itself\n classes: {\n _$: ':root',\n attribute: 'class' // Extract class attribute of the same element\n }\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"items\": {\n \"_$r\": \".item\",\n \"someElement\": \":root\", # Extract text of the .item element itself\n \"classes\": {\n \"_$\": \":root\",\n \"attribute\": \"class\" # Extract class attribute of the same element\n }\n }\n})\n\n### Property Extraction\n\nYou can extract JavaScript properties from elements:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n dimensions: {\n _$: '.box',\n property: 'getBoundingClientRect' // Get element dimensions\n },\n html: {\n _$: '.content',\n property: 'innerHTML' // Get inner HTML\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"dimensions\": {\n \"_$\": \".box\",\n \"property\": \"getBoundingClientRect\" # Get element dimensions\n },\n \"html\": {\n \"_$\": \".content\",\n \"property\": \"innerHTML\" # Get inner HTML\n }\n})\n\n## Transformation Pipelines\n\nHerd includes powerful transformation pipelines to process extracted data:\n\n### Available Transformations\n\n| Pipe | Description | Example Input | Example Output |\n|------|-------------|--------------|----------------|\n| `trim` | Removes whitespace from start/end | `\" Hello \"` | `\"Hello\"` |\n| `toLowerCase` | Converts text to lowercase | `\"HELLO\"` | `\"hello\"` |\n| `toUpperCase` | Converts text to uppercase | `\"hello\"` | `\"HELLO\"` |\n| `parseNumber` | Extracts numbers from text | `\"$1,2K.45\"` | `1200.45` |\n| `parseDate` | Converts text to date | `\"2024-01-15\"` | `\"2024-01-15T00:00:00.000Z\"` |\n| `parseDateTime` | Converts text to datetime | `\"2024-01-15T12:00:00Z\"` | `\"2024-01-15T12:00:00.000Z\"` |\n\n### Using Transformations\n\nApply transformations using the `pipes` property:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n price: {\n _$: '.price',\n pipes: ['parseNumber'] // Convert \"$1,234.56\" to 1234.56\n },\n title: {\n _$: 'h1',\n pipes: ['trim', 'toLowerCase'] // Apply multiple transformations\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"price\": {\n \"_$\": \".price\",\n \"pipes\": [\"parseNumber\"] # Convert \"$1,234.56\" to 1234.56\n },\n \"title\": {\n \"_$\": \"h1\",\n \"pipes\": [\"trim\", \"toLowerCase\"] # Apply multiple transformations\n }\n})\n\n### Handling Currency and Large Numbers\n\nThe `parseNumber` transformation handles various formats:\n\n## javascript\n\nCode (javascript):\nconst data = await page.extract({\n price1: {\n _$: '.price-1', // Contains \"$1,234.56\"\n pipes: ['parseNumber'] // Result: 1234.56\n },\n price2: {\n _$: '.price-2', // Contains \"$1.5M\"\n pipes: ['parseNumber'] // Result: 1500000\n },\n price3: {\n _$: '.price-3', // Contains \"1.5T€\"\n pipes: ['parseNumber'] // Result: 1500000000000\n }\n});\n\n## python\n\nCode (python):\ndata = await page.extract({\n \"price1\": {\n \"_$\": \".price-1\", # Contains \"$1,234.56\"\n \"pipes\": [\"parseNumber\"] # Result: 1234.56\n },\n \"price2\": {\n \"_$\": \".price-2\", # Contains \"$1.5M\"\n \"pipes\": [\"parseNumber\"] # Result: 1500000\n },\n \"price3\": {\n \"_$\": \".price-3\", # Contains \"1.5T€\"\n \"pipes\": [\"parseNumber\"] # Result: 1500000000000\n }\n})\n\n## Real-World Examples\n\nLet's look at some practical examples of data extraction:\n\n### E-commerce Product Listing\n\nExtract products from a search results page:\n\n## javascript\n\nCode (javascript):\nconst searchResults = await page.extract({\n products: {\n _$r: '[data-component-type=\"s-search-result\"]',\n title: {\n _$: 'h2 .a-link-normal',\n pipes: ['trim']\n },\n price: {\n _$: '.a-price .a-offscreen',\n pipes: ['parseNumber']\n },\n rating: {\n _$: '.a-icon-star-small .a-icon-alt',\n pipes: ['trim']\n },\n reviews: {\n _$: '.a-size-base.s-underline-text',\n pipes: ['trim']\n }\n }\n});\n\n## python\n\nCode (python):\nsearchResults = await page.extract({\n \"products\": {\n \"_$r\": '[data-component-type=\"s-search-result\"]',\n \"title\": {\n \"_$\": \"h2 .a-link-normal\",\n \"pipes\": [\"trim\"]\n },\n \"price\": {\n \"_$\": \".a-price .a-offscreen\",\n \"pipes\": [\"parseNumber\"]\n },\n \"rating\": {\n \"_$\": \".a-icon-star-small .a-icon-alt\",\n \"pipes\": [\"trim\"]\n },\n \"reviews\": {\n \"_$\": \".a-size-base.s-underline-text\",\n \"pipes\": [\"trim\"]\n }\n }\n})\n\n### News Article List\n\nExtract articles from a news site:\n\n## javascript\n\nCode (javascript):\nconst articles = await page.extract({\n items: {\n _$r: '.item',\n title: {\n _$: 'h2',\n pipes: ['trim', 'toLowerCase']\n },\n price: {\n _$: '.price',\n pipes: ['parseNumber']\n },\n date: {\n _$: 'time',\n pipes: ['parseDate']\n }\n }\n});\n\n## python\n\nCode (python):\narticles = await page.extract({\n \"items\": {\n \"_$r\": \".item\",\n \"title\": {\n \"_$\": \"h2\",\n \"pipes\": [\"trim\", \"toLowerCase\"]\n },\n \"price\": {\n \"_$\": \".price\",\n \"pipes\": [\"parseNumber\"]\n },\n \"date\": {\n \"_$\": \"time\",\n \"pipes\": [\"parseDate\"]\n }\n }\n})\n\n## Advanced Techniques\n\n### Handling Dynamic Content\n\nFor dynamic content that loads after the page is ready:\n\n## javascript\n\nCode (javascript):\n// Wait for dynamic content to load\nawait page.waitForElement('#dynamic span');\n\n// Then extract the content\nconst data = await page.extract({\n content: '#dynamic span'\n});\n\n## python\n\nCode (python):\n# Wait for dynamic content to load\nawait page.waitForElement('#dynamic span')\n\n# Then extract the content\ndata = await page.extract({\n \"content\": \"#dynamic span\"\n})\n\n### Extracting Page Metadata\n\nExtract information about the page itself:\n\n## javascript\n\nCode (javascript):\nconst pageInfo = await page.extract({\n title: 'title',\n metaDescription: 'meta[name=\"description\"]',\n canonicalUrl: {\n _$: 'link[rel=\"canonical\"]',\n attribute: 'href'\n }\n});\n\n## python\n\nCode (python):\npageInfo = await page.extract({\n \"title\": \"title\",\n \"metaDescription\": 'meta[name=\"description\"]',\n \"canonicalUrl\": {\n \"_$\": 'link[rel=\"canonical\"]',\n \"attribute\": \"href\"\n }\n})\n\n## Tips for Effective Extraction\n\n1. **Use Specific Selectors**: The more specific your CSS selectors, the more reliable your extraction\n2. **Test Incrementally**: Build your extraction schema step by step, testing each part\n3. **Handle Missing Data**: Always account for elements that might not exist on the page\n4. **Apply Appropriate Transformations**: Use pipes to clean and format data as needed\n5. **Combine with Interactions**: For complex sites, interact with the page before extraction\n\n## Next Steps\n\nNow that you understand Herd's data extraction system, you can:\n\n- Create complex extraction schemas for any website\n- Transform raw data into structured, usable formats\n- Build powerful automations that collect and process web data\n\n================================================================================\n\nDocument: Device Management\nURL: https://herd.garden/docs/device-management\n\n# Device Management\n\nManaging your devices in Herd is simple and intuitive. This guide will walk you through the various actions you can perform on the Devices page.\n\n## Understanding the Devices Page\n\nThe Devices page is your central hub for managing all browsers and headless devices connected to your Herd account. Here you can:\n\n- View all your connected devices\n- Register new devices\n- Access device registration URLs\n- Delete devices you no longer need\n\n## Viewing Your Devices\n\nWhen you visit the Devices page, you'll see a list of all your registered devices. For each device, you can view:\n\n- Device name\n- Status (active or inactive)\n- Device ID\n- Device type (browser or headless)\n- Last active timestamp\n\nDevices with an active status will display a pulsing green indicator, while inactive devices will show a gray status indicator.\n\n## Registering a New Device\n\nTo add a new device to your Herd account:\n\n1. Click the **Register New Device** button at the top of the Devices page\n2. Enter a name for your device (or use the suggested name)\n3. Select the device type:\n - **Browser**: For devices with a visual interface such as your own browser\n - **Headless**: For devices running in headless mode (for docker and kubernetes deployments)\n4. Click **Register Device**\n5. A registration URL will be generated - use this URL to connect your device to Herd\n\nThe registration URL will be stored locally in your browser, allowing you to access it again later if needed.\n\n## Accessing Registration URLs\n\nIf you need to access a previously generated registration URL:\n\n1. Find the device in your devices list\n2. Look for the \"Registration URL available\" indicator\n3. Click the **View URL** button\n4. The registration URL will be displayed in a modal window\n\nThis is particularly useful if you need to reconnect a device or share the registration link with team members.\n\n## Deleting a Device\n\nTo remove a device from your Herd account:\n\n1. Find the device you want to delete in your devices list\n2. Click the **Delete** button for that device\n3. Confirm the deletion in the confirmation dialog\n\nPlease note that deleting a device is permanent and cannot be undone. The device will be removed from your account, and any stored registration URLs for that device will be cleared from your local storage.\n\n## Device Status\n\nDevices in Herd can have different statuses:\n\n- **Active**: The device is currently connected and ready to use\n- **Inactive**: The device is registered but not currently connected\n\nAn active device can be used immediately for automation tasks, while inactive devices need to be reconnected before use.\n\n## Best Practices\n\nHere are some tips for effective device management:\n\n- Use descriptive names for your devices to easily identify them\n- Regularly clean up unused devices to keep your dashboard organized\n- Store registration URLs securely if you plan to share them with team members\n- Check the \"Last Active\" timestamp to identify devices that haven't been used recently\n\nBy following these guidelines, you'll be able to maintain an organized and efficient device management system in Herd.\n\n================================================================================\n\nDocument: Getting Started\nURL: https://herd.garden/docs/getting-started\n\n# Getting Started with Herd\n\nThis guide will help you get up and running with Herd quickly to run your first trail.\n\n## What is Herd?\n\nHerd connects AI Agents to websites using your own browser credentials. It enables you to:\n\n- **Run Trails** - pre-built automations for specific websites and tasks\n- **Extract data and interact with websites** using your logged-in browser sessions\n- **Interact with web pages** through AI Agents like OpenAI's ChatGPT and Anthropic's Claude\n\n## Quick Start\n\n### 1. Install the Browser Extension\n\n Chrome\n\n Edge\n\n Brave\n\n### 2. Register Your Browser\n\nAfter installing the extension:\n\n1. Click the Herd icon in your browser toolbar\n2. Sign in with your Herd account (or create one)\n3. Name your device and register it\n\n![Browser Registration](https://herd.garden/register-device.png)\n\n### 3. Install the Herd SDK\n\nInstall the Herd SDK using npm:\n\n## npm\n\nCode (bash):\nnpm install -g @monitoro/herd\n\n## yarn\n\nCode (bash):\nyarn global add @monitoro/herd\n\n## pnpm\n\nCode (bash):\npnpm add -g @monitoro/herd\n\n### 4. Run Your First Trail\n\nThe browser trail provides core functionality for navigating and extracting data from any website. Run this command to test it out:\n\nCode (bash):\nherd trail run @herd/browser -a markdown -p '{\"url\": \"https://example.com\"}'\n\nThat's it! Add it to your MCP config to use it in your AI agents like in this example. Note, you can add as many trails as you want to your MCP config:\n\nCode (json):\n{\n \"mcpServers\": {\n \"browser\": {\n \"command\": \"herd\",\n \"args\": [\n \"trail\",\n \"server\",\n \"@herd/browser\"\n ]\n }\n }\n}\n\n## For Developers\n\nYou can also automate your browser with the Herd SDK. Connect to it with your AI agents or code:\n\n## javascript\n\nCode (javascript):\n// Connect to your Herd device\nconst client = new HerdClient('your-token');\nawait client.initialize();\nconst devices = await client.listDevices();\nconst device = devices[0];\n\n// Create a new page and navigate\nconst page = await device.newPage();\nawait page.goto(\"https://example.com\");\n\n// Extract data using simple selectors\nconst data = await page.extract({\n title: \"h1\",\n description: \"p\",\n link: \"a\"\n});\n\nconsole.log(\"Extracted data:\", data);\n\n## python\n\nCode (python):\nfrom monitoro_herd import HerdClient\n\n# Connect to your Herd device\nclient = HerdClient(\"your-token\")\nawait client.initialize()\ndevices = await client.list_devices()\ndevice = devices[0]\n\n# Create a new page and navigate\npage = await device.new_page()\nawait page.goto(\"https://example.com\")\n\n# Extract data using simple selectors\ndata = await page.extract({\n \"title\": \"h1\",\n \"description\": \"p\",\n \"link\": \"a\"\n})\n\nprint(\"Extracted data:\", data)\n\n## What's Next?\n\nNow that you've run your first trail, you can:\n\n- [Explore available trails](/trails) - Browse pre-built trails for various websites\n- [Learn about data extraction](/docs/data-extraction) - Extract structured data from web pages\n- [Create your own trail](/docs/trails-automations) - Build and share your own custom trails\n\n## Need Help?\n\nIf you encounter any issues during setup:\n\n- Make sure your browser extension is correctly installed and you're signed in\n- Check that your device is registered in the [device dashboard](/devices)\n- Visit our [troubleshooting guide](/docs/troubleshooting) for common solutions\n\n.browser-btn {\n display: inline-flex;\n align-items: center;\n padding: 0.2rem 1rem;\n background-color: #1f2937;\n color: white;\n border-radius: 0.375rem;\n font-size: 1.2rem;\n font-weight: 500;\n text-decoration: none;\n border: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.browser-btn:hover {\n background-color: #374151;\n}\n\n================================================================================\n\nDocument: Installation\nURL: https://herd.garden/docs/installation\n\n# Installing the Herd Extension\n\nThe Herd extension is the client component that allows your browser to be remotely managed. This guide provides detailed instructions for installing the extension on different browsers.\n\n## Chrome Installation\n\nThe Herd extension is primarily designed for Google Chrome and Chromium-based browsers. Follow these steps to install:\n\n### Standard Installation\n\n1. Download the Herd extension from your dashboard by clicking \"Download Herd\" in the navigation bar\n2. Open Chrome and navigate to `chrome://extensions`\n3. Enable \"Developer mode\" by toggling the switch in the top-right corner\n4. Drag and drop the downloaded `herd-latest.zip` file onto the extensions page\n5. Chrome will automatically install the extension\n\n### Verifying Installation\n\nAfter installation, you should see the Herd extension in your extensions list. To verify it's working correctly:\n\n1. Look for the Herd icon in your browser toolbar\n2. If it's not visible, click the puzzle piece icon to see all extensions and pin the Herd extension\n3. The icon should be colored, indicating it's ready to be connected\n\n## Installation on Other Browsers\n\nWhile Herd works best with Chrome, it's also compatible with other Chromium-based browsers:\n\n### Microsoft Edge\n\n1. Download the Herd extension zip file\n2. Open Edge and navigate to `edge://extensions`\n3. Enable \"Developer mode\" using the toggle in the left sidebar\n4. Drag and drop the `herd-latest.zip` file onto the extensions page\n5. Follow the prompts to complete installation\n\n### Brave Browser\n\n1. Download the Herd extension zip file\n2. Open Brave and navigate to `brave://extensions`\n3. Enable \"Developer mode\" in the top-right corner\n4. Drag and drop the `herd-latest.zip` file onto the extensions page\n5. Confirm the installation when prompted\n\n## Enterprise Deployment\n\nFor enterprise environments, you may want to deploy the Herd extension to multiple browsers. Here are some options:\n\n### Chrome Enterprise Policy\n\nYou can use Chrome Enterprise policies to automatically install and configure the Herd extension:\n\n1. Extract the Herd extension zip file to a network location accessible to all users\n2. Configure a policy to force-install extensions from a local path\n3. Set up the appropriate extension settings via policy\n\n### Manual Distribution\n\nFor smaller teams, you can manually distribute the extension:\n\n1. Download the extension once\n2. Share the zip file with team members\n3. Provide them with instructions for installation\n4. Create device registrations for each team member in your Herd dashboard\n\n## Troubleshooting Installation Issues\n\nIf you encounter issues during installation, try these solutions:\n\n### Extension Won't Install\n\n* Make sure Developer mode is enabled in your browser's extensions page\n* Check that you're using a supported browser (Chrome, Edge, Brave)\n* Verify that the zip file wasn't corrupted during download (try re-downloading)\n* Make sure you're dragging the zip file itself, not an extracted folder\n\n### Extension Installed But Not Working\n\n* Check if the extension is enabled in your browser\n* Try restarting your browser\n* Verify that you've completed the device registration process\n* Check your browser's console for any error messages\n\nFor more troubleshooting tips, see our [Troubleshooting](troubleshooting) guide.\n\n================================================================================\n\nDocument: Reference Device\nURL: https://herd.garden/docs/reference-device\n\n# Device\n\nThe Device class represents a connected browser or device in the Herd platform. It provides methods for managing pages, handling events, and controlling the device's lifecycle. \n\nEach Device instance gives you full control over a browser, allowing you to create and manage pages (tabs), handle various browser events, and automate browser interactions.\n\n## javascript\n\nYou can obtain a Device instance either by calling `client.listDevices()` to get all available devices, or `client.getDevice(deviceId)` to get a specific device by its ID.\n\n## Properties\n\n### deviceId\nThe unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered.\n\n### type\nThe type of device, which indicates its capabilities and behavior. Currently supported types include:\n- 'browser': A browser instance that can be automated\n- 'headless': A headless browser instance running on docker or kubernetes\n\n### name\nAn optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard.\n\n### status\nThe current status of the device. Possible values include:\n- 'online': The device is connected and ready to receive commands\n- 'offline': The device is not currently connected\n- 'busy': The device is processing a command\n- 'error': The device encountered an error\n\n### lastActive\nA timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a JavaScript Date object.\n\n## Methods\n\n### newPage()\nCreates a new page (tab) in the device.\n\nCode (javascript):\n// Create a new page\nconst page = await device.newPage();\nconsole.log('New page created:', page.id);\n\n### listPages()\nReturns a list of all pages (tabs) currently open in the device.\n\nCode (javascript):\n// List all open pages\nconst pages = await device.listPages();\npages.forEach(page =\u003e {\n console.log(`Page ${page.id}: ${page.url}`);\n});\n\n### getPage(pageId)\nGets a specific page by ID.\n\nCode (javascript):\n// Get a specific page\nconst page = await device.getPage(123);\nconsole.log('Current URL:', page.url);\n\n### onEvent(callback)\nSubscribes to all events from the device. Returns an unsubscribe function.\n\nCode (javascript):\n// Subscribe to all device events\nconst unsubscribe = device.onEvent((event) =\u003e {\n console.log('Device event:', event);\n});\n\n// Later: stop listening to events\nunsubscribe();\n\n### on(eventName, callback)\nSubscribes to a specific event from the device. Returns the device instance for chaining.\n\nCode (javascript):\n// Subscribe to specific events\ndevice.on('navigation', (event) =\u003e {\n console.log('Navigation occurred:', event);\n}).on('console', (event) =\u003e {\n console.log('Console message:', event);\n});\n\n### close()\nCloses the device and cleans up resources. This will close all pages and remove event listeners.\n\nCode (javascript):\n// Close the device and cleanup\nawait device.close();\n\n## Example Usage\n\nHere's a complete example showing how to use the Device class:\n\nCode (javascript):\nimport { HerdClient } from '@monitoro/herd';\n\nasync function main() {\n const client = new HerdClient({\n token: 'your-auth-token'\n });\n \n await client.initialize();\n \n // Get a device\n const device = await client.getDevice('my-browser');\n \n // Create a new page and navigate\n const page = await device.newPage();\n await page.goto('https://example.com');\n \n // Listen for navigation events\n device.on('navigation', (event) =\u003e {\n console.log('Page navigated:', event.url);\n });\n \n // List all pages\n const pages = await device.listPages();\n console.log(`Device has ${pages.length} pages open`);\n \n // Cleanup when done\n await device.close();\n await client.close();\n}\n\nmain().catch(console.error);\n\n## python\n\nYou can obtain a Device instance either by calling `client.list_devices()` to get all available devices, or `client.get_device(device_id)` to get a specific device by its ID.\n\n## Properties\n\n### device_id\nThe unique identifier for the device in the Herd platform. This is an internal ID that uniquely identifies the device in our system and is automatically generated when the device is registered.\n\n### type\nThe type of device, which indicates its capabilities and behavior. Currently supported types include:\n- 'browser': A browser instance that can be automated\n- 'headless': A headless browser instance running on docker or kubernetes\n\n### name\nAn optional display name for the device. This can be used to give the device a human-readable label for easier identification in your application or the Herd dashboard.\n\n### status\nThe current status of the device. Possible values include:\n- 'online': The device is connected and ready to receive commands\n- 'offline': The device is not currently connected\n- 'busy': The device is processing a command\n- 'error': The device encountered an error\n\n### last_active\nA timestamp indicating when the device was last active. This is automatically updated whenever the device performs an action or responds to a command. The value is a Python datetime object.\n\n## Methods\n\n### new_page()\nCreates a new page (tab) in the device.\n\nCode (python):\n# Create a new page\npage = await device.new_page()\nprint(f\"New page created: {page.id}\")\n\n### list_pages()\nReturns a list of all pages (tabs) currently open in the device.\n\nCode (python):\n# List all open pages\npages = await device.list_pages()\nfor page in pages:\n print(f\"Page {page.id}: {page.url}\")\n\n### get_page(page_id)\nGets a specific page by ID.\n\nCode (python):\n# Get a specific page\npage = await device.get_page(123)\nprint(f\"Current URL: {page.url}\")\n\n### on_event(callback)\nSubscribes to all events from the device. Returns an unsubscribe function.\n\nCode (python):\n# Subscribe to all device events\ndef handle_event(event):\n print(\"Device event:\", event)\n\nunsubscribe = device.on_event(handle_event)\n\n# Later: stop listening to events\nunsubscribe()\n\n### on(event_name, callback)\nSubscribes to a specific event from the device. Returns the device instance for chaining.\n\nCode (python):\n# Subscribe to specific events\ndef handle_navigation(event):\n print(\"Navigation occurred:\", event)\n\ndef handle_console(event):\n print(\"Console message:\", event)\n\ndevice.on(\"navigation\", handle_navigation)\\\n .on(\"console\", handle_console)\n\n### close()\nCloses the device and cleans up resources. This will close all pages and remove event listeners.\n\nCode (python):\n# Close the device and cleanup\nawait device.close()\n\n## Example Usage\n\nHere's a complete example showing how to use the Device class:\n\nCode (python):\nfrom monitoro_herd import HerdClient\n\nasync def main():\n client = HerdClient(\n token=\"your-auth-token\"\n )\n \n await client.initialize()\n \n # Get a device\n device = await client.get_device(\"my-browser\")\n \n # Create a new page and navigate\n page = await device.new_page()\n await page.goto(\"https://example.com\")\n \n # Listen for navigation events\n def handle_navigation(event):\n print(\"Page navigated:\", event[\"url\"])\n \n device.on(\"navigation\", handle_navigation)\n \n # List all pages\n pages = await device.list_pages()\n print(f\"Device has {len(pages)} pages open\")\n \n # Cleanup when done\n await device.close()\n await client.close()\n\n# Run the async function\nimport asyncio\nasyncio.run(main())\n\n================================================================================\n\nDocument: Reference Herd Client\nURL: https://herd.garden/docs/reference-herd-client\n\n# HerdClient\n\nThe HerdClient is the main entry point for interacting with the Herd platform. It provides methods for managing devices, pages, and executing browser automation commands.\n\n## javascript\n\n## Installation\n\nCode (bash):\nnpm install @monitoro/herd\n# or\nyarn add @monitoro/herd\n\n## Usage\n\nCode (javascript):\nimport { HerdClient } from '@monitoro/herd';\n\n// Create a client instance\nconst client = new HerdClient({\n token: 'your-auth-token' // Get your token at herd.garden\n});\n\n// Initialize the client\nawait client.initialize();\n\n## Methods\n\n### initialize()\nInitializes the client by establishing connections to the Herd platform. Must be called before using other methods.\n\nCode (javascript):\nawait client.initialize();\n\n### listDevices()\nReturns a list of all available devices.\n\nCode (javascript):\nconst devices = await client.listDevices();\nconsole.log('Available devices:', devices);\n\n### getDevice(deviceId)\nGets a specific device by ID.\n\nCode (javascript):\nconst device = await client.getDevice('device-123');\n\n### registerDevice(options)\nRegisters a new device with the platform.\n\nCode (javascript):\nconst device = await client.registerDevice({\n deviceId: 'my-device',\n type: 'browser',\n name: 'My Test Browser'\n});\n\n### sendCommand(deviceId, command, params)\nSends a command to a specific device. This is a low-level method that allows you to send arbitrary commands to a device and is not recommended for most use cases.\n\nCode (javascript):\nconst result = await client.sendCommand('device-123', 'Page.click', {\n selector: '#submit-button'\n});\n\n### subscribeToDeviceEvents(deviceId, callback)\nSubscribes to all events from a device.\n\nCode (javascript):\nconst unsubscribe = client.subscribeToDeviceEvents('device-123', (event) =\u003e {\n console.log('Device event:', event);\n});\n\n// Later: unsubscribe to stop receiving events\nunsubscribe();\n\n### subscribeToDeviceEvent(deviceId, eventName, callback) \nSubscribes to a specific event from a device.\n\nCode (javascript):\nconst unsubscribe = client.subscribeToDeviceEvent('device-123', 'navigation', (event) =\u003e {\n console.log('Navigation event:', event);\n});\n\n### close()\nCloses the client and cleans up resources.\n\nCode (javascript):\nawait client.close();\n\n## python\n\n## Installation\n\nCode (bash):\npip install monitoro-herd\n\n## Usage\n\nCode (python):\nfrom monitoro_herd import HerdClient\n\n# Create a client instance\nclient = HerdClient(\n token='your-auth-token' # Get your token at herd.garden\n)\n\n# Initialize the client\nawait client.initialize()\n\n## Methods\n\n### initialize()\nInitializes the client by establishing connections to the Herd platform. Must be called before using other methods.\n\nCode (python):\nawait client.initialize()\n\n### list_devices()\nReturns a list of all available devices.\n\nCode (python):\ndevices = await client.list_devices()\nprint('Available devices:', devices)\n\n### get_device(device_id)\nGets a specific device by ID.\n\nCode (python):\ndevice = await client.get_device('device-123')\n\n### register_device(device_id, device_type, name)\nRegisters a new device with the platform.\n\nCode (python):\ndevice = await client.register_device(\n device_id='my-device',\n device_type='browser',\n name='My Test Browser'\n)\n\n### send_command(device_id, command, payload)\nSends a command to a specific device.\n\nCode (python):\nresult = await client.send_command(\n 'device-123',\n 'Page.click',\n {'selector': '#submit-button'}\n)\n\n### subscribe_to_device_events(device_id, callback)\nSubscribes to all events from a device.\n\nCode (python):\ndef handle_event(event):\n print('Device event:', event)\n\nunsubscribe = client.subscribe_to_device_events('device-123', handle_event)\n\n# Later: unsubscribe to stop receiving events\nunsubscribe()\n\n### subscribe_to_device_event(device_id, event_name, callback)\nSubscribes to a specific event from a device.\n\nCode (python):\ndef handle_navigation(event):\n print('Navigation event:', event)\n\nunsubscribe = client.subscribe_to_device_event('device-123', 'navigation', handle_navigation)\n\n### close()\nCloses the client and cleans up resources.\n\nCode (python):\nawait client.close()\n\n================================================================================\n\nDocument: Reference Mcp Server\nURL: https://herd.garden/docs/reference-mcp-server\n\n# MCP Server\n\nHerd's MCP Server allows you to securely expose web applications to Large Language Models (LLMs) through local browser automation. Using the Model Context Protocol (MCP), you can create a secure bridge between AI models and your favorite websites without sharing credentials or running browsers in the cloud.\n\n## Key Benefits\n\n- **Secure Access**: Your browser runs locally, keeping your credentials and cookies secure\n- **Privacy First**: No need to share sensitive data or tokens with third-party services\n- **Native Experience**: Interact with web apps through your actual browser, maintaining all your preferences and login state\n- **Universal Compatibility**: Works with any web application without needing API access\n- **Custom Tools**: Create tailored tools that encapsulate complex web interactions\n\n## javascript\n\n## Installation\n\nCode (bash):\nnpm install @monitoro/herd\n\n## Basic Setup\n\nHere's how to create an MCP server that exposes web application functionality:\n\nCode (javascript):\nimport { HerdMcpServer } from '@monitoro/herd';\n\nconst server = new HerdMcpServer({\n info: {\n name: \"gmail-assistant\",\n version: \"1.0.0\",\n description: \"Gmail automation tools for LLMs\"\n },\n transport: {\n type: \"sse\",\n port: 3000\n },\n herd: {\n token: \"your-herd-token\" // Get from herd.garden\n }\n});\n\n// Start the server\nawait server.start();\n\n## Creating Web App Tools\n\nTools encapsulate web application functionality for LLMs. Here are some examples:\n\nCode (javascript):\n// Gmail: Compose new email\nserver.tool({\n name: \"composeEmail\",\n description: \"Compose and send a new email\",\n schema: {\n to: z.string().email(),\n subject: z.string(),\n body: z.string()\n }\n}, async ({ to, subject, body }, devices) =\u003e {\n const device = devices[0];\n const page = await device.newPage();\n \n // Navigate to Gmail compose\n await page.goto('https://mail.google.com/mail/u/0/#compose');\n \n // Fill out the email form\n await page.type('input[aria-label=\"To\"]', to);\n await page.type('input[aria-label=\"Subject\"]', subject);\n await page.type('div[aria-label=\"Message Body\"]', body);\n \n // Send the email\n await page.click('div[aria-label=\"Send\"]');\n \n return { success: true };\n});\n\n// Twitter: Post a tweet\nserver.tool({\n name: \"postTweet\",\n description: \"Post a new tweet\",\n schema: {\n content: z.string().max(280)\n }\n}, async ({ content }, devices) =\u003e {\n const device = devices[0];\n const page = await device.newPage();\n \n await page.goto('https://twitter.com/compose/tweet');\n await page.type('div[aria-label=\"Tweet text\"]', content);\n await page.click('div[data-testid=\"tweetButton\"]');\n \n return { success: true };\n});\n\n## Creating Web App Resources\n\nResources provide structured data from web applications:\n\nCode (javascript):\n// Gmail: Unread emails\nserver.resource({\n name: \"unreadEmails\",\n uriOrTemplate: \"gmail/unread\",\n}, async (devices) =\u003e {\n const device = devices[0];\n const page = await device.newPage();\n \n await page.goto('https://mail.google.com/mail/u/0/#inbox');\n \n // Extract unread email information\n const emails = await page.evaluate(() =\u003e {\n return Array.from(document.querySelectorAll('tr.unread'))\n .map(row =\u003e ({\n sender: row.querySelector('.sender').textContent,\n subject: row.querySelector('.subject').textContent,\n date: row.querySelector('.date').textContent\n }));\n });\n \n return { emails };\n});\n\n// LinkedIn: Profile Information\nserver.resource({\n name: \"linkedinProfile\",\n uriOrTemplate: \"linkedin/profile/{username}\",\n}, async ({ username }, devices) =\u003e {\n const device = devices[0];\n const page = await device.newPage();\n \n await page.goto(`https://www.linkedin.com/in/${username}`);\n \n // Extract profile information\n return await page.extract({\n name: 'h1',\n headline: '.headline',\n about: '.about-section p',\n experience: '.experience-section li'\n });\n});\n\n## Complete Example: Twitter Assistant\n\nHere's a complete example showing how to create an MCP server that provides Twitter automation capabilities to LLMs:\n\nCode (javascript):\nimport { HerdMcpServer } from '@monitoro/herd';\nimport { z } from 'zod';\n\nconst server = new HerdMcpServer({\n info: {\n name: \"twitter-assistant\",\n version: \"1.0.0\",\n description: \"Twitter automation for LLMs\"\n },\n transport: {\n type: \"sse\",\n port: 3000\n },\n herd: {\n token: process.env.HERD_TOKEN\n }\n});\n\n// Post a tweet\nserver.tool({\n name: \"postTweet\",\n description: \"Post a new tweet\",\n schema: {\n content: z.string().max(280)\n }\n}, async ({ content }, devices) =\u003e {\n const device = devices[0];\n const page = await device.newPage();\n await page.goto('https://twitter.com/compose/tweet');\n await page.type('div[aria-label=\"Tweet text\"]', content);\n await page.click('div[data-testid=\"tweetButton\"]');\n return { success: true };\n});\n\n// Get timeline\nserver.resource({\n name: \"timeline\",\n uriOrTemplate: \"twitter/timeline\",\n}, async (devices) =\u003e {\n const device = devices[0];\n const page = await device.newPage();\n await page.goto('https://twitter.com/home');\n \n return await page.extract({\n tweets: {\n _$r: 'article[data-testid=\"tweet\"]',\n author: '[data-testid=\"User-Name\"]',\n content: '[data-testid=\"tweetText\"]',\n stats: {\n likes: '[data-testid=\"like\"]',\n retweets: '[data-testid=\"retweet\"]'\n }\n }\n });\n});\n\n// Like a tweet\nserver.tool({\n name: \"likeTweet\",\n description: \"Like a tweet by its URL\",\n schema: {\n tweetUrl: z.string().url()\n }\n}, async ({ tweetUrl }, devices) =\u003e {\n const device = devices[0];\n const page = await device.newPage();\n await page.goto(tweetUrl);\n await page.click('div[data-testid=\"like\"]');\n return { success: true };\n});\n\n// Start the server\nserver.start().then(() =\u003e {\n console.log('Twitter Assistant ready!');\n}).catch(console.error);\n\nThis setup allows LLMs to:\n1. Post tweets\n2. Read the timeline\n3. Like tweets\n4. All through your local browser, maintaining your security and privacy\n\n## python\n\nThe MCP Server implementation is currently only available in JavaScript. Python support is coming soon!\n\nIn the meantime, you can:\n1. Use the JavaScript implementation to create your MCP server\n2. Connect to it from Python using standard MCP client libraries\n3. Use the Python Herd SDK for direct browser automation without MCP\n\nExample of direct web automation with Python:\n\nCode (python):\nfrom monitoro_herd import HerdClient\n\nasync def main():\n client = HerdClient(token=\"your-token\")\n await client.initialize()\n \n device = await client.get_device(\"my-browser\")\n page = await device.new_page()\n \n # Navigate to Twitter\n await page.goto(\"https://twitter.com\")\n \n # Extract timeline content\n content = await page.extract({\n \"tweets\": {\n \"_$r\": \"article[data-testid='tweet']\",\n \"author\": \"[data-testid='User-Name']\",\n \"content\": \"[data-testid='tweetText']\"\n }\n })\n print(\"Timeline:\", content)\n\n# Run the async function\nimport asyncio\nasyncio.run(main())\n\nStay tuned for native Python MCP support!\n\nRead more about Model Context Protocol in the MCP official documentation.\n\n================================================================================\n\nDocument: Reference Node\nURL: https://herd.garden/docs/reference-node\n\n# Node\n\nThe Node class provides a DOM-like API for interacting with elements on a page. It allows you to inspect and manipulate elements using familiar DOM methods and properties.\n\n## javascript\n\nYou can obtain Node instances through Page query methods:\n- `page.querySelector(selector)` - Find first matching element\n- `page.querySelectorAll(selector)` - Find all matching elements\n- `node.querySelector(selector)` - Find first matching element within this node\n- `node.querySelectorAll(selector)` - Find all matching elements within this node\n\n## Properties\n\n### nodeType\nThe type of node (1 for Element, 3 for Text).\n\n### nodeName\nThe name of the node (tag name for elements, '#text' for text nodes).\n\n### nodeValue\nThe text content for text nodes, null for elements.\n\n### tagName\nThe tag name of the element (empty string for non-elements).\n\n### textContent\nThe text content of the node and its descendants.\n\n### innerHTML\nThe HTML content inside the element.\n\n### childNodes\nArray of child nodes.\n\n### firstChild\nThe first child node, or null if none exists.\n\n### lastChild\nThe last child node, or null if none exists.\n\n## Methods\n\n### getAttribute(name)\nGets the value of an attribute.\n\nCode (javascript):\nconst href = element.getAttribute('href');\n\n### hasAttribute(name)\nChecks if an attribute exists.\n\nCode (javascript):\nif (element.hasAttribute('disabled')) {\n console.log('Element is disabled');\n}\n\n### click([options])\nClicks the element.\n\nCode (javascript):\n// Simple click\nawait element.click();\n\n// Click with navigation wait\nawait element.click({ waitForNavigation: 'networkidle2' });\n\n### type(text[, options])\nTypes text into the element.\n\nCode (javascript):\nawait element.type('Hello world');\n\n### focus([options])\nFocuses the element.\n\nCode (javascript):\nawait element.focus();\n\n### blur([options])\nRemoves focus from the element.\n\nCode (javascript):\nawait element.blur();\n\n### hover([options])\nHovers over the element.\n\nCode (javascript):\nawait element.hover();\n\n### scrollIntoView([options])\nScrolls the element into view.\n\nCode (javascript):\nawait element.scrollIntoView();\n\n### setValue(value[, options])\nSets the value of a form element.\n\nCode (javascript):\n// Set input value\nawait element.setValue('test@example.com');\n\n// Set checkbox\nawait element.setValue(true);\n\n### dispatchEvent(eventName[, detail, options])\nDispatches an event on the element.\n\nCode (javascript):\nawait element.dispatchEvent('click');\n\n### dragTo(target[, options])\nDrags this element to another element or selector.\n\nCode (javascript):\n// Drag to another element\nconst target = await page.querySelector('.dropzone');\nawait element.dragTo(target);\n\n// Drag to selector\nawait element.dragTo('.dropzone');\n\n### querySelector(selector)\nFinds the first matching element within this node.\n\nCode (javascript):\nconst child = await element.querySelector('.child');\n\n### querySelectorAll(selector)\nFinds all matching elements within this node.\n\nCode (javascript):\nconst children = await element.querySelectorAll('.child');\n\n### getBoundingClientRect()\nGets the element's position and size.\n\nCode (javascript):\nconst rect = element.getBoundingClientRect();\nconsole.log(rect.x, rect.y, rect.width, rect.height);\n\n## Example Usage\n\nHere's a complete example showing how to use the Node class:\n\nCode (javascript):\n// Get a form element\nconst form = await page.querySelector('form');\n\n// Fill out form fields\nconst emailInput = await form.querySelector('input[type=\"email\"]');\nawait emailInput.type('test@example.com');\n\n// Check a checkbox\nconst checkbox = await form.querySelector('.terms-checkbox');\nawait checkbox.setValue(true);\n\n// Get form dimensions\nconst rect = form.getBoundingClientRect();\nconsole.log('Form size:', rect.width, rect.height);\n\n// Submit the form\nconst submitButton = await form.querySelector('button[type=\"submit\"]');\nawait submitButton.click({ waitForNavigation: 'networkidle2' });\n\n## python\n\nThe Node API is currently only available in JavaScript. In Python, you should use the Page methods directly with CSS selectors to interact with elements:\n\nCode (python):\n# Instead of:\n# element = await page.querySelector('.button')\n# await element.click()\n\n# Use:\nawait page.click('.button')\n\n# Instead of:\n# element = await page.querySelector('input')\n# await element.type('Hello')\n\n# Use:\nawait page.type('input', 'Hello')\n\nThis provides the same functionality but with a slightly different API. The Node API will be available in Python in a future release.\n\n================================================================================\n\nDocument: Reference Page\nURL: https://herd.garden/docs/reference-page\n\n# Page\n\nThe Page class represents a browser tab or page in the Herd platform. It provides methods for navigating, interacting with elements, handling events, and automating browser actions.\n\n## javascript\n\nYou can obtain a Page instance using any of these Device methods:\n- `device.newPage()` - Create a new page\n- `device.listPages()` - Get all pages\n- `device.getPage(pageId)` - Get a specific page by ID\n\n## Properties\n\n### id\nThe unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab.\n\n### url\nThe current URL of the page. Returns an empty string if the page hasn't loaded any URL yet.\n\n### title\nThe current title of the page. Returns an empty string if the page hasn't loaded or has no title.\n\n### active\nWhether this page is currently the active tab in the browser window.\n\n## Methods\n\n### goto(url[, options])\nNavigates the page to the specified URL.\n\nCode (javascript):\n// Navigate to a URL and wait for network to be idle\nawait page.goto('https://example.com');\n\n// Navigate with custom options\nawait page.goto('https://example.com', {\n waitForNavigation: 'load' // Wait for load event instead of network idle\n});\n\nOptions:\n- `waitForNavigation`: When to consider navigation complete\n - `'load'`: Wait for load event\n - `'domcontentloaded'`: Wait for DOMContentLoaded event\n - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms)\n - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms)\n\n### querySelector(selector)\nFinds the first element matching the CSS selector. Returns a Node object that can be used for further interactions.\n\nCode (javascript):\nconst element = await page.querySelector('.submit-button');\nif (element) {\n console.log('Element found:', element.textContent);\n}\n\n### querySelectorAll(selector)\nFinds all elements matching the CSS selector. Returns an array of Node objects.\n\nCode (javascript):\nconst elements = await page.querySelectorAll('li.item');\nfor (const element of elements) {\n console.log('Item text:', element.textContent);\n}\n\n### dom()\nReturns the DOM of the page as a JSDOM object for ultimate flexibility. This is useful for extracting data by walking the DOM and finding elements manually.\nNote: This is a read-only view of the DOM, so you cannot trigger events or modify the DOM this way.\n\nCode (javascript):\nconst dom = await page.dom();\nconsole.log(dom);\n\n### waitForElement(selector[, options])\nWaits for an element matching the selector to appear or disappear on the page.\n\nCode (javascript):\n// Wait for an element to be visible\nawait page.waitForElement('#loading-indicator'); // or the following which is equivalent \nawait page.waitForElement('#loading-indicator', { state: 'visible' });\n\n// Wait for an element to be hidden\nawait page.waitForElement('#loading-indicator', { state: 'hidden' });\n\n// Wait for an element to be attached to DOM\nawait page.waitForElement('.dynamic-content', { state: 'attached' });\n\n// Wait for an element to be detached from DOM\nawait page.waitForElement('.old-content', { state: 'detached' });\n\n// Wait with timeout\nawait page.waitForElement('.dynamic-content', { \n state: 'visible',\n timeout: 10000 // 10 seconds (default is 5 seconds)\n});\n\nOptions:\n- `state`: The state to wait for\n - `'visible'`: Wait for element to be visible (default)\n - `'hidden'`: Wait for element to be hidden\n - `'attached'`: Wait for element to be attached to DOM\n - `'detached'`: Wait for element to be detached from DOM\n- `timeout`: Maximum time to wait in milliseconds (default: 5000)\n\n### waitForSelector(selector[, options])\nAlias for waitForElement. Waits for an element matching the selector to appear or disappear.\n\nCode (javascript):\n// Wait for a selector to be visible\nawait page.waitForSelector('.search-results', { state: 'visible' });\n\n// Wait for a selector to be detached\nawait page.waitForSelector('.loading-spinner', { state: 'detached', timeout: 5000 });\n\n### waitForNavigation(condition)\nWaits for navigation to complete based on the specified condition.\n\nCode (javascript):\n// Wait for page load event\nawait page.waitForNavigation('load');\n\n// Wait for network to be idle\nawait page.waitForNavigation('networkidle0');\n\n// Wait for URL change\nawait page.waitForNavigation('change');\n\nConditions:\n- `'load'`: Wait for load event\n- `'domcontentloaded'`: Wait for DOMContentLoaded event\n- `'change'`: Wait for URL change\n- `'networkidle0'`: Wait for network to be idle (0 connections for 500ms)\n- `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms)\n\n### click(selector[, options])\nClicks an element that matches the selector.\n\nCode (javascript):\n// Simple click\nawait page.click('#submit-button');\n\n// Click with navigation wait\nawait page.click('a.link', { waitForNavigation: 'networkidle2' });\n\n### type(selector, text[, options])\nTypes text into an input element.\n\nCode (javascript):\n// Type into an input field\nawait page.type('#search-input', 'search query');\n\n// Type with navigation wait (for auto-submit forms)\nawait page.type('#search-input', 'search query', {\n waitForNavigation: 'networkidle2'\n});\n\n### focus(selector[, options])\nFocuses an element on the page.\n\nCode (javascript):\nawait page.focus('#email-input');\n\n### hover(selector[, options])\nHovers over an element.\n\nCode (javascript):\nawait page.hover('.dropdown-trigger');\n\n### press(key[, options])\nPresses a keyboard key.\n\nCode (javascript):\nawait page.press('Enter');\n\n### scroll(x, y[, options])\nScrolls the page by the specified amount.\n\nCode (javascript):\n// Scroll down 500 pixels\nawait page.scroll(0, 500);\n\n### scrollIntoView(selector[, options])\nScrolls an element into view.\n\nCode (javascript):\nawait page.scrollIntoView('#bottom-content');\n\n### back([options])\nNavigates back in the browser history.\n\nCode (javascript):\nawait page.back({ waitForNavigation: 'networkidle2' });\n\n### forward([options])\nNavigates forward in the browser history.\n\nCode (javascript):\nawait page.forward({ waitForNavigation: 'networkidle2' });\n\n### reload([options])\nReloads the current page.\n\nCode (javascript):\nawait page.reload({ waitForNavigation: 'networkidle2' });\n\n### activate()\nActivates the page (makes it the active tab).\n\nCode (javascript):\nawait page.activate();\n\n### close()\nCloses the page (tab).\n\nCode (javascript):\nawait page.close();\n\n## Example Usage\n\nHere's a complete example showing how to use the Page class:\n\nCode (javascript):\n// Create a new page\nconst page = await device.newPage();\n\n// Navigate to a URL\nawait page.goto('https://example.com');\n\n// Fill out a form\nawait page.type('#username', 'myuser');\nawait page.type('#password', 'mypass');\nawait page.click('#submit-button', { waitForNavigation: 'networkidle2' });\n\n// Extract some data\nconst title = await page.evaluate(() =\u003e document.title);\nconsole.log('Page title:', title);\n\n// Close the page when done\nawait page.close();\n\n## python\n\nYou can obtain a Page instance using any of these Device methods:\n- `device.new_page()` - Create a new page\n- `device.list_pages()` - Get all pages\n- `device.get_page(page_id)` - Get a specific page by ID\n\n## Properties\n\n### id\nThe unique identifier for the page (tab) in the browser. This is a number that uniquely identifies the tab.\n\n### url\nThe current URL of the page. Returns an empty string if the page hasn't loaded any URL yet.\n\n### title\nThe current title of the page. Returns an empty string if the page hasn't loaded or has no title.\n\n### active\nWhether this page is currently the active tab in the browser window.\n\n## Methods\n\n### goto(url[, options])\nNavigates the page to the specified URL.\n\nCode (python):\n# Navigate to a URL and wait for network to be idle\nawait page.goto(\"https://example.com\")\n\n# Navigate with custom options\nawait page.goto(\"https://example.com\", {\n \"waitForNavigation\": \"load\" # Wait for load event instead of network idle\n})\n\nOptions:\n- `waitForNavigation`: When to consider navigation complete\n - `'load'`: Wait for load event\n - `'domcontentloaded'`: Wait for DOMContentLoaded event\n - `'networkidle0'`: Wait for network to be idle (0 connections for 500ms)\n - `'networkidle2'`: Wait for network to be idle (≤ 2 connections for 500ms)\n\n### querySelector(selector) / Q(selector)\nFinds the first element matching the CSS selector. Returns a dictionary representing the element.\n\nCode (python):\n# Using querySelector (alias for Q)\nelement = await page.querySelector(\".submit-button\")\nif element:\n print(\"Element found:\", element)\n\n# Using Q directly\nelement = await page.Q(\".submit-button\")\n\n### querySelectorAll(selector) / QQ(selector)\nFinds all elements matching the CSS selector. Returns a list of dictionaries representing the elements.\n\nCode (python):\n# Using querySelectorAll (alias for QQ)\nelements = await page.querySelectorAll(\"li.item\")\nfor element in elements:\n print(\"Item:\", element)\n\n# Using QQ directly\nelements = await page.QQ(\"li.item\")\n\n### click(selector[, options])\nClicks an element that matches the selector.\n\nCode (python):\n# Simple click\nawait page.click(\"#submit-button\")\n\n# Click with navigation wait\nawait page.click(\"a.link\", {\"waitForNavigation\": \"networkidle2\"})\n\n### type(selector, text[, options])\nTypes text into an input element.\n\nCode (python):\n# Type into an input field\nawait page.type(\"#search-input\", \"search query\")\n\n# Type with navigation wait (for auto-submit forms)\nawait page.type(\"#search-input\", \"search query\", {\n \"waitForNavigation\": \"networkidle2\"\n})\n\n### focus(selector[, options])\nFocuses an element on the page.\n\nCode (python):\nawait page.focus(\"#email-input\")\n\n### hover(selector[, options])\nHovers over an element.\n\nCode (python):\nawait page.hover(\".dropdown-trigger\")\n\n### scroll(x, y[, options])\nScrolls the page by the specified amount.\n\nCode (python):\n# Scroll down 500 pixels\nawait page.scroll(0, 500)\n\n### scroll_into_view(selector[, options])\nScrolls an element into view.\n\nCode (python):\nawait page.scroll_into_view(\"#bottom-content\")\n\n### set_value(selector, value[, options])\nSets the value of a form element directly.\n\nCode (python):\n# Set input value\nawait page.set_value(\"#quantity\", \"5\")\n\n# Set checkbox\nawait page.set_value(\"#agree\", True)\n\n### dispatch_event(selector, event_name[, detail, options])\nDispatches a DOM event on an element.\n\nCode (python):\nawait page.dispatch_event(\"#my-button\", \"click\")\n\n### close()\nCloses the page (tab).\n\nCode (python):\nawait page.close()\n\n## Example Usage\n\nHere's a complete example showing how to use the Page class:\n\nCode (python):\n# Create a new page\npage = await device.new_page()\n\n# Navigate to a URL\nawait page.goto(\"https://example.com\")\n\n# Fill out a form\nawait page.type(\"#username\", \"myuser\")\nawait page.type(\"#password\", \"mypass\")\nawait page.click(\"#submit-button\", {\"waitForNavigation\": \"networkidle2\"})\n\n# Extract some data using the extract method\ndata = await page.extract({\n \"title\": \"h1\",\n \"description\": \".description\"\n})\nprint(\"Extracted data:\", data)\n\n# Close the page when done\nawait page.close()\n\n================================================================================\n\nDocument: Security Privacy\nURL: https://herd.garden/docs/security-privacy\n\n# Security \u0026 Privacy in Herd\n\nAt Herd, we take security and privacy seriously. This guide outlines the security features built into the platform and the privacy measures we take to protect your data.\n\n## Security Architecture\n\nHerd is built with security at its core:\n\n### End-to-End Encryption\n\nAll communication between your browsers and the Herd platform is encrypted end-to-end:\n\n- **Transport Layer Security (TLS)**: All API requests and responses use TLS 1.3.\n- **WebRTC Encryption**: Remote control sessions use WebRTC with DTLS-SRTP encryption.\n- **Secure WebSockets**: Real-time communication uses encrypted WebSocket connections.\n- **NATS**: All communication between your browser and the code you run is encrypted end-to-end using a NATS-based PKI infrastructure and we do not intercept or inspect the content of the communication.\n\n### Authentication \u0026 Authorization\n\nMultiple layers of security protect access to your account and devices:\n\n- **Multi-factor Authentication**: Optional 2FA for account access\n- **Device Registration Codes**: One-time codes for connecting browsers\n- **Session Management**: Automatic timeouts and the ability to revoke sessions\n- **Role-Based Access Control**: Granular permissions for team members\n\n### Infrastructure Security\n\nOur platform infrastructure implements industry best practices:\n\n- **Regular Security Audits**: Third-party security audits of our systems\n- **Vulnerability Scanning**: Continuous monitoring for vulnerabilities\n- **Secure Development**: Strict coding practices and security reviews\n- **Cloud Security**: Leveraging secure cloud infrastructure with isolation between customers\n\n## Privacy Features\n\nHerd includes several features to protect your privacy:\n\n### Data Minimization\n\nWe only collect the data necessary for the platform to function:\n\n- **Selective Access**: You control which browsers are connected and which data is shared\n- **No Unnecessary Telemetry**: Limited data collection focused on service performance\n- **Automatic Data Expiry**: Logs and temporary data are automatically purged after set periods\n\n### User Control\n\nYou maintain control over your data and connections:\n\n- **Connection Visibility**: Clear indicators when a browser is being monitored or controlled\n- **Permission Prompts**: Optional prompts before remote control is initiated\n- **Incognito Mode Handling**: Special handling of private browsing sessions\n- **Activity Logs**: Transparent logs of all remote control activities\n\n### Compliance Features\n\nFor organizations with specific compliance requirements:\n\n- **Data Residency Options**: Select where your data is stored (Enterprise plan)\n- **Compliance Reporting**: Generate reports for audit purposes\n- **Custom Retention Policies**: Set data retention periods to match your policies\n- **Privacy Mode**: Additional restrictions for sensitive environments\n\n## Security Best Practices\n\nTo maximize security when using Herd:\n\n### Account Security\n\n- Use strong, unique passwords for your Herd account\n- Enable two-factor authentication\n- Regularly review active sessions and revoke any suspicious ones\n- Limit account access to necessary team members only\n\n### Device Security\n\n- Register devices with descriptive names for easy identification\n- Regularly review connected devices and remove unused ones\n- Use device tagging to organize and manage access\n- Consider network-level restrictions for sensitive devices\n\n### Remote Control Security\n\n- Always end remote control sessions when not in use\n- Use view-only mode when full control isn't necessary\n- Be cautious about what information is visible during remote sessions\n- Consider scheduling remote sessions in advance when possible\n\n## Privacy Policy\n\nHerd's formal privacy policy can be found at [monitoro.co/privacy](https://monitoro.co/privacy). Key points include:\n\n- We do not sell your data to third parties\n- We only process your data to provide the Herd service\n- You retain ownership of all content viewed or managed through Herd\n- We implement strong security measures to protect your data\n- We are transparent about any data breaches or security incidents\n\n## Security Updates\n\nWe continuously improve our security and privacy features:\n\n- Security updates are automatically applied to the platform\n- Extension updates are released regularly with security improvements\n- Follow our blog for detailed information on security enhancements\n\n## Reporting Security Issues\n\nIf you discover a security vulnerability, please report it responsibly:\n\n1. Email security@herd.garden with details of the vulnerability\n2. Include steps to reproduce if possible\n3. Allow time for us to address the issue before public disclosure\n\nNote: We unfortunately do not offer a bug bounty program as we are a small team and our resources are limited. We do appreciate your responsible disclosure and help keeping the internet a safer place.\n\n================================================================================\n\nDocument: Trails Automations\nURL: https://herd.garden/docs/trails-automations\n\n# Trails\n\nTrails in the Herd platform are packaged automations that perform specific tasks such as extracting data or submitting forms. They make it easy to reuse automation logic across different projects and achieve high reliability through a solid and accessible testing process.\n\n## javascript\n\nTrails are fully supported in the JavaScript SDK.\n\n## Creating a Trail\n\nA trail defines the following components:\n\n- **urls.ts**: Exports an array of URL definitions\n- **selectors.ts**: Exports an array of selector configurations\n- **actions.ts**: Exports action classes that implement the `TrailAction` interface\n\nA trail at the minimum has the following structure:\n\nCode:\ngoogle-search/\n urls.ts\n selectors.ts\n actions.ts\n package.json\n\nThe `package.json` file defines the trail and its dependencies:\n\nCode (json):\n{\n \"name\": \"google-search\",\n \"description\": \"Search google for webpages.\",\n \"version\": \"1.0.0\",\n \"dependencies\": {\n \"@monitoro/herd\": \"latest\"\n }\n}\n\nYou should never run the .ts files manually. Instead, use the Herd CLI to run, test, debug, and publish trails. Make sure to use version control to manage your trails, as publishing submits a built version to the Herd registry, not the source code.\n\n## Trail Implementation Guide\n\n### Step 1: Set up the trail structure\n\nCreate a new directory for your trail with the following files:\n\nCode:\nmy-trail/\n urls.ts\n selectors.ts\n actions.ts\n package.json\n\nAdd the basic package.json configuration:\n\nCode (json):\n{\n \"name\": \"my-trail\",\n \"version\": \"1.0.0\",\n \"dependencies\": {\n \"@monitoro/herd\": \"latest\"\n }\n}\n\n### Step 2: Define URLs\n\nIn `urls.ts`, export an array of URL definitions that your trail will interact with:\n\nCode (typescript):\nexport default [{\n \"id\": \"my-url\",\n \"template\": \"https://example.com/path?param1={param1}\u0026param2={param2}\",\n \"description\": \"Description of what this URL represents\",\n \"examples\": [\n { \"param1\": \"value1\", \"param2\": \"value2\" }\n ],\n \"params\": {\n \"param1\": {\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Description of param1\"\n },\n \"param2\": {\n \"type\": \"string\",\n \"required\": false,\n \"default\": \"defaultValue\",\n \"description\": \"Description of param2\"\n }\n }\n}];\n\n### Step 3: Define Selectors\n\nIn `selectors.ts`, export an array of selector configurations that define how to extract data from web pages:\n\nCode (typescript):\nexport default [{\n \"id\": \"my-selector\",\n \"value\": {\n \"dataKey\": {\n \"_$r\": \"#main-container\",\n \"title\": { \"_$\": \".title\" },\n \"description\": { \"_$\": \".description\" },\n \"link\": { \"_$\": \"a.link\", \"attribute\": \"href\" }\n }\n },\n \"description\": \"Selector for extracting specific data\",\n \"examples\": [\n {\n \"urlId\": \"my-url\",\n \"urlParams\": { \"param1\": \"value1\", \"param2\": \"value2\" }\n }\n ]\n}];\n\n### Step 4: Implement Actions\n\nIn `actions.ts`, define one or more action classes that implement the `TrailAction` interface:\n\nCode (typescript):\nimport type { Device, TrailAction, TrailActionManifest, TrailRunResources } from \"@monitoro/herd\";\n\nexport class MyTrailAction implements TrailAction {\n manifest: TrailActionManifest = {\n name: \"my-action\",\n description: \"Description of what this action does\",\n params: {\n param1: {\n type: \"string\",\n description: \"Description of param1\"\n },\n param2: {\n type: \"number\",\n description: \"Description of param2\",\n default: 10\n }\n },\n result: {\n type: \"array\",\n description: \"Description of the result\",\n items: {\n type: \"object\",\n properties: {\n property1: { type: \"string\" },\n property2: { type: \"number\" }\n }\n }\n },\n examples: [\n {\n \"param1\": \"value1\",\n \"param2\": 10\n }\n ]\n }\n\n async test(device: Device, params: Record, resources: TrailRunResources) {\n try {\n const result = await this.run(device, params, resources);\n // Validate result\n if (!result || result.length === 0) {\n return { status: \"error\", message: \"No results found\", result: [] };\n }\n return { status: \"success\", result };\n } catch (e) {\n return { status: \"error\", message: `Error: ${e}`, result: null };\n }\n }\n\n async run(device: Device, params: Record, resources: TrailRunResources) {\n const { param1, param2 } = params;\n const page = await device.newPage();\n \n try {\n // Navigate to URL using the URL template from urls.ts\n await page.goto(resources.url('my-url', { param1, param2 }));\n \n // Extract data using selectors from selectors.ts\n const extracted = await page.extract(resources.selector('my-selector'));\n \n // Process extracted data\n const results = (extracted as any)?.dataKey || [];\n \n // Return processed results\n return results;\n } finally {\n await page.close();\n }\n }\n}\n\n### Step 5: Testing and debugging\n\nUse the Herd CLI to test your trail locally (make sure to define test cases as `examples` in the trail action manifest):\n\nCode (bash):\nherd trail test --action my-trail\n\nYou can also watch for changes in the trail and re-run tests:\n\nCode (bash):\nherd trail test --action my-trail --watch # or herd trail test -a my-trail -w\n\nAnd you can also test selectors only:\n\nCode (bash):\nherd trail test --selector my-selector\n\nAnd watch for changes in the selectors:\n\nCode (bash):\nherd trail test --selector my-selector --watch # or herd trail test -s my-selector -w\n\n### Step 6: Publish your trail\n\nPublishing is coming soon!\n\n### Best Practices\n\n1. **Error handling**: Implement robust error handling in your actions to handle network issues, missing elements, etc.\n2. **Performance**: Minimize page loads and extract as much data as possible from each page.\n3. **Maintainability**: Use descriptive names and add comments to make your trail easier to maintain.\n4. **Testing**: Test your trail with different parameters to ensure it works in various scenarios.\n5. **Versioning**: Increment your trail's version in package.json when making changes.\n\n## python\n\nTrails support for Python SDK is coming soon. Stay tuned for updates!\n\nIn the meantime, you can use the JavaScript SDK to create trails and then use the Herd CLI to publish them.\n\n================================================================================\n\nDocument: Troubleshooting\nURL: https://herd.garden/docs/troubleshooting\n\n# Troubleshooting Herd\n\nThis guide provides solutions for common issues you might encounter when using the Herd platform. If you can't find a solution here, please contact our [support team](/docs/getting-started) for further assistance.\n\n## Installation Issues\n\n### Extension Won't Install\n\n**Problem**: You can't install the Herd extension in your browser.\n\n**Solutions**:\n- Verify Developer mode is enabled in your browser's extensions page\n- Make sure you're using a supported browser (Chrome, Edge, Brave)\n- Try downloading the extension file again as it might be corrupted\n- Check if your browser has restrictions on installing third-party extensions\n- Try installing from a different browser profile\n\nIf all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share.\n\n### Extension Shows as Corrupted\n\n**Problem**: Your browser shows the Herd extension as corrupted or invalid.\n\n**Solutions**:\n- Re-download the extension package\n- Clear your browser cache before installing\n- Try extracting the zip file and loading it as an unpacked extension\n- Verify that you have the latest version of the extension\n\nIf all else fails, follow the [Getting Started guide](/docs/getting-started), or [contact](mailto:support@herd.garden) us for help with as much context about the issue as you can share.\n\n## Connection Issues\n\n### Browser is disconnected or no browser registered\n\n**Problem**: Running a trail or calling any Herd command throws an exception \"Browser is disconnected or no browser registered\".\nThis means that your browser is not connected to the Herd platform \n\n**Solutions**:\n- First ensure that you have installed Herd and registered your browser following our [Getting Started guide](/docs/getting-started).\n- Check the internet connection of the computer where you installed Herd extension\n- Go to `chrome://extensions` and click the reload icon next to Herd extension\n- If that doesn't work, delete the extension and reconnect it again from scratch, following our [Getting Started guide](/docs/getting-started).\n\nIf nothing works, [contact](mailto:support@herd.garden) us for additional help with as much context about the issue as you can share.\n\n### Can't Connect to Herd Server\n\n**Problem**: The extension is installed but can't connect to the Herd server.\n\n**Solutions**:\n- Check your internet connection\n- Verify that the registration code is correct and hasn't expired\n- Make sure your firewall isn't blocking the connection\n- Try disabling any VPN or proxy services temporarily\n- Check if your organization blocks WebSocket connections\n\n### Connection Keeps Dropping\n\n**Problem**: The connection between your browser and Herd keeps disconnecting.\n\n**Solutions**:\n- Check for network stability issues\n- Make sure your computer isn't going to sleep\n- Verify that the browser is allowed to run in the background\n- Check if other extensions are conflicting with Herd\n- Try connecting using a wired network connection if possible\n\n## Remote Control Issues\n\n### Black Screen During Remote Control\n\n**Problem**: You see a black screen when trying to view a remote browser.\n\n**Solutions**:\n- Check if the remote device is in sleep mode or locked\n- Refresh the remote control session\n- Make sure the remote browser tab is active (not minimized)\n- Try restarting the remote browser\n- Verify that the remote device has granted screen sharing permissions\n\n### High Latency in Remote Control\n\n**Problem**: There's significant lag when controlling a remote browser.\n\n**Solutions**:\n- Lower the streaming quality in the remote control settings\n- Check network conditions on both ends\n- Close unnecessary tabs and applications on both devices\n- Make sure no bandwidth-heavy activities are running (like video streaming)\n- Try using a wired connection if possible\n\n### Input Not Registering\n\n**Problem**: Mouse clicks or keyboard input aren't registering on the remote browser.\n\n**Solutions**:\n- Check if you're in \"View Only\" mode and switch to \"Control\" mode\n- Try clicking on the remote view area to ensure it has focus\n- Refresh the remote control session\n- Check if the remote browser is responding to local inputs\n- Try restarting the remote control session\n\n## Account and Management Issues\n\n### Device Not Appearing in Dashboard\n\n**Problem**: A connected device isn't showing up in your Herd dashboard.\n\n**Solutions**:\n- Verify the device is properly connected\n- Refresh the dashboard page\n- Check if the device is registered under a different account\n- Make sure the extension is enabled and running\n- Try reconnecting the device using a new registration code\n\n### Can't Create New Device Registration\n\n**Problem**: You're unable to create a new device registration.\n\n**Solutions**:\n- Check if you've reached your plan's device limit\n- Verify that you have the necessary permissions in your account\n- Try using a different browser to access the dashboard\n- Clear your browser cache and cookies\n- Check if your account has any restrictions\n\n## System Requirements\n\nIf you're experiencing persistent issues, verify that your system meets these minimum requirements:\n\n- **Browser**: Chrome 70+, Edge 79+, or Brave 1.0+\n- **Operating System**: Windows 10+, macOS 10.14+, or Ubuntu 18.04+\n- **RAM**: 4GB minimum (8GB recommended)\n- **Network**: Stable internet connection with at least 1Mbps upload/download\n- **Processor**: Dual-core processor at 2GHz or higher\n\n## Contacting Support\n\nIf you've tried the solutions above and are still experiencing issues, please contact our support team:\n\n1. Email: support@herd.garden\n2. In-app: Click the \"Help\" icon in the dashboard footer\n3. Documentation: Check for updated troubleshooting guides on our website\n\nWhen contacting support, please include:\n- Your browser type and version\n- Your operating system\n- A description of the issue\n- Any error messages you've received\n- Steps you've already taken to resolve the issue\n\n================================================================================\n","robots_txt_url":"/api/v1/crawler/top-sites/herd.garden/robots.txt","llms_txt_url":"/api/v1/crawler/top-sites/herd.garden/llms.txt","llms_full_txt_url":"/api/v1/crawler/top-sites/herd.garden/llms-full.txt"}}