Home/ Blog /SEO

Core Web Vitals Guide: How to Improve LCP, CLS and INP

Turan Doğan
Turan Doğan
SEO & GEO Specialist
SEO April 25, 2026 19 min read
Core Web Vitals Guide: How to Improve LCP, CLS and INP
SUMMARY
Core Web Vitals consist of three metrics: LCP measures how long it takes for the main content to appear, CLS measures unexpected layout shifts, and INP measures the delay in the visual response to a tap or click. Google's good thresholds are 2.5 seconds, 0.1 and 200 milliseconds respectively, and they are assessed not in a single test but at the 75th percentile of real visits. The right order is to use field data to find which metric misses its threshold, reproduce the cause in a lab tool, and fix the cause rather than the score.

Three different things can frustrate you when you open a page. The first is waiting: the screen stays blank or half-finished, and the image or heading you came for arrives late. The second is jumping: you start reading, something loads above at that exact moment and the line you were on slides down; in the worst case, the button moves just as your finger reaches it. The third is silence: you tap, the page looks ready, and nothing happens.

Core Web Vitals are three metrics that map directly onto these three annoyances. Seeing content late is LCP (Largest Contentful Paint), jumping is CLS (Cumulative Layout Shift), and an unresponsive tap is INP (Interaction to Next Paint). The values Google considers "good" are 2.5 seconds or less, 0.1 or less, and 200 milliseconds or less, respectively. Because the three describe different failures of the same page, one can improve while another gets worse. That is why you need to read the three metrics separately instead of chasing a single speed score.

The Three Metrics Side by Side

Metric What it measures Good Poor Typical culprit
LCP The moment the largest content element in the viewport is painted 2.5 seconds or less Over 4 seconds Slow server response, a late-discovered hero image, resources that block rendering
CLS The score of the largest burst of unexpected layout shifts 0.1 or less Over 0.25 Images without dimensions, ads and embeds without reserved space, font swaps
INP The delay of the visual response to clicks, taps and key presses 200 ms or less Over 500 ms Long JavaScript tasks that block the main thread, heavy event handlers

The range between the two thresholds is the "needs improvement" band. For LCP that is 2.5 to 4 seconds, for CLS 0.1 to 0.25, and for INP 200 to 500 milliseconds: neither a pass nor a fail. The page works, but users feel the difference.

Why the Threshold Is Based on 75% of Visits, Not a Single Test

For a metric to count as good, it is not enough for one visit to that page to meet the threshold; 75% of visits have to meet it. Measurement is also done separately for mobile and desktop. This detail is little known, but it settles half the arguments: a page that loads in 1.2 seconds on your own computer looking poor in field data is not a contradiction. What you measured is a single visit, while the threshold reflects the experience of three quarters of visits.

The 75th percentile sits between two competing goals. On one hand, the chosen percentile should guarantee that most visits experience the target performance, which argues for a high percentile. On the other hand, the chosen value should not be overly influenced by outliers, which argues against a high percentile. If a page with a hundred visits used the 95th percentile, five visits on a stalled network could decide its classification on their own. At the 75th percentile, you know three quarters of visits reached the target or better, and isolated glitches are unlikely to take over the result.

LCP: When Main Content Counts as On Screen

LCP marks the moment the largest content element in the viewport is painted. The set of candidate elements is deliberately narrow to reduce complexity: <img> elements, <image> elements inside <svg>, <video> elements (the load time of the poster image or the presentation time of the first frame, whichever comes first), elements with a background image loaded via url(), and block-level elements containing text nodes. A CSS gradient does not count as a background image.

Size calculation is subtler than it looks and is the most common reason teams chase the wrong element. Only the part of the element that stays inside the viewport counts; any overflowing or clipped portion is excluded. For an image displayed smaller than its intrinsic size, whichever is smaller, the displayed size or the intrinsic size, is used. For text elements, the smallest rectangle enclosing all text nodes is measured. Margin, padding and border set in CSS are never added to the size of any element.

The candidate element is not fixed either. While the page loads, the largest element may first be a heading, and once the hero image arrives the candidate switches to it. The browser keeps updating this until the user's first interaction; the last candidate at that point is reported as the final LCP element. So optimization cannot begin until you identify which element is actually the LCP element.

The Four Parts of LCP and a Healthy Breakdown

LCP is not a single event but the sum of four consecutive durations: the server sending the first byte (TTFB), the delay until the LCP resource is discovered, the resource download time, and the delay between download and paint. It is no accident that two of the parts have "delay" in their name; both are dead time that should approach zero. The other two are network work and naturally take time.

Part Share on a well-optimized page
TTFB (time to first byte)about 40%
Resource load delayunder 10%
Resource load durationabout 40%
Element render delayunder 10%

These ratios are a diagnostic tool, not a target. Google explicitly warns against converting them into milliseconds and treating them as fixed goals; if LCP is already under 2.5 seconds, the ratios of the parts do not matter. The useful takeaway is this: most of the time should be spent downloading the HTML document and the LCP resource. Any interval in which neither of these two requests is downloading is time you can win back.

The Order of Work for Lowering LCP

The first question should not be "how many kilobytes is the image" but "when does the browser learn about this resource". The browser's preload scanner picks up resources to download ahead of time while reading the HTML response. If the LCP resource is visible in this scan, the download starts early; if not, it has to wait for a script or stylesheet to arrive and run first.

The cases the preload scanner catches are clear: the LCP element is an <img> whose src or srcset is present in the initial HTML, or the resource is declared with <link rel="preload">. The cases it misses are just as clear: the image is added later with JavaScript, a lazy-loading library has hidden the real URL in an attribute such as data-src, or the element uses a CSS background image. These three patterns are the real reason behind the complaint "I shrank the image but LCP didn't drop". If a text-based LCP element depends on a web font, the same logic applies to the font file.

<link rel="preload" as="image" href="https://seobaz.com/hero.avif" fetchpriority="high">

Once the discovery problem is solved, it is time for download duration, and the gains here come from bytes. Serving whichever modern-format version of the same image the browser supports shrinks the file noticeably without reducing visible quality; the details are in our article on using WebP and AVIF formats. For the fourth part, render delay, the culprit is usually not the content but resources that hold up painting: render-blocking stylesheets and synchronous scripts. Separating out the styles needed to paint the first screen and delivering them early cuts this delay directly; for the method, see our article on inlining critical CSS.

TTFB is a matter of scale. As long as the server response is slow, every other improvement sits on top of that delay. Caching at the application layer, static generation where possible and serving content from a point close to the user are the main interventions that shorten this first part.

CLS: The Page Shifting Under Your Feet

CLS measures the largest burst of unexpected layout shifts over the life of the page. It is not the total amount of shifting, and this distinction changes the result completely. Shifts are grouped into what are called session windows: shifts with less than 1 second between them fall into the same window, and a window lasts at most 5 seconds. The page's CLS value is the score of the highest-scoring window.

The practical consequence: browsing a long page for minutes does not keep inflating the score, but a single large burst of shifts at one point determines the page's grade on its own. In other words, CLS is not the sum of dozens of small flaws but a snapshot of the worst moment.

How the Layout Shift Score Is Calculated

layout shift score = impact fraction × distance fraction

The impact fraction is the share of the viewport affected by unstable elements between two frames. The distance fraction is the greatest distance any unstable element moved horizontally or vertically, divided by the viewport's larger dimension. For a block that affects three quarters of the viewport and moves by a quarter of the screen height, the calculation gives 0.75 × 0.25 = 0.1875. A single shift is already almost twice the good threshold. This arithmetic explains why CLS usually comes down to a few large errors.

The distance fraction was added to the formula later. Originally the score was calculated from the impact fraction alone, which penalized large elements that moved only slightly more than they deserved.

Where Expected Shifts End and Unexpected Shifts Begin

Shifts triggered by the user's own actions are not penalized. When someone clicks an accordion, pushing the content below it down is expected behavior. This distinction runs on a 500-millisecond window: shifts that occur within 500 ms after user input are flagged with hadRecentInput and can be excluded from the calculation.

The window has two hard edges, and both are often missed. First, the flag is only true for discrete inputs (taps, clicks, key presses); scrolling, dragging and pinch-zoom do not count as recent input. So if late-loading content pushes the blocks below it while the user scrolls down, that goes straight into CLS. Second, a change that arrives after 500 ms is considered unexpected: if a heavy request returns after a click and updates the DOM two seconds later, that shift is added to the score. Transitions in single-page applications fall right into this trap. The fix is not to try to speed up the request but to reserve the space at the moment of the click and put a loading indicator there.

The Real Sources of Layout Shift

  • Images and videos without dimensions. The browser cannot reserve space for an element whose size it does not know, so when the file arrives the element expands to its real size and everything below it shifts. Giving every image width and height, or reserving the space with CSS, eliminates this shift entirely.
  • Ads and embeds without reserved space. Ad networks and social media embeds fetch content asynchronously. If the space is not reserved in advance, the incoming box pushes the whole page. This problem even left its mark on the history of the CLS threshold: although field data showed about half of origins met 0.05, the more lenient 0.1 threshold was judged more balanced because of third-party embeds whose height cannot be known before they load.
  • Web fonts. Shifts happen both when a fallback font is shown first and then swapped for the web font (FOUT) and when text is kept invisible until the web font arrives (FOIT); even when text is not visible, layout is done with the fallback font. font-display: optional prevents relayout. The fallback font also needs to be chosen carefully: writing font-family: "Brand Sans", sans-serif is very different from writing only font-family: "Brand Sans", because in the second case the browser's default font kicks in and usually produces a much worse match. To close the font metrics gap, use size-adjust, ascent-override, descent-override and line-gap-override declarations.
  • Blocks injected after render. If a cookie notice, announcement bar, personalized banner or A/B test variant is added at the top after the page has been painted, it pushes content down. These components should either sit in a layer that does not disturb the layout or have their space reserved from the start.
<img src="/urun.avif" alt="Product image" width="1200" height="675">

.embed-slot {
  width: 100%;
  aspect-ratio: 16 / 9;
}

INP: The Screen Responding After You Tap

INP tracks the latency of the clicks, taps and key presses a user makes during a visit and generally reports the slowest interaction. Knowing what is not measured is as useful as knowing what is: hovering, scrolling and zooming are outside INP's scope. If scrolling stutters, the problem is real, but INP will not show it.

The slowest-interaction rule has one exception. So that a random hiccup on a highly interactive page does not decide the whole page's grade, the highest value is ignored for every 50 interactions. Since the vast majority of visits have fewer than 50 interactions, in practice the worst interaction is reported. Then, as usual, the 75th percentile of page views is taken, so outliers are filtered out in two stages.

What the Difference Between INP and FID Changes

FID (First Input Delay) measured only the waiting time of the first interaction, and only the delay portion of that interaction. In other words, it was a loading metric showing how long you waited the first time you tapped while the page was opening. INP, by contrast, tracks every interaction on the page as a whole, from input delay through running the event handlers to painting the next frame.

The practical consequence is sharp: improving load performance could rescue FID, but it does not rescue INP. The filter menu a user opens in the third minute, the search box that stutters while typing and the add-to-cart button that freezes are now all part of the measurement. INP work is not page-load optimization; it is runtime JavaScript optimization.

The Three Phases of INP and the Fix for Each

An interaction breaks down into three parts. An intervention made without knowing which one is long usually lands in the wrong place.

  1. Input delay: the time from when the user starts the interaction until the event callbacks begin to run. If it is long, the main thread is busy and the culprit is long tasks over 50 milliseconds. The fix is to break up work and yield to the main thread often.
  2. Processing duration: how long the event callbacks take to run from start to finish. If it is long, the handler is doing too much. Reducing the work inside the callback, deferring heavy computation or splitting it into chunks pays off directly here.
  3. Presentation delay: the time from when the callbacks finish until the browser paints the next frame containing the result. If it is long, the cost is on the rendering side: large DOM trees, cascading style recalculations and DOM access that interleaves reads and writes.

Even breaking up long work arbitrarily is better than not breaking it up at all. The more precise method, however, is to yield right after the callback that updates the UI; that way the rendering work runs early instead of waiting at the end of the queue, and the user sees the response.

Hydration: Where Two Metrics Meet on Framework Sites

When server-rendered HTML reaches the browser, the page becomes visible but is not yet live. Until the JavaScript bundle downloads and runs and the framework attaches event listeners to elements, the page can be seen but not clicked. A user presses a button during this interval and nothing happens. In metric terms, this experience is INP's input delay phase, because hydration can run as a single task that keeps the main thread busy for a long time on large component trees.

On the LCP side, the situation is conditional, and this is usually where the confusion comes from. If the LCP element is in the server-delivered HTML, the browser paints it without waiting for JavaScript, so hydration does not delay LCP directly. There are two cases where the delay does show up in LCP: when the LCP element is not on screen until client-side JavaScript creates it or makes it visible (measured as element render delay), and when a hydration mismatch occurs and the framework treats the server markup as unreliable and rebuilds that tree on the client from scratch.

The sources of mismatch come down to a few recurring patterns: dates that the server and client format according to different time zones, random values that change on every run, and conditional rendering based on browser APIs that have no counterpart on the server. The common fix is to keep these values out of the initial render entirely and insert them on the client after load. On the architecture side, the direction is clear: make hydration splittable, isolate interactive areas as independent islands, and never ship components that can stay on the server to the client. All three share the same goal: reducing the amount of JavaScript that has to be downloaded and run on the client.

Field Data vs. Lab Data: What Each Tool Tells You

The Core Web Vitals assessment is based on field data. Field data is anonymous measurement collected from real Chrome users' visits, and it accumulates in the Chrome User Experience Report (CrUX) dataset. Search Console's Core Web Vitals report is fed directly from this dataset, while PageSpeed Insights shows both field and lab data for the same page side by side.

Lab data is a single controlled load: a specific device profile, a specific network scenario, usually an empty cache. When the two disagree, it is not a malfunction but a consequence of the definitions. The main reasons they diverge:

  • Cache state. Lab tests usually load with a cold cache, while some real visitors find resources already cached. Sites with many returning visitors can look faster in the field than in the lab.
  • Measurement window. Lab tools mostly measure the initial load, while field data tracks CLS over the page's entire lifetime. Shifts that occur after load only appear in field data.
  • Visibility gap. Shifts inside an iframe cannot be measured with web APIs, but users see them and CrUX includes them. Your own real user monitoring may therefore differ from CrUX.
  • Device and connection mix. Field data carries the real device mix of your audience, while a lab test represents a single profile.

There is also a rule for why a page might not appear in field data at all. To be included in CrUX, a page must be publicly discoverable, which is the same criterion search engines use for indexability. Pages that return a status code other than 200 after redirects, or that are served with an X-Robots-Tag: noindex header or a noindex meta tag, do not meet this condition. For a disciplined approach to reading the reports, our guide to tracking Search Console data makes the work easier.

Where Core Web Vitals Sit in Rankings

Google explicitly recommends achieving good Core Web Vitals for success in Search and says this, together with other page experience aspects, aligns with what its core ranking systems seek to reward. The same documentation also settles one point: there is no single page experience signal; the core ranking systems look at a variety of signals that align with page experience.

Read together, these two statements rule out both exaggeration and dismissal. Getting LCP under 2.5 seconds will not push a page up for a query it is not relevant to; performance does not replace content. On the other hand, a page that makes users wait, shifts under them and ignores their taps loses on every page experience aspect, and that loss is measurable. In practice, Core Web Vitals are a foundation more than a lever: once they are solid, the obstacle in front of your content and authority work is removed, but on their own they build nothing.

A Priority Flow From Diagnosis to Fix

  1. Start with field data. Read which metric misses the threshold at the 75th percentile from the Search Console report or the field data section of PageSpeed Insights. At this stage the lab score does not decide anything; it only gives hints.
  2. Separate mobile and desktop. Thresholds are assessed separately for each, and the failure often appears in only one. The same JavaScript costs far more on low-end phones.
  3. Find the template, not the single URL. Pages generated from the same template carry the same error. An image without dimensions in the product detail template produces the same shift on thousands of URLs, so the fix also rescues thousands of URLs at once.
  4. Reproduce the cause in the lab. For LCP, identify which element was chosen and how the four parts break down; for CLS, which element shifted; for INP, which interaction and which phase is long. Teams that skip this step usually apply the wrong fix to the right metric.
  5. Choose the fix by cause. Different causes of the same metric call for different interventions: load delay is solved with early declaration, download duration with format and size, render delay by separating critical styles, and server latency with caching and static generation.
  6. Account for measurement lag. Field data is an accumulation of past visits, so it takes weeks for the report to fully refresh after a fix goes live. Validation tracking in Search Console also runs a 28-day monitoring window and expects the issue not to appear on any URL during that window.

Making this flow repeatable across the whole site rather than a single page requires a technical inventory of your page templates; an on-page SEO analysis builds that inventory and the order of interventions together.

Frequently Asked Questions

If my Lighthouse performance score is 100, are my Core Web Vitals good too?

Not necessarily. Lighthouse runs a lab measurement and loads the page once in its default audit. INP cannot be measured without simulating realistic interactions, and the part of CLS that occurs after load does not show up in this audit either. A high score shows that the page behaves well under lab conditions; classification is still based on field data from real visits.

Why don't I see Core Web Vitals data in Search Console?

There are two typical reasons. Either the page does not meet CrUX's eligibility criteria (a status code other than 200 after redirects, or a noindex header or meta tag), or the page has not received enough real visits to produce a meaningful classification. In the second case, origin-level data for the whole site and your own real user monitoring fill the gap.

Are mobile and desktop assessed separately?

Yes. Thresholds are read separately for mobile and desktop at the 75th percentile, and the Search Console report shows the two device types on separate screens. A page that looks good on desktop and poor on mobile is a common picture, because the same JavaScript and the same image weight exact a much higher price on weak hardware and an unstable connection.

Was this article helpful?
Add Seobaz as a preferred source on Google to see us more often in your search results and AI answers.
Add as preferred source
Share this article
Turan Doğan
Founder · SEO & GEO Specialist
Publishing up-to-date guides on SEO, GEO and AEO since 2014, helping brands get seen on both Google and AI engines.
WhatsApp Online · Quick reply
Gift Wheel A discount on every spin
View Cart