Most sites I audit pass two of the three Core Web Vitals and fail the third. Usually INP or LCP. The pattern tells you where to focus: stop running broad speed audits and start diagnosing the specific metric that’s failing. This guide walks through how to fix each of the three metrics individually, using tools that give you real user data instead of lab estimates.
I’ve used this process on 40+ sites over the past year, ranging from small WordPress blogs to enterprise commerce stacks. The fixes are similar across technology stacks; the diagnostic paths differ slightly.
Before You Fix Anything, Measure the Right Way
PageSpeed Insights shows two data sources: lab data (simulated) and field data (real users from Chrome UX Report). Lab data is consistent but often misleading. Field data is noisy but shows what users actually experience, and it’s what Google uses for ranking signals.
Always read the CrUX data first. Look for the “Origin Summary” section and confirm the metric that’s failing. A site can show a 95 lab score while failing CrUX field data because the lab test runs on a fast connection and a newer device.
The ranking-relevant threshold is the 75th percentile of real users. Google counts you as passing a metric when 75% of visits have a “good” value. That means outliers on slow networks or older phones matter. Fixing for the 50th percentile user isn’t enough.
Use the Chrome DevTools Performance panel with CPU throttling set to 4x slowdown and network throttling to Fast 3G. This matches roughly the median mobile user in the US. On that profile, you’ll see problems that a clean desktop Chrome hides.
Fix LCP: Speed Up the Largest Content Element
Largest Contentful Paint measures when the main content element becomes visible. Usually it’s the hero image, a headline block, or a featured article image on list pages. A failing LCP means that element takes longer than 2.5 seconds to render for 25% or more of your users.
- Identify the LCP element. In Chrome DevTools Performance panel, run a recording and expand the Timings row. The LCP event shows exactly which element triggered the measurement.
- Preload the LCP resource. If it’s an image, add
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">in the head. If it’s a font-rendered heading, preload the font. - Remove lazy-loading from above-the-fold images. WordPress themes sometimes apply loading=”lazy” to every image including the hero. Remove it from LCP candidates.
- Serve the image in next-gen format. WebP typically cuts image weight 30 to 50% versus JPEG at the same visual quality.
- Reduce server response time. Time to First Byte over 600ms guarantees failing LCP. Check your server response with WebPageTest and fix the backend if TTFB is the issue.
Common miss: render-blocking CSS. If your CSS bundle loads synchronously and is 200KB+, the LCP element waits for CSS before painting. Inline critical CSS for above-the-fold content and defer the rest.
Fix CLS: Stop the Layout Shifts
Cumulative Layout Shift measures how much visible content moves during page load. Anything above 0.1 fails. The fix is almost always about reserving space before content loads.
Images without width and height attributes are the number one cause. When the browser doesn’t know the dimensions, it lays out the page assuming zero height, then pushes everything down when the image loads. Add width and height to every image, even when using CSS for responsive sizing.
Ad units are the second common cause. If your site runs Google AdSense or Ezoic, those ad containers often resize after loading. Reserve minimum heights on every ad slot using aspect-ratio CSS or a min-height declaration.
Web fonts cause subtle shift when the fallback font metrics don’t match the custom font. Use font-display: optional to skip the custom font when it’s not cached, or use size-adjust in your @font-face declaration to match the fallback more closely. A recent client site dropped CLS from 0.24 to 0.04 with only a font-display and size-adjust update.
Dynamically injected content (banners, cookie notices, newsletter popups) is the trickiest. Use CSS transforms instead of changing layout properties when animating these elements into view. Transform changes don’t trigger layout shift.
Fix INP: Reduce JavaScript Main-Thread Work
Interaction to Next Paint replaced First Input Delay in March 2024 and is strictly harder to pass. INP measures the worst interaction on the page, not the first. Scroll, tap, click, keypress — any one of them going over 200ms counts against you.
The root cause for failing INP is almost always JavaScript blocking the main thread. Heavy third-party scripts, oversized frameworks, and unchunked bundles all contribute. Diagnose in DevTools Performance panel by looking for long tasks (red triangles) during interaction.
- Move third-party scripts off the main thread with Partytown or similar web-worker approaches
- Break up long JavaScript tasks using setTimeout or requestIdleCallback to yield to the browser
- Lazy-load non-critical widgets like chat bubbles, social feeds, and video embeds until user interaction
- Remove unused JavaScript using the Coverage tab in DevTools to find dead code
- Defer analytics and tag manager scripts to load after the user’s first interaction
On one WooCommerce client, we reduced INP from 520ms to 180ms by moving Google Tag Manager and Hotjar into Partytown. That single change, with no plugin removals, moved the site from failing to passing on CrUX data within 30 days of deploy.
Monitor Core Web Vitals Without Drowning in Data
Don’t rely on PageSpeed Insights alone for monitoring. The CrUX data there updates on a 28-day rolling window, so fixes take nearly a month to show full effect. You need faster feedback.
Set up a Real User Monitoring tool that captures Core Web Vitals per page. Google Analytics 4 includes basic RUM if you enable the web-vitals JS library and pipe events in. Alternatives include Vercel Analytics, SpeedCurve, and Cloudflare Web Analytics. All four capture LCP, CLS, and INP per page view.
Review the data weekly, not daily. Weekly rollups smooth out network noise and catch regressions without creating alert fatigue. Track the 75th percentile, not the average, so you see what your slow users experience.
When you deploy a speed fix, mark the deploy date in your RUM tool and check the metric 14 days later. That window gives enough data to confirm real improvement instead of random variance.

