What Core Web Vitals Actually Measure
Core Web Vitals are three metrics that Google uses to quantify user experience. They became a ranking factor in 2021 and have only grown in importance since.
Largest Contentful Paint (LCP): How long until the largest visible element (hero image, heading, video thumbnail) renders. Target: under 2.5 seconds. This measures perceived load speed.
Interaction to Next Paint (INP): How long the browser takes to respond to user interactions (clicks, taps, keyboard input). Replaced First Input Delay (FID) in March 2024. Target: under 200ms. This measures responsiveness.
Cumulative Layout Shift (CLS): How much the page layout shifts unexpectedly during loading. Text jumping around, buttons moving, images loading and pushing content down. Target: under 0.1. This measures visual stability.
Google's Chrome User Experience Report (CrUX) collects these metrics from real Chrome users visiting your site. Your scores in Google Search Console reflect real-world performance, not lab tests. This means optimization must work across devices, networks, and geographies, not just on your fast development machine.
Fixing LCP: Make the Big Thing Load Fast
LCP is usually the easiest to fix and the most impactful for SEO. The biggest LCP improvements come from three areas: images, server response time, and render-blocking resources.
Image Optimization
The LCP element is an image in 70% of cases. Optimizing images is the single highest-leverage change you can make.
- Use modern formats: WebP is 25 to 35% smaller than JPEG at equivalent quality. AVIF is 50% smaller. Next.js Image component handles format negotiation automatically. For custom setups, use the picture element with source sets for AVIF, WebP, and JPEG fallback.
- Size images correctly: Serve images at the display size, not larger. A hero image displayed at 1200px wide should not be a 4000px original. Use responsive srcset attributes to serve different sizes at different breakpoints.
- Preload the LCP image: Add a preload link tag in the head for your hero image. This tells the browser to fetch it immediately instead of waiting until it discovers the image in the HTML. Use: link rel="preload" as="image" href="/hero.webp"
- Use a CDN: Serve images from a CDN (Cloudflare, CloudFront, Imgix) with edge caching. This reduces delivery time by serving from a server geographically close to the user.
Server Response Time (TTFB)
If your server takes 800ms to respond, your LCP cannot be under 2.5 seconds on slow connections. Target a TTFB under 200ms for the initial HTML document. Use server-side rendering (SSR) or static site generation (SSG) for content pages. Cache database queries. Use a CDN for static assets. Upgrade your hosting if your server is underpowered.
Render-Blocking Resources
CSS and synchronous JavaScript in the head block rendering. Inline critical CSS (the CSS needed for above-the-fold content) and load the rest asynchronously. Defer non-critical JavaScript. Move analytics and chat widgets below the fold or load them after the main content renders.
Fixing INP: Make Interactions Feel Instant
INP measures the time from when a user interacts with your page to when the browser paints the response. Long tasks on the main thread block interaction responsiveness.
Identify Long Tasks
Open Chrome DevTools, go to the Performance panel, and record a user session. Look for tasks longer than 50ms (marked in red). These are your INP killers. Common culprits: heavy JavaScript parsing, complex DOM manipulation, synchronous layout calculations, and third-party scripts.
Break Up Long Tasks
If a function takes 200ms to execute, the browser cannot respond to user input during that time. Split it into smaller chunks using requestIdleCallback, setTimeout with 0 delay, or the scheduler.yield() API. Each chunk should be under 50ms to keep the main thread responsive.
Reduce JavaScript Bundle Size
Every kilobyte of JavaScript must be parsed and compiled before it can execute. For a Next.js app, use dynamic imports (next/dynamic) for components that are not needed on initial render. For React apps, use React.lazy and Suspense. For third-party scripts, load them asynchronously with defer or async attributes.
Audit your bundle with tools like webpack-bundle-analyzer or source-map-explorer. We regularly find that 30 to 50% of a client's JavaScript bundle is unused on the initial page load. Tree shaking and code splitting address this.
Optimize Event Handlers
If a click handler triggers a database call and waits for the response before updating the UI, the interaction feels slow. Use optimistic UI updates: show the expected result immediately and reconcile with the server response in the background. This makes interactions feel instant even when the server takes 500ms to respond.
Fixing CLS: Stop the Layout Jumping
Layout shifts frustrate users and hurt your CLS score. The most common causes are straightforward to fix.
Set Dimensions on Images and Videos
Always include width and height attributes on img and video elements. This lets the browser reserve the correct space before the asset loads. Without dimensions, the browser does not know how tall the image will be, so it allocates zero space and shifts content down when the image loads.
For responsive images, use CSS aspect-ratio instead of fixed pixel dimensions. This reserves space proportionally across screen sizes.
Preload Web Fonts
Web fonts cause layout shifts when they load and replace the fallback font (FOUT, flash of unstyled text). Use font-display: swap in your @font-face declarations and preload your primary fonts with link rel="preload". Better yet, use font-display: optional for non-critical fonts, which shows the fallback if the font does not load within 100ms.
The most reliable approach: use system fonts (system-ui, -apple-system) for body text and only load custom fonts for headings and brand elements. System fonts are instantly available and eliminate layout shifts entirely.
Avoid Dynamic Content Injection Above the Fold
Banner ads, cookie consent bars, notification prompts, and A/B test variations that inject content at the top of the page cause significant layout shifts. Reserve fixed-height space for these elements in your HTML, even before the JavaScript loads. Use min-height on container elements to prevent collapse.
Skeleton Screens
For content that loads asynchronously (API data, dynamic components), show a skeleton placeholder that matches the expected layout. Skeleton screens prevent layout shifts by maintaining consistent dimensions throughout the loading process. Libraries like react-loading-skeleton make this trivial to implement.
Measuring and Monitoring
You cannot optimize what you do not measure. Set up continuous monitoring to track your Core Web Vitals over time.
Lab Testing Tools
- Lighthouse (built into Chrome DevTools): Run an audit on any page. Provides scores for each Core Web Vital plus detailed recommendations. Good for development-time checks.
- PageSpeed Insights (pagespeed.web.dev): Shows both lab data (Lighthouse) and field data (CrUX) for your URL. The field data reflects real user experience and is what Google uses for rankings.
- WebPageTest (webpagetest.org): Advanced testing with filmstrip view, waterfalls, and network throttling. Test from different locations and connection speeds. Essential for understanding global performance.
Real User Monitoring (RUM)
Lab tests show potential performance. RUM shows actual performance. Integrate the web-vitals JavaScript library into your application to collect Core Web Vitals from real users. Send the data to your analytics platform (Vercel Analytics, Datadog RUM, or a custom endpoint). Track p75 values (Google's threshold) and monitor for regressions.
Setting Up Alerts
Configure alerts for when Core Web Vitals degrade past your thresholds. An LCP regression from 1.8s to 3.5s after a deployment should trigger an immediate alert, not be discovered two weeks later in Google Search Console. Vercel provides this natively if you are hosting there. Otherwise, use Datadog or a custom monitoring solution.
Framework-Specific Optimizations
Modern frameworks have built-in features that help with Core Web Vitals. Use them.
Next.js
The Next.js Image component (next/image) automatically handles lazy loading, responsive sizing, WebP/AVIF format negotiation, and blur placeholders. Use it for every image. The Script component (next/script) controls loading priority for third-party scripts. App Router with React Server Components reduces client-side JavaScript by rendering on the server.
React SPA (Vite/CRA)
React SPAs have inherently worse LCP than SSR frameworks because the browser must download, parse, and execute JavaScript before any content renders. Mitigate this with SSR (use a framework like Next.js or Remix), aggressive code splitting (React.lazy for route-based splitting), and prerendering critical pages at build time with vite-plugin-ssr or react-snap.
WordPress
For WordPress sites, use a caching plugin (WP Rocket at $59/year or W3 Total Cache, free). Enable lazy loading for images below the fold. Use a CDN (Cloudflare free tier works well). Minimize plugins, as each one adds JavaScript and database queries. Consider a headless WordPress setup with Next.js frontend for the best Core Web Vitals.
The Business Case for Performance
Performance optimization is not just a technical exercise. It directly affects revenue.
Google's research shows that when mobile page load goes from 1 second to 3 seconds, bounce rate increases by 32%. From 1 to 5 seconds, it increases by 90%. Every 100ms improvement in LCP correlates with a 1% increase in conversion rate (Deloitte's "Milliseconds Make Millions" report).
For SEO, Core Web Vitals are a confirmed ranking factor. Pages that pass all three Core Web Vitals thresholds rank higher than equivalent pages that do not. The impact is not massive (content relevance still dominates), but in competitive search results, it can be the tiebreaker.
What Optimization Costs
- Quick wins audit (1 to 2 days, $2K to $5K): Image optimization, font loading fixes, render-blocking resource elimination. These fixes alone can move you from "Needs Improvement" to "Good" on most pages.
- Comprehensive optimization (1 to 2 weeks, $8K to $20K): Full audit, JavaScript bundle optimization, lazy loading implementation, CDN configuration, server response time improvements, and monitoring setup.
- Ongoing performance engineering ($2K to $5K/month): Continuous monitoring, regression prevention, optimization of new features, and quarterly performance audits.
We help companies optimize their web performance for both user experience and search rankings. Book a free strategy call to get a performance audit of your application.
Need help building this?
Our team has launched 50+ products for startups and ambitious brands. Let's talk about your project.