claw-code/rust/claw/skills/chrome-devtools-mcp/SKILL.md

19 KiB

name description
chrome-devtools-mcp Use when browsing web pages, extracting content from restricted sites (login walls, paywalls), debugging JS errors, analyzing network requests, or running performance audits via browser DevTools.

Chrome DevTools MCP — Web Browsing & Debugging Skill

Operation guide for the chrome-devtools-mcp toolset covering web browsing, interactive debugging, content extraction, and performance analysis.

When to Use

Use this skill when any of the following apply:

  1. Browsing — need to navigate web pages, extract content, bypass login walls/paywalls
  2. Debugging — need to inspect console errors, network requests, DOM elements, or page performance
  3. Content extraction — need to extract article text from restricted pages (Zhihu, CSDN, etc.)
  4. Interaction — need to fill forms, click elements, handle dialogs on web pages
  5. Performance — need to run Lighthouse audits, trace performance, or capture heap snapshots

Core Workflow

1. new_page(url) / navigate_page(url)   → Open/navigate to page
2. wait_for(["keyword"])                  → Wait for content to load
3. take_snapshot()                        → Get element structure (uid)
4. take_screenshot()                      → Confirm visual state
5. evaluate_script(() => ...)            → Execute JS / extract data
6. list_console_messages()                → Check console errors

Key Capabilities

  • Bypass restrictions: Remove login/paywall overlays, unlock copy restrictions, expand truncated articles
  • Debug JS errors: List and inspect console messages, identify uncaught exceptions
  • Network analysis: List network requests, inspect request/response bodies
  • DOM interaction: Click, fill, type, hover, drag — all via accessibility tree (uid)
  • Performance: Lighthouse audits, performance traces, memory heap snapshots
  • Device emulation: Mobile viewport, user agent switching

Part 1 — Browsing & Restriction Bypass

Based on chrome-devtools-mcp toolset for bypassing login walls, copy restrictions, and paywall overlays on sites like Zhihu, CSDN.

Standard Browsing Flow

Step 1: new_page(url)          → Open page
Step 2: wait_for(["keyword"])  → Wait for content load
Step 3: take_snapshot()        → Get accessibility tree (text structure)
Step 4: take_screenshot()      → Confirm visual state (optional)
Step 5: evaluate_script()      → Extract specific data

Restriction Bypass Guide

0. Standard Detect-Remove-Extract Pattern

// Step 1: Detect
evaluate_script(() => {
  JSON.stringify({
    hasMask: !!document.querySelector('[class*="mask"], [class*="overlay"], [class*="passport"]'),
    hasReadMore: !!document.querySelector('.btn-readmore, [class*="readmore"], [class*="expand"]'),
    articleLen: document.querySelector('article')?.innerText.length || 0,
    title: document.title
  })
})

// Step 2: Remove mask
evaluate_script(() => {
  document.querySelectorAll('[class*="mask"], [class*="overlay"], [class*="passport"], [class*="login"], [class*="modal"], .hide-article-box')
    .forEach(el => el.remove());
  document.body.style.overflow = 'auto';
  document.body.style.position = '';
  const a = document.querySelector('article');
  if (a) { a.style.height = 'auto'; a.style.maxHeight = 'none'; }
})

// Step 3: Extract content
evaluate_script(() => {
  const a = document.querySelector('article') || document.querySelector('[class*="content"]') || document.querySelector('[class*="article"]');
  return a?.innerText || 'not found';
})

1. Bypass Login Wall / Paywall Overlay

// Remove overlay elements
evaluate_script(() => {
  document.querySelectorAll('.login-guard, .pay-wall, .modal-mask, [class*="mask"], [class*="overlay"]')
    .forEach(el => el.remove());
})
// Remove body scroll lock and show content
evaluate_script(() => {
  document.body.style.overflow = 'auto';
  document.querySelectorAll('.login-guard, .pay-wall, .sign-in, .modal, .overlay')
    .forEach(el => el.remove());
  // Restore hidden content
  document.querySelectorAll('[class*="content"], [class*="article"], [class*="main"]')
    .forEach(el => el.style.display = 'block');
})

2. Unlock Copy Restrictions

evaluate_script(() => {
  document.addEventListener('copy', e => e.stopPropagation(), true);
  document.addEventListener('selectstart', e => e.stopPropagation(), true);
  document.body.style.userSelect = 'auto';
  document.querySelectorAll('*').forEach(el => el.style.userSelect = 'auto');
})

3. Extract Truncated Full Text

// Standard flow: detect → remove mask → extract
evaluate_script(() => {
  const hasMask = !!document.querySelector('[class*="mask"], [class*="overlay"], [class*="passport"]');
  const hasReadMore = !!document.querySelector('.btn-readmore, [class*="readmore"], [class*="expand"]');
  return JSON.stringify({hasMask, hasReadMore, articleLen: document.querySelector('article')?.innerText.length || 0});
})

// If read-more button exists, click it first
evaluate_script(() => {
  const btn = [...document.querySelectorAll('button, a, span, div')]
    .find(el => el.textContent.includes('展开阅读全文') || el.textContent.includes('全文'));
  btn?.click();
})
// Zhihu — expand full text
evaluate_script(() => {
  const btn = [...document.querySelectorAll('button, a, span')]
    .find(el => el.textContent.includes('展开阅读全文') || el.textContent.includes('全文'));
  if (btn) btn.click();
})
// CSDN — remove login overlay + extract full text (verified 2026)
evaluate_script(() => {
  document.querySelectorAll('.mask, .mask-dark, .passport-login-tip-container, .passport-login-container, .passport-login-box, .passport-login-mark, .hide-article-box')
    .forEach(el => el.remove());
  document.body.style.overflow = 'auto';
  document.body.style.position = '';
  const article = document.querySelector('article') || document.querySelector('.article_content');
  if (article) {
    article.style.setProperty('height', 'auto', 'important');
    article.style.setProperty('max-height', 'none', 'important');
  }
})

// Extract content
evaluate_script(() => {
  const art = document.querySelector('article') || document.querySelector('.article_content') || document.querySelector('#article_content');
  return 'Title: ' + document.title + '\n\n' + art.innerText;
})

4. Extract Page Text

// Get article plain text
evaluate_script(() => {
  const article = document.querySelector('article') ||
    document.querySelector('[class*="content"]') ||
    document.querySelector('[class*="article"]') ||
    document.querySelector('main');
  return article ? article.innerText : document.body.innerText;
})
// Get all page text (preserving structure)
evaluate_script(() => {
  return [...document.querySelectorAll('h1, h2, h3, p, li, pre, code')]
    .map(el => el.tagName + ': ' + el.innerText.trim())
    .filter(s => s.length > 3)
    .join('\n---\n');
})

5. Zhihu-Specific Bypass

evaluate_script(() => {
  // Close dialog
  document.querySelector('.Modal-closeButton, button[class*="close"]')?.click();
  document.querySelector('[class*="signIn"], [class*="Modal"]')?.remove();
  // Expand all collapsed answers
  document.querySelectorAll('.RichContent.is-collapsed').forEach(el => {
    el.classList.remove('is-collapsed');
    el.style.height = 'auto';
    el.style.maxHeight = 'none';
    el.style.overflow = 'visible';
  });
  document.body.style.overflow = 'auto';
})

6. WeChat Public Account Articles (Sogou Gateway)

WeChat public account articles are normally login-gated in browsers, but Sogou WeChat Search (the official content index) allows direct access.

// Step 1: Search for articles
navigate_page('https://weixin.sogou.com/weixin?type=2&s_from=input&query=' + encodeURIComponent('search keyword'))

// Step 2: Get result list
evaluate_script(() => {
  const items = [...document.querySelectorAll('.news-list2 .wx-rb, .news-list2 li')].filter(el => el.querySelector('h3 a'));
  return items.slice(0, 10).map(el => ({
    title: el.querySelector('h3 a')?.textContent?.trim(),
    link: el.querySelector('h3 a')?.href,
    source: el.querySelector('.account')?.textContent?.trim(),
    date: el.querySelector('.time')?.textContent?.trim(),
    summary: el.querySelector('.txt-info')?.textContent?.trim()?.slice(0, 80)
  }));
})

// Step 3: Open article link (no login required)
navigate_page('result-link')

// Step 4: Extract content
evaluate_script(() => document.body.innerText)

Verified (2026): Sogou WeChat Search for chrome devtools returns 634 results. Opening the link gives full 2856-character article with no restrictions.

7. Mobile Emulation (some sites have fewer restrictions on mobile)

emulate({
  userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
  viewport: '375x667x2,mobile,touch'
})

Quick Command Reference

Operation Tool Description
Open page new_page(url) Open in new tab
Navigate navigate_page(url) Navigate current tab
Wait for content wait_for(["text"]) Wait for text to appear
Screenshot take_screenshot() Full-page screenshot
DOM snapshot take_snapshot() Accessibility tree text structure
Execute JS evaluate_script(fn) Arbitrary JS operations
JS with args evaluate_script(fn, args) Execute with parameters
Extract content evaluate_script(() => document.body.innerText) Plain text extraction
Remove element evaluate_script(() => el.remove()) Remove overlay/popup
Click element click(uid) Click by snapshot uid
Emulate device emulate({userAgent, viewport}) Switch UA/viewport
Scroll press_key({key: "Space"}) Simulate key press

FAQ (Practical Experience)

1. Popup class names don't match?

First inspect the actual overlay elements:

evaluate_script(() => {
  [...document.querySelectorAll('div[style*="fixed"], div[style*="absolute"], [class*="overlay"], [class*="modal"], [class*="mask"], [class*="popup"]')]
    .map(el => ({tag: el.tagName, cls: el.className.slice(0,80), visible: el.offsetParent !== null}))
})

2. How to tell if content is complete or truncated?

evaluate_script(() => {
  const a = document.querySelector('article') || document.querySelector('.Post-RichText');
  const ratio = a.scrollHeight / a.clientHeight;
  JSON.stringify({
    textLen: a.innerText.length,
    scrollH: a.scrollHeight, clientH: a.clientHeight,
    ratio: ratio.toFixed(2), // > 1.2 means overflow hidden
    endText: a.innerText.slice(-100)
  })
})

If it ends with -- The End --, copyright notice, or a natural ending, it's complete.

3. CSDN overlay class names (verified 2026)

CSDN Class Description
.mask + .mask-dark Background overlay
.passport-login-tip-container Login prompt bar
.passport-login-container Login dialog container
.passport-login-box / .passport-login-mark Login box and overlay
.hide-article-box Article collapse bar

4. Zhihu overlay class names (verified 2026)

Zhihu Class Description
.Modal.Modal--default.signFlowModal Login dialog
.signFlowModal-container Login container
Content selector: .Post-RichText or .RichText

5. Short article vs truncated article

  • Some articles are genuinely short (many images/code, few words) — e.g., 2081 chars but scrollHeight = 8550px
  • Verification: check end for natural termination, or confirm via document.title
  • Zhihu columns without login may redirect to search page — check location.href

6. What can vs cannot be bypassed

Type Principle Bypassable? Example
DOM overlay Content in DOM, hidden behind a div Yes — just remove it CSDN, Zhihu columns
Lazy load Content loaded on scroll Yes — trigger scroll Most comment sections
API auth Content fetched via cookie-authenticated API No — no cookie = no data Bilibili comments, Weibo
SSR hidden Server-rendered but hidden via class Yes — change style Juejin paid articles

7. Chrome restart / disconnect handling

MCP mode manages browser lifecycle automatically. CLI mode:

chrome-devtools stop     # Stop background process
chrome-devtools status   # Check status

Part 2 — Debugging Guide

Based on chrome-devtools-mcp toolset for debugging web pages, inspecting errors, and analyzing performance.

Tool Overview

Category         Tool                             Purpose
──────           ───                              ───
Navigation       new_page / navigate_page         Open/navigate pages
                 close_page / select_page         Close/switch tabs
                 list_pages                       List all tabs
                 wait_for                         Wait for text

Debugging        evaluate_script                  Execute JS in page
                 take_snapshot                    Get accessibility tree (uid)
                 take_screenshot                  Screenshot
                 list_console_messages            List console logs
                 get_console_message(msgid)       View specific log details
                 lighthouse_audit                 Lighthouse audit

Interaction      click(uid)                       Click element
                 fill(uid, value)                 Fill input field
                 fill_form([{uid,value}])         Batch form fill
                 type_text(text)                  Keyboard input
                 press_key(key)                   Key press (Enter/Tab/Ctrl+A)
                 hover(uid)                       Hover
                 drag(from_uid, to_uid)           Drag
                 handle_dialog(action)            Handle browser dialogs
                 upload_file(path, uid)           Upload file

Network          list_network_requests            List network requests
                 get_network_request(reqid)       View request details/response

Performance      performance_start_trace          Start performance recording
                 performance_stop_trace           Stop + analyze
                 performance_analyze_insight      Analyze specific metric
                 take_memory_snapshot             Heap snapshot

Emulation        emulate({userAgent, viewport})   Simulate device
                 resize_page(width, height)       Resize window

Standard Debugging Flows

Flow 1: JS Error Investigation

1. navigate_page(url)                      → Enter page
2. list_console_messages()                 → View errors
3. get_console_message(msgid)              → View error details
4. evaluate_script(() => { /* fix */ })   → Fix the issue
5. verify

Flow 2: Network Request Analysis

1. navigate_page(url)                      → Load page
2. list_network_requests()                 → List all requests
3. get_network_request(reqid)              → View request/response body
4. Identify 404s, CORS errors, slow requests

Flow 3: DOM / Style Debugging

1. take_snapshot()                         → Get element structure (with uid)
2. click(uid) / fill(uid, value)           → Interact
3. evaluate_script(() => getComputedStyle(el))  → Check styles
4. evaluate_script(() => { el.style.color = 'red' })  → Temporary modification
5. take_screenshot()                       → Confirm visually

Flow 4: Performance Analysis

1. performance_start_trace({reload: true})  → Start recording + reload
2. (wait for page to load)
3. performance_stop_trace()                 → Stop and analyze
4. performance_analyze_insight({insightName, insightSetId})  → Deep dive

Debugging Quick Reference

Console

// View all console messages
list_console_messages({includePreservedMessages: true})

// View specific message
get_console_message({msgid: 0})

Element Inspection

// Get interactive elements list (with uid)
take_snapshot()

// Verbose version (more properties)
take_snapshot({verbose: true})

// Inspect element styles
evaluate_script(() => {
  const el = document.querySelector('h1');
  return getComputedStyle(el);
})

// Get element dimensions / position
evaluate_script(() => {
  const el = document.querySelector('h1');
  return el.getBoundingClientRect();
})

Page Interaction

// Click (get uid via take_snapshot first)
click({uid: "element-123"})

// Fill input
fill({uid: "input-456", value: "search text"})

// Fill + Enter
fill({uid: "input-456", value: "search text"})
press_key({key: "Enter"})

// Keyboard shortcuts
press_key({key: "Control+A"})
press_key({key: "Control+C"})

// Handle browser dialogs (alert/confirm)
handle_dialog({action: "accept"})
handle_dialog({action: "dismiss"})

Network

// View all network requests
list_network_requests({pageSize: 50, resourceTypes: ["XHR", "Fetch", "Document"]})

// View request details
get_network_request({reqid: 0})

// Save response body to file
get_network_request({reqid: 0, responseFilePath: "response.json"})

Memory Debugging

// Capture heap snapshot (for memory leak analysis)
take_memory_snapshot({filePath: "heap.heapsnapshot"})

Lighthouse Audit

// Accessibility + SEO + Best Practices
lighthouse_audit({device: "desktop"})
lighthouse_audit({device: "mobile"})
lighthouse_audit({mode: "snapshot"}) // No reload, analyze current state

Typical Scenarios

Scenario A: White Screen / JS Error Fix

1. list_console_messages()             → Check for JS errors
2. get_console_message(0)             → View first error details
3. evaluate_script(() => { ... })     → Temporary fix in page
4. Fix in source code, reload, verify

Scenario B: API Endpoint Debugging

1. navigate_page('https://example.com')
2. list_network_requests({resourceTypes: ["XHR", "Fetch"]})  → Filter API calls
3. get_network_request(0)  → View request params + response data

Scenario C: Form Submission Verification

1. take_snapshot()                    → Get form element uids
2. fill({uid, value})                 → Fill each field
3. click({uid})                       → Click submit button
4. list_network_requests()            → Check if request was sent
5. list_console_messages()            → Check for errors

Scenario D: Responsive Layout Debugging

1. emulate({viewport: '375x667x2,mobile,touch'})   → Switch to mobile
2. take_screenshot()                                 → Screenshot for review
3. emulate({viewport: '1280x720'})                   → Switch back to desktop
4. take_screenshot()                                 → Compare results