chrome-devtools
Browser automation, debugging, performance profiling, and DevTools-driven diagnostics via Playwright
Best use case
chrome-devtools is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Browser automation, debugging, performance profiling, and DevTools-driven diagnostics via Playwright
Teams using chrome-devtools should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/chrome-devtools/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How chrome-devtools Compares
| Feature / Agent | chrome-devtools | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Browser automation, debugging, performance profiling, and DevTools-driven diagnostics via Playwright
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Chrome DevTools
## Purpose
This skill provides browser-based debugging, inspection, performance profiling, and automation capabilities via Playwright MCP. It enables direct interaction with web pages — navigating, clicking, reading content, capturing screenshots, monitoring network requests, and evaluating JavaScript — all without requiring a manual browser session.
## Key Concepts
### Available Capabilities
Through Playwright MCP, this skill can:
| Capability | Tools | Use Case |
|------------|-------|----------|
| **Navigation** | browser_navigate, browser_navigate_back | Load pages, follow flows |
| **Inspection** | browser_snapshot, browser_take_screenshot | Read page structure, capture visual state |
| **Interaction** | browser_click, browser_type, browser_fill_form | Automate user actions |
| **Evaluation** | browser_evaluate | Run JavaScript in page context |
| **Monitoring** | browser_console_messages, browser_network_requests | Capture logs and network traffic |
| **Waiting** | browser_wait_for | Wait for content to appear/disappear |
| **Tabs** | browser_tabs | Manage multiple pages |
### Snapshot vs Screenshot
- **Snapshot** (`browser_snapshot`): Returns the accessibility tree as structured text. Best for understanding page structure, finding interactive elements, and getting element references for actions. Use this for most inspection tasks.
- **Screenshot** (`browser_take_screenshot`): Returns a visual image. Best for visual regression checking, capturing current state for review, and when the visual layout matters more than the DOM structure.
**Rule**: Use snapshot first to understand the page, screenshot to capture visual evidence.
## Workflows
### Workflow 1: Page Inspection
```
STEP 1: Navigate to the target URL
→ browser_navigate(url)
STEP 2: Capture the accessibility snapshot
→ browser_snapshot()
→ Analyze the page structure, identify key elements
STEP 3: Take a screenshot for visual reference
→ browser_take_screenshot(type: "png")
STEP 4: Check console for errors
→ browser_console_messages(level: "error")
STEP 5: Check network requests
→ browser_network_requests(includeStatic: false)
OUTPUT:
PAGE STRUCTURE: [From snapshot]
VISUAL STATE: [Screenshot reference]
ERRORS: [Console errors found]
FAILED REQUESTS: [4xx/5xx responses]
RECOMMENDATIONS: [Based on findings]
```
### Workflow 2: Performance Profiling
```
STEP 1: Navigate with timing
→ browser_navigate(url)
→ Note: Playwright captures load timing automatically
STEP 2: Capture network waterfall
→ browser_network_requests(includeStatic: true)
→ Analyze: total requests, total transfer size, slow requests
STEP 3: Evaluate performance metrics via JavaScript
→ browser_evaluate:
() => {
const perf = performance.getEntriesByType('navigation')[0];
const paint = performance.getEntriesByType('paint');
return {
dns: perf.domainLookupEnd - perf.domainLookupStart,
tcp: perf.connectEnd - perf.connectStart,
ttfb: perf.responseStart - perf.requestStart,
domLoad: perf.domContentLoadedEventEnd - perf.navigationStart,
fullLoad: perf.loadEventEnd - perf.navigationStart,
fcp: paint.find(p => p.name === 'first-contentful-paint')?.startTime,
resources: performance.getEntriesByType('resource').length,
};
}
STEP 4: Check for layout shifts
→ browser_evaluate:
() => {
return new Promise(resolve => {
new PerformanceObserver(list => {
resolve(list.getEntries().map(e => ({
value: e.value,
sources: e.sources?.map(s => s.node?.nodeName)
})));
}).observe({ type: 'layout-shift', buffered: true });
setTimeout(() => resolve([]), 3000);
});
}
STEP 5: Analyze resource sizes
→ browser_evaluate:
() => {
return performance.getEntriesByType('resource')
.map(r => ({ name: r.name.split('/').pop(), size: r.transferSize, duration: r.duration }))
.sort((a, b) => b.size - a.size)
.slice(0, 20);
}
OUTPUT:
METRICS:
TTFB: [value] ms [good < 200, needs work 200-600, poor > 600]
FCP: [value] ms [good < 1800, needs work 1800-3000, poor > 3000]
DOM Load: [value] ms
Full Load: [value] ms
TOP RESOURCES BY SIZE: [list]
LAYOUT SHIFTS: [count and sources]
RECOMMENDATIONS: [prioritized list]
```
### Workflow 3: Interactive Debugging
```
STEP 1: Navigate to the page with the issue
→ browser_navigate(url)
STEP 2: Capture initial state
→ browser_snapshot() — get element references
→ browser_console_messages(level: "error") — check for existing errors
STEP 3: Reproduce the issue
→ browser_click(ref: "element_ref") — interact with elements
→ browser_type(ref: "input_ref", text: "test data") — fill inputs
→ browser_wait_for(text: "expected text") — wait for results
STEP 4: Capture post-action state
→ browser_console_messages(level: "error") — new errors
→ browser_network_requests(includeStatic: false) — failed requests
→ browser_snapshot() — updated page structure
STEP 5: Evaluate application state
→ browser_evaluate:
() => {
// Inspect React state (if React app)
const fiber = document.querySelector('#root')?._reactRootContainer;
// Or check global state
return window.__STORE__?.getState();
}
STEP 6: Diagnose
→ Correlate console errors with network failures and state changes
→ Identify the root cause
→ Suggest fixes
```
### Workflow 4: Automated Testing Flow
```
STEP 1: Navigate to starting page
→ browser_navigate(url)
→ browser_snapshot()
STEP 2: Execute user flow
→ browser_click(ref: "login_button")
→ browser_fill_form(fields: [
{ name: "email", type: "textbox", ref: "email_input", value: "test@example.com" },
{ name: "password", type: "textbox", ref: "password_input", value: "testpass123" }
])
→ browser_click(ref: "submit_button")
→ browser_wait_for(text: "Dashboard")
STEP 3: Verify results
→ browser_snapshot() — confirm expected page loaded
→ browser_take_screenshot(type: "png") — visual evidence
→ browser_console_messages(level: "error") — no errors
STEP 4: Report
FLOW: [description of what was tested]
RESULT: [pass/fail]
EVIDENCE: [screenshots, console output, network log]
ISSUES: [any problems encountered]
```
## Diagnostic Patterns
### Pattern: Broken Layout Diagnosis
```
1. browser_snapshot() — check accessibility tree for structural issues
2. browser_evaluate(() => {
// Find overflow issues
return [...document.querySelectorAll('*')].filter(el => {
const r = el.getBoundingClientRect();
return r.right > window.innerWidth || r.bottom > window.innerHeight;
}).map(el => ({ tag: el.tagName, class: el.className, width: el.scrollWidth }));
})
3. browser_resize(width: 375, height: 812) — test mobile viewport
4. browser_take_screenshot(type: "png") — capture mobile rendering
5. browser_resize(width: 1280, height: 720) — restore desktop
```
### Pattern: API Error Investigation
```
1. browser_navigate(url)
2. browser_network_requests(includeStatic: false)
3. Filter for failed requests (4xx, 5xx)
4. For each failed request:
- Note the URL, method, status code
- browser_evaluate to inspect request/response headers
- Check if CORS errors appear in console
5. Report: endpoint, error type, likely cause, fix
```
### Pattern: Memory Leak Detection
```
1. browser_navigate(url)
2. browser_evaluate(() => performance.memory) — initial memory
3. Perform the suspected leaking action N times:
→ browser_click / browser_navigate / browser_type
4. browser_evaluate(() => performance.memory) — final memory
5. Compare: if usedJSHeapSize grows proportionally, leak confirmed
6. browser_evaluate(() => {
// Check for detached DOM nodes
return performance.getEntriesByType('resource').length;
})
```
## JavaScript Evaluation Recipes
### Get All Links on Page
```javascript
() => [...document.querySelectorAll('a')].map(a => ({
text: a.textContent.trim(),
href: a.href,
external: a.hostname !== location.hostname
}))
```
### Check Image Loading
```javascript
() => [...document.querySelectorAll('img')].map(img => ({
src: img.src,
alt: img.alt || 'MISSING ALT',
loaded: img.complete && img.naturalWidth > 0,
size: `${img.naturalWidth}x${img.naturalHeight}`,
lazy: img.loading === 'lazy'
}))
```
### Extract Meta Tags
```javascript
() => [...document.querySelectorAll('meta')].map(m => ({
name: m.name || m.getAttribute('property'),
content: m.content
})).filter(m => m.name)
```
### Check Accessibility Basics
```javascript
() => ({
title: document.title,
lang: document.documentElement.lang,
h1Count: document.querySelectorAll('h1').length,
imagesWithoutAlt: [...document.querySelectorAll('img:not([alt])')].length,
buttonsWithoutLabel: [...document.querySelectorAll('button')].filter(
b => !b.textContent.trim() && !b.getAttribute('aria-label')
).length,
formInputsWithoutLabel: [...document.querySelectorAll('input:not([type="hidden"])')].filter(
i => !i.labels?.length && !i.getAttribute('aria-label')
).length,
focusableElements: document.querySelectorAll('a, button, input, select, textarea, [tabindex]').length
})
```
## Anti-Patterns
1. **Screenshot-first**: Taking screenshots before snapshots. Snapshots are more information-dense and provide element references for interaction. Always snapshot first.
2. **Missing wait states**: Clicking a button and immediately reading the page. Always use `browser_wait_for` after actions that trigger async operations.
3. **Hardcoded selectors**: Using brittle CSS selectors that break with minor DOM changes. Prefer element references from snapshots.
4. **Ignoring console**: Not checking console messages after interactions. Many client-side errors only appear in the console.
5. **Not closing browsers**: Leaving browser instances open after completing tasks. Always use `browser_close` when finished.
## Integration Notes
- Hand off visual findings to **ui-ux-pro** for design system recommendations.
- Hand off screenshots to **ai-multimodal** for detailed visual analysis.
- Hand off error patterns to **error-handling** for systematic resolution strategies.
- When performance issues are found, link to **media-processing** for asset optimization recommendations.Related Skills
ultrathink
UltraThink Workflow OS — 4-layer skill mesh with persistent memory and privacy hooks for complex engineering tasks. Routes prompts through intent detection to activate the right domain skills automatically.
ultrathink_review
Multi-pass code review powered by UltraThink's quality gate — checks correctness, security (OWASP), performance, readability, and project conventions in a single structured pass.
ultrathink_memory
Persistent memory system for UltraThink — search, save, and recall project context, decisions, and patterns across sessions using Postgres-backed fuzzy search with synonym expansion.
ui-design
Comprehensive UI design system: 230+ font pairings, 48 themes, 65 design systems, 23 design languages, 30 UX laws, 14 color systems, Swiss grid, Gestalt principles, Pencil.dev workflow. Inherits ui-ux-pro-max (99 UX rules) + impeccable-frontend-design (anti-AI-slop). Triggers on any design, UI, layout, typography, color, theme, or styling task.
Zod
> TypeScript-first schema validation with static type inference.
webinar-registration-page
Build a webinar or live event registration page as a self-contained HTML file with countdown timer, speaker bio, agenda, and registration form. Triggers on: "build a webinar registration page", "create a webinar sign-up page", "event registration landing page", "live training registration page", "workshop sign-up page", "create a webinar page", "build an event page", "free webinar landing page", "live demo registration page", "online event page", "create a registration page for my webinar", "build a training event page".
webhooks
Webhook design patterns — delivery, retry with exponential backoff, HMAC signature verification, payload validation, idempotency keys
web-workers
Offload heavy computation from the main thread using Web Workers, SharedWorkers, and Comlink — structured messaging, transferable objects, and off-main-thread architecture patterns
web-vitals
Core Web Vitals monitoring (LCP, FID, CLS, INP, TTFB), measurement with web-vitals library, reporting to analytics, and optimization strategies for Next.js
web-components
Native Web Components, custom elements API, Shadow DOM, HTML templates, slots, lifecycle callbacks, and framework-agnostic design patterns
wasm
WebAssembly integration — Rust to WASM with wasm-pack/wasm-bindgen, WASI, browser usage, server-side WASM, and performance considerations
vue
Vue 3 Composition API, Nuxt patterns, reactivity system, component architecture, and production development practices