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:
| Feature | web_fetch | browser |
|---|---|---|
| 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
Navigate to URL
{
"tool": "browser",
"action": "navigate",
"url": "https://example.com"
}
Options:
waitUntil:load|domcontentloaded|networkidletimeout: 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 DOMwaitVisible: Element visiblewaitHidden: 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
- Playwright Docs - Browser API reference
- CSS Selectors Guide
- Tools Overview
Questions? Discord #automation