mcpField
W
webperf-core-web-vitals

webperf-core-web-vitals

github.com/nucliwebTesting & quality1.5k290 installsUpdated today
Repository

About webperf-core-web-vitals

A skill for measuring and investigating Core Web Vitals with JavaScript snippets in Chrome DevTools. It guides audits and metric-specific follow-ups, with a CLI option for running snippets in headless Chromium.

Key features

  1. 01LCP, CLS, and INP measurement
  2. 02LCP candidate and phase analysis
  3. 03Metric-based investigation workflows
  4. 04Structured result objects
  5. 05CLI execution with headless Chromium

Use cases

  1. 01Auditing a page's Core Web Vitals
  2. 02Tracing slow LCP phases or candidates
  3. 03Investigating layout shifts
  4. 04Examining slow interactions

MCP support

Uses Chrome DevTools MCP's `mcp__chrome-devtools__evaluate_script` to run snippets and retrieve results; tracking metrics can be collected after user interactions.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/nucliweb/webperf-snippets --skill webperf-core-web-vitals

After installing, type/webperf-core-web-vitalsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
schema.md
snippets.md
scripts/
CLS.js
INP.js
LCP-Image-Entropy.js
LCP-Subparts.js
LCP-Trail.js
LCP-Video-Candidate.js
LCP.js

Details

From the project README

WebPerf: Core Web Vitals

JavaScript snippets for measuring web performance in Chrome DevTools.

Running a script

  1. Run the script with mcp__chrome-devtools__evaluate_script and read the object it returns. The scripts have no console output, so the returned object is the result: script, status and the metric data (value, rating, details, items, issues), as described in references/schema.md.
  2. When status is "tracking", the script keeps observing the page. After the interactions, call the function named in getDataFn with another mcp__chrome-devtools__evaluate_script call, for example getINP(), and read the object it returns.
  3. When status is "error" or "unsupported", read error: the page may not have loaded yet, or the browser lacks the API.

Without Chrome DevTools MCP, run the same snippet with the webperf-snippets CLI, which loads the page in headless Chromium and prints the same result objects: npx webperf-snippets <url> --snippet <Name> --json, where <Name> is the script name without .js. It needs Playwright and Chromium (npm install --save-dev webperf-snippets playwright, then npx playwright install chromium), and tracking snippets take --interact-script <file> to drive the interactions.

Scripts

  • scripts/CLS.js — Cumulative layout shift (CLS)
  • scripts/INP.js — Interaction to next paint (INP)
  • scripts/LCP-Image-Entropy.js — LCP image entropy
  • scripts/LCP-Subparts.js — LCP subparts
  • scripts/LCP-Trail.js — LCP trail
  • scripts/LCP-Video-Candidate.js — LCP video candidate
  • scripts/LCP.js — Largest contentful paint (LCP)

Common Workflows

Complete Core Web Vitals Audit

When the user asks for a comprehensive Core Web Vitals analysis or "audit CWV":

  1. LCP.js - Measure Largest Contentful Paint
  2. CLS.js - Measure Cumulative Layout Shift
  3. INP.js - Measure Interaction to Next Paint
  4. LCP-Subparts.js - Break down LCP timing phases
  5. LCP-Trail.js - Track LCP candidate evolution
LCP Deep Dive

When LCP is slow or the user asks "debug LCP" or "why is LCP slow":

  1. LCP.js - Establish baseline LCP value
  2. LCP-Subparts.js - Break down into TTFB, resource load, render delay
  3. LCP-Trail.js - Identify all LCP candidates and changes
  4. LCP-Image-Entropy.js - Check if LCP image has visual complexity issues
  5. LCP-Video-Candidate.js - Detect if LCP is a video (poster or video element)
CLS Investigation

When layout shifts are detected or the user asks "debug CLS" or "layout shift issues":

  1. CLS.js - Measure overall CLS score
  2. Layout-Shift-Loading-and-Interaction.js (pending — available in webperf-interaction skill)
  3. Cross-reference with webperf-loading skill:
    • Find-Above-The-Fold-Lazy-Loaded-Images.js (lazy images causing shifts)
    • Fonts-Preloaded-Loaded-and-used-above-the-fold.js (font swap causing shifts)
INP Debugging

When interactions feel slow or the user asks "debug INP" or "slow interactions":

  1. INP.js - Measure overall INP value; call getINP() after interactions, getINPDetails() for the 15 slowest interactions
  2. Interactions.js (pending — available in webperf-interaction skill)
  3. Input-Latency-Breakdown.js (pending — available in webperf-interaction skill)
  4. Long-Animation-Frames.js (pending — available in webperf-interaction skill)
  5. Long-Animation-Frames-Script-Attribution.js (pending — available in webperf-interaction skill)
Video as LCP Investigation

When LCP is a video element (detected by LCP-Video-Candidate.js):

  1. LCP-Video-Candidate.js - Identify video as LCP candidate
  2. Video-Element-Audit.js (from Media skill) - Audit video loading strategy
  3. LCP-Subparts.js - Analyze video loading phases
  4. Cross-reference with webperf-loading skill:
    • Resource-Hints-Validation.js (check for video preload)
    • Priority-Hints-Audit.js (check for fetchpriority on video)
Image as LCP Investigation

When LCP is an image (most common case):

  1. LCP.js - Measure LCP timing
  2. LCP-Subparts.js - Break down timing phases
  3. LCP-Image-Entropy.js - Analyze image complexity
  4. Cross-reference with webperf-media skill:
    • Image-Element-Audit.js (check format, dimensions, lazy loading)
  5. Cross-reference with webperf-loading skill:
    • Find-Above-The-Fold-Lazy-Loaded-Images.js (check if incorrectly lazy)
    • Priority-Hints-Audit.js (check for fetchpriority="high")
    • Resource-Hints-Validation.js (check for preload)

Decision Tree

Use this decision tree to automatically run follow-up snippets based on results:

After LCP.js
  • If LCP > 2.5s → Run LCP-Subparts.js to diagnose which phase is slow
  • If LCP > 4.0s (poor) → Run full LCP deep dive workflow (5 snippets)
  • If LCP candidate is an image → Run LCP-Image-Entropy.js and webperf-media:Image-Element-Audit.js
  • If LCP candidate is a video → Run LCP-Video-Candidate.js and webperf-media:Video-Element-Audit.js
  • Always run → LCP-Trail.js to understand candidate evolution
After LCP-Subparts.js
  • If TTFB phase > 600ms → Switch to webperf-loading skill and run TTFB-Sub-Parts.js
  • If Resource Load Time > 1500ms → Run:
    1. webperf-loading:Resource-Hints-Validation.js (check for preload/preconnect)
    2. webperf-loading:Priority-Hints-Audit.js (check fetchpriority)
    3. webperf-loading:Find-render-blocking-resources.js (competing resources)
  • If Render Delay > 200ms → Run:
    1. webperf-loading:Find-render-blocking-resources.js (blocking CSS/JS)
    2. webperf-loading:Script-Loading.js (parser-blocking scripts)
    3. webperf-interaction:Long-Animation-Frames.js (main thread blocking)
After LCP-Trail.js
  • If many LCP candidate changes (>3) → This causes visual instability, investigate:
    1. webperf-loading:Find-Above-The-Fold-Lazy-Loaded-Images.js (late-loading images)
    2. webperf-loading:Fonts-Preloaded-Loaded-and-used-above-the-fold.js (font swaps)
    3. CLS.js (layout shifts contributing to LCP changes)
  • If final LCP candidate appears late → Run webperf-loading:Resource-Hints-Validation.js
  • If early candidate was replaced → Understand why initial content was pushed down (likely CLS issue)
After LCP-Image-Entropy.js
  • If entropy is very high → Image is visually complex, recommend:
    • Modern formats (WebP, AVIF)
    • Appropriate compression
    • Potentially a placeholder strategy
  • If entropy is low → Image may be over-optimized or placeholder-like
  • If large file size detected → Run webperf-media:Image-Element-Audit.js for format/sizing analysis
After LCP-Video-Candidate.js
  • If video is LCP → Run:
    1. webperf-media:Video-Element-Audit.js (check poster, preload, formats)
    2. webperf-loading:Priority-Hints-Audit.js (check fetchpriority on poster)
    3. LCP-Subparts.js (analyze video loading phases)
  • If poster image is LCP → Treat as image LCP (run image workflows)
After CLS.js
  • If CLS > 0.1 → Run webperf-interaction:Layout-Shift-Loading-and-Interaction.js (pending — available in webperf-interaction skill)
  • If CLS > 0.25 (poor) → Run comprehensive shift investigation:
    1. webperf-loading:Find-Above-The-Fold-Lazy-Loaded-Images.js (images without dimensions)
    2. webperf-loading:Fonts-Preloaded-Loaded-and-used-above-the-fold.js (font loading strategy)
    3. webperf-loading:Critical-CSS-Detection.js (late-loading styles)
    4. webperf-media:Image-Element-Audit.js (missing width/height)
  • If CLS = 0 → Confirm with multiple page loads (might be timing-dependent)
After INP.js
  • If INP > 200ms → Run webperf-interaction:Interactions.js to identify slow interactions
  • If INP > 500ms (poor) → Run full INP debugging workflow:
    1. webperf-interaction:Interactions.js (list all interactions)
    2. webperf-interaction:Input-Latency-Breakdown.js (phase breakdown)
    3. webperf-interaction:Long-Animation-Frames.js (blocking frames)
    4. webperf-interaction:Long-Animation-Frames-Script-Attribution.js (culprit scripts)
  • If specific interaction type is slow (e.g., keyboard) → Focus analysis on that interaction type
  • After INP data is collected → call getINPDetails() for the 15 slowest interactions, slowest first (useful for identifying patterns across multiple slow interactions)
Error Recovery
  • If any script returns status: "error" → Check if the page has finished loading:
    • If early in load: wait and re-run the script
    • If page is an SPA: user may need to navigate to the target route first
  • If LCP.js / LCP-Subparts.js returns status: "error" → Tell the user: "LCP data is not available yet. Please ensure the page has fully loaded, then run the analysis again."
  • If INP.js getINP() returns status: "error" → The getDataFn: "getINP" field signals the agent can retry after user interaction. Prompt the user to click, type, or scroll, then call getINP() again.
Cross-Skill Triggers

Context fork note: This skill runs with context: fork. Cross-skill triggers below are recommendations to report back to the parent agent, not direct calls this subagent can execute. When a cross-skill trigger fires, tell the user which skill and script to run next. Scripts marked (pending) are not yet available — skip them and note the limitation.

These triggers recommend using snippets from other skills:

From LCP to Loading Skill
  • If LCP > 2.5s and TTFB phase is dominant → Use webperf-loading skill:

    • TTFB.js, TTFB-Sub-Parts.js, Service-Worker-Analysis.js
  • If LCP image is lazy-loaded → Use webperf-loading skill:

    • Find-Above-The-Fold-Lazy-Loaded-Images.js
  • If LCP has no fetchpriority → Use webperf-loading skill:

    • Priority-Hints-Audit.js
From CLS to Loading Skill
  • If CLS caused by fonts → Use webperf-loading skill:

    • Fonts-Preloaded-Loaded-and-used-above-the-fold.js
    • Resource-Hints-Validation.js (for font preload)
  • If CLS caused by images → Use webperf-media skill:

    • Image-Element-Audit.js (check for width/height attributes)
From INP to Interaction Skill
  • If INP > 200ms → Use webperf-interaction skill for full debugging:
    • Interactions.js, Input-Latency-Breakdown.js
    • Long-Animation-Frames.js, Long-Animation-Frames-Script-Attribution.js
    • LongTask.js (if pre-interaction blocking suspected)
From LCP/INP to Interaction Skill
  • If render delay or interaction delay is high → Use webperf-interaction skill:
    • Long-Animation-Frames.js (main thread blocking)
    • LongTask.js (long tasks delaying rendering)
Multi-Metric Correlation

When multiple CWV metrics are poor, prioritize investigation:

  • If LCP > 2.5s AND CLS > 0.1 → Likely shared root cause:

    1. Check for late-loading content pushing LCP element
    2. Run LCP-Trail.js to see LCP candidate changes
    3. Run Layout-Shift-Loading-and-Interaction.js to correlate timing
  • If LCP > 2.5s AND INP > 200ms → Main thread congestion:

    1. Run Long-Animation-Frames.js
    2. Run webperf-loading:Script-Loading.js
    3. Run webperf-loading:JS-Execution-Time-Breakdown.js
  • If CLS > 0.1 AND INP > 200ms → Layout thrashing or interaction-triggered shifts:

    1. Run Layout-Shift-Loading-and-Interaction.js
    2. Run Interactions.js
    3. Check if shifts occur during/after interactions

References

  • references/snippets.md — Descriptions and thresholds for each script
  • references/schema.md — Return value schema for interpreting script output

Comments

Markdown supported