Skip to content
Back to skills

684 Performance Guide E9391eda

ASecurity

Comprehensive guide to analyzing web performance using Chrome DevTools Protocol, Puppeteer, and chrome-devtools skill.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentjavascriptgojavanodeexpresstestingci/cdperformance

Works with

  • cli
  • mcp

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 684-performance-guide_e9391eda --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 684 Performance Guide E9391eda?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 684 Performance Guide E9391eda
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-684-performance-guide-e9391eda/badge)](https://www.skillsdirectory.com/skills/tools-only-684-performance-guide-e9391eda)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Performance Analysis Guide

Comprehensive guide to analyzing web performance using Chrome DevTools Protocol, Puppeteer, and chrome-devtools skill.

## Table of Contents

- [Core Web Vitals](#core-web-vitals)
- [Performance Tracing](#performance-tracing)
- [Network Analysis](#network-analysis)
- [JavaScript Performance](#javascript-performance)
- [Rendering Performance](#rendering-performance)
- [Memory Analysis](#memory-analysis)
- [Optimization Strategies](#optimization-strategies)

---

## Core Web Vitals

### Overview

Core Web Vitals are Google's standardized metrics for measuring user experience:

- **LCP (Largest Contentful Paint)** - Loading performance (< 2.5s good)
- **FID (First Input Delay)** - Interactivity (< 100ms good)
- **CLS (Cumulative Layout Shift)** - Visual stability (< 0.1 good)

### Measuring with chrome-devtools-mcp

```javascript
// Start performance trace
await useTool('performance_start_trace', {
  categories: ['loading', 'rendering', 'scripting']
});

// Navigate to page
await useTool('navigate_page', {
  url: 'https://example.com'
});

// Wait for complete load
await useTool('wait_for', {
  waitUntil: 'networkidle'
});

// Stop trace and get data
await useTool('performance_stop_trace');

// Get AI-powered insights
const insights = await useTool('performance_analyze_insight');

// insights will include:
// - LCP timing
// - FID analysis
// - CLS score
// - Performance recommendations
```

### Measuring with Puppeteer

```javascript
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();

// Measure Core Web Vitals
await page.goto('https://example.com', {
  waitUntil: 'networkidle2'
});

const vitals = await page.evaluate(() => {
  return new Promise((resolve) => {
    const vitals = {
      LCP: null,
      FID: null,
      CLS: 0
    };

    // LCP
    new PerformanceObserver((list) => {
      const entries = list.getEntries();
      vitals.LCP = entries[entries.length - 1].renderTime ||
                   entries[entries.length - 1].loadTime;
    }).observe({ entryTypes: ['largest-contentful-paint'] });

    // FID
    new PerformanceObserver((list) => {
      vitals.FID = list.getEntries()[0].processingStart -
                   list.getEntries()[0].startTime;
    }).observe({ entryTypes: ['first-input'] });

    // CLS
    new PerformanceObserver((list) => {
      list.getEntries().forEach((entry) => {
        if (!entry.hadRecentInput) {
          vitals.CLS += entry.value;
        }
      });
    }).observe({ entryTypes: ['layout-shift'] });

    // Wait 5 seconds for metrics
    setTimeout(() => resolve(vitals), 5000);
  });
});

console.log('Core Web Vitals:', vitals);
```

### Other Important Metrics

**TTFB (Time to First Byte)**
```javascript
const ttfb = await page.evaluate(() => {
  const [navigationEntry] = performance.getEntriesByType('navigation');
  return navigationEntry.responseStart - navigationEntry.requestStart;
});
```

**FCP (First Contentful Paint)**
```javascript
const fcp = await page.evaluate(() => {
  const paintEntries = performance.getEntriesByType('paint');
  const fcpEntry = paintEntries.find(e => e.name === 'first-contentful-paint');
  return fcpEntry ? fcpEntry.startTime : null;
});
```

**TTI (Time to Interactive)**
```javascript
// Requires lighthouse or manual calculation
const tti = await page.evaluate(() => {
  // Complex calculation based on network idle and long tasks
  // Best to use Lighthouse for accurate TTI
});
```

---

## Performance Tracing

### Chrome Trace Categories

**Loading:**
- Page load events
- Resource loading
- Parser activity

**Rendering:**
- Layout calculations
- Paint operations
- Compositing

**Scripting:**
- JavaScript execution
- V8 compilation
- Garbage collection

**Network:**
- HTTP requests
- WebSocket traffic
- Resource fetching

**Input:**
- User input processing
- Touch/scroll events

**GPU:**
- GPU operations
- Compositing work

### Record Performance Trace

**Using chrome-devtools-mcp:**
```javascript
// Start trace with specific categories
await useTool('performance_start_trace', {
  categories: ['loading', 'rendering', 'scripting', 'network']
});

// Perform actions
await useTool('navigate_page', { url: 'https://example.com' });
await useTool('wait_for', { waitUntil: 'networkidle' });

// Optional: Interact with page
await useTool('click', { uid: 'button-uid' });

// Stop trace
const traceData = await useTool('performance_stop_trace');

// Analyze trace
const insights = await useTool('performance_analyze_insight');
```

**Using Puppeteer:**
```javascript
// Start tracing
await page.tracing.start({
  path: 'trace.json',
  categories: [
    'devtools.timeline',
    'disabled-by-default-devtools.timeline',
    'disabled-by-default-v8.cpu_profiler'
  ]
});

// Navigate
await page.goto('https://example.com', {
  waitUntil: 'networkidle2'
});

// Stop tracing
await page.tracing.stop();

// Analyze in Chrome DevTools (chrome://tracing)
```

### Analyze Trace Data

**Key Metrics from Trace:**

1. **Main Thread Activity**
   - JavaScript execution time
   - Layout/reflow time
   - Paint time
   - Long tasks (> 50ms)

2. **Network Waterfall**
   - Request start times
   - DNS lookup
   - Connection time
   - Download time

3. **Rendering Pipeline**
   - DOM construction
   - Style calculation
   - Layout
   - Paint
   - Composite

**Common Issues to Look For:**
- Long tasks blocking main thread
- Excessive JavaScript execution
- Layout thrashing
- Unnecessary repaints
- Slow network requests
- Large bundle sizes

---

## Network Analysis

### Monitor Network Requests

**Using chrome-devtools-mcp:**
```javascript
// Navigate to page
await useTool('navigate_page', { url: 'https://example.com' });

// Wait for all requests
await useTool('wait_for', { waitUntil: 'networkidle' });

// List all requests
const requests = await useTool('list_network_requests', {
  resourceTypes: ['Document', 'Script', 'Stylesheet', 'Image', 'XHR', 'Fetch'],
  pageSize: 100
});

// Analyze specific request
for (const req of requests.requests) {
  const details = await useTool('get_network_request', {
    requestId: req.id
  });

  console.log({
    url: details.url,
    method: details.method,
    status: details.status,
    size: details.encodedDataLength,
    time: details.timing.receiveHeadersEnd - details.timing.requestTime,
    cached: details.fromCache
  });
}
```

**Using Puppeteer:**
```javascript
const requests = [];

// Capture all requests
page.on('request', (request) => {
  requests.push({
    url: request.url(),
    method: request.method(),
    resourceType: request.resourceType(),
    headers: request.headers()
  });
});

// Capture responses
page.on('response', (response) => {
  const request = response.request();
  console.log({
    url: response.url(),
    status: response.status(),
    size: response.headers()['content-length'],
    cached: response.fromCache(),
    timing: response.timing()
  });
});

await page.goto('https://example.com');
```

### Network Performance Metrics

**Calculate Total Page Weight:**
```javascript
let totalBytes = 0;
let resourceCounts = {};

page.on('response', async (response) => {
  const type = response.request().resourceType();
  const buffer = await response.buffer();

  totalBytes += buffer.length;
  resourceCounts[type] = (resourceCounts[type] || 0) + 1;
});

await page.goto('https://example.com');

console.log('Total size:', (totalBytes / 1024 / 1024).toFixed(2), 'MB');
console.log('Resources:', resourceCounts);
```

**Identify Slow Requests:**
```javascript
page.on('response', (response) => {
  const timing = response.timing();
  const totalTime = timing.receiveHeadersEnd - timing.requestTime;

  if (totalTime > 1000) { // Slower than 1 second
    console.log('Slow request:', {
      url: response.url(),
      time: totalTime.toFixed(2) + 'ms',
      size: response.headers()['content-length']
    });
  }
});
```

### Network Throttling

**Simulate Slow Connection:**
```javascript
// Using chrome-devtools-mcp
await useTool('emulate_network', {
  throttlingOption: 'Slow 3G'  // or 'Fast 3G', 'Slow 4G'
});

// Using Puppeteer
const client = await page.createCDPSession();
await client.send('Network.emulateNetworkConditions', {
  offline: false,
  downloadThroughput: 400 * 1024 / 8,  // 400 Kbps
  uploadThroughput: 400 * 1024 / 8,
  latency: 2000  // 2000ms RTT
});
```

---

## JavaScript Performance

### Identify Long Tasks

**Using Performance Observer:**
```javascript
await page.evaluate(() => {
  return new Promise((resolve) => {
    const longTasks = [];

    const observer = new PerformanceObserver((list) => {
      list.getEntries().forEach((entry) => {
        longTasks.push({
          name: entry.name,
          duration: entry.duration,
          startTime: entry.startTime
        });
      });
    });

    observer.observe({ entryTypes: ['longtask'] });

    // Collect for 10 seconds
    setTimeout(() => {
      observer.disconnect();
      resolve(longTasks);
    }, 10000);
  });
});
```

### CPU Profiling

**Using Puppeteer:**
```javascript
// Start CPU profiling
const client = await page.createCDPSession();
await client.send('Profiler.enable');
await client.send('Profiler.start');

// Navigate and interact
await page.goto('https://example.com');
await page.click('.button');

// Stop profiling
const { profile } = await client.send('Profiler.stop');

// Analyze profile (flame graph data)
// Import into Chrome DevTools for visualization
```

### JavaScript Coverage

**Identify Unused Code:**
```javascript
// Start coverage
await Promise.all([
  page.coverage.startJSCoverage(),
  page.coverage.startCSSCoverage()
]);

// Navigate
await page.goto('https://example.com');

// Stop coverage
const [jsCoverage, cssCoverage] = await Promise.all([
  page.coverage.stopJSCoverage(),
  page.coverage.stopCSSCoverage()
]);

// Calculate unused bytes
function calculateUnusedBytes(coverage) {
  let usedBytes = 0;
  let totalBytes = 0;

  for (const entry of coverage) {
    totalBytes += entry.text.length;
    for (const range of entry.ranges) {
      usedBytes += range.end - range.start - 1;
    }
  }

  return {
    usedBytes,
    totalBytes,
    unusedBytes: totalBytes - usedBytes,
    unusedPercentage: ((totalBytes - usedBytes) / totalBytes * 100).toFixed(2)
  };
}

console.log('JS Coverage:', calculateUnusedBytes(jsCoverage));
console.log('CSS Coverage:', calculateUnusedBytes(cssCoverage));
```

### Bundle Size Analysis

**Analyze JavaScript Bundles:**
```javascript
page.on('response', async (response) => {
  const url = response.url();
  const type = response.request().resourceType();

  if (type === 'script') {
    const buffer = await response.buffer();
    const size = buffer.length;

    console.log({
      url: url.split('/').pop(),
      size: (size / 1024).toFixed(2) + ' KB',
      gzipped: response.headers()['content-encoding'] === 'gzip'
    });
  }
});
```

---

## Rendering Performance

### Layout Thrashing Detection

**Monitor Layout Recalculations:**
```javascript
// Using Performance Observer
await page.evaluate(() => {
  return new Promise((resolve) => {
    const measurements = [];

    const observer = new PerformanceObserver((list) => {
      list.getEntries().forEach((entry) => {
        if (entry.entryType === 'measure' &&
            entry.name.includes('layout')) {
          measurements.push({
            name: entry.name,
            duration: entry.duration,
            startTime: entry.startTime
          });
        }
      });
    });

    observer.observe({ entryTypes: ['measure'] });

    setTimeout(() => {
      observer.disconnect();
      resolve(measurements);
    }, 5000);
  });
});
```

### Paint and Composite Metrics

**Get Paint Metrics:**
```javascript
const paintMetrics = await page.evaluate(() => {
  const paints = performance.getEntriesByType('paint');
  return {
    firstPaint: paints.find(p => p.name === 'first-paint')?.startTime,
    firstContentfulPaint: paints.find(p => p.name === 'first-contentful-paint')?.startTime
  };
});
```

### Frame Rate Analysis

**Monitor FPS:**
```javascript
await page.evaluate(() => {
  return new Promise((resolve) => {
    let frames = 0;
    let lastTime = performance.now();

    function countFrames() {
      frames++;
      requestAnimationFrame(countFrames);
    }

    countFrames();

    setTimeout(() => {
      const now = performance.now();
      const elapsed = (now - lastTime) / 1000;
      const fps = frames / elapsed;
      resolve(fps);
    }, 5000);
  });
});
```

### Layout Shifts (CLS)

**Track Individual Shifts:**
```javascript
await page.evaluate(() => {
  return new Promise((resolve) => {
    const shifts = [];
    let totalCLS = 0;

    const observer = new PerformanceObserver((list) => {
      list.getEntries().forEach((entry) => {
        if (!entry.hadRecentInput) {
          totalCLS += entry.value;
          shifts.push({
            value: entry.value,
            time: entry.startTime,
            elements: entry.sources?.map(s => s.node)
          });
        }
      });
    });

    observer.observe({ entryTypes: ['layout-shift'] });

    setTimeout(() => {
      observer.disconnect();
      resolve({ totalCLS, shifts });
    }, 10000);
  });
});
```

---

## Memory Analysis

### Memory Metrics

**Get Memory Usage:**
```javascript
// Using chrome-devtools-mcp
await useTool('evaluate_script', {
  expression: `
    ({
      usedJSHeapSize: performance.memory?.usedJSHeapSize,
      totalJSHeapSize: performance.memory?.totalJSHeapSize,
      jsHeapSizeLimit: performance.memory?.jsHeapSizeLimit
    })
  `,
  returnByValue: true
});

// Using Puppeteer
const metrics = await page.metrics();
console.log({
  jsHeapUsed: (metrics.JSHeapUsedSize / 1024 / 1024).toFixed(2) + ' MB',
  jsHeapTotal: (metrics.JSHeapTotalSize / 1024 / 1024).toFixed(2) + ' MB',
  domNodes: metrics.Nodes,
  documents: metrics.Documents,
  jsEventListeners: metrics.JSEventListeners
});
```

### Memory Leak Detection

**Monitor Memory Over Time:**
```javascript
async function detectMemoryLeak(page, duration = 30000) {
  const samples = [];
  const interval = 1000; // Sample every second
  const samples_count = duration / interval;

  for (let i = 0; i < samples_count; i++) {
    const metrics = await page.metrics();
    samples.push({
      time: i,
      heapUsed: metrics.JSHeapUsedSize
    });

    await page.waitForTimeout(interval);
  }

  // Analyze trend
  const firstSample = samples[0].heapUsed;
  const lastSample = samples[samples.length - 1].heapUsed;
  const increase = ((lastSample - firstSample) / firstSample * 100).toFixed(2);

  return {
    samples,
    memoryIncrease: increase + '%',
    possibleLeak: increase > 50 // > 50% increase indicates possible leak
  };
}

const leakAnalysis = await detectMemoryLeak(page, 30000);
console.log('Memory Analysis:', leakAnalysis);
```

### Heap Snapshot

**Capture Heap Snapshot:**
```javascript
const client = await page.createCDPSession();

// Take snapshot
await client.send('HeapProfiler.enable');
const { result } = await client.send('HeapProfiler.takeHeapSnapshot');

// Snapshot is streamed in chunks
// Save to file or analyze programmatically
```

---

## Optimization Strategies

### Image Optimization

**Detect Unoptimized Images:**
```javascript
const images = await page.evaluate(() => {
  const images = Array.from(document.querySelectorAll('img'));
  return images.map(img => ({
    src: img.src,
    naturalWidth: img.naturalWidth,
    naturalHeight: img.naturalHeight,
    displayWidth: img.width,
    displayHeight: img.height,
    oversized: img.naturalWidth > img.width * 1.5 ||
               img.naturalHeight > img.height * 1.5
  }));
});

const oversizedImages = images.filter(img => img.oversized);
console.log('Oversized images:', oversizedImages);
```

### Font Loading

**Detect Render-Blocking Fonts:**
```javascript
const fonts = await page.evaluate(() => {
  return Array.from(document.fonts).map(font => ({
    family: font.family,
    weight: font.weight,
    style: font.style,
    status: font.status,
    loaded: font.status === 'loaded'
  }));
});

console.log('Fonts:', fonts);
```

### Third-Party Scripts

**Measure Third-Party Impact:**
```javascript
const thirdPartyDomains = ['googletagmanager.com', 'facebook.net', 'doubleclick.net'];

page.on('response', async (response) => {
  const url = response.url();
  const isThirdParty = thirdPartyDomains.some(domain => url.includes(domain));

  if (isThirdParty) {
    const buffer = await response.buffer();
    console.log({
      url: url,
      size: (buffer.length / 1024).toFixed(2) + ' KB',
      type: response.request().resourceType()
    });
  }
});
```

### Critical Rendering Path

**Identify Render-Blocking Resources:**
```javascript
await page.goto('https://example.com');

const renderBlockingResources = await page.evaluate(() => {
  const resources = performance.getEntriesByType('resource');
  return resources.filter(resource => {
    return (resource.initiatorType === 'link' &&
            resource.name.includes('.css')) ||
           (resource.initiatorType === 'script' &&
            !resource.name.includes('async'));
  }).map(r => ({
    url: r.name,
    duration: r.duration,
    startTime: r.startTime
  }));
});

console.log('Render-blocking resources:', renderBlockingResources);
```

### Lighthouse Integration

**Run Lighthouse Audit:**
```javascript
import lighthouse from 'lighthouse';
import { launch } from 'chrome-launcher';

// Launch Chrome
const chrome = await launch({ chromeFlags: ['--headless'] });

// Run Lighthouse
const { lhr } = await lighthouse('https://example.com', {
  port: chrome.port,
  onlyCategories: ['performance']
});

// Get scores
console.log({
  performanceScore: lhr.categories.performance.score * 100,
  metrics: {
    FCP: lhr.audits['first-contentful-paint'].displayValue,
    LCP: lhr.audits['largest-contentful-paint'].displayValue,
    TBT: lhr.audits['total-blocking-time'].displayValue,
    CLS: lhr.audits['cumulative-layout-shift'].displayValue,
    SI: lhr.audits['speed-index'].displayValue
  },
  opportunities: lhr.audits['opportunities']
});

await chrome.kill();
```

---

## Performance Budgets

### Set Performance Budgets

```javascript
const budgets = {
  // Core Web Vitals
  LCP: 2500,        // ms
  FID: 100,         // ms
  CLS: 0.1,         // score

  // Other metrics
  FCP: 1800,        // ms
  TTI: 3800,        // ms
  TBT: 300,         // ms

  // Resource budgets
  totalPageSize: 2 * 1024 * 1024,  // 2 MB
  jsSize: 500 * 1024,               // 500 KB
  cssSize: 100 * 1024,              // 100 KB
  imageSize: 1 * 1024 * 1024,       // 1 MB

  // Request counts
  totalRequests: 50,
  jsRequests: 10,
  cssRequests: 5
};

async function checkBudgets(page, budgets) {
  // Measure actual values
  const vitals = await measureCoreWebVitals(page);
  const resources = await analyzeResources(page);

  // Compare against budgets
  const violations = [];

  if (vitals.LCP > budgets.LCP) {
    violations.push(`LCP: ${vitals.LCP}ms exceeds budget of ${budgets.LCP}ms`);
  }

  if (resources.totalSize > budgets.totalPageSize) {
    violations.push(`Page size: ${resources.totalSize} exceeds budget of ${budgets.totalPageSize}`);
  }

  // ... check other budgets

  return {
    passed: violations.length === 0,
    violations
  };
}
```

---

## Automated Performance Testing

### CI/CD Integration

```javascript
// performance-test.js
import puppeteer from 'puppeteer';

async function performanceTest(url) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  // Measure metrics
  await page.goto(url, { waitUntil: 'networkidle2' });
  const metrics = await page.metrics();
  const vitals = await measureCoreWebVitals(page);

  await browser.close();

  // Check against thresholds
  const thresholds = {
    LCP: 2500,
    FID: 100,
    CLS: 0.1,
    jsHeapSize: 50 * 1024 * 1024  // 50 MB
  };

  const failed = [];
  if (vitals.LCP > thresholds.LCP) failed.push('LCP');
  if (vitals.FID > thresholds.FID) failed.push('FID');
  if (vitals.CLS > thresholds.CLS) failed.push('CLS');
  if (metrics.JSHeapUsedSize > thresholds.jsHeapSize) failed.push('Memory');

  if (failed.length > 0) {
    console.error('Performance test failed:', failed);
    process.exit(1);
  }

  console.log('Performance test passed');
}

performanceTest(process.env.TEST_URL);
```

---

## Best Practices

### Performance Testing Checklist

1. **Measure Multiple Times**
   - Run tests 3-5 times
   - Use median values
   - Account for variance

2. **Test Different Conditions**
   - Fast 3G
   - Slow 3G
   - Offline
   - CPU throttling

3. **Test Different Devices**
   - Mobile (low-end)
   - Mobile (high-end)
   - Desktop
   - Tablet

4. **Monitor Over Time**
   - Track metrics in CI/CD
   - Set up alerts for regressions
   - Create performance dashboards

5. **Focus on User Experience**
   - Prioritize Core Web Vitals
   - Test real user journeys
   - Consider perceived performance

6. **Optimize Critical Path**
   - Minimize render-blocking resources
   - Defer non-critical JavaScript
   - Optimize font loading
   - Lazy load images

---

## Resources

- [Web.dev Performance](https://web.dev/performance/)
- [Chrome DevTools Performance](https://developer.chrome.com/docs/devtools/performance/)
- [Core Web Vitals](https://web.dev/vitals/)
- [Lighthouse](https://developer.chrome.com/docs/lighthouse/)
- [WebPageTest](https://www.webpagetest.org/)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.