performance-audit
Conducts detailed website performance audits including Core Web Vitals, load times, and memory bottleneck analysis.
Install
mkdir -p .claude/skills/performance-audit && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11121" && unzip -o skill.zip -d .claude/skills/performance-audit && rm skill.zipInstalls to .claude/skills/performance-audit
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when the user asks to run a performance audit, profile a website, check page load speeds, measure Core Web Vitals (LCP, CLS, FCP, INP, TTFB), run a Lighthouse audit, test mobile performance, capture a performance trace, hunt memory leaks, or diagnose rendering / layout-shift / third-party bottlenecks of any URL using Chrome DevTools.Key capabilities
- →Measure Core Web Vitals including LCP, CLS, and FCP
- →Run Lighthouse audits for performance scoring
- →Capture performance traces for memory leak analysis
- →Identify third-party impact and critical request chains
- →Provide P0 to P2 optimization recommendations
How it works
The agent uses the chrome-devtools-mcp server to navigate to a URL, capture performance traces, and run diagnostic scripts to extract metrics.
Inputs & outputs
When to use performance-audit
- →Run a Lighthouse audit for a landing page
- →Diagnose layout shifts and slow load times
- →Capture a performance trace to hunt memory leaks
About this skill
Web Performance Audit
End-to-end performance audit of any URL using the
chrome-devtools-mcp server.
Produces a structured report covering Core Web Vitals, Lighthouse scores, the
critical request chain, third-party impact, forced reflow, cache policy, and
optional memory profiling, with P0 / P1 / P2 recommendations.
Prerequisites
The chrome-devtools-mcp server must be registered with the client. For cold-load
measurements, start it with --isolated --headless (neither is on by default —
without --isolated the server reuses a persistent profile and the "cold" load
may be warm). Two workflow steps need extra opt-in flags: heap snapshots
(step 11) require --memoryDebugging, and screencast recording requires
--experimentalScreencast plus ffmpeg. Never use --slim — it strips the
performance and network tools this skill depends on. See
references/tools-cheatsheet.md for the full CLI
and tool inventory; consult it whenever you are unsure of a tool name or
parameter — it is the source of truth for this skill.
Workflow
1. Clarify the run
Before the first tool call, confirm with the user (one line each is fine):
- URL and any auth / cookie requirements
- Device: desktop (default) or mobile
- Throttling: none (default), or
Slow 4G+4× CPUfor a realistic mobile test - Memory profiling?: off by default — opt in for suspected leaks / SPA bloat
- Report language: default to the page's language
2. Configure the environment
Apply emulation before navigation so the trace reflects the target conditions.
emulate takes named options — there is no type: "mobile" shortcut.
Mobile + throttled example:
{
"viewport": { "width": 412, "height": 915, "deviceScaleFactor": 2.625, "isMobile": true, "hasTouch": true },
"userAgent": "Mozilla/5.0 (Linux; Android 13; moto g power) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",
"cpuThrottlingRate": 4,
"networkConditions": "Slow 4G"
}
networkConditions accepts "Slow 3G", "Fast 3G", "Slow 4G", "Fast 4G",
"No throttling".
Optional: screencast_start({ filePath: "load.webm" }) to record the load
(only available when the server runs with --experimentalScreencast and
ffmpeg is installed — skip silently otherwise).
3. Load the page
new_page({ url })(orlist_pages+select_pageif a tab already exists). In--isolatedmode the profile is fresh, so this is already a cold load.wait_for({ text: "<text expected when settled>" })if the page needs an explicit settle signal. Note:wait_foris text-only; it does not support "network idle" or CSS selectors.- Only if the session is not isolated and the cache may be warm, force a
cold reload before tracing:
navigate_page({ url, type: "navigate", ignoreCache: true }). Skip this step in the recommended isolated/headless config —new_pageplus the trace's own reload below is enough.
4. Capture the trace
performance_start_trace({ filePath: "trace.json", reload: true, autoStop: true })
performance_stop_trace({ filePath: "trace.json" })
The stop response returns insight IDs and (unless --no-performance-crux was
passed) CrUX field data. If CrUX is absent, record one of:
"no field data — site lacks sufficient CrUX traffic" (origin not in the dataset)
or "CrUX disabled — server started with --no-performance-crux" (check the
client's MCP config).
5. Run Lighthouse
lighthouse_audit({ device: "desktop", mode: "navigation" })
Match device to the run chosen in step 1 (desktop by default, mobile for a
mobile audit). lighthouse_audit runs against the currently selected page and
does not take a URL or category list. device: mobile or desktop. mode:
navigation (default), timespan, or snapshot. Optionally pass
outputDirPath to persist the full HTML report.
6. Extract detailed metrics
Inject the metrics collector via evaluate_script. The script is in
references/metrics-script.js — read the file and
pass its async function (comment header excluded) as the function argument;
the returned promise is awaited automatically. It registers buffered
PerformanceObservers for LCP, layout-shift, long-task, and event entries
(these are not returned by getEntriesByType, so reading them any other way
yields a null LCP and 0 CLS) and awaits ~250 ms to drain them. It returns
navigation timings, FCP, LCP (element + selector), CLS (max session window, with
sources), an INP approximation, resource inventory, third-party grouping, a
critical-path heuristic tree, and long tasks. It also reports a lab TBT
estimate, long-animation-frame script attribution (per-script forced
style/layout time, Chrome 123+), DOM-size stats, and a hygiene block
(oversized / unsized / wrongly-lazy images, resource hints vs missing
preconnects, uncompressed text assets, HTTP/1.1 hosts, service-worker
presence) — these feed the report's hygiene and forced-reflow sections.
7. Drill into trace insights
For each relevant insight ID from step 4, call
performance_analyze_insight({ insightName, insightSetId }). Useful names:
LCPBreakdown— TTFB / Resource Load Delay / Render Delay splitLayoutShifts— authoritative CLS source attributionRenderBlockingRequests— JS / CSS blocking the first paintDocumentLatency— server response, redirects, compressionThirdParties— main-thread cost per originFontDisplay,ImageDelivery,LongTasks,SlowCSSSelectors
8. Measure INP (optional, recommended)
A cold load has zero user interactions, so INP from step 6 will be null. For
a real value:
- Install the event observer first — the browser only auto-buffers
evententries withduration >= 104 ms, so sub-104 ms interactions are silently dropped unless an observer is registered before they happen. Inject this once, before any interaction:evaluate_script({ function: `() => { if (window.__inpEvents__) return 'already-installed'; window.__inpEvents__ = []; new PerformanceObserver(list => { // Only entries with interactionId > 0 count toward INP — skip raw event timings. for (const e of list.getEntries()) { if (e.interactionId > 0) window.__inpEvents__.push(e.duration); } }).observe({ type: 'event', durationThreshold: 40, buffered: true }); return 'installed'; }` }) take_snapshot()→ returnsuidvalues for interactive elements.- Drive 3–5 representative interactions:
click({ uid }),hover({ uid }),fill_form({ elements: [...] }),press_key({ key }). End with a scroll pass —press_key({ key: "PageDown" })3–4 times — to trigger lazy-loaded content and surface below-fold layout shifts the cold load can't see. - Re-run the metrics script — it merges
window.__inpEvents__with the ≥104 ms auto-buffer (read via its own buffered observer) and anyfirst-inputentry, then reports the p98 of measured event durations.
9. Inspect network headers (cache audit)
list_network_requests({ resourceTypes: ["script", "stylesheet", "image", "font", "document"] })
Then get_network_request({ reqid }) on the largest / suspicious entries to
read Cache-Control, Expires, Age, ETag, and Content-Encoding.
Skip this step if the server runs with --redact-network-headers.
10. Surface console diagnostics
list_console_messages({ types: ["error", "warning"] })
Look especially for [Violation] 'X' handler took Nms and
Forced reflow while executing JavaScript — these flag long-task and
layout-thrash hotspots. Use get_console_message({ msgid }) for full stacks.
Cross-reference with longAnimationFrames.topScripts from step 6: its
forcedStyleAndLayoutMs is measured per script, so it names the layout-thrash
offender directly, whereas the console violations only hint at it.
11. Memory profiling (only if requested)
Requires the server to be running with --memoryDebugging — if the
heap-snapshot tools are missing, ask the user to add that flag to the MCP
config and restart the server. For suspected leaks or heavy SPA heap usage:
take_heapsnapshot({ filePath: "heap1.heapsnapshot" })after the page settles.- Interact with the suspected feature (open/close modal, navigate tabs, etc.).
take_heapsnapshot({ filePath: "heap2.heapsnapshot" }).get_heapsnapshot_summaryon both — compare retained sizes.- For suspicious classes (e.g.
Detached HTMLDivElement, framework component names):get_heapsnapshot_class_nodes({ filePath, id })→ pick a leaking node →get_heapsnapshot_retainers({ filePath, nodeId })to trace the reference chain back to the leaker. - When done,
close_heapsnapshot({ filePath })on each snapshot to free server memory.
12. Generate the report
Build a markdown report following references/report-template.md. Skip sections that produced no findings (typically Memory and Forced Reflow if not investigated). Every recommendation in the P0/P1/P2 plan must name the specific resource, the expected impact (e.g. "−400 ms LCP"), and the fix.
If screencast_start was used, end with screencast_stop and reference the
video file in the report.
Tips
- Run the audit twice (cold + warm) when caching strategy is in question — pass
ignoreCache: trueonly on the cold pass. - Mobile audits use
cpuThrottlingRate: 4to approximate a mid-tier Android. Don't apply throttling on a desktop audit unless the user asks. largest-contentful-paint,layout-shift,longtask, andevententries are invisible toperformance.getEntriesByType()— they can only be read by aPerformanceObserverwithbuffered: true. The metrics script handles this; if you write ad-hoc `evaluate
Content truncated.
When not to use it
- →Non-web URL performance analysis
- →Situations where Chrome DevTools cannot be registered
Prerequisites
Limitations
- →Requires specific server flags for memory and screencast features
- →Wait_for is limited to text-only signals
- →CrUX data availability depends on site traffic
How it compares
This workflow automates the collection of specific performance metrics and provides structured recommendations, replacing manual DevTools inspection.
Compared to similar skills
performance-audit side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| performance-audit (this skill) | 0 | 1mo | No flags | Advanced |
| chrome-devtools | 41 | 7mo | Review | Intermediate |
| analyzing-logs | 14 | 25d | Review | Beginner |
| obsidian-observability | 5 | 25d | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
chrome-devtools
mrgoonie
Browser automation, debugging, and performance analysis using Puppeteer CLI scripts. Use for automating browsers, taking screenshots, analyzing performance, monitoring network traffic, web scraping, form automation, and JavaScript debugging.
analyzing-logs
jeremylongshore
Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.
obsidian-observability
jeremylongshore
Set up comprehensive logging and monitoring for Obsidian plugins. Use when implementing debug logging, tracking plugin performance, or setting up error reporting for your Obsidian plugin. Trigger with phrases like "obsidian logging", "obsidian monitoring", "obsidian debug", "track obsidian plugin".
instruments-profiling
steipete
Use when profiling native macOS or iOS apps with Instruments/xctrace. Covers correct binary selection, CLI arguments, exports, and common gotchas.
worker-benchmarks
ruvnet
Run comprehensive worker system benchmarks and performance analysis
sentry-rate-limits
jeremylongshore
Manage Sentry rate limits and quota optimization. Use when hitting rate limits, optimizing event volume, or managing Sentry costs. Trigger with phrases like "sentry rate limit", "sentry quota", "reduce sentry events", "sentry 429".