Nhảy tới nội dung

Browser Automation với OpenClaw

OpenClaw tích hợp browser automation để tương tác với websites, test apps, và scrape dữ liệu.

Tại sao cần Browser Tool?

web_fetch vs browser:

Featureweb_fetchbrowser
Speed⚡ Nhanh🐌 Chậm hơn
JavaScript❌ Không✅ Full support
Screenshots
Form interaction
SPA support❌ Limited✅ Full
Resource usage💚 Low🔴 High

Use browser khi:

  • Site cần JavaScript để render
  • Cần screenshots
  • Fill forms, click buttons
  • Test web apps
  • Scrape SPAs (React, Vue, Angular)

Setup

1. Install Browser Binary

OpenClaw support Chrome/Chromium hoặc Firefox.

Linux (Ubuntu/Debian):

# Chromium
sudo apt-get install chromium-browser

# Or Chrome
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome-stable_current_amd64.deb

macOS:

# Chrome (recommended)
brew install --cask google-chrome

# Or Chromium
brew install chromium

Windows (WSL2):

# In WSL
sudo apt-get install chromium-browser

2. Enable Browser Tool

Edit ~/.openclaw/openclaw.json:

{
"tools": {
"browser": {
"enabled": true,
"headless": true, // No GUI
"executablePath": "/usr/bin/chromium-browser" // Auto-detect if omitted
}
}
}

3. Test

openclaw doctor --check browser

Expected output:

✅ Browser: Chrome 120.0.6099.109
✅ Headless mode: Enabled
✅ Screenshot support: Available

Basic Usage

{
"tool": "browser",
"action": "navigate",
"url": "https://example.com"
}

Options:

  • waitUntil: load | domcontentloaded | networkidle
  • timeout: milliseconds (default 30000)

Take Screenshot

{
"tool": "browser",
"action": "screenshot",
"fullPage": true,
"path": "./screenshot.png"
}

Options:

  • fullPage: Capture entire page (vs viewport)
  • quality: 0-100 (for JPEG)
  • type: png | jpeg

Example use:

You: "Screenshot Google homepage"
Bot: [Navigates to google.com]
[Takes screenshot]
"Here's the screenshot: /workspace/google.png"

Click Element

{
"tool": "browser",
"action": "click",
"selector": "button.login"
}

Selectors:

  • CSS: button.login, #submit, .btn-primary
  • XPath: //button[text()='Login']
  • Text: text=Login

Type Text

{
"tool": "browser",
"action": "type",
"selector": "input[name='email']",
"text": "user@example.com"
}

Options:

  • delay: Typing speed (ms between keystrokes)
  • clear: Clear existing text first

Extract Content

{
"tool": "browser",
"action": "evaluate",
"script": "document.querySelector('h1').textContent"
}

JavaScript in browser context:

// Get all links
Array.from(document.querySelectorAll('a')).map(a => a.href)

// Get table data
Array.from(document.querySelectorAll('table tr')).map(tr =>
Array.from(tr.querySelectorAll('td')).map(td => td.textContent)
)

Real-World Examples

Example 1: Login Flow

// Navigate
{ action: "navigate", url: "https://app.example.com/login" }

// Fill email
{ action: "type", selector: "input[name='email']", text: "user@example.com" }

// Fill password
{ action: "type", selector: "input[name='password']", text: "secret123" }

// Submit
{ action: "click", selector: "button[type='submit']" }

// Wait for dashboard
{ action: "wait", selector: ".dashboard" }

// Screenshot dashboard
{ action: "screenshot", path: "./dashboard.png" }

Example 2: Scrape Product Data

// Navigate to product page
{ action: "navigate", url: "https://shop.example.com/product/123" }

// Extract data
{
action: "evaluate",
script: `({
title: document.querySelector('.product-title').textContent,
price: document.querySelector('.price').textContent,
stock: document.querySelector('.stock').textContent,
images: Array.from(document.querySelectorAll('.gallery img')).map(img => img.src)
})`
}

Result:

{
"title": "Gaming Mouse X",
"price": "$49.99",
"stock": "In Stock",
"images": ["https://cdn.example.com/img1.jpg", "..."]
}

Example 3: Monitor Website Changes

Setup cron (see Cron Guide):

// Every hour, check product price
{
schedule: "0 * * * *",
task: [
{ action: "navigate", url: "https://shop.com/product/123" },
{
action: "evaluate",
script: "document.querySelector('.price').textContent"
},
// If price changed, notify via Telegram
{
tool: "message",
channel: "telegram",
target: "@me",
message: "Price changed to: $NEW_PRICE"
}
]
}

Example 4: Form Automation

// Fill complex form
{ action: "navigate", url: "https://forms.example.com" }

// Text inputs
{ action: "type", selector: "#name", text: "John Doe" }
{ action: "type", selector: "#email", text: "john@example.com" }

// Radio button
{ action: "click", selector: "input[value='male']" }

// Checkbox
{ action: "click", selector: "#agree-terms" }

// Dropdown
{ action: "select", selector: "#country", value: "Vietnam" }

// File upload
{ action: "upload", selector: "#avatar", path: "/workspace/photo.jpg" }

// Submit
{ action: "click", selector: "button[type='submit']" }

// Wait for success message
{ action: "wait", selector: ".success-message" }

Advanced Features

Wait for Elements

{
action: "wait",
selector: ".loaded-content",
timeout: 10000
}

Wait types:

  • wait: Element appears in DOM
  • waitVisible: Element visible
  • waitHidden: Element disappears

Network Interception

Block ads, trackers:

{
"tools": {
"browser": {
"interceptRequests": {
"enabled": true,
"block": [
"*.doubleclick.net",
"*.googlesyndication.com",
"*.facebook.com/tr"
]
}
}
}
}

Modify requests:

{
interceptRequests: {
modify: {
"*/api/*": {
headers: {
"Authorization": "Bearer TOKEN"
}
}
}
}
}

PDF Generation

{
action: "pdf",
path: "./report.pdf",
format: "A4",
margin: {
top: "1cm",
bottom: "1cm"
}
}

Mobile Emulation

{
action: "emulate",
device: "iPhone 12"
}

Supported devices:

  • iPhone 12, 13, 14
  • iPad Pro
  • Samsung Galaxy S21
  • Pixel 5

Performance Optimization

1. Headless Mode

Always use headless trừ khi debugging:

{
"tools": {
"browser": {
"headless": true
}
}
}

Headless = 50% faster + less RAM


2. Disable Images

{
"tools": {
"browser": {
"disableImages": true // Faster page loads
}
}
}

3. Reuse Browser Context

// BAD: New browser per task
navigate(...) // Browser starts
screenshot(...) // Browser closes
navigate(...) // Browser starts again ❌

// GOOD: Keep browser open
{
keepAlive: true,
tasks: [
navigate(...),
screenshot(...),
navigate(...),
screenshot(...)
]
} // Browser closes once

4. Resource Limits

{
"tools": {
"browser": {
"maxInstances": 2, // Parallel browsers
"timeout": 30000,
"memory": "512MB" // Per browser
}
}
}

Security Considerations

1. Sandbox Browser

Run browser on isolated node:

{
"agents": {
"list": [
{
"id": "scraper",
"tools": {
"browser": {
"host": "node", // Not gateway
"nodeId": "scraper-node"
}
}
}
]
}
}

2. Block Dangerous Sites

{
"tools": {
"browser": {
"blocklist": [
"*.onion",
"*.torrent",
"known-malware-domains.txt"
]
}
}
}

3. Limit Domains

{
"tools": {
"browser": {
"allowedDomains": [
"example.com",
"api.example.com",
"cdn.example.com"
]
}
}
}

Agent tries to visit evil.com → ❌ Blocked


Troubleshooting

"Browser not found"

# Check path
which chromium-browser
which google-chrome

# Set explicitly
openclaw configure --set tools.browser.executablePath=/usr/bin/chromium-browser

"Timeout waiting for page load"

Increase timeout:

{
action: "navigate",
url: "...",
timeout: 60000 // 60 seconds
}

Or use different wait strategy:

{
waitUntil: "domcontentloaded" // Don't wait for all resources
}

"Out of memory"

Browser eating RAM:

# Check memory
openclaw health

# Reduce concurrent browsers
openclaw configure --set tools.browser.maxInstances=1

# Enable headless + disable images

Screenshots blank/white

Wait for content:

{ action: "navigate", url: "..." }
{ action: "wait", selector: "main", timeout: 5000 } // Wait for content
{ action: "screenshot", path: "./screen.png" }

Best Practices

1. Always Screenshot

Helpful for debugging:

try {
navigate(url)
click(selector)
} catch (error) {
screenshot("./error.png") // See what went wrong
throw error
}

2. Use Specific Selectors

// ❌ BAD: Too generic
{ selector: "button" }

// ✅ GOOD: Specific
{ selector: "button[data-test='login-submit']" }
{ selector: "button.btn-primary:contains('Login')" }

3. Handle Popups

// Dismiss cookie banners
{ action: "click", selector: ".cookie-accept", optional: true }

// Close modals
{ action: "click", selector: ".modal-close", optional: true }

4. Error Handling

{
action: "click",
selector: "button.submit",
timeout: 5000,
onError: {
screenshot: true,
notify: "telegram"
}
}

Resources


Questions? Discord #automation