Claude
Skills
Sign in
Back

console-intelligence

Included with Lifetime
$97 forever

Capture and categorize all console output with stack traces, source attribution, frequency deduplication, and temporal grouping. Uses CDP Runtime and Log domains for browser-level entries and unhandled exceptions.

General

What this skill does


# Console Intelligence

Capture every console message, unhandled exception, and browser-level log
entry from a page session. Categorize by severity, group by source file,
deduplicate repeated messages, detect framework-specific warnings (React,
Vue, Angular), identify CSP violations, and produce a prioritized report.

## When to Use

- Debugging production pages where console errors indicate broken functionality.
- Auditing a page for JavaScript errors, deprecation warnings, and CSP violations before release.
- Identifying noisy third-party scripts that flood the console.
- Detecting React/Vue/Angular framework warnings that indicate misuse or performance issues.
- Understanding the temporal sequence of errors during page load and interaction.

## Prerequisites

- **Playwright MCP server** connected and responding.
- **Chromium-based browser** for CDP Runtime and Log domain access.
- Target page must be reachable from the browser instance.

## Workflow

### Phase 1: Install Console Interceptors via CDP

Install CDP listeners **before** navigation so that early page errors are
captured. This uses three complementary channels:

1. **Runtime.exceptionThrown** -- catches unhandled exceptions with async stack traces.
2. **Log.entryAdded** -- catches browser-level entries (network errors, security warnings, interventions).
3. **Console method patching** via `browser_evaluate` -- catches all `console.*` calls with caller location.

```javascript
browser_run_code({
  code: `async (page) => {
    const client = await page.context().newCDPSession(page);

    await client.send('Runtime.enable');
    await client.send('Log.enable');

    const entries = [];
    let idCounter = 0;

    // Channel 1: Unhandled exceptions (async stack traces included)
    client.on('Runtime.exceptionThrown', (params) => {
      const ex = params.exceptionDetails;
      const entry = {
        id: ++idCounter,
        channel: 'exception',
        level: 'error',
        timestamp: params.timestamp,
        text: ex.text || '',
        description: ex.exception ? (ex.exception.description || ex.exception.value || '') : '',
        url: ex.url || null,
        lineNumber: ex.lineNumber,
        columnNumber: ex.columnNumber,
        stackTrace: null
      };

      if (ex.stackTrace && ex.stackTrace.callFrames) {
        entry.stackTrace = ex.stackTrace.callFrames.map(f => ({
          functionName: f.functionName || '(anonymous)',
          url: f.url,
          lineNumber: f.lineNumber,
          columnNumber: f.columnNumber
        }));
      }

      entries.push(entry);
    });

    // Channel 2: Browser-level log entries
    client.on('Log.entryAdded', (params) => {
      const e = params.entry;
      entries.push({
        id: ++idCounter,
        channel: 'browser',
        level: e.level,
        timestamp: e.timestamp,
        text: e.text,
        url: e.url || null,
        lineNumber: e.lineNumber || null,
        source: e.source,
        category: e.category || null,
        networkRequestId: e.networkRequestId || null
      });
    });

    globalThis.__consoleIntel = { client, entries };
    return 'CDP console interceptors installed';
  }`
})
```

### Phase 2: Install Console Method Patches

Patch `console.*` methods in the page context to capture calls with caller
information. This runs in the page's JavaScript context.

```javascript
browser_evaluate({
  function: `() => {
    window.__consoleCaptures = [];
    const methods = ['log', 'warn', 'error', 'info', 'debug', 'trace', 'assert'];
    const originals = {};

    methods.forEach(method => {
      originals[method] = console[method].bind(console);
      console[method] = (...args) => {
        // Capture caller location from stack trace
        const stack = new Error().stack || '';
        const callerLine = stack.split('\\n')[2] || '';
        const match = callerLine.match(/(?:at\\s+)?(?:.*?)\\(?(.+?):(\\d+):(\\d+)\\)?/);

        window.__consoleCaptures.push({
          method: method,
          timestamp: Date.now(),
          args: args.map(a => {
            try {
              if (typeof a === 'object') return JSON.stringify(a).substring(0, 500);
              return String(a).substring(0, 500);
            } catch { return '[unserializable]'; }
          }),
          sourceUrl: match ? match[1] : null,
          line: match ? parseInt(match[2]) : null,
          column: match ? parseInt(match[3]) : null
        });

        originals[method](...args);
      };
    });

    return 'Console methods patched (' + methods.length + ' methods)';
  }`
})
```

### Phase 3: Navigate and Interact

Navigate to the target page. Console interceptors are already active.

```
browser_navigate({ url: "<target_url>" })
```

Wait for page load and deferred scripts:

```
browser_wait_for({ time: 3 })
```

Perform interactions that may trigger console output:

1. Scroll the page to trigger lazy-loaded content:
   ```javascript
   browser_evaluate({
     function: `() => {
       window.scrollTo(0, document.body.scrollHeight / 2);
       return 'scrolled to midpoint';
     }`
   })
   ```

2. Wait for async operations:
   ```
   browser_wait_for({ time: 2 })
   ```

3. Take a snapshot and click interactive elements (buttons, tabs) to trigger
   event handler errors:
   ```
   browser_snapshot()
   ```
   Then use `browser_click` on elements identified in the snapshot.

4. Wait again for async responses:
   ```
   browser_wait_for({ time: 2 })
   ```

### Phase 4: Collect Baseline from Built-in Tool

Cross-reference with the built-in console capture.

```
browser_console_messages({ level: "debug" })
```

### Phase 5: Harvest and Analyze

Collect all captured data and perform categorization, deduplication, and
framework detection.

```javascript
browser_run_code({
  code: `async (page) => {
    const intel = globalThis.__consoleIntel;
    if (!intel) return { error: 'Interceptors not installed' };

    // Collect CDP entries
    const cdpEntries = [...intel.entries];

    // Collect page-context captures
    const pageCaptures = await page.evaluate(() => window.__consoleCaptures || []);

    // Merge into unified list
    const all = [];

    cdpEntries.forEach(e => all.push(e));
    pageCaptures.forEach(c => {
      all.push({
        id: all.length + 1,
        channel: 'console-patch',
        level: c.method === 'warn' ? 'warning'
             : c.method === 'assert' ? 'error'
             : c.method === 'trace' ? 'info'
             : c.method,
        timestamp: c.timestamp,
        text: c.args.join(' '),
        url: c.sourceUrl,
        lineNumber: c.line,
        method: c.method
      });
    });

    // Sort by timestamp
    all.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));

    // Deduplicate: group identical messages
    const deduped = new Map();
    all.forEach(entry => {
      const key = entry.level + '|' + (entry.text || '').substring(0, 200);
      if (deduped.has(key)) {
        const existing = deduped.get(key);
        existing.count++;
        existing.lastSeen = entry.timestamp;
      } else {
        deduped.set(key, { ...entry, count: 1, lastSeen: entry.timestamp });
      }
    });

    // Framework detection patterns
    const frameworkPatterns = [
      { regex: /Warning:.*React/, framework: 'React', type: 'warning' },
      { regex: /react-dom\\.development/, framework: 'React', type: 'dev-mode' },
      { regex: /Each child in a list should have a unique/, framework: 'React', type: 'key-warning' },
      { regex: /Cannot update a component.*while rendering/, framework: 'React', type: 'state-during-render' },
      { regex: /\\[Vue warn\\]/, framework: 'Vue', type: 'warning' },
      { regex: /\\[deprecation\\]|NG\\d{4}/, framework: 'Angular', type: 'deprecation' },
      { regex: /Content.Security.Policy|CSP/, framework: 'Browser', type: 'csp-violation' },
      { regex: /Mixed Content/, framework: 'Browser', type: 'mixed-content' },
      { regex: /DEPRECATED|deprecated/, fram

Related in General