Core Web Vitals in Practice: How to Diagnose and Prioritize LCP, INP, and CLS Fixes
1. What each metric measures: know the difference before you touch anything
Many teams jump straight into Lighthouse, see a wall of red flags, and start fixing things at random. Figure out what each metric measures first, then you can target the real problem.
| Metrics | What it measures | Pass line | Common culprits |
|---|---|---|---|
| LCP (Largest Contentful Paint) | Time for the largest element above the fold to finish loading | ≤ 2.5s | Oversized hero images, blocking fonts, slow server response |
| INP: interaction to next paint | Delay before the interface responds after a user clicks | ≤ 200ms | Long tasks on the main thread, oversized JS, third-party scripts |
| CLS: cumulative layout shift | How much elements jump around while the page loads | ≤ 0.1 | Images without width and height, ad slots without placeholders, font swaps |
You have to judge by the 75th percentile: of 100 visitors, the fastest 75 must pass. Averages and medians mean nothing. You’ll find CrUX data in the Search Console experience report, and it’s the same data Google uses for ranking signals.
Also note that the three metrics pull against each other: compressing images lowers LCP, but a bad lazy-load strategy can push the LCP element to the second frame; preloading fonts lowers LCP, but preloading too many fonts eats into network requests and hurts INP. After any change, wait 14 days to see real user data. Don’t make changes back to back.
2. Fixing LCP: start with the biggest payoff
LCP usually accounts for more than 50% of the gains from optimizing the three metrics. It breaks into four phases, so first find out which one you’re stuck on.
| LCP phase | Diagnostic tool | Common bottleneck | Fix |
|---|---|---|---|
| TTFB: server response | WebPageTest waterfall | Slow PHP rendering, no CDN | CDN edge caching, PHP upgrade |
| Resource loading | Chrome DevTools performance | Hero image not compressed, not preloaded | WebP/AVIF, preload the key image |
| Resource rendering | Lighthouse opportunities | Fonts block rendering | font-display: swap + preload |
| Client-side rendering | Trace performance panel | SPA renders only after JS finishes downloading | SSR or skeleton screen |
Example: A B2B industrial site’s hero product image was 1.8MB uncompressed. TTFB was fine, but LCP was stuck at 4.2 seconds. Converting the image to WebP and compressing it to 320KB, plus adding fetchpriority=”high”, brought LCP down to 1.9 seconds within a week. The only change was one img tag, with no server configuration touched.
CDN node selection and caching strategy directly affect TTFB, see Global CDN acceleration. Image localization for multilingual sites also needs to be considered together with Charts and tables on multilingual sites.
3. Fixing INP: the most time-consuming but unavoidable
INP is the new metric that replaced FID in March 2024, measuring the full delay from user interaction to the interface actually responding. It’s harder to fix than LCP because the problems are scattered across the entire JS bundle.
| Issue | How to diagnose | Fix | Expected gain |
|---|---|---|---|
| Main thread long tasks > 50ms | Performance panel long task markers | Code splitting, Web Worker | INP drops 100 to 200 milliseconds |
| Third-party scripts blocking | Coverage panel to see the percentage | Lazy loading, async/defer | INP drops 50 to 150 milliseconds |
| Event callbacks too heavy | Call stack to see time-consuming functions | Debounce and throttle, split callbacks | INP drops 30 to 80 milliseconds |
| Render-blocking resources | Lighthouse unused CSS/JS | Inline critical CSS, defer non-critical | INP drops 50 to 100 milliseconds |
Counterintuitive point: poor INP isn’t necessarily a problem with your own code. B2B sites often have LinkedIn pixels, HubSpot form plugins, and live chat scripts embedded, and together these three can block the main thread for over 300 milliseconds. Sorting third-party scripts by loading priority first pays off faster than changing business code.
4. Fixing CLS: the low-hanging fruit that stabilizes once fixed
CLS is the easiest of the three metrics to fix: 90% of CLS problems come from two causes—images without width and height, and ads or embedded content without reserved space.
| CLS culprits | How to judge | Fix |
|---|---|---|
| Images without width/height | DevTools to see layout shift | Add width/height + aspect-ratio to img tags |
| Font swap jitter | FOIT/FOUT behavior | font-display: swap + size-adjust |
| Ads/embeds without reserved space | Ads push content after loading | Reserve a fixed-height container |
| Dynamically injected banners | Top notification bar pops up | Reserve space so it doesn’t squeeze content |
Example 2: An overseas SaaS site’s blog had a CLS of 0.35 for a long time, because a “Subscribe to Newsletter” banner at the top of the article was inserted after JS loaded, pushing the entire article down 120 pixels. Changing the banner to server-side rendering and reserving 120px of space brought CLS down to 0.04 within a week.
5. Diagnostic tools and verification process
| Stage | Tools | Data source | Verification window |
|---|---|---|---|
| Locate the problem | CrUX report / GSC experience report | 28 days of real user data | Check once a week |
| Reproduce in the lab | Lighthouse / WebPageTest | Simulate Moto G4 on slow 4G | Run once before fixing |
| Live monitoring | CrUX / RUM tools | 75th percentile metric trends | 14 days after launch |
| Acceptance | GSC Core Web Vitals report | All three metric types “passed” | 28 days after launch |
A common mistake is looking only at your local Lighthouse score. Lighthouse runs in a clean environment: no real user networks, no third-party scripts, no logged-in state. Plenty of sites score 95 locally yet fail CrUX. After you fix things, wait for the 28-day rolling data to update. Don’t call it a win on day three.
Performance optimization and the Core Web Vitals framework are ongoing work, not a one-time project.Website Maintenance Schedule should include a monthly CWV report as a standing item.
6. How to write performance budgets into your release process
Fixing one round of CWV issues doesn’t mean you’re done for good. New features, new plugins, and new marketing scripts will drag your metrics back down. The right approach is to build performance budgets into your release process and check them before every deploy.
| Page type | LCP budget | INP budget | CLS budget | Total JS budget |
|---|---|---|---|---|
| Homepage and landing pages | ≤ 2.0s | ≤ 150ms | ≤ 0.05 | ≤ 250KB gzip |
| Product detail page | ≤ 2.5s | ≤ 200ms | ≤ 0.1 | ≤ 350KB gzip |
| Blog post page | ≤ 2.5s | ≤ 200ms | ≤ 0.1 | ≤ 300KB gzip |
| Contact and form pages | ≤ 2.0s | ≤ 150ms | ≤ 0.05 | ≤ 200KB gzip |
Before each release, run Lighthouse CI on these core page types in staging. If they exceed budget, block the merge. When marketing wants to add a popup, support chat script, or tracking pixel on short notice, it goes through a review checklist: can this script be lazy-loaded, can it load below the fold, can it run only on specific pages? Every three months, pull a CrUX report and watch the 75th percentile trend. If a page type declines two months in a row, open a project to fix it.
One more thing people overlook: image asset governance. If a new blog post uploads an uncompressed original image, LCP takes an immediate hit. Wire an image compression pipeline into your CMS by default: convert to WebP on upload, compress to a sensible size, and generate srcset. That’s far less work than fixing posts one by one later. This pipeline aligns with your media asset governance process, see Media Asset Governance.
Third-party scripts are the number one driver of INP decline. Pixels, chat widgets, and form embeds that marketing adds for a new campaign often aren’t lazy-loaded, so they all pile into first render. Every quarter, pull the full list of third-party scripts across your site and go through it: which are still in use, which can be deferred until after first render, which nobody looks at anymore and can just be deleted. Make this review a fixed part of your release process. It’s far less painful than optimizing after the fact every time.
One last point on how to measure success: after fixing things, don’t just look at your local Lighthouse score. Wait for the 28-day rolling CrUX data from real users to update. Local scores are only good for finding problems, not for declaring victory. Send the monthly CWV report to your engineering and marketing leads. Make performance a metric the whole team watches, not just the SEO person’s KPI.
FAQ
LCP, INP, or CLS: which should you fix first?
Why does Search Console still flag my site when Lighthouse gives it 95?
How long does it take to bring INP down from 500 ms to under 200?
What’s a normal CLS score?
Do Core Web Vitals directly affect rankings?
Should mobile and desktop CWV be looked at separately?
Final thoughts
Core Web Vitals is the clearest return on investment in technical SEO: every metric has a defined threshold, defined diagnostic tools, and defined fixes. Don’t be fooled by your Lighthouse score. Look at real user data from CrUX.
Three steps to get it done: this week, use the GSC experience report to find your worst metric; next week, fix the first one in LCP → CLS → INP order; 28 days after launch, check whether CrUX shows all three passing. If all three metrics are within the thresholds, you’re already ahead of 70% of B2B sites going global.
One line worth remembering: CWV isn’t a scoring game, it’s about how long real users wait. LCP is what the eye sees, INP is what the hand feels, CLS is what the eye endures. You pass only when all three feel right.
