Core Web Vitals & Speed Audit — Phase 10
Executive Summary
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.
Tools for This Phase
| 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) |
Step 1: Read Project Context
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.
Step 2: Baseline CWV Data Collection
2025 CWV Thresholds (Updated — INP replaced FID March 2024)
| 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):
- < 100ms = Excellent (competitive advantage)
- 100–200ms = Good (meets threshold)
- 200–500ms = Needs Improvement (flag for fixes)
500ms = Poor (critical — likely INP veto trigger)
Data Collection Protocol
PageSpeed Insights → Mobile (primary — Google ranks mobile-first):
URL: https://pagespeed.web.dev/ Test: [client URL] Record: Performance score, LCP, INP, CLS, TTFB, FCP, TBTPageSpeed Insights → Desktop (secondary benchmark):
Record same metrics — gap > 30pts Mobile vs Desktop = mobile-specific issueTop 3 Competitors — test same URL structure (homepage):
Record mobile performance scores for competitive benchmark tableWebPageTest (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 RequestsField 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
Section 1: LCP Optimization
Identify LCP Element
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 |
LCP Image Fixes (Most Common — 68% of LCP failures)
<!-- 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:
- AVIF: 50–80% smaller than JPEG — ideal for LCP (Chrome + Firefox + Safari 16+)
- WebP: 25–35% smaller than JPEG — broad browser support
- Max LCP image size: ≤ 200KB (above fold, compressed)
LCP Server Response (TTFB Fix)
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 |
Section 2: INP Optimization (2025 Priority Signal)
INP measures how quickly a page responds to user interactions (clicks, taps, keyboard input). It's the hardest CWV to fix — requires JavaScript profiling.
Common INP Culprits
| 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):
- Open DevTools → Performance tab
- Click "Record" → perform click/interaction on page → Stop
- Look for "Interaction" entries in the timeline → identify blocking time
Section 3: CLS Optimization
| 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 |
Section 4: Image Optimization (Highest ROI Area)
Image issues cause 60–75% of speed failures on local business sites (Screaming Frog audit data, 2024).
Image Audit Checklist
From python3 scripts/site_crawler.py output + manual check:
- All above-fold images in WebP or AVIF?
- Hero/LCP image ≤ 200KB?
- Below-fold images use
loading="lazy"? -
srcsetdefined for responsive images? -
width+heightattributes on all<img>(prevents CLS)? - No images served larger than display size (e.g., 2000px image at 400px display)?
- Images served from CDN (not same server as HTML)?
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 |
Section 5: JavaScript Optimization
JS budget targets (2025):
- Total JS payload: < 300KB compressed
- Unused JS: < 20% of total
- Render-blocking scripts in
<head>: 0 (except critical) - Third-party scripts: audit any > 50ms INP impact
| 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 |
Section 6: Server & Infrastructure
| 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 |
Section 7: Competitor Speed Benchmark
| 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.
Section 8: AI Visibility Speed Connection (2025)
AI Overviews (AIO) and voice search results strongly favor fast pages:
- AIO sources pages with LCP < 2.5s at 78% rate vs. 41% for LCP > 4s (SparkToro 2025)
- Voice search results: 97% come from pages with mobile score > 70 (Backlinko 2024)
- PageSpeed is a direct GBP ranking factor for "near me" queries (Google 2024 documentation)
Flag AIO/voice impact when speed issues are found.
Priority Matrix
| 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.
Output
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:
- Score X/100 with per-section breakdown
- CWV baseline table (client vs. 3 competitors)
- LCP element identified + specific fix steps
- INP profiling results + specific scripts causing delay
- CLS causes identified + fixes
- Image audit (page-level — pages with largest images)
- JS payload breakdown (total, unused, render-blocking)
- Server/infrastructure assessment
- Priority matrix (all issues, Impact × Feasibility scored)
- 30-day speed improvement plan (quick wins first)
Output files:
{AUDIT_DIR}/speed-findings.md— CWV findings with score and fix roadmap{REPORTS_DIR}/phase-10-speed.pdf— auto-generated PDF viapython3 scripts/generate_pdf.py
Key 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
Quick Reference: CWV Fix Priority Table
Action Priority by Issue Type
| 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 |
Numbered Action Plan (10+ Steps)
Immediate (Week 1, No Dev — Quick Wins)
- Run PageSpeed Insights for mobile + desktop — record LCP, INP, CLS, TTFB baseline. Screenshot all scores. Effort: 10 min. Priority: 25.
- Compress and convert hero images to WebP — use Squoosh.app (free) or ShortPixel → target <200KB for hero. Add
fetchpriority="high"attribute. Effort: 30 min. Priority: 20. - Add
widthandheightto all<img>tags — eliminates CLS from images. Use Screaming Frog to find missing attributes. Effort: 30 min + 1 hr dev. Priority: 20. - Enable browser caching + GZIP compression — check
.htaccessor Nginx config. 1-line addition. Most CDNs do this automatically. Effort: 15 min. Priority: 20. - Defer non-critical JavaScript — add
deferorasyncto all non-essential JS<script>tags. Doesn't require code changes, only attribute additions. Effort: 30 min. Priority: 20.
Short-Term (Week 2–4, Developer Involvement)
- Implement CDN — Cloudflare free tier provides instant TTFB improvement globally. Set up in 1 hr. Expected TTFB drop: 200–600ms. Effort: 1 hr. Priority: 20.
- Profile INP with Chrome DevTools — record → filter for Interaction events → identify long tasks >50ms → break into smaller chunks with
setTimeout(0)orscheduler.postTask(). Effort: 4–8 hrs. Priority: 20. - Defer or eliminate third-party scripts — Google Tag Manager, chat widgets, and analytics are top INP killers. Load after user interaction where possible. Effort: 2–4 hrs. Priority: 16.
- Enable lazy loading on below-fold images — add
loading="lazy"to all<img>tags below the fold. Single attribute addition. Effort: 30 min dev. Priority: 15. - Test mobile CWV separately — Google uses mobile-first indexing. Run CrUX field data (real-user INP) vs. Lighthouse lab data. Fix the field data metric, not just the lab score. Effort: 30 min analysis. Priority: 20.
GBP Speed Connection (2025)
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.