Performance Optimization: Core Web Vitals

Type: Execution Recipe Confidence: 0.92 Sources: 7 Verified: 2026-03-12

Purpose

This recipe optimizes a landing page to pass all three Core Web Vitals thresholds — LCP under 2.5 seconds, INP under 200 milliseconds, and CLS under 0.1. Covers image compression, lazy loading, CDN configuration, font optimization, JavaScript reduction, and mobile-specific techniques. Sites passing all CWV see 24% lower bounce rates and improved rankings. [src1]

Prerequisites

Constraints

Tool Selection Decision

Which optimization path?
├── Image-heavy with LCP > 2.5s
│   └── PATH A: Image Optimization First
├── JavaScript-heavy with INP > 200ms
│   └── PATH B: JavaScript Optimization
├── Layout shifts with CLS > 0.1
│   └── PATH C: Layout Stability
└── All metrics poor
    └── PATH D: Full Optimization (A → C → B)
PathFocusTypical ImprovementTime Required
A: ImagesLCP + page weightLCP -40-60%, weight -50%1-2 hours
B: JavaScriptINP + interactivityINP -30-50%1-2 hours
C: LayoutCLS + stabilityCLS to near 030-60 min
D: FullAll CWV metricsPSI +20-40 points2-4 hours

Execution Flow

Step 1: Run Baseline Audit

Duration: 10 minutes · Tool: PageSpeed Insights + Lighthouse

Run PageSpeed Insights on your URL and record baseline LCP, INP, CLS, total page weight, and number of requests. Use Lighthouse CLI for more detailed lab data.

Verify: Numeric values for all three CWV metrics recorded. · If failed: Use lab data from Lighthouse if field data unavailable.

Step 2: Optimize Images (Highest Impact for LCP)

Duration: 30-60 minutes · Tool: Squoosh, Sharp, or image CDN

Identify LCP element in DevTools Performance tab. Convert images to WebP/AVIF using Sharp or Squoosh. Implement responsive images with <picture> element and format fallback. Use fetchpriority="high" for hero images, loading="lazy" for below-fold images. Serve responsive sizes with srcset. [src3] [src7]

<!-- Hero: eager + high priority -->
<picture>
  <source srcset="/images/hero.avif" type="image/avif">
  <source srcset="/images/hero.webp" type="image/webp">
  <img src="/images/hero.jpg" width="1200" height="630"
       fetchpriority="high" decoding="async">
</picture>

<!-- Below fold: lazy load -->
<img src="/images/feature.webp" width="600" height="400"
     loading="lazy" decoding="async">

Verify: LCP improved by 0.5-2s, page weight decreased 30-60%. · If failed: Check TTFB — server response may be the bottleneck. [src4]

Step 3: Fix Layout Shifts (CLS)

Duration: 20-30 minutes · Tool: Code editor

Add explicit width and height to all images, videos, and iframes. Preload fonts with font-display: swap. Reserve space for dynamic content with min-height. [src5]

Verify: CLS <= 0.1 in Lighthouse. No layout shift entries in Performance tab. · If failed: Check for late-loading third-party scripts injecting content.

Step 4: Configure CDN and Caching

Duration: 15-30 minutes · Tool: CDN provider or hosting platform

Set Cache-Control headers: max-age=31536000, immutable for static assets, max-age=0, must-revalidate for HTML. Add preconnect for third-party origins.

Verify: Response headers show correct Cache-Control. Second load is significantly faster. · If failed: Check for Vary headers preventing caching; purge CDN cache.

Step 5: Optimize JavaScript and CSS

Duration: 20-40 minutes · Tool: Code editor + bundler

Defer non-critical JavaScript. Inline critical CSS, preload full stylesheet. Delay third-party widgets until after page load. Break long tasks with setTimeout(resolve, 0) yields. [src5]

Verify: INP < 200ms. No long tasks in Performance tab. · If failed: Profile specific interactions to find blocking scripts.

Step 6: Run Final Audit and Document Results

Duration: 10 minutes · Tool: PageSpeed Insights

Record after metrics alongside before metrics. Verify all three CWV are in "Good" range. Document all optimizations applied.

Verify: PSI Performance score >= 90 on mobile. All CWV green. · If failed: Focus on the single worst remaining metric.

Output Schema

{
  "output_type": "performance_optimized_page",
  "format": "live URL + audit report",
  "columns": [
    {"name": "url", "type": "string", "description": "Landing page URL", "required": true},
    {"name": "lcp_before", "type": "number", "description": "LCP before (seconds)", "required": true},
    {"name": "lcp_after", "type": "number", "description": "LCP after (seconds)", "required": true},
    {"name": "inp_before", "type": "number", "description": "INP before (ms)", "required": true},
    {"name": "inp_after", "type": "number", "description": "INP after (ms)", "required": true},
    {"name": "cls_before", "type": "number", "description": "CLS before", "required": true},
    {"name": "cls_after", "type": "number", "description": "CLS after", "required": true},
    {"name": "psi_score_before", "type": "number", "description": "PSI mobile before", "required": true},
    {"name": "psi_score_after", "type": "number", "description": "PSI mobile after", "required": true}
  ],
  "expected_row_count": "1",
  "sort_order": "N/A",
  "deduplication_key": "url"
}

Quality Benchmarks

Quality MetricMinimum AcceptableGoodExcellent
LCP<= 2.5s<= 1.5s<= 1.0s
INP<= 200ms<= 100ms<= 50ms
CLS<= 0.1<= 0.05<= 0.01
PSI Mobile Score>= 70>= 90>= 95
Total Page Weight< 1 MB< 500 KB< 200 KB
HTTP Requests< 50< 30< 15

If below minimum: Focus on the single worst metric. LCP: optimize hero image and TTFB. INP: eliminate long JS tasks. CLS: add dimensions to media.

Error Handling

ErrorLikely CauseRecovery Action
LCP worse after optimizationHero image was lazy-loadedRemove loading="lazy" from LCP element; add fetchpriority="high"
CLS increased after font changesfont-display: swap causes FOUTAdd size-adjust to @font-face; preload fonts
WebP/AVIF not servingServer not configured for formatsUse <picture> element with fallback
PSI score varies between runsLab test variance (±5 points)Run 3 times, take median; rely on field data
CDN not cachingWrong Cache-Control headersCheck response headers; purge CDN cache
Third-party script blocking INPChat widget blocking main threadDelay until after load event; use web worker

Cost Breakdown

ComponentFree TierPaid TierAt Scale
PageSpeed Insights$0$0$0
Lighthouse CLI$0$0$0
Image compression$0 (Squoosh/Sharp)$0$0
Image CDN$0 (Cloudinary free)$89/mo$224/mo
CDN (Cloudflare)$0$20/mo Pro$200/mo Business
Total$0$0-20/mo$89-224/mo

Anti-Patterns

Wrong: Lazy-loading above-the-fold images

Adding loading="lazy" to the hero image delays LCP because the browser deprioritizes the image load. [src3]

Correct: Use fetchpriority="high" for the LCP element

Hero images should be eagerly loaded with fetchpriority="high". Only lazy-load below-the-fold images.

Wrong: Serving all images at full resolution

A 3000x2000 image is wasteful on a 375px mobile viewport. [src7]

Correct: Use responsive images with srcset and sizes

Serve different image sizes for different viewports using srcset and sizes attributes.

When This Matters

Use this recipe when the agent needs to improve landing page load speed, Core Web Vitals scores, or PageSpeed Insights scores. Requires a deployed page with code editing access. This recipe diagnoses and fixes performance issues.

Related Units