Web Performance Skill
Tooling Notes
This skill relies on Chrome DevTools MCP. If the MCP server is missing, stop and ask the user to configure it.
First: Verify MCP Tools Available
Run a quick check before starting. If navigate_page or performance_start_trace is unavailable, stop and ask the user to add the MCP config.
"chrome-devtools": {
"type": "local",
"command": ["npx", "-y", "chrome-devtools-mcp@latest"]
}
Key Guidelines
- •Be assertive and verify claims with network, DOM, or codebase evidence.
- •Verify before recommending any removals or refactors.
- •Quantify impact using estimated savings; skip 0ms impact changes.
- •Skip non-issues: document low impact without recommending changes.
- •Be specific: name exact assets and sizes when suggesting optimisation.
- •Prioritise ruthlessly: excellent metrics should be called out as such.
Workflow
Copy this checklist and use it to track progress through the audit:
Audit Progress - [ ] Phase 1: Performance trace (navigate + record) - [ ] Phase 2: Core Web Vitals analysis (includes CLS culprits) - [ ] Phase 3: Network analysis - [ ] Phase 4: Accessibility snapshot - [ ] Phase 5: Codebase analysis (skip if third-party site)
Phase 1: Performance Trace
The problem is unknown page performance; capture a cold-load trace so you can diagnose it.
- •
Navigate to the target URL:
codenavigate_page(url: "<target-url>")
- •
Start a performance trace with reload:
codeperformance_start_trace(autoStop: true, reload: true)
- •
Wait for trace completion and capture the results.
Troubleshooting:
- •If the trace is empty, confirm the page loaded via
navigate_page. - •If insight names do not match, inspect the trace response to list available insights.
Phase 2: Core Web Vitals Analysis
Use performance_analyze_insight to extract key metrics. If an insight name fails, use the insightSetId from the trace response to discover available insights.
Common insight names:
| Metric | Insight Name | What to Look For |
|---|---|---|
| LCP | LCPBreakdown | TTFB, resource load, render delay |
| CLS | CLSCulprits | Images without dimensions, injected content, font swaps |
| Render Blocking | RenderBlocking | CSS/JS blocking first paint |
| Document Latency | DocumentLatency | Server response time issues |
| Network Dependencies | NetworkRequestsDepGraph | Chains delaying critical resources |
Example:
performance_analyze_insight(insightSetId: "<id-from-trace>", insightName: "LCPBreakdown")
Key thresholds (good/needs-improvement/poor):
- •TTFB: < 800ms / < 1.8s / > 1.8s
- •FCP: < 1.8s / < 3s / > 3s
- •LCP: < 2.5s / < 4s / > 4s
- •INP: < 200ms / < 500ms / > 500ms
- •TBT: < 200ms / < 600ms / > 600ms
- •CLS: < 0.1 / < 0.25 / > 0.25
- •Speed Index: < 3.4s / < 5.8s / > 5.8s
Phase 3: Network Analysis
List requests to identify optimisation opportunities:
list_network_requests(resourceTypes: ["Script", "Stylesheet", "Document", "Font", "Image"])
Look for:
- •Render-blocking resources: JS/CSS in
<head>withoutasync/defer/media. - •Network chains: late-discovered resources that delay critical assets.
- •Missing preloads: fonts, hero images, key scripts without preload.
- •Caching issues: weak
Cache-Control, missingETag/Last-Modified. - •Large payloads: oversized or uncompressed JS/CSS.
- •Unused preconnects: confirm zero requests to the origin before removal.
For details:
get_network_request(reqid: <id>)
Phase 4: Accessibility Snapshot
Take an accessibility tree snapshot:
take_snapshot(verbose: true)
Flag high-level gaps:
- •Missing or duplicate ARIA IDs.
- •Poor contrast ratios (WCAG AA: 4.5:1 normal text, 3:1 large text).
- •Focus traps or missing focus indicators.
- •Interactive elements without accessible names.
Phase 5: Codebase Analysis
Skip if auditing a third-party site without codebase access.
Detect the stack by searching for config files:
| Tool | Config Files |
|---|---|
| Webpack | webpack.config.js, webpack.*.js |
| Vite | vite.config.js, vite.config.ts |
| Rollup | rollup.config.js, rollup.config.mjs |
| esbuild | esbuild.config.js, build scripts with esbuild |
| Parcel | .parcelrc, package.json (parcel field) |
| Next.js | next.config.js, next.config.mjs |
| Nuxt | nuxt.config.js, nuxt.config.ts |
| SvelteKit | svelte.config.js |
| Astro | astro.config.mjs |
Also check package.json for framework dependencies and build scripts.
Tree-shaking and dead code:
- •Webpack: confirm
mode: "production",sideEffects, andusedExports. - •Vite/Rollup: tree-shaking is default; check
treeshakeoptions. - •Watch for barrel files and large libraries imported wholesale.
Unused JS/CSS:
- •Check for CSS-in-JS versus static extraction.
- •Look for PurgeCSS/UnCSS, or Tailwind
contentconfig. - •Identify dynamic imports versus eager loading.
Polyfills:
- •Check
@babel/preset-envtargets anduseBuiltIns. - •Look for oversized
core-jsimports. - •Verify
browserslistis not overly broad.
Compression and minification:
- •Check for
terser,esbuild, orswcminification. - •Verify gzip/brotli compression in server config.
- •Confirm source maps are external or disabled in production.
Output Format
Present findings in this order:
- •Core Web Vitals Summary: table with metric, value, rating.
- •Top Issues: prioritised list with estimated impact (high/medium/low).
- •Recommendations: specific, actionable fixes with snippets.
- •Codebase Findings: framework/bundler and optimisation notes (omit if no codebase access).