19 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	Browser Automation Examples
Complete workflows demonstrating the use_browser tool capabilities.
Table of Contents
- E-Commerce Workflows
 - Form Automation
 - Data Extraction
 - Multi-Tab Operations
 - Dynamic Content Handling
 - Authentication Workflows
 
E-Commerce Workflows
Complete Booking Flow
Navigate multi-step booking process with validation:
// Step 1: Search
{action: "navigate", payload: "https://booking.example.com"}
{action: "await_element", selector: "input[name=destination]"}
{action: "type", selector: "input[name=destination]", payload: "San Francisco"}
{action: "type", selector: "input[name=checkin]", payload: "2025-12-01"}
{action: "click", selector: "button.search"}
// Step 2: Select hotel
{action: "await_element", selector: ".hotel-results"}
{action: "click", selector: ".hotel-card:first-child .select"}
// Step 3: Choose room
{action: "await_element", selector: ".room-options"}
{action: "click", selector: ".room[data-type=deluxe] .book"}
// Step 4: Guest info
{action: "await_element", selector: "form.guest-info"}
{action: "type", selector: "input[name=firstName]", payload: "Jane"}
{action: "type", selector: "input[name=lastName]", payload: "Smith"}
{action: "type", selector: "input[name=email]", payload: "jane@example.com"}
// Step 5: Review
{action: "click", selector: "button.review"}
{action: "await_element", selector: ".summary"}
// Validate
{action: "extract", payload: "text", selector: ".hotel-name"}
{action: "extract", payload: "text", selector: ".total-price"}
Price Comparison Across Sites
Open multiple stores in tabs and compare:
// Store 1
{action: "navigate", payload: "https://store1.com/product/12345"}
{action: "await_element", selector: ".price"}
// Open Store 2
{action: "new_tab"}
{action: "navigate", tab_index: 1, payload: "https://store2.com/product/12345"}
{action: "await_element", tab_index: 1, selector: ".price"}
// Open Store 3
{action: "new_tab"}
{action: "navigate", tab_index: 2, payload: "https://store3.com/product/12345"}
{action: "await_element", tab_index: 2, selector: ".price"}
// Extract all prices
{action: "extract", tab_index: 0, payload: "text", selector: ".price"}
{action: "extract", tab_index: 1, payload: "text", selector: ".price"}
{action: "extract", tab_index: 2, payload: "text", selector: ".price"}
// Get product info
{action: "extract", tab_index: 0, payload: "text", selector: ".product-name"}
{action: "extract", tab_index: 0, payload: "text", selector: ".stock-status"}
Product Data Extraction
Scrape structured product information:
{action: "navigate", payload: "https://shop.example.com/product/123"}
{action: "await_element", selector: ".product-details"}
// Extract all product data with one eval
{action: "eval", payload: `
  ({
    name: document.querySelector('h1.product-name').textContent.trim(),
    price: document.querySelector('.price').textContent.trim(),
    image: document.querySelector('.product-image img').src,
    description: document.querySelector('.description').textContent.trim(),
    stock: document.querySelector('.stock-status').textContent.trim(),
    rating: document.querySelector('.rating').textContent.trim(),
    reviews: Array.from(document.querySelectorAll('.review')).map(r => ({
      author: r.querySelector('.author').textContent,
      rating: r.querySelector('.stars').textContent,
      text: r.querySelector('.review-text').textContent
    }))
  })
`}
Batch Product Extraction
Get multiple products from category page:
{action: "navigate", payload: "https://shop.example.com/category/electronics"}
{action: "await_element", selector: ".product-grid"}
// Extract all products as array
{action: "eval", payload: `
  Array.from(document.querySelectorAll('.product-card')).map(card => ({
    name: card.querySelector('.product-name').textContent.trim(),
    price: card.querySelector('.price').textContent.trim(),
    image: card.querySelector('img').src,
    url: card.querySelector('a').href,
    inStock: !card.querySelector('.out-of-stock')
  }))
`}
Form Automation
Multi-Step Registration Form
Handle progressive form with validation at each step:
// Step 1: Personal info
{action: "navigate", payload: "https://example.com/register"}
{action: "await_element", selector: "input[name=firstName]"}
{action: "type", selector: "input[name=firstName]", payload: "John"}
{action: "type", selector: "input[name=lastName]", payload: "Doe"}
{action: "type", selector: "input[name=email]", payload: "john@example.com"}
{action: "click", selector: "button.next"}
// Wait for step 2
{action: "await_element", selector: "input[name=address]"}
// Step 2: Address
{action: "type", selector: "input[name=address]", payload: "123 Main St"}
{action: "type", selector: "input[name=city]", payload: "Springfield"}
{action: "select", selector: "select[name=state]", payload: "IL"}
{action: "type", selector: "input[name=zip]", payload: "62701"}
{action: "click", selector: "button.next"}
// Wait for step 3
{action: "await_element", selector: "input[name=cardNumber]"}
// Step 3: Payment
{action: "type", selector: "input[name=cardNumber]", payload: "4111111111111111"}
{action: "select", selector: "select[name=expMonth]", payload: "12"}
{action: "select", selector: "select[name=expYear]", payload: "2028"}
{action: "type", selector: "input[name=cvv]", payload: "123"}
// Review before submit
{action: "click", selector: "button.review"}
{action: "await_element", selector: ".summary"}
// Extract confirmation
{action: "extract", payload: "markdown", selector: ".summary"}
Search with Multiple Filters
Use dropdowns, checkboxes, and text inputs:
{action: "navigate", payload: "https://library.example.com/search"}
{action: "await_element", selector: "form.search"}
// Category dropdown
{action: "select", selector: "select[name=category]", payload: "books"}
// Price range
{action: "type", selector: "input[name=priceMin]", payload: "10"}
{action: "type", selector: "input[name=priceMax]", payload: "50"}
// Checkboxes via JavaScript
{action: "eval", payload: "document.querySelector('input[name=inStock]').checked = true"}
{action: "eval", payload: "document.querySelector('input[name=freeShipping]').checked = true"}
// Search term and submit
{action: "type", selector: "input[name=query]", payload: "chrome devtools\n"}
// Wait for results
{action: "await_element", selector: ".results"}
// Count and extract
{action: "eval", payload: "document.querySelectorAll('.result').length"}
{action: "extract", payload: "text", selector: ".result-count"}
File Upload
Handle file input using JavaScript:
{action: "navigate", payload: "https://example.com/upload"}
{action: "await_element", selector: "input[type=file]"}
// Read file and set via JavaScript (for testing)
{action: "eval", payload: `
  const fileInput = document.querySelector('input[type=file]');
  const dataTransfer = new DataTransfer();
  const file = new File(['test content'], 'test.txt', { type: 'text/plain' });
  dataTransfer.items.add(file);
  fileInput.files = dataTransfer.files;
`}
// Submit
{action: "click", selector: "button.upload"}
{action: "await_text", payload: "Upload complete"}
Data Extraction
Article Scraping
Extract blog post with metadata:
{action: "navigate", payload: "https://blog.example.com/article"}
{action: "await_element", selector: "article"}
// Extract complete article structure
{action: "eval", payload: `
  ({
    title: document.querySelector('article h1').textContent.trim(),
    author: document.querySelector('.author-name').textContent.trim(),
    date: document.querySelector('time').getAttribute('datetime'),
    tags: Array.from(document.querySelectorAll('.tag')).map(t => t.textContent.trim()),
    content: document.querySelector('article .content').textContent.trim(),
    images: Array.from(document.querySelectorAll('article img')).map(img => ({
      src: img.src,
      alt: img.alt
    })),
    links: Array.from(document.querySelectorAll('article a')).map(a => ({
      text: a.textContent.trim(),
      href: a.href
    }))
  })
`}
Table Data Extraction
Convert HTML table to structured JSON:
{action: "navigate", payload: "https://example.com/data/table"}
{action: "await_element", selector: "table"}
// Extract table with headers
{action: "eval", payload: `
  (() => {
    const headers = Array.from(document.querySelectorAll('table thead th'))
      .map(th => th.textContent.trim());
    const rows = Array.from(document.querySelectorAll('table tbody tr'))
      .map(tr => {
        const cells = Array.from(tr.cells).map(td => td.textContent.trim());
        return Object.fromEntries(headers.map((h, i) => [h, cells[i]]));
      });
    return rows;
  })()
`}
Paginated Results
Extract data across multiple pages:
{action: "navigate", payload: "https://example.com/results?page=1"}
{action: "await_element", selector: ".results"}
// Page 1
{action: "eval", payload: "Array.from(document.querySelectorAll('.result')).map(r => r.textContent.trim())"}
// Navigate to page 2
{action: "click", selector: "a.next-page"}
{action: "await_element", selector: ".results"}
{action: "await_text", payload: "Page 2"}
// Page 2
{action: "eval", payload: "Array.from(document.querySelectorAll('.result')).map(r => r.textContent.trim())"}
// Continue pattern for additional pages...
Multi-Tab Operations
Email Receipt Extraction
Find specific email and extract data:
// List available tabs
{action: "list_tabs"}
// Switch to email tab (assume index 2 from list)
{action: "click", tab_index: 2, selector: "a[title*='Receipt']"}
{action: "await_element", tab_index: 2, selector: ".email-body"}
// Extract receipt details
{action: "extract", tab_index: 2, payload: "text", selector: ".order-number"}
{action: "extract", tab_index: 2, payload: "text", selector: ".total-amount"}
{action: "extract", tab_index: 2, payload: "markdown", selector: ".items-list"}
Cross-Site Data Correlation
Extract from one site, verify on another:
// Get company phone from website
{action: "navigate", payload: "https://company.com/contact"}
{action: "await_element", selector: ".contact-info"}
{action: "extract", payload: "text", selector: ".phone-number"}
// Store result: "+1-555-0123"
// Open verification site in new tab
{action: "new_tab"}
{action: "navigate", tab_index: 1, payload: "https://phonevalidator.com"}
{action: "await_element", tab_index: 1, selector: "input[name=phone]"}
// Fill and search
{action: "type", tab_index: 1, selector: "input[name=phone]", payload: "+1-555-0123\n"}
{action: "await_element", tab_index: 1, selector: ".results"}
// Extract validation result
{action: "extract", tab_index: 1, payload: "text", selector: ".verification-status"}
Parallel Data Collection
Collect data from multiple sources simultaneously:
// Tab 0: Weather
{action: "navigate", tab_index: 0, payload: "https://weather.com/city"}
{action: "await_element", tab_index: 0, selector: ".temperature"}
// Tab 1: News
{action: "new_tab"}
{action: "navigate", tab_index: 1, payload: "https://news.com"}
{action: "await_element", tab_index: 1, selector: ".headlines"}
// Tab 2: Stock prices
{action: "new_tab"}
{action: "navigate", tab_index: 2, payload: "https://stocks.com"}
{action: "await_element", tab_index: 2, selector: ".market-summary"}
// Extract all data
{action: "extract", tab_index: 0, payload: "text", selector: ".temperature"}
{action: "extract", tab_index: 1, payload: "text", selector: ".headline:first-child"}
{action: "extract", tab_index: 2, payload: "text", selector: ".market-summary"}
Dynamic Content Handling
Infinite Scroll Loading
Load all content with scroll-triggered pagination:
{action: "navigate", payload: "https://example.com/feed"}
{action: "await_element", selector: ".feed-item"}
// Count initial items
{action: "eval", payload: "document.querySelectorAll('.feed-item').length"}
// Scroll and wait multiple times
{action: "eval", payload: "window.scrollTo(0, document.body.scrollHeight)"}
{action: "eval", payload: "new Promise(r => setTimeout(r, 2000))"}
{action: "eval", payload: "window.scrollTo(0, document.body.scrollHeight)"}
{action: "eval", payload: "new Promise(r => setTimeout(r, 2000))"}
{action: "eval", payload: "window.scrollTo(0, document.body.scrollHeight)"}
{action: "eval", payload: "new Promise(r => setTimeout(r, 2000))"}
// Extract all loaded items
{action: "eval", payload: `
  Array.from(document.querySelectorAll('.feed-item')).map(item => ({
    title: item.querySelector('.title').textContent.trim(),
    date: item.querySelector('.date').textContent.trim(),
    url: item.querySelector('a').href
  }))
`}
Wait for AJAX Response
Wait for loading indicator to disappear:
{action: "navigate", payload: "https://app.com/dashboard"}
{action: "await_element", selector: ".content"}
// Trigger AJAX request
{action: "click", selector: "button.load-data"}
// Wait for spinner to appear then disappear
{action: "eval", payload: `
  new Promise(resolve => {
    const checkGone = () => {
      const spinner = document.querySelector('.spinner');
      if (!spinner || spinner.style.display === 'none') {
        resolve(true);
      } else {
        setTimeout(checkGone, 100);
      }
    };
    checkGone();
  })
`}
// Now safe to extract
{action: "extract", payload: "text", selector: ".data-table"}
Modal Dialog Handling
Open modal, interact, wait for close:
{action: "click", selector: "button.open-settings"}
{action: "await_element", selector: ".modal.visible"}
// Interact with modal
{action: "type", selector: ".modal input[name=username]", payload: "newuser"}
{action: "select", selector: ".modal select[name=theme]", payload: "dark"}
{action: "click", selector: ".modal button.save"}
// Wait for modal to close
{action: "eval", payload: `
  new Promise(resolve => {
    const check = () => {
      const modal = document.querySelector('.modal.visible');
      if (!modal) {
        resolve(true);
      } else {
        setTimeout(check, 100);
      }
    };
    check();
  })
`}
// Verify settings saved
{action: "await_text", payload: "Settings saved"}
Wait for Button Enabled
Wait for form validation before submission:
{action: "type", selector: "input[name=email]", payload: "user@example.com"}
{action: "type", selector: "input[name=password]", payload: "securepass123"}
// Wait for submit button to become enabled
{action: "eval", payload: `
  new Promise(resolve => {
    const check = () => {
      const btn = document.querySelector('button[type=submit]');
      if (btn && !btn.disabled && !btn.classList.contains('disabled')) {
        resolve(true);
      } else {
        setTimeout(check, 100);
      }
    };
    check();
  })
`}
// Now safe to click
{action: "click", selector: "button[type=submit]"}
Authentication Workflows
Standard Login
{action: "navigate", payload: "https://app.example.com/login"}
{action: "await_element", selector: "form.login"}
// Fill credentials
{action: "type", selector: "input[name=email]", payload: "user@example.com"}
{action: "type", selector: "input[name=password]", payload: "password123\n"}
// Wait for redirect
{action: "await_text", payload: "Dashboard"}
// Verify logged in
{action: "extract", payload: "text", selector: ".user-name"}
OAuth Flow
{action: "navigate", payload: "https://app.example.com/connect"}
{action: "await_element", selector: "button.oauth-login"}
// Trigger OAuth
{action: "click", selector: "button.oauth-login"}
// Wait for OAuth provider page
{action: "await_text", payload: "Authorize"}
// Fill OAuth credentials
{action: "await_element", selector: "input[name=username]"}
{action: "type", selector: "input[name=username]", payload: "oauthuser"}
{action: "type", selector: "input[name=password]", payload: "oauthpass\n"}
// Wait for redirect back
{action: "await_text", payload: "Connected successfully"}
Session Persistence Check
// Load page
{action: "navigate", payload: "https://app.example.com/dashboard"}
{action: "await_element", selector: "body"}
// Check if logged in via cookie/localStorage
{action: "eval", payload: "document.cookie.includes('session_id')"}
{action: "eval", payload: "localStorage.getItem('auth_token') !== null"}
// Verify user data loaded
{action: "extract", payload: "text", selector: ".user-profile"}
Advanced Patterns
Conditional Workflow
Branch based on page content:
{action: "navigate", payload: "https://example.com/status"}
{action: "await_element", selector: "body"}
// Check status
{action: "extract", payload: "text", selector: ".status-message"}
// If result contains "Available":
{action: "click", selector: "button.purchase"}
{action: "await_text", payload: "Added to cart"}
// If result contains "Out of stock":
{action: "click", selector: "button.notify-me"}
{action: "type", selector: "input[name=email]", payload: "notify@example.com\n"}
Error Recovery
Handle and retry failed operations:
{action: "navigate", payload: "https://app.example.com/data"}
{action: "await_element", selector: ".content"}
// Attempt operation
{action: "click", selector: "button.load"}
// Check for error
{action: "eval", payload: "!!document.querySelector('.error-message')"}
// If error present, retry
{action: "click", selector: "button.retry"}
{action: "await_element", selector: ".data-loaded"}
Screenshot Comparison
Capture before and after states:
// Initial state
{action: "navigate", payload: "https://example.com"}
{action: "await_element", selector: ".content"}
{action: "screenshot", payload: "/tmp/before.png"}
// Make changes
{action: "click", selector: "button.dark-mode"}
{action: "await_element", selector: "body.dark"}
// Capture new state
{action: "screenshot", payload: "/tmp/after.png"}
// Or screenshot specific element
{action: "screenshot", payload: "/tmp/header.png", selector: "header"}
Tips for Complex Workflows
Build Incrementally
Start simple, add complexity:
- Navigate and verify page loads
 - Extract one element
 - Add interaction
 - Add waiting logic
 - Add error handling
 - Add validation
 
Use JavaScript for Complex Logic
When multiple operations needed, use eval:
{action: "eval", payload: `
  (async () => {
    // Complex multi-step logic
    const results = [];
    const items = document.querySelectorAll('.item');
    
    for (const item of items) {
      if (item.classList.contains('active')) {
        results.push({
          id: item.dataset.id,
          text: item.textContent.trim()
        });
      }
    }
    
    return results;
  })()
`}
Validate Selectors
Always test selectors return expected elements:
// Check element exists
{action: "eval", payload: "!!document.querySelector('button.submit')"}
// Check element visible
{action: "eval", payload: "window.getComputedStyle(document.querySelector('button.submit')).display !== 'none'"}
// Check element count
{action: "eval", payload: "document.querySelectorAll('.item').length"}