| name | browser-automation |
| description | Browser automation via Puppeteer MCP for JS-rendered content |
Browser Automation
Use Puppeteer MCP for browser automation when WebFetch isn't sufficient.
Overview
Puppeteer MCP provides headless browser control for:
- JS-rendered content extraction
- Screenshot capture
- Form filling and submission
- Interactive testing
- Auth-protected page access
MCP Server
Package: puppeteer-mcp-server
Transport: stdio
Install: claude mcp add puppeteer -- npx -y puppeteer-mcp-server
Available Tools
Navigation
puppeteer_navigate
Navigate to a URL and wait for page load.
url: "https://example.com"
waitUntil: "networkidle0" | "domcontentloaded" | "load"
Screenshots
puppeteer_screenshot
Capture the current page or specific element.
name: "screenshot-name"
selector: "#element-id" (optional, full page if omitted)
fullPage: true (optional)
Interaction
puppeteer_click
Click an element by CSS selector.
selector: "button.submit"
puppeteer_fill
Fill an input field with text.
selector: "input[name=email]"
value: "user@example.com"
puppeteer_select
Select an option from a dropdown.
selector: "select#country"
value: "US"
puppeteer_hover
Hover over an element (for tooltips, dropdowns).
selector: ".menu-trigger"
JavaScript Execution
puppeteer_evaluate
Run JavaScript in the page context and return results.
script: "document.title"
Usage Patterns
Extract JS-Rendered Content
1. puppeteer_navigate(url="https://spa-app.com/data")
2. puppeteer_evaluate(script="JSON.stringify(window.__DATA__)")
Fill and Submit Form
1. puppeteer_navigate(url="https://example.com/login")
2. puppeteer_screenshot(name="before-login")
3. puppeteer_fill(selector="input[name=email]", value="user@example.com")
4. puppeteer_fill(selector="input[name=password]", value="secret")
5. puppeteer_click(selector="button[type=submit]")
6. puppeteer_screenshot(name="after-login")
Capture Visual Evidence
1. puppeteer_navigate(url="https://example.com")
2. puppeteer_screenshot(name="homepage", fullPage=true)
3. puppeteer_click(selector=".open-modal")
4. puppeteer_screenshot(name="modal-open")
Decision Tree
Need web content?
│
├─ Static HTML? ──────────────────→ WebFetch
│
├─ JS-rendered (React, Vue, etc.)? → Puppeteer
│
├─ Need screenshot? ──────────────→ Puppeteer
│
├─ Need to fill forms? ───────────→ Puppeteer
│
├─ Auth-protected? ───────────────→ Puppeteer (can maintain session)
│
└─ Default ───────────────────────→ WebFetch (simpler, faster)
Error Handling
Element Not Found
If a selector doesn't match:
- Take screenshot to see current page state
- Use
puppeteer_evaluateto check DOM - Try alternative selectors
- Add wait time for dynamic content
Timeout
If page takes too long:
- Try
waitUntil: "domcontentloaded"instead ofnetworkidle0 - Check if site blocks automation
- Look for loading spinners/skeleton screens
Session Management
- Browser sessions persist within the conversation
- Use for multi-step flows (login → navigate → action)
- Session cleared on conversation end
Comparison with WebFetch
| Feature | WebFetch | Puppeteer |
|---|---|---|
| Speed | Fast | Slower |
| JS execution | No | Yes |
| Screenshots | No | Yes |
| Form filling | No | Yes |
| Session/cookies | No | Yes |
| Resource usage | Low | Higher |
Best Practices
- Screenshot liberally - Visual evidence helps debugging
- Use specific selectors - IDs are most reliable
- Wait for content - Dynamic sites need time to load
- Handle failures gracefully - Not all elements exist
- Close when done - Don't leave orphan sessions
Troubleshooting
"Element not found"
- Page may not be fully loaded
- Selector may be wrong
- Element may be in iframe
"Navigation timeout"
- Site may be slow
- Site may block headless browsers
- Network issues
"Click had no effect"
- Element may be covered by overlay
- May need to scroll into view
- May need to wait for animation