Browser automation for AI agents using PinchTab. Control Chrome programmatically for testing, scraping, and interaction. Features token-efficient text extraction, multi-instance orchestration, headless/headed modes, and MCP integration. Use when automating browser tasks, extracting web data, testing web apps, or validating sites in real browsers.
Install to Claude Code
npx -y skills add Lord1Egypt/awesome-skill-forge --skill browser-automation-pin --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Browser Automation Pin?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/lord1egypt-browser-automation-pin)More formats (shields.io, HTML) on the badges page.
---
name: browser-automation
description: Browser automation for AI agents using PinchTab. Control Chrome programmatically for testing, scraping, and interaction. Features token-efficient text extraction, multi-instance orchestration, headless/headed modes, and MCP integration. Use when automating browser tasks, extracting web data, testing web apps, or validating sites in real browsers.
metadata:
version: "1.0"
origin: "PinchTab"
---
# Browser Automation
Browser automation for AI agents using [PinchTab](https://pinchtab.com) — a high-performance Chrome bridge with HTTP API.
## What is PinchTab?
- **Standalone HTTP server** — Control Chrome via HTTP API
- **Token-efficient** — 800 tokens/page with text extraction (vs 10,000+ for screenshots)
- **Multi-instance** — Run multiple parallel Chrome processes with isolated profiles
- **Headless or Headed** — Run without window or with visible Chrome
- **Self-contained** — 12MB binary, no external dependencies
- **MCP integration** — Native SMCP plugin for Claude Code
## Quick Start
### Installation
```bash
# macOS / Linux
curl -fsSL https://pinchtab.com/install.sh | bash
# npm
npm install -g pinchtab
# Docker
docker run -d -p 9867:9867 pinchtab/pinchtab
```
### Start Server
```bash
# Terminal 1: Start PinchTab server
pinchtab
# Server runs on http://localhost:9867
```
### Basic Commands
```bash
# Navigate
pinchtab nav https://pinchtab.com
# Wait 3 seconds for accessibility tree
sleep 3
# Get interactive elements
pinchtab snap -i -c
# Extract text (token-efficient)
pinchtab text
# Click element by ref
pinchtab click e5
# Fill input
pinchtab fill e3 "user@example.com"
```
---
## Core Concepts
### Instance
A running Chrome process. Each instance has isolated state.
```bash
# Create headless instance
pinchtab instances create --mode=headless
# Create headed instance (visible window)
pinchtab instances create --mode=headed
# List instances
pinchtab instances list
# Stop instance
pinchtab instances stop <instance-id>
```
### Profile
Browser state (cookies, history, localStorage). Log in once, stay logged in.
```bash
# Create instance with profile
pinchtab instances create --profile=work
# Profile persists across restarts
```
### Tab
A single webpage. Each instance can have multiple tabs.
```bash
# Open new tab
pinchtab tabs open https://example.com
# List tabs
pinchtab tabs list
# Close tab
pinchtab tabs close <tab-id>
```
---
## Token-Efficient Patterns
### The 3-Second Wait Rule
**Critical:** Chrome's accessibility tree takes ~3 seconds to populate after navigation.
```bash
# ❌ Too fast - empty tree
pinchtab nav https://example.com
pinchtab snap
# Returns: {"count": 1, "nodes": [{"ref": "e0"}]}
# ✅ Wait 3 seconds
pinchtab nav https://example.com
sleep 3
pinchtab snap
# Returns: {"count": 2645, "nodes": [...]}
```
### Optimal Extraction Pattern
```bash
# Navigate + wait + filter (14x token savings)
curl -X POST http://localhost:9867/navigate \
-d '{"url": "https://example.com"}' && \
sleep 3 && \
curl http://localhost:9867/snapshot | \
jq '.nodes[] | select(.name | length > 15) | .name' | \
head -30
```
**Why this works:**
1. Navigate + wait ensures full accessibility tree
2. jq filter extracts text nodes only
3. `length > 15` filters buttons/labels
4. `head -30` limits output
**Token comparison:**
- Exploratory approach: ~3,800 tokens
- Pattern-driven: ~270 tokens
- **Savings: 14x**
---
## HTTP API Reference
### Base URL
```
http://localhost:9867
```
### Instances
```bash
# Create instance
TAB=$(curl -s -X POST http://localhost:9867/instances \
-d '{"profile":"work","mode":"headless"}' | jq -r '.id')
# List instances
curl http://localhost:9867/instances
# Stop instance
curl -X POST "http://localhost:9867/instances/$TAB/stop"
```
### Navigation
```bash
# Navigate to URL
curl -X POST "http://localhost:9867/instances/$TAB/tabs/open" \
-d '{"url":"https://example.com"}'
# Wait for load
sleep 3
```
### Snapshot
```bash
# Full snapshot
curl "http://localhost:9867/instances/$TAB/snapshot"
# Interactive elements only
curl "http://localhost:9867/instances/$TAB/snapshot?filter=interactive"
# With coordinates
curl "http://localhost:9867/instances/$TAB/snapshot?includeCoords=true"
```
### Actions
```bash
# Click element
curl -X POST "http://localhost:9867/instances/$TAB/action" \
-d '{"kind":"click","ref":"e5"}'
# Type text
curl -X POST "http://localhost:9867/instances/$TAB/action" \
-d '{"kind":"type","ref":"e12","text":"hello"}'
# Press key
curl -X POST "http://localhost:9867/instances/$TAB/action" \
-d '{"kind":"key","ref":"e12","key":"Enter"}'
# Scroll
curl -X POST "http://localhost:9867/instances/$TAB/action" \
-d '{"kind":"scroll","direction":"down"}'
```
### Extraction
```bash
# Extract text (token-efficient)
curl "http://localhost:9867/instances/$TAB/text"
# Take screenshot
curl "http://localhost:9867/instances/$TAB/screenshot" \
--output screenshot.png
# Generate PDF
curl "http://localhost:9867/instances/$TAB/pdf" \
--output page.pdf
# Evaluate JavaScript
curl -X POST "http://localhost:9867/instances/$TAB/evaluate" \
-d '{"script": "document.title"}'
```
---
## Common Patterns
### Pattern 1: Web Scraping
```bash
#!/bin/bash
# scrape-headlines.sh
URL=$1
INST=$(curl -s -X POST http://localhost:9867/instances \
-d '{"mode":"headless"}' | jq -r '.id')
# Navigate and wait
curl -s -X POST "http://localhost:9867/instances/$INST/tabs/open" \
-d "{\"url\":\"$URL\"}"
sleep 3
# Extract headlines (filter by length)
curl -s "http://localhost:9867/instances/$INST/snapshot" | \
jq '.nodes[] | select(.name | length > 20) | .name' | \
head -20
# Cleanup
curl -s -X POST "http://localhost:9867/instances/$INST/stop"
```
### Pattern 2: Form Interaction
```bash
#!/bin/bash
# fill-form.sh
INST=$(curl -s -X POST http://localhost:9867/instances \
-d '{"mode":"headless"}' | jq -r '.id')
# Navigate to form
curl -s -X POST "http://localhost:9867/instances/$INST/tabs/open" \
-d '{"url":"https://example.com/login"}'
sleep 3
# Get snapshot to find element refs
SNAPSHOT=$(curl -s "http://localhost:9867/instances/$INST/snapshot?filter=interactive")
# Extract refs (example: e5=email, e7=password, e9=submit)
EMAIL_REF=$(echo $SNAPSHOT | jq -r '.nodes[] | select(.name | contains("email")) | .ref')
PASS_REF=$(echo $SNAPSHOT | jq -r '.nodes[] | select(.name | contains("password")) | .ref')
SUBMIT_REF=$(echo $SNAPSHOT | jq -r '.nodes[] | select(.role == "button") | .ref')
# Fill form
curl -s -X POST "http://localhost:9867/instances/$INST/action" \
-d "{\"kind\":\"type\",\"ref\":\"$EMAIL_REF\",\"text\":\"user@example.com\"}"
curl -s -X POST "http://localhost:9867/instances/$INST/action" \
-d "{\"kind\":\"type\",\"ref\":\"$PASS_REF\",\"text\":\"password123\"}"
# Submit
curl -s -X POST "http://localhost:9867/instances/$INST/action" \
-d "{\"kind\":\"click\",\"ref\":\"$SUBMIT_REF\"}"
# Wait for navigation
sleep 3
# Verify login
curl -s "http://localhost:9867/instances/$INST/text" | jq -r '.title'
# Cleanup
curl -s -X POST "http://localhost:9867/instances/$INST/stop"
```
### Pattern 3: Multi-Instance Parallel Processing
```bash
#!/bin/bash
# parallel-scrape.sh
URLS=("https://site1.com" "https://site2.com" "https://site3.com")
INSTANCES=()
# Create instances
for i in {0..2}; do
INST=$(curl -s -X POST http://localhost:9867/instances \
-d '{"mode":"headless"}' | jq -r '.id')
INSTANCES[$i]=$INST
done
# Launch parallel jobs
for i in {0..2}; do
(
curl -s -X POST "http://localhost:9867/instances/${INSTANCES[$i]}/tabs/open" \
-d "{\"url\":\"${URLS[$i]}\"}"
sleep 3
TITLE=$(curl -s "http://localhost:9867/instances/${INSTANCES[$i]}/text" | jq -r '.title')
echo "Result $i: $TITLE"
curl -s -X POST "http://localhost:9867/instances/${INSTANCES[$i]}/stop"
) &
done
wait
echo "All complete"
```
### Pattern 4: Visual Regression Testing
```bash
#!/bin/bash
# visual-regression.sh
URLS=("https://staging.example.com" "https://production.example.com")
INST=$(curl -s -X POST http://localhost:9867/instances \
-d '{"mode":"headless"}' | jq -r '.id')
for URL in "${URLS[@]}"; do
curl -s -X POST "http://localhost:9867/instances/$INST/tabs/open" \
-d "{\"url\":\"$URL\"}"
sleep 3
# Take screenshot
FILENAME=$(echo $URL | sed 's/[^a-zA-Z0-9]/_/g').png
curl -s "http://localhost:9867/instances/$INST/screenshot" \
--output "$FILENAME"
echo "Saved: $FILENAME"
done
curl -s -X POST "http://localhost:9867/instances/$INST/stop"
```
### Pattern 5: Session Persistence
```bash
#!/bin/bash
# persistent-session.sh
# Create instance with named profile
INST=$(curl -s -X POST http://localhost:9867/instances \
-d '{"profile":"myaccount","mode":"headless"}' | jq -r '.id')
# Login once
curl -s -X POST "http://localhost:9867/instances/$INST/tabs/open" \
-d '{"url":"https://example.com/login"}'
sleep 3
# ... perform login ...
# Stop (cookies saved to profile)
curl -s -X POST "http://localhost:9867/instances/$INST/stop"
# Later: Resume with same profile
INST2=$(curl -s -X POST http://localhost:9867/instances \
-d '{"profile":"myaccount","mode":"headless"}' | jq -r '.id')
# Already logged in!
curl -s -X POST "http://localhost:9867/instances/$INST2/tabs/open" \
-d '{"url":"https://example.com/dashboard"}'
```
---
## MCP Integration
PinchTab provides an SMCP plugin for native Claude Code integration.
### Setup
```bash
# Set plugin directory
export MCP_PLUGINS_DIR=/path/to/pinchtab/plugins
# Restart Claude Code to load plugin
```
### Available Tools
| Tool | Description |
|------|-------------|
| `pinchtab__navigate` | Navigate to URL |
| `pinchtab__snapshot` | Get page structure |
| `pinchtab__action` | Click, type, press keys |
| `pinchtab__text` | Extract text content |
| `pinchtab__screenshot` | Capture screenshot |
| `pinchtab__pdf` | Generate PDF |
| `pinchtab__evaluate` | Run JavaScript |
| `pinchtab__cookies_get` | Get cookies |
| `pinchtab__stealth_status` | Check stealth mode |
### Usage in Claude Code
```
Use pinchtab to navigate to example.com and extract the main headlines.
```
Claude will:
1. Call `pinchtab__navigate` with URL
2. Wait 3 seconds
3. Call `pinchtab__snapshot` with filter
4. Extract headlines from result
---
## Headless vs Headed
| Aspect | Headless | Headed |
|--------|----------|--------|
| **Window** | No visible UI | Chrome window visible |
| **Speed** | ~20% faster | Slower (rendering overhead) |
| **Memory** | ~50-80 MB | ~100-150 MB |
| **Use Case** | CI/CD, scraping, batch | Debugging, visual QA |
| **Interaction** | API only | API + manual |
```bash
# Headless for production
pinchtab instances create --mode=headless
# Headed for debugging
pinchtab instances create --mode=headed
```
---
## Best Practices
### DO
- ✅ Wait 3+ seconds after navigation
- ✅ Use text extraction over screenshots (token-efficient)
- ✅ Filter snapshots to reduce tokens
- ✅ Use profiles for persistent sessions
- ✅ Run headless in production
- ✅ Clean up instances after use
- ✅ Handle errors gracefully
### DON'T
- ❌ Skip the 3-second wait
- ❌ Take screenshots for text extraction
- ❌ Parse full snapshots without filtering
- ❌ Use headed mode in CI/CD
- ❌ Leave instances running indefinitely
- ❌ Hardcode element refs (they change)
---
## Troubleshooting
### Only getting 1 node in snapshot
**Cause:** Accessibility tree not ready
**Fix:** Increase wait time to 3+ seconds
```bash
pinchtab nav https://example.com
sleep 3 # Increase if needed
pinchtab snap
```
### Timeouts
**Cause:** Page too slow or Chrome overloaded
**Fix:** Increase sleep or use headless mode
```bash
# Increase wait
sleep 5
# Or use headless for faster rendering
pinchtab instances create --mode=headless
```
### Element not found
**Cause:** Refs change between snapshots
**Fix:** Re-snapshot before each action
```bash
# Get fresh refs before each action
REF=$(pinchtab snap -i | jq -r '.nodes[] | select(.name == "Submit") | .ref')
pinchtab click "$REF"
```
### Connection refused
**Cause:** PinchTab server not running
**Fix:** Start server first
```bash
pinchtab # In separate terminal
```
---
## References
- [PinchTab Documentation](https://pinchtab.com/docs)
- [PinchTab GitHub](https://github.com/pinchtab/pinchtab)
- [Agent Optimization Guide](https://pinchtab.com/docs/guides/agent-optimization)
- [Common Patterns](https://pinchtab.com/docs/guides/common-patterns)
- [SMCP Plugin](https://github.com/pinchtab/pinchtab/tree/main/plugins)
---
*Token-efficient browser automation for AI agents.*
Scanned 9/9/2026
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!