Debug-first browser automation with always-on visibility. Console logs, network requests, and errors captured by default. USE WHEN browser, screenshot, debug web, verify UI, troubleshoot frontend.
Replace the token-heavy Playwright MCP with direct code execution.
| Approach | Tokens | Performance | |----------|--------|-------------| | Playwright MCP | ~13,700 at load | MCP protocol overhead | | Code-first | ~50-200 per op | Direct Playwright API | | Savings | 99%+ | Faster execution |
# Install dependencies
cd ~/.claude/skills/Browser
bun install
# Take a screenshot
bun examples/screenshot.ts https://example.com
# Verify a page loads
bun examples/verify-page.ts https://example.com
import { PlaywrightBrowser } from '~/.claude/skills/Browser/index.ts'
const browser = new PlaywrightBrowser()
await browser.launch()
await browser.navigate('https://example.com')
await browser.screenshot({ path: 'screenshot.png' })
await browser.close()
const browser = new PlaywrightBrowser()
await browser.launch({ headless: false }) // Watch it work
await browser.navigate('https://example.com/login')
await browser.fill('#email', 'test@example.com')
await browser.fill('#password', 'secret')
await browser.click('button[type="submit"]')
await browser.waitForNavigation()
const title = await browser.getTitle()
console.log(`Logged in! Page: ${title}`)
await browser.close()
const browser = new PlaywrightBrowser()
await browser.launch()
await browser.navigate('https://example.com')
// Check specific element exists
await browser.waitForSelector('h1')
const heading = await browser.getVisibleText('h1')
console.log(`Found heading: ${heading}`)
// Check for console errors
const errors = browser.getConsoleLogs({ type: 'error' })
if (errors.length > 0) {
console.log('Console errors:', errors)
}
// Get accessibility tree (like MCP uses)
const a11yTree = await browser.getAccessibilityTree()
await browser.close()
const browser = new PlaywrightBrowser()
await browser.launch()
// Emulate iPhone
await browser.setDevice('iPhone 14')
await browser.navigate('https://example.com')
await browser.screenshot({ path: 'mobile.png' })
// Or set custom viewport
await browser.resize(375, 812)
await browser.close()
const browser = new PlaywrightBrowser()
await browser.launch({
browser: 'chromium', // 'chromium' | 'firefox' | 'webkit'
headless: true, // false to see browser
viewport: { width: 1280, height: 720 },
userAgent: 'Custom UA'
})
| Method | Description |
|--------|-------------|
| navigate(url, options?) | Go to URL |
| goBack() | Browser back |
| goForward() | Browser forward |
| reload() | Refresh page |
| getUrl() | Current URL |
| getTitle() | Page title |
| Method | Description |
|--------|-------------|
| screenshot(options?) | Take screenshot |
| getVisibleText(selector?) | Extract text |
| getVisibleHtml(options?) | Get HTML |
| savePdf(path, options?) | Export PDF |
| getAccessibilityTree() | A11y snapshot |
| Method | Description |
|--------|-------------|
| click(selector) | Click element |
| hover(selector) | Mouse hover |
| fill(selector, value) | Fill input |
| type(selector, text, delay?) | Type with delay |
| select(selector, value) | Select dropdown |
| pressKey(key, selector?) | Keyboard |
| drag(source, target) | Drag and drop |
| uploadFile(selector, path) | File upload |
| Method | Description |
|--------|-------------|
| waitForSelector(selector) | Wait for element |
| waitForNavigation() | Wait for page |
| waitForNetworkIdle() | Wait for idle |
| wait(ms) | Fixed delay |
| Method | Description |
|--------|-------------|
| evaluate(script) | Run JS |
| getConsoleLogs() | Console output |
| setUserAgent(ua) | Change UA |
| Method | Description |
|--------|-------------|
| iframeClick(iframe, el) | Click in iframe |
| iframeFill(iframe, el, val) | Fill in iframe |
The key insight: Playwright MCP loads ~13,700 tokens of tool definitions at startup. This code-first approach:
Scenario: Take 5 screenshots during a session
| Approach | Tokens | |----------|--------| | MCP (loaded at start) | 13,700 | | Code-first (5 × ~100) | 500 | | Savings | 96.4% |
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
// Just import and use - no MCP server needed
import { PlaywrightBrowser } from '~/.claude/skills/Browser/index.ts'
const browser = new PlaywrightBrowser()
// ... use it
bun add playwright)Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer