Core Web Vitals Optimization: A Complete Guide for 2025
Learn how to achieve green Core Web Vitals scores for LCP, INP, and CLS. Practical techniques with real examples from our Next.js projects.
Why Core Web Vitals Matter in 2025
Google uses Core Web Vitals as a direct ranking signal. A page that achieves "Good" scores across all three metrics gets a ranking boost over competing pages with identical content quality. For competitive keywords, this technical edge can be the difference between page 1 and page 2.
Beyond rankings, Core Web Vitals measure what users actually experience. A 4-second LCP means users are staring at a spinner. A high CLS means buttons jumping around as the user tries to click them. These aren't abstract metrics — they describe real frustration.
In 2025, the three Core Web Vitals are:
Diagnosing Your Current Scores
Before optimizing, measure. Use these tools:
Field data (real user measurements) matters more than lab data for rankings. A page might score 95 in Lighthouse but have poor CWV in the field due to real-world network conditions and device diversity.
Optimizing LCP
The Largest Contentful Paint is almost always the hero image or the H1 heading. Identify it first using PageSpeed Insights — it highlights the LCP element.
The critical mistake: Animating your hero with opacity 0 to opacity 1. We see this constantly. An invisible element is not discovered by the browser's LCP algorithm until it becomes visible. If your animation takes 600ms to run, your LCP is delayed by 600ms minimum — even though the image was loaded.
Fix: Start hero content at full opacity. Use transform: translateY() for the animation effect instead, which doesn't hide the element from LCP calculation.
Preload your LCP image: Add the priority prop to the Next.js Image component for above-fold images. This generates a link rel=preload in the HTML head, telling the browser to fetch the image immediately.
Use modern image formats: WebP is 25-35% smaller than JPEG at equivalent quality. AVIF is 50% smaller. Next.js serves these automatically when supported. Ensure your source images are reasonably sized — a 4MB PNG source forces more processing time even if the output is WebP.
Eliminate render-blocking resources: CSS and synchronous JavaScript in the document head block rendering. Audit your third-party scripts — Google Tag Manager, chat widgets, analytics — and ensure they're loaded with async or defer. Consider loading them only after the user interacts.
Optimizing INP
INP replaced FID (First Input Delay) in March 2024. It measures responsiveness to all interactions throughout the page lifetime, not just the first one.
The main culprit: Long tasks on the main thread. Any JavaScript that runs for more than 50ms blocks user input response. Find them in Chrome DevTools → Performance → Long Tasks.
Code splitting: Don't ship JavaScript that isn't needed for the current page. In Next.js, dynamic imports split components into separate chunks loaded only when needed.
Debounce and defer: Event handlers that trigger expensive computations should debounce. For visual updates that don't need to happen synchronously, wrap in requestAnimationFrame.
React 18's startTransition: Marks state updates as non-urgent. React will interrupt them if the user interacts, keeping INP green even during heavy re-renders.
Virtualize long lists: Rendering 1,000 DOM nodes kills INP. Libraries like react-window or @tanstack/virtual render only visible rows, keeping the DOM lean.
Optimizing CLS
Layout shift happens when elements move unexpectedly. The most common causes:
Images without dimensions: A browser that doesn't know an image's dimensions can't reserve space for it. When the image loads, everything below it shifts down. Always specify width and height on images, or use aspect-ratio CSS.
Web fonts: Fonts loading after initial render cause FOUT (Flash of Unstyled Text) or FOFS (Flash of Faux Text), both causing CLS. Use font-display: swap combined with link rel=preload for critical fonts. In Next.js, use next/font which handles this automatically with zero CLS.
Dynamic content injection: Ads, cookie banners, and lazy-loaded components that appear above existing content cause shift. Reserve space with fixed-height containers or inject below the fold.
Animations that affect layout: Changes to width, height, top, or left trigger layout recalculation. Use transform: translate() and opacity instead — these are compositor-only and don't cause CLS.
A Realistic Optimization Sprint
Here's how we approach CWV optimization for a new client site:
A well-optimized Next.js site typically achieves 90+ across all CWV metrics. Want us to audit yours? Contact us.
The Beyond Horizon Team
We are a digital agency based in Ajmer, India, specializing in Next.js web applications, React Native mobile apps, and UI/UX design. 150+ projects delivered.
About Us →Have a project in mind?
We build fast, SEO-ready web and mobile applications.
Get a Free Consultation→