Install
$ agentstack add skill-manhvann-codexkit-chrome-devtools ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Chrome DevTools Agent Skill
Browser automation via Puppeteer scripts with persistent sessions. All scripts output JSON.
Skill Location
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope.
# Detect skill location (no cd needed - scripts use __dirname for paths)
SKILL_DIR=""
if [ -d ".agents/skills/chrome-devtools/scripts" ]; then
SKILL_DIR=".agents/skills/chrome-devtools/scripts"
elif [ -d "$HOME/.codex/skills/chrome-devtools/scripts" ]; then
SKILL_DIR="$HOME/.codex/skills/chrome-devtools/scripts"
fi
# Run scripts with full path: node "$SKILL_DIR/script.js" --args
Choosing Your Approach
| Scenario | Approach | |----------|----------| | Source-available sites | Read source code first, write selectors directly | | Unknown layouts | Use aria-snapshot.js for semantic discovery | | Visual inspection | Take screenshots to verify rendering | | Debug issues | Collect console logs, analyze with session storage | | Accessibility audit | Use ARIA snapshot for semantic structure analysis |
Automation Browsing Running Mode
Browser visibility is resolved automatically by resolveHeadless() in lib/browser.js:
| Environment | Default | Why | |-------------|---------|-----| | macOS / Windows | Headed (visible) | Better debugging, OAuth login support | | Linux / WSL | Headless | Servers typically have no display | | CI (CI, GITHUB_ACTIONS, GITLAB_CI, JENKINS_URL env vars) | Headless | No display available |
Override with --headless true or --headless false on any script.
- Run multiple scripts/sessions in parallel to simulate real user interactions.
- Run multiple scripts/sessions in parallel to simulate different device types (mobile, tablet, desktop).
ARIA Snapshot (Element Discovery)
When page structure is unknown, use aria-snapshot.js to get a YAML-formatted accessibility tree with semantic roles, accessible names, states, and stable element references.
Get ARIA Snapshot
# Generate ARIA snapshot and output to stdout
node "$SKILL_DIR/aria-snapshot.js" --url https://example.com
# Save to file in snapshots directory
node "$SKILL_DIR/aria-snapshot.js" --url https://example.com --output ./.codex/chrome-devtools/snapshots/page.yaml
Example YAML Output
- banner:
- link "Hacker News" [ref=e1]
/url: https://news.ycombinator.com
- navigation:
- link "new" [ref=e2]
- link "past" [ref=e3]
- link "comments" [ref=e4]
- main:
- list:
- listitem:
- link "Show HN: My new project" [ref=e8]
- text: "128 points by user 3 hours ago"
- contentinfo:
- textbox [ref=e10]
/placeholder: "Search"
Interpreting ARIA Notation
| Notation | Meaning | |----------|---------| | [ref=eN] | Stable identifier for interactive elements | | [checked] | Checkbox/radio is selected | | [disabled] | Element is inactive | | [expanded] | Accordion/dropdown is open | | [level=N] | Heading hierarchy (1-6) | | /url: | Link destination | | /placeholder: | Input placeholder text | | /value: | Current input value |
Interact by Ref
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope. Use select-ref.js to interact with elements by their ref:
# Click element with ref e5
node "$SKILL_DIR/select-ref.js" --ref e5 --action click
# Fill input with ref e10
node "$SKILL_DIR/select-ref.js" --ref e10 --action fill --value "search query"
# Get text content
node "$SKILL_DIR/select-ref.js" --ref e8 --action text
# Screenshot specific element
node "$SKILL_DIR/select-ref.js" --ref e1 --action screenshot --output ./logo.png
# Focus element
node "$SKILL_DIR/select-ref.js" --ref e10 --action focus
# Hover over element
node "$SKILL_DIR/select-ref.js" --ref e5 --action hover
Store Snapshots
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope. Store snapshots for analysis in /.codex/chrome-devtools/snapshots/:
# Create snapshots directory
mkdir -p .codex/chrome-devtools/snapshots
# Capture and store with timestamp
SESSION="$(date +%Y%m%d-%H%M%S)"
node "$SKILL_DIR/aria-snapshot.js" --url https://example.com --output .codex/chrome-devtools/snapshots/$SESSION.yaml
Workflow: Unknown Page Structure
- Get snapshot to discover elements:
``bash node "$SKILL_DIR/aria-snapshot.js" --url https://example.com ``
- Identify target from YAML output (e.g.,
[ref=e5]for a button)
- Interact by ref:
``bash node "$SKILL_DIR/select-ref.js" --ref e5 --action click ``
- Verify result with screenshot or new snapshot:
``bash node "$SKILL_DIR/screenshot.js" --output ./result.png ``
Local HTML Files
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope. IMPORTANT: Never browse local HTML files via file:// protocol. Always serve via local server: Why: file:// protocol blocks many browser features (CORS, ES modules, fetch API, service workers). Local server ensures proper HTTP behavior.
# Option 1: npx serve (recommended)
npx serve ./dist -p 3000 &
node "$SKILL_DIR/navigate.js" --url http://localhost:3000
# Option 2: Python http.server
python -m http.server 3000 --directory ./dist &
node "$SKILL_DIR/navigate.js" --url http://localhost:3000
Note: when port 3000 is busy, find an available port with lsof -i :3000 and use a different one.
Quick Start
# Install dependencies (one-time setup)
npm install --prefix "$SKILL_DIR"
# Test (browser stays running for session reuse)
node "$SKILL_DIR/navigate.js" --url https://example.com
# Output: {"success": true, "url": "...", "title": "..."}
Linux/WSL only: Run "$SKILL_DIR/install-deps.sh" first for Chrome system libraries.
Session Persistence
Browser state persists across script executions via WebSocket endpoint file (.browser-session.json).
Default behavior: Scripts disconnect but keep browser running for session reuse.
# First script: launches browser, navigates, disconnects (browser stays running)
node "$SKILL_DIR/navigate.js" --url https://example.com/login
# Subsequent scripts: connect to existing browser, reuse page state
node "$SKILL_DIR/fill.js" --selector "#email" --value "user@example.com"
node "$SKILL_DIR/fill.js" --selector "#password" --value "secret"
node "$SKILL_DIR/click.js" --selector "button[type=submit]"
# Close browser when done
node "$SKILL_DIR/navigate.js" --url about:blank --close true
Session management:
--close true: Close browser and clear session- Default (no flag): Keep browser running for next script
Available Scripts
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope. All in .agents/skills/chrome-devtools/scripts/:
| Script | Purpose | |--------|---------| | navigate.js | Navigate to URLs | | screenshot.js | Capture screenshots (auto-compress >5MB via Sharp) | | click.js | Click elements | | fill.js | Fill form fields | | evaluate.js | Execute JS in page context | | snapshot.js | Extract interactive elements (JSON format) | | aria-snapshot.js | Get ARIA accessibility tree (YAML format with refs) | | select-ref.js | Interact with elements by ref from ARIA snapshot | | console.js | Monitor console messages/errors | | network.js | Track HTTP requests/responses | | performance.js | Measure Core Web Vitals | | ws-debug.js | Debug WebSocket connections (basic) | | ws-full-debug.js | Debug WebSocket with full events/frames | | inject-auth.js | Inject cookies/tokens for authentication | | import-cookies.js | Import cookies from JSON/Netscape file | | connect-chrome.js | Connect to Chrome with remote debugging |
Workflow Loop
- Execute focused script for single task
- Observe JSON output
- Assess completion status
- Decide next action
- Repeat until done
Writing Custom Test Scripts
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope. For complex automation, write scripts to /.codex/chrome-devtools/tmp/:
# Create tmp directory for test scripts
mkdir -p $SKILL_DIR/.codex/chrome-devtools/tmp
# Write a test script
cat > $SKILL_DIR/.codex/chrome-devtools/tmp/login-test.js user-scope.
Store screenshots for analysis in `/.codex/chrome-devtools/screenshots/`:
```bash
# Basic screenshot
node "$SKILL_DIR/screenshot.js" --url https://example.com --output ./.codex/chrome-devtools/screenshots/page.png
# Full page
node "$SKILL_DIR/screenshot.js" --url https://example.com --output ./.codex/chrome-devtools/screenshots/page.png --full-page true
# Specific element
node "$SKILL_DIR/screenshot.js" --url https://example.com --selector ".main-content" --output ./.codex/chrome-devtools/screenshots/element.png
Auto-Compression (Sharp)
Screenshots >5MB auto-compress using Sharp (4-5x faster than ImageMagick):
# Default: compress if >5MB
node "$SKILL_DIR/screenshot.js" --url https://example.com --output ./.codex/chrome-devtools/screenshots/page.png
# Custom threshold (3MB)
node "$SKILL_DIR/screenshot.js" --url https://example.com --output ./.codex/chrome-devtools/screenshots/page.png --max-size 3
# Disable compression
node "$SKILL_DIR/screenshot.js" --url https://example.com --output ./.codex/chrome-devtools/screenshots/page.png --no-compress
Store screenshots for analysis in /.codex/chrome-devtools/screenshots/.
Console Log Collection & Analysis
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope.
Capture Logs
# Capture all logs for 10 seconds
node "$SKILL_DIR/console.js" --url https://example.com --duration 10000
# Filter by type
node "$SKILL_DIR/console.js" --url https://example.com --types error,warn --duration 5000
Session Storage Pattern
Store logs for analysis in /.codex/chrome-devtools/logs//:
# Create session directory
SESSION="$(date +%Y%m%d-%H%M%S)"
mkdir -p .codex/chrome-devtools/logs/$SESSION
# Capture and store
node "$SKILL_DIR/console.js" --url https://example.com --duration 10000 > .codex/chrome-devtools/logs/$SESSION/console.json
node "$SKILL_DIR/network.js" --url https://example.com > .codex/chrome-devtools/logs/$SESSION/network.json
# View errors
jq '.messages[] | select(.type=="error")' .codex/chrome-devtools/logs/$SESSION/console.json
Root Cause Analysis
# 1. Check for JavaScript errors
node "$SKILL_DIR/console.js" --url https://example.com --types error,pageerror --duration 5000 | jq '.messages'
# 2. Correlate with network failures
node "$SKILL_DIR/network.js" --url https://example.com | jq '.requests[] | select(.response.status >= 400)'
# 3. Check specific error stack traces
node "$SKILL_DIR/console.js" --url https://example.com --types error --duration 5000 | jq '.messages[].stack'
Finding Elements
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope. Use snapshot.js to discover selectors before interacting:
# Get all interactive elements
node "$SKILL_DIR/snapshot.js" --url https://example.com | jq '.elements[] | {tagName, text, selector}'
# Find buttons
node "$SKILL_DIR/snapshot.js" --url https://example.com | jq '.elements[] | select(.tagName=="button")'
# Find by text content
node "$SKILL_DIR/snapshot.js" --url https://example.com | jq '.elements[] | select(.text | contains("Submit"))'
Error Recovery
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope. If script fails:
# 1. Capture current state (without navigating to preserve state)
node "$SKILL_DIR/screenshot.js" --output ./.agents/skills/chrome-devtools/screenshots/debug.png
# 2. Get console errors
node "$SKILL_DIR/console.js" --url about:blank --types error --duration 1000
# 3. Discover correct selector
node "$SKILL_DIR/snapshot.js" | jq '.elements[] | select(.text | contains("Submit"))'
# 4. Try XPath if CSS fails
node "$SKILL_DIR/click.js" --selector "//button[contains(text(),'Submit')]"
Common Patterns
Web Scraping
node "$SKILL_DIR/evaluate.js" --url https://example.com --script "
Array.from(document.querySelectorAll('.item')).map(el => ({
title: el.querySelector('h2')?.textContent,
link: el.querySelector('a')?.href
}))
" | jq '.result'
Form Automation
node "$SKILL_DIR/navigate.js" --url https://example.com/form
node "$SKILL_DIR/fill.js" --selector "#search" --value "query"
node "$SKILL_DIR/click.js" --selector "button[type=submit]"
Performance Testing
node "$SKILL_DIR/performance.js" --url https://example.com | jq '.vitals'
Script Options
All scripts support:
--headless true/false- Override auto-detected headless mode (default: auto by OS)--close true- Close browser completely (default: stay running)--timeout 30000- Set timeout (ms)--wait-until networkidle2- Wait strategy
navigate.js additionally supports:
--wait-for-login- Interactive login: open headed, wait for URL regex match--login-timeout- Max wait for login completion (default: 300000 = 5 min)
Troubleshooting
Skills can exist in project-scope or user-scope. Priority: project-scope > user-scope.
| Error | Solution | |-------|----------| | Cannot find package 'puppeteer' | Run npm install in scripts directory | | libnss3.so missing (Linux) | Run ./install-deps.sh | | Element not found | Use snapshot.js to find correct selector | | Script hangs | Use --timeout 60000 or --wait-until load | | Screenshot >5MB | Auto-compressed; use --max-size 3 for lower | | Session stale | Delete .browser-session.json and retry |
Screenshot Analysis: Missing Images
If images don't appear in screenshots, they may be waiting for animation triggers:
- Scroll-triggered animations: Scroll element into view first
``bash node "$SKILL_DIR/evaluate.js" --script "document.querySelector('.lazy-image').scrollIntoView()" # Wait for animation node "$SKILL_DIR/evaluate.js" --script "await new Promise(r => setTimeout(r, 1000))" node "$SKILL_DIR/screenshot.js" --output ./result.png ``
- Sequential animation queue: Wait longer and retry
```bash # First attempt node "$SKILL_DIR/screenshot.js" --url http://localhost:3000 --output ./attempt1.png
# Wait for animations to complete node "$SKILL_DIR/evaluate.js" --script "await new Promise(r => setTimeout(r, 2000))"
# Retry screenshot node "$SKILL_DIR/screenshot.js" --output ./attempt2.png ```
- Intersection Observer animations: Trigger by scrolling through page
``bash node "$SKILL_DIR/evaluate.js" --script "window.scrollTo(0, document.body.scrollHeight)" node "$SKILL_DIR/evaluate.js" --script "await new Promise(r => setTimeout(r, 1500))" node "$SKILL_DIR/evaluate.js" --script "window.scrollTo(0, 0)" node "$SKILL_DIR/screenshot.js" --output ./full-loaded.png --full-page true ``
Authentication & Cookies
For accessing protected/authenticated pages, use one of these methods:
Method 1: Inject Cookies Directly
Use when you have cookie values (from DevTools or manual extraction):
# Inject single cookie
node "$SKILL_DIR/inject-auth.js" --url https://site.com \
--cookies '[{"name":"session","value":"abc123","domain":".site.com"}]'
# Multiple cookies with all properties
node "$SKILL_DIR/inject-auth.js" --url https://site.com \
--cookies '[{"name":"session","value":"abc","domain":".site.com","httpOnly":true,"secure":true}]'
# With Bearer token header
node "$SKILL_DIR/inject-auth.js" --url https://api.site.com \
--token "Bearer eyJhbG..." --header Authorization
Method 2: Import from Browser Extension
Best for complex auth (OAuth, multi-cookie sessions):
# 1. Ins
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [manhvann](https://github.com/manhvann)
- **Source:** [manhvann/codexkit](https://github.com/manhvann/codexkit)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.