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]
fetchpriority="high" for above-the-fold content. [src3]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)
| Path | Focus | Typical Improvement | Time Required |
|---|---|---|---|
| A: Images | LCP + page weight | LCP -40-60%, weight -50% | 1-2 hours |
| B: JavaScript | INP + interactivity | INP -30-50% | 1-2 hours |
| C: Layout | CLS + stability | CLS to near 0 | 30-60 min |
| D: Full | All CWV metrics | PSI +20-40 points | 2-4 hours |
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.
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]
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.
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.
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.
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_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 Metric | Minimum Acceptable | Good | Excellent |
|---|---|---|---|
| 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 | Likely Cause | Recovery Action |
|---|---|---|
| LCP worse after optimization | Hero image was lazy-loaded | Remove loading="lazy" from LCP element; add fetchpriority="high" |
| CLS increased after font changes | font-display: swap causes FOUT | Add size-adjust to @font-face; preload fonts |
| WebP/AVIF not serving | Server not configured for formats | Use <picture> element with fallback |
| PSI score varies between runs | Lab test variance (±5 points) | Run 3 times, take median; rely on field data |
| CDN not caching | Wrong Cache-Control headers | Check response headers; purge CDN cache |
| Third-party script blocking INP | Chat widget blocking main thread | Delay until after load event; use web worker |
| Component | Free Tier | Paid Tier | At 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 |
Adding loading="lazy" to the hero image delays LCP because the browser deprioritizes the image load. [src3]
Hero images should be eagerly loaded with fetchpriority="high". Only lazy-load below-the-fold images.
A 3000x2000 image is wasteful on a 375px mobile viewport. [src7]
Serve different image sizes for different viewports using srcset and sizes attributes.
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.