Skip to content
Beta Multi-model support (OpenAI, Gemini, and more) launching soon.

perf-cwv-audit

Installable Ships in performance-auditor — or copy the raw skill below.
Open Claude.ai

Paste into Claude Code, Claude.ai, the desktop app, or the browser extension — ⌘/Ctrl+V.

ExperimentalNo security review

Core Web Vitals Audit

Full Lighthouse and CrUX diagnostic for LCP, INP, and CLS. Produces a finding report ranked by estimated user impact, with code-level fixes and next-step skill references.

Usage

/perf-cwv-audit <URL> [--platform sitecore|optimizely|umbraco|headless] [--device mobile|desktop|both] [--runs <n>]

Examples:

  • /perf-cwv-audit https://localhost:3000 — mobile + desktop, autodetect stack
  • /perf-cwv-audit https://staging.client.com --platform sitecore --device mobile --runs 3
  • /perf-cwv-audit https://www.client.com --device both — production CWV baseline

Phase 1 — Environment and Toolchain Check

Check what Lighthouse tooling is available:

npx lighthouse --version 2>/dev/null && echo "lighthouse available"
npx lhci --version 2>/dev/null && echo "lhci available"
node --version 2>/dev/null

If no CLI is available, proceed with static analysis (Phases 3–5) and note the limitation.


Phase 2 — Run Lighthouse

Single run (quick baseline)

npx lighthouse <URL> \
  --output json \
  --output-path ./lh-report.json \
  --chrome-flags="--headless --no-sandbox" \
  --form-factor=mobile \
  --throttling-method=simulate \
  --preset=perf

For desktop:

npx lighthouse <URL> \
  --output json \
  --output-path ./lh-report-desktop.json \
  --chrome-flags="--headless --no-sandbox" \
  --form-factor=desktop \
  --throttling-method=simulate \
  --preset=perf

Run 3–5 times and average the metric values. Variance >10% in LCP suggests unstable server response times or third-party script interference — flag as a finding.

for i in 1 2 3; do
  npx lighthouse <URL> \
    --output json \
    --output-path ./lh-run-$i.json \
    --chrome-flags="--headless --no-sandbox" \
    --form-factor=mobile \
    --quiet
done

Parse and average lcp, inp, cls, fcp, tbt, si across runs.


Phase 3 — Extract Key Metrics

From the Lighthouse JSON, extract these values from audits and categories:

performance score         → categories.performance.score × 100
LCP                       → audits['largest-contentful-paint'].numericValue (ms)
INP                       → audits['interaction-to-next-paint'].numericValue (ms)
CLS                       → audits['cumulative-layout-shift'].numericValue
FCP                       → audits['first-contentful-paint'].numericValue (ms)
TBT                       → audits['total-blocking-time'].numericValue (ms)
Speed Index               → audits['speed-index'].numericValue (ms)
TTFB                      → audits['server-response-time'].numericValue (ms)
Render-blocking savings   → audits['render-blocking-resources'].details.overallSavingsMs
Unused JS savings         → audits['unused-javascript'].details.overallSavingsBytes
Unused CSS savings        → audits['unused-css-rules'].details.overallSavingsBytes

Phase 4 — Root Cause Diagnosis per Metric

4.1 LCP (Largest Contentful Paint)

Identify the LCP element from audits['largest-contentful-paint-element']. Common causes:

Cause Lighthouse Signal Platform Pattern
Slow TTFB server-response-time > 600 ms Sitecore uncached rendering; Optimizely DXP cold start
Render-blocking resources render-blocking-resources savings > 0 Synchronous CSS/JS in <head>
LCP image not preloaded uses-rel-preload flags LCP image Missing fetchpriority="high" or <link rel="preload">
LCP image uncompressed uses-optimized-images or uses-webp-images Sitecore Media Library serving JPEG; Umbraco ImageSharp not configured
Lazy-loaded LCP image efficient-animated-content or source inspection loading="lazy" on above-the-fold hero
No CDN uses-long-cache-ttl or headers inspection Origin responses without CDN in front

4.2 INP (Interaction to Next Paint)

INP > 200 ms typically traces to main-thread blocking during user interactions. Inspect:

  • audits['total-blocking-time'] — proxy for long tasks; TBT > 300 ms on mobile → likely INP issues
  • Long JavaScript tasks (> 50 ms) blocking the main thread during user interaction
  • DOM size (audits['dom-size']) > 1,500 nodes slows style/layout recalculations
  • Third-party scripts injecting after interaction (audits['third-party-summary'])

Common patterns:

  • React event handlers that trigger synchronous state updates and large re-renders
  • Optimizely personalisation JS running on click
  • Analytics/tag manager firing synchronous callbacks on interaction

4.3 CLS (Cumulative Layout Shift)

Identify the shifting elements from audits['layout-shift-elements']. Causes:

Cause Signal Fix
Unsized images/iframes No width/height attributes Add explicit dimensions or CSS aspect-ratio
Font FOUT uses-rel-preload misses font; no font-display: swap Preload + font-display: swap
Dynamic content injection Cookie banner, chat widget, personalisation slot Reserve space with min-height; use contain: layout
Ad slot without reserved height Ad tags in body Fixed-height container around ad units
CMS content above existing DOM Sitecore personalisation variant swap Use contain: size layout on swappable regions

Phase 5 — Platform-Specific Checks

Sitecore XM Cloud / JSS

  • TTFB: Is Sitecore output cache enabled for rendering hosts? Check rendering-host-config.json for cacheProfiles.
  • LCP image: Is the hero image served from Sitecore Media Library with proper CDN rules? Look for /~/media/ URL patterns.
  • JSS hydration gap: LCP candidate rendered on server but re-rendered on client causes layout shift. Check for data-hydration wrappers without dimensions.
  • XM Cloud CDN: Is the XM Cloud Edge CDN configured with stale-while-revalidate for content pages?

Optimizely Content Cloud / DXP

  • DXP CDN caching: Is Cache-Control set on content page responses? Check for no-store on pages that could be cached.
  • Block rendering: Does the page waterfall show sequential block fetch requests? Use IContentLoader.GetItems() batching.
  • Personalisation scripts: Optimizely's personalisation JS must be loaded with defer; synchronous load blocks FCP.

Umbraco

  • Output caching: Is UmbracoOutputCacheAttribute applied to controllers? Uncached Umbraco pages on high-traffic routes bottleneck TTFB.
  • ImageSharp: Is Umbraco.Cms.Web.Common.Media.ImageSharpImageUrlGenerator configured with WebP output?
  • Examine index: Is index warm-up happening on startup to prevent first-request latency spikes?

Headless / Composable (Next.js on Azure)

  • Rendering strategy: Is ISR (revalidate) configured for content-heavy pages, or are they falling back to SSR on every request?
  • <Image> component: Are all images going through next/image? Bypassed images miss automatic lazy loading, sizing, and format negotiation.
  • App Router RSC: Are data-fetching components Server Components, or are they 'use client' components doing unnecessary client-side fetches?
  • Azure Static Web Apps / App Service: Is the origin behind Azure Front Door with compression and caching rules?

Phase 6 — Build the Finding Report

Output a structured Markdown report. See templates.md for the full schema.

Report structure:

## CWV Audit Report — [URL]

**Audited:** [date] | **Device:** [mobile/desktop/both] | **Platform:** [detected/specified]
**Lighthouse version:** [x.x.x] | **Runs:** [n] (averaged)

### Metric Summary
| Metric | Score | Value | Target | Status |
|--------|-------|-------|--------|--------|
| LCP    | —     | X.Xs  | ≤ 2.5s | PASS/FAIL |
| INP    | —     | XXms  | ≤ 200ms | PASS/FAIL |
| CLS    | —     | 0.XX  | ≤ 0.1  | PASS/FAIL |
| TBT    | —     | XXXms | — | INFO |
| FCP    | —     | X.Xs  | — | INFO |
| TTFB   | —     | XXXms | ≤ 600ms | PASS/FAIL |
| Perf Score | XX | — | ≥ 90 | PASS/FAIL |

### Findings (ranked by impact)
[one block per finding — see templates.md]

### Quick Wins (< 1 hour each)
[list of low-effort, high-impact items]

### Next Steps
- Run `/perf-render-blocking-analysis` for CSS/JS critical-path detail
- Run `/perf-asset-optimisation` for image/font/media detail
- Run `/perf-caching-review` for CDN and cache-header detail
- Run `/perf-backlog-builder ./cwv-audit-report.md` to generate sprint stories

Quality Checklist

  • LCP element identified with tagName, src/text, and estimated size
  • INP root cause traced (TBT, DOM size, or specific third-party script)
  • Every CLS shift element named with its cause
  • Every finding has a specific action, not "consider improving"
  • CWV targets cited: LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1 at p75
  • Platform-specific patterns checked where stack identified

Reference files

  • reference.md — CWV metric definitions, Lighthouse audit IDs, scoring thresholds
  • templates.md — Report template and finding record schema
  • examples.md — Real-world finding examples with before/after fixes
Technical details
Plugin
performance-auditor
Author
Dakota Smith
Skill name
perf-cwv-audit
Maturity
experimental
Security review
No security review
Owners
  • engineering
Argument hint
<URL> [--platform sitecore|optimizely|umbraco|headless] [--device mobile|desktop|both] [--runs <n>]
Allowed tools
  • Read
  • Write
  • Edit
  • Glob
  • Grep
  • Bash(npx lighthouse *)
  • Bash(npx lhci *)
  • Bash(node *)
  • Bash(cat *)
  • Bash(ls *)
  • WebFetch(domain:localhost)
  • WebFetch(domain:web.dev)
  • WebFetch(domain:developers.google.com)
  • WebFetch(domain:pagespeed.web.dev)
Source
plugins/performance-auditor/skills/perf-cwv-audit/SKILL.md

Edit this skill on GitHub — opens GitHub's web editor. No git knowledge needed.