Performance and Core Web Vitals expertise. Activates when discussing page speed, Core Web Vitals, LCP, INP, CLS, TTFB, FCP, performance optimization, image compression, JavaScript optimization, or site speed issues. Phase 10. Output: {AUDIT_DIR}/speed-findings.md
From local-seo-auditnpx claudepluginhub anthropics/claude-plugins-community --plugin local-seo-audit-systemThis skill uses the workspace's default tool permissions.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Core Web Vitals are confirmed Google ranking signals. In 2025, INP (replaced FID March 2024) is the hardest CWV metric to pass — only ~65% of sites meet Good threshold (Cloudflare 2025). Pages with all CWV in "Good" range see average 15–25% CTR improvement (Google CrUX 2024). Speed directly impacts conversion: 1-second LCP delay = 20% conversion drop (Portent 2023). Always compare client CWV against top 3 competitors.
| Tool | Purpose | Cost |
|---|---|---|
| Google PageSpeed Insights | CWV scores + diagnostics (mobile + desktop) | Free |
| Chrome DevTools → Lighthouse | Lab data with filmstrip, coverage tab | Free |
| Chrome DevTools → Performance | INP profiling, main thread analysis | Free |
| WebPageTest (webpagetest.org) | Waterfall, filmstrip, multi-location test | Free |
| GTmetrix | Performance grade, waterfall, page size, requests | Free/Paid |
| CrUX (Chrome User Experience Report) | Real-user field data from CrUX dataset | Free |
| Cloudflare Speed (speed.cloudflare.com) | INP + TTFB from Cloudflare edge | Free |
| DebugBear | CWV monitoring, regression detection | Paid |
| site_crawler.py | Identify image-heavy pages, JS payload size | Free (local) |
Read {AUDIT_DIR}/intake-data.md — URL, tech stack (CMS affects optimization options).
Read {AUDIT_DIR}/technical-findings.md — any speed-related technical issues already flagged.
| Metric | Good | Needs Improvement | Poor | Measures |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | < 2.5s | 2.5–4.0s | > 4.0s | Perceived load speed |
| INP (Interaction to Next Paint) | < 200ms | 200–500ms | > 500ms | Responsiveness to interaction |
| CLS (Cumulative Layout Shift) | < 0.1 | 0.1–0.25 | > 0.25 | Visual stability |
| TTFB (Time to First Byte) | < 800ms | 800ms–1.8s | > 1.8s | Server responsiveness |
| FCP (First Contentful Paint) | < 1.8s | 1.8–3.0s | > 3.0s | Initial render |
| TBT (Total Blocking Time) | < 200ms | 200–600ms | > 600ms | Main thread blocking |
INP scoring guide (2025 priority):
500ms = Poor (critical — likely INP veto trigger)
PageSpeed Insights → Mobile (primary — Google ranks mobile-first):
URL: https://pagespeed.web.dev/
Test: [client URL]
Record: Performance score, LCP, INP, CLS, TTFB, FCP, TBT
PageSpeed Insights → Desktop (secondary benchmark):
Record same metrics — gap > 30pts Mobile vs Desktop = mobile-specific issue
Top 3 Competitors — test same URL structure (homepage):
Record mobile performance scores for competitive benchmark table
WebPageTest (real network conditions):
Location: nearest city to target audience
Connection: Mobile 4G LTE
Run: 3 tests → median result
Record: TTFB, Start Render, Fully Loaded, Total Page Size, Total Requests
Field data vs. Lab data check (PageSpeed "Discover what your real users are experiencing"):
CrUX field data available? Compare field vs. lab — large gaps indicate real-user outliers
PageSpeed Insights "Diagnostics" section identifies the LCP element automatically.
LCP element type → fix strategy:
| LCP Element Type | Primary Fix | Secondary Fix |
|---|---|---|
| Hero image | Preload + WebP/AVIF + fetchpriority="high" | Serve from CDN |
| H1 text block | Improve TTFB (server/hosting) + self-host fonts | Inline critical CSS |
| Background image (CSS) | Move to <img> tag to allow preload | fetchpriority="high" |
| Video thumbnail | Replace with image poster + lazy-load video | Serve from CDN |
<!-- Preload the LCP image in <head> -->
<link rel="preload" as="image" href="hero.webp" fetchpriority="high">
<!-- LCP img tag -->
<img src="hero.webp" width="1200" height="630"
fetchpriority="high" loading="eager"
alt="[descriptive alt]">
Image format targets:
If TTFB > 800ms — server is bottleneck:
| Action | Expected TTFB Improvement | Effort |
|---|---|---|
| Add Cloudflare (free tier) | 30–50% reduction | 30 min |
| Enable page caching (WP: WP Rocket/LiteSpeed) | 50–80% reduction | 1–2 hrs |
| Upgrade shared → VPS hosting | 40–70% reduction | 2–4 hrs |
| Move server geographically closer | 20–40% reduction | 4–8 hrs |
| Enable Brotli compression | 10–20% reduction | 30 min |
INP measures how quickly a page responds to user interactions (clicks, taps, keyboard input). It's the hardest CWV to fix — requires JavaScript profiling.
| Culprit | How to Detect | Fix | Effort |
|---|---|---|---|
| Long tasks on main thread (>50ms) | Chrome DevTools → Performance → "Long Tasks" | Break with scheduler.yield() or setTimeout(fn, 0) | 4–16 hrs |
| Third-party scripts (chat, analytics) | DevTools → Performance → filter by domain | Delay load until after user interaction | 1–4 hrs |
| Large JavaScript bundles | DevTools → Coverage tab → unused JS | Code splitting + tree shaking | 8–24 hrs |
| Excessive DOM nodes (>1,500) | DevTools → Performance Insights | Virtualize long lists | 4–16 hrs |
| Unthrottled scroll/resize handlers | DevTools → Performance → Event Listeners | Debounce/throttle + passive listeners | 1–4 hrs |
INP profiling command (Chrome DevTools):
| Cause | Fix | Effort |
|---|---|---|
| Images without dimensions | Add width and height to all <img> tags | 1–2 hrs |
| Ads / iframes without reserved space | Add min-height CSS container before ad loads | 2–4 hrs |
| Web fonts causing FOUT | font-display: optional + preload font | 1–2 hrs |
| Late-loading embeds (maps, social) | Use fixed-height skeleton placeholder | 1–4 hrs |
| Dynamically injected content above fold | Reserve space or inject only below fold | 2–8 hrs |
CSS animation not using transform | Replace top/margin with transform: translateY() | 30 min |
Image issues cause 60–75% of speed failures on local business sites (Screaming Frog audit data, 2024).
From python3 scripts/site_crawler.py output + manual check:
loading="lazy"?srcset defined for responsive images?width + height attributes on all <img> (prevents CLS)?Image optimization tools:
| Tool | Purpose | Cost |
|---|---|---|
| Squoosh (squoosh.app) | Manual WebP/AVIF conversion | Free |
| ImageOptim (Mac app) | Batch lossless compression | Free |
| TinyPNG API | Automated batch PNG/JPG compression | Free/Paid |
| Cloudinary | On-the-fly optimization + CDN | Free/Paid |
| ShortPixel (WordPress) | Auto-convert + compress on upload | Paid |
JS budget targets (2025):
<head>: 0 (except critical)| Fix | Impact | Effort |
|---|---|---|
Add defer to non-critical scripts | Removes render-blocking | 30 min |
| Delay chat widget to user interaction | -50–200ms INP | 1–2 hrs |
| Code splitting (lazy-load by route) | -30–100KB initial JS | 8–24 hrs |
| Remove unused jQuery plugins | -20–60KB | 1–4 hrs |
| Replace social share buttons with static links | -100–400ms INP | 30 min |
| Check | Good | Flag |
|---|---|---|
| Hosting type | Cloud/VPS/Managed WordPress | Shared hosting (shared = unpredictable TTFB) |
| CDN | Cloudflare / Fastly / BunnyCDN active | No CDN |
| Browser caching | Cache-Control: max-age=31536000 for static assets | No cache headers |
| Compression | Brotli (preferred) or GZIP enabled | No compression |
| HTTP version | HTTP/2 or HTTP/3 | HTTP/1.1 (slower) |
| Server location | < 50ms latency to target audience | > 100ms to target city |
| Metric | Client | Comp 1 | Comp 2 | Comp 3 | Target |
|---|---|---|---|---|---|
| Mobile PSI Score | > 70 | ||||
| LCP (mobile) | < 2.5s | ||||
| INP (mobile) | < 200ms | ||||
| CLS (mobile) | < 0.1 | ||||
| TTFB | < 800ms | ||||
| Page Size | < 2MB |
Competitive insight: If client's mobile score is ≥ 10 points below top competitor → speed gap is a ranking factor risk.
AI Overviews (AIO) and voice search results strongly favor fast pages:
Flag AIO/voice impact when speed issues are found.
| Issue | Impact (1–5) | Feasibility (1–5) | Priority | Effort |
|---|---|---|---|---|
| LCP > 4s (mobile) | 5 | 4 | 20 | 2–8 hrs |
| INP > 500ms | 5 | 3 | 15 | 4–16 hrs |
| No CDN (TTFB > 1.8s) | 5 | 5 | 25 | 30 min–2 hrs |
| Images not WebP/AVIF | 4 | 5 | 20 | 2–4 hrs |
| CLS > 0.25 | 4 | 4 | 16 | 1–4 hrs |
| Render-blocking JS | 4 | 4 | 16 | 1–4 hrs |
| No browser caching | 3 | 5 | 15 | 30 min |
| Third-party script bloat | 4 | 3 | 12 | 1–4 hrs |
| No GZIP/Brotli | 3 | 5 | 15 | 30 min |
Veto check: LCP > 6s on mobile → maximum SERP-TRUST score capped at 30/100.
Write complete findings to {AUDIT_DIR}/speed-findings.md with YAML frontmatter:
---
skill: audit/speed-optimization
phase: 10
date: [YYYY-MM-DD]
business: [Business Name]
url: [URL]
score: [X/100]
mobile_psi: [X]
desktop_psi: [X]
lcp_mobile: [Xs]
inp_mobile: [Xms]
cls_mobile: [X.XX]
ttfb: [Xms]
cwv_pass: [yes|no|partial]
---
Include:
Output files:
{AUDIT_DIR}/speed-findings.md — CWV findings with score and fix roadmap{REPORTS_DIR}/phase-10-speed.pdf — auto-generated PDF via python3 scripts/generate_pdf.pyKey consumers:
strategy/ux-cro-audit — speed directly impacts conversion rate (1s delay = 20% drop)cross-cutting/serp-trust-auditor — User Experience dimension U scoresai-visibility/voice-search — voice results require mobile score > 70cross-cutting/local-impact-auditor — Website Performance dimension| Issue | Root Cause | Fix | Effort | Impact |
|---|---|---|---|---|
| LCP >4s: render-blocking resources | CSS/JS blocking first paint | Defer non-critical JS; inline critical CSS | 2–4 hrs dev | High |
| LCP >4s: slow server TTFB | Unoptimized hosting/no CDN | Add CDN (Cloudflare free tier); enable server caching | 1–2 hrs | High |
| LCP >4s: large unoptimized image | No WebP/AVIF, no lazy load | Convert hero to WebP; add fetchpriority="high" on LCP image | 30 min | High |
| INP >500ms: slow event handlers | Heavy JS on user interactions | Profile with Chrome DevTools → break up long tasks (>50ms) | 4–8 hrs dev | Critical |
| INP >200ms: third-party scripts | Analytics/chat widgets blocking | Defer third-party scripts; use Partytown for off-main-thread | 2–4 hrs dev | High |
| CLS >0.25: images without dimensions | No width/height on img tags | Add width + height attributes to all images | 30 min | Medium |
| CLS >0.25: late-injected banners | Ads/cookie banners shifting layout | Reserve space with CSS min-height; use contain: layout | 1–2 hrs dev | Medium |
| TTFB >800ms: no caching | Dynamic pages not cached | Add WP Super Cache / W3 Total Cache / server-side caching | 1 hr | High |
fetchpriority="high" attribute. Effort: 30 min. Priority: 20.width and height to all <img> tags — eliminates CLS from images. Use Screaming Frog to find missing attributes. Effort: 30 min + 1 hr dev. Priority: 20..htaccess or Nginx config. 1-line addition. Most CDNs do this automatically. Effort: 15 min. Priority: 20.defer or async to all non-essential JS <script> tags. Doesn't require code changes, only attribute additions. Effort: 30 min. Priority: 20.setTimeout(0) or scheduler.postTask(). Effort: 4–8 hrs. Priority: 20.loading="lazy" to all <img> tags below the fold. Single attribute addition. Effort: 30 min dev. Priority: 15.GBP links drive 25–35% of local website visits. Users arriving via GBP "Website" button have high intent — slow load (>3s) = 53% abandonment rate (Google 2025). Fast pages also rank higher in AI Overviews citation pool. Target: mobile PageSpeed score ≥90.