I Spent Six Months Chasing Core Web Vitals. Here’s What Actually Moved the Needle. — CoPilot Blog
    Neura MarketNeura Market/CoPilot
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityCoPilotCoPilot
    DeepSeekDeepSeekStable DiffusionStable DiffusionMidjourneyMidjourney
    View All Directories
    OverviewRulesPromptsMCPsAgentsBlogVideosGuidesCoursesCommunityPluginsTrendingGenerate
    CoPilotBlogI Spent Six Months Chasing Core Web Vitals. Here’s What Actually Moved the Needle.
    Back to Blog
    I Spent Six Months Chasing Core Web Vitals. Here’s What Actually Moved the Needle.
    webdev

    I Spent Six Months Chasing Core Web Vitals. Here’s What Actually Moved the Needle.

    Shudhanshu Raj April 23, 2026
    0 views

    A field guide to LCP, INP, and CLS that skips the theory and gets to what breaks in...

    *A field guide to LCP, INP, and CLS that skips the theory and gets to what breaks in production.* --- Our dashboard said green. Our users said otherwise. For the better part of a year, we shipped features, ran Lighthouse locally, watched scores float between 92 and 98, and patted ourselves on the back. Then one Monday morning, support pinged us: a product manager testing on her own phone swore the listing page felt "stuck" for a second every time she tapped a filter. She wasn't wrong. She just wasn't in our lab. That was the moment I learned the most important thing about Core Web Vitals: **the number in your terminal is not the number Google cares about.** Google cares about what happens to real users, on real devices, on real networks — the 75th percentile of them — and it measures that over a rolling 28 days through the Chrome User Experience Report (CrUX). Your Lighthouse run is a simulation. CrUX is the scoreboard. That distinction — lab versus field — reshaped how our team approached performance. What follows is the short version of six months of work, minus the dead ends, focused on the three metrics that matter in 2026: **LCP, INP, and CLS.** --- ## The metric most teams are losing on Let me start with the one that hurts: INP. Interaction to Next Paint replaced First Input Delay in March 2024, and unlike FID — which only measured the delay *before* the browser started processing your click — INP measures the full round trip. Click to visual update. Every interaction on the page, not just the first one. The reported score is essentially your worst case. Roughly 43% of sites currently fail the 200 ms "good" threshold, and on most of the apps I've touched, it's the metric that takes the deepest rework to fix. LCP is a logistics problem (ship bytes faster). CLS is a discipline problem (reserve space). INP is an architecture problem. Here's where it bit us hardest: filters on a product listing page. Each tap triggered a `setState` that ran through a context provider, re-rendered about 40 components, recomputed a sort, and then — only then — painted the new chip as "selected." On a mid-range Android over 4G, that round trip hit 480 ms. The user felt it. Chrome reported it. No amount of bundle trimming was going to fix a long task. What actually fixed it: **1. Break the task, then yield.** The single highest-impact change was introducing yield points using `scheduler.yield()` (with a fallback to a `setTimeout(0)` shim for browsers without it). We split the interaction into "visual feedback first, everything else second." ```javascript async function handleFilterTap(filter) { // Paint the selected state immediately setSelectedFilter(filter); await yieldToMain(); // Then do the expensive work const filtered = applyFilters(products, filter); await yieldToMain(); setResults(filtered); } function yieldToMain() { if ('scheduler' in window && 'yield' in window.scheduler) { return window.scheduler.yield(); } return new Promise(resolve => setTimeout(resolve, 0)); } ``` The perceived responsiveness change was dramatic. The filter chip highlighted instantly. The list updated a tick later. INP at p75 dropped from 480 ms to 170 ms on the same page, with no change to the actual filtering logic. **2. Defer non-critical renders with `useDeferredValue`.** In React, marking the filtered results as a deferred value let the input stay responsive while the heavy list re-rendered in the background. Free win, about a week to roll out safely across the product. **3. Kill the long tasks you don't know you're running.** This one is humbling. Open the Performance panel in Chrome DevTools, record an interaction, and look for any task over 50 ms. In our case, a third-party analytics script was running a synchronous JSON serialization on every click. We had no idea. We moved the script to a web worker. INP dropped another 40 ms on pages where that analytics event fired. The pattern that emerged: **INP rewards event handlers that do almost nothing synchronously.** Anything expensive — filtering, sorting, logging, heavy computations — gets yielded, deferred, or offloaded. If you take one thing from this post, take that. --- ## LCP: it's almost always the hero image Every team I've worked with has the same story with LCP. Someone optimized "the images." LCP was still 3.2 seconds. Because "the images" is not the fix — *the LCP element* is the fix, and the LCP element is almost always one specific image above the fold. Before you touch anything, identify what the LCP element actually is. You can read it straight from the `web-vitals` library in production: ```javascript import { onLCP } from 'web-vitals'; onLCP(metric => { console.log('LCP element:', metric.entries.at(-1)?.element); console.log('LCP value:', metric.value); }); ``` Ninety percent of the time, it's a hero image. Once you know that, the playbook is short and boring, which is the highest compliment I can give a performance playbook: - **Preload it.** `<link rel="preload" as="image" href="..." fetchpriority="high">` in the document head. This one line moved our LCP from 2.8 s to 2.1 s on the homepage. Don't preload everything — just the LCP resource. Preload abuse is its own problem. - **Set `fetchpriority="high"`** on the image tag itself. Browsers are conservative about image priority by default; you're telling it this one matters. - **Use modern formats.** AVIF first, WebP fallback, JPEG as a last resort. The file size difference between JPEG and AVIF at equivalent quality is routinely 40 to 60 percent. - **Serve the right size.** A responsive `srcset` is not optional. Shipping a 2000-pixel-wide image to a phone that displays it at 400 is the most common unforced error in frontend performance. - **Do not lazy-load the LCP image.** I've seen this mistake on production sites shipping in 2026. `loading="lazy"` on the hero image is a guaranteed LCP regression. The harder part of LCP is when the element isn't an image — when it's a block of text that depends on a custom font, for example. In that case, `font-display: swap` and preloading the font file are your friends. Accept the brief flash of fallback type. Your users won't notice. Your 75th-percentile LCP will. --- ## CLS: the metric that makes you look unprofessional CLS is the cheapest to fix and the one that makes your site feel the most amateur when you don't. When buttons jump out from under thumbs and ads push content down after the user has started reading, people lose trust in the interface, even if they can't articulate why. Three rules. That's all. I have not found a CLS problem in the last three years that wasn't covered by these: 1. **Every image, video, and iframe gets explicit width and height attributes.** Even if you're styling them with CSS, the HTML attributes let the browser reserve space before the asset loads. Aspect-ratio boxes work too, but the width/height attributes are simpler and work everywhere. 2. **Reserve space for anything injected late.** Ad slots, cookie banners, personalization widgets — any element that arrives after first paint needs a height reserved upfront. A `min-height` on the container is usually enough. If the slot stays empty, leave it empty. The shift is worse than the blank space. 3. **Use `font-display: swap` with care.** Swap prevents invisible text, but it can cause a layout shift if your fallback font has significantly different metrics. The `size-adjust` descriptor on `@font-face` lets you match fallback metrics to your web font and eliminates that shift entirely. This is underused. Most teams haven't heard of it. That's it. CLS under 0.05 is achievable on nearly any site if you follow those three rules. Ours runs at 0.02. --- ## The monitoring setup that actually helped You cannot fix what you cannot see, and DevTools on your machine is not "seeing." We installed the `web-vitals` npm package, shipped real-user metrics to our analytics pipeline, and — this was the unlock — **sliced the data by route, device class, and country.** A single aggregate INP number hides everything. The same site can have great INP for desktop users in Germany and awful INP for mobile users in Brazil, and the aggregate will look mid. Slicing is how you find the real fire. We also set alerts at 80% of Google's thresholds — INP at 160 ms, LCP at 2.0 s, CLS at 0.08 — so we'd see regressions before they started eating our CrUX window. A deploy that bumps INP from 150 to 190 still reports "good," but three of those deploys in a month and you're in trouble. --- ## What I'd tell past-me on day one Three things. First, **stop optimizing for Lighthouse.** Use it as a diagnostic tool, not a scoreboard. The scoreboard lives at CrUX, and the gap between the two can be an order of magnitude. We spent weeks chasing a 98 when we needed to spend a day fixing a filter handler. Second, **fix the metric that's actually failing, not the one you have opinions about.** I like LCP. I find it tractable and satisfying. For three weeks I optimized LCP while INP silently tanked. Look at your CrUX dashboard, find the worst of the three, and start there. Then the next worst. No hero shots. Third, **performance is a product feature, not a cleanup task.** Every team I've seen succeed at Core Web Vitals treated them like any other product metric: someone owned them, they were reviewed weekly, regressions were treated as bugs, and they were part of the definition of done for new features. Every team I've seen fail at Core Web Vitals treated them as something to "get to after the next launch." You know which team gets to the next launch faster. --- *If this was useful, a clap helps other engineers find it. I write about frontend architecture, performance, and the unglamorous parts of shipping software.*

    Tags

    webdevperformancejavascriptreact

    Comments

    More Blog

    View all
    Minimalist EKS: The Easy Waykubernetes

    Minimalist EKS: The Easy Way

    Amazon EKS manages the Kubernetes control plane, but you remain responsible for provisioning the...

    J
    Joaquin Menchaca
    Never forget to enter the Stern Grove lottery again!ai

    Never forget to enter the Stern Grove lottery again!

    Browser automation with Playwright, Python, GitHub Actions, and Entire to auto-enter San Francisco Stern Grove concert lotteries each week!

    L
    Lizzie Siegle
    A Free Screenshot Editor That Never Uploads Your Imagetypescript

    A Free Screenshot Editor That Never Uploads Your Image

    A free screenshot and image editor that runs entirely in your browser. Keeping every edit reversible and handling big phone photos, in plain TypeScript and Canvas2D.

    M
    Martin Stark
    I built a CLI to break my highlights out of Apple Booksshowdev

    I built a CLI to break my highlights out of Apple Books

    A macOS CLI + MCP server that exports Apple Books highlights to Markdown and gives AI assistants direct access to your reading notes.

    A
    Andrey Korchak
    A Developer's Guide to Agent Hooks in Antigravity CLIai

    A Developer's Guide to Agent Hooks in Antigravity CLI

    Motivation To be quite honest, "Hooks"—the shell commands we trigger at specific points...

    T
    Tanaike
    Tactical vs. Strategic Agentic AI Development — A Playbook for Developersagents

    Tactical vs. Strategic Agentic AI Development — A Playbook for Developers

    The Strategic Engineer: Why Writing Code Is No Longer Your Most Valuable Skill ...

    A
    Adewumi Saheed Adewale

    Stay up to date

    Get the latest CoPilot prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for CoPilot and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.