Core Web Vitals for agencies: LCP, INP, CLS without the marketing rebrand

CWV affects Google rankings, but most of what gets sold to clients as 'page speed optimization' addresses metrics that don't matter. Here's what each CWV actually measures and what to fix.

Core Web Vitals is the Google-mandated set of three numbers that affect search rankings since 2021. Every agency has been pitched "Core Web Vitals optimization" by a consultant. Most of that optimization fixes the wrong things.

This post is the operator's reference: what each metric actually measures, what causes regressions in agency-managed sites, what to monitor.

The three metrics that matter

Google's current Core Web Vitals (as of March 2024 — INP replaced FID):

| Metric | Measures | Good threshold | |---|---|---| | LCP — Largest Contentful Paint | When the biggest visible element finished loading | < 2.5 seconds | | INP — Interaction to Next Paint | How fast the page responds to user interactions | < 200 ms | | CLS — Cumulative Layout Shift | How much the page jumps around as it loads | < 0.1 |

Pass all three (above the 75th-percentile field-data threshold) and you have "good" Core Web Vitals. Fail any one and Google flags you in Search Console.

What "field data" vs "lab data" means

Two ways to measure CWV:

  • Lab data — run a synthetic test in a controlled environment (e.g. Lighthouse, PageSpeed Insights lab mode). One reading, no real users involved.
  • Field data — collected from real Chrome users via the Chrome User Experience Report (CrUX). Aggregated 28-day window. This is what Google uses for ranking.

Lab data is what you optimize against during development. Field data is what Google judges you on. They can disagree significantly — a site might score 95 in Lighthouse lab and still fail CWV in the field because real users have slower connections and devices than your dev environment.

When clients (or their SEO consultants) panic about a Lighthouse score in the 60s, ask first: what does the field data say? Search Console → Core Web Vitals → URL groups. If field data is good but lab is bad, the field data is what counts.

LCP — the biggest element

LCP is the time from page load start to when the largest visible content element (image, video poster, big block of text) finishes rendering above the fold.

What slow LCP looks like

In 90% of agency client sites with bad LCP, the culprit is a hero image:

  • High-resolution image (4K+) served as JPG at full resolution to all devices, including mobile
  • No loading="eager" or fetchpriority="high" hint
  • Loaded from a CDN with a cold cache at the user's region
  • Hosted at the client's WordPress, served with no Cloudflare/CDN at all

What fixes it (in order of leverage)

  1. Resize the hero image properly. A 1920px-wide image is fine for desktop. Mobile should get 800px. Use <picture> with <source srcset> and sizes attribute. Or in WordPress, ensure the theme is using wp_get_attachment_image_srcset properly.
  2. Use modern formats. AVIF or WebP cut file size 30-50% over JPEG. Most CDNs (Cloudflare, BunnyCDN, ImgIX, Cloudinary) can auto-serve AVIF based on Accept headers.
  3. Add fetchpriority="high" to the hero <img> tag. Tells the browser this is the load-priority element. Single attribute, huge wins on many sites.
  4. Preload critical fonts. Custom fonts can delay LCP if they affect the largest text element. <link rel="preload" as="font" type="font/woff2" crossorigin> for the critical fonts.
  5. Move the CDN closer. If your client's traffic is 80% North American but their CDN is European, regional CDN like Cloudflare Pro tier or fastly closes 200-500ms of latency.

Skip "lazy loading the hero image" — that's a common bad recommendation. The hero is above the fold, lazy-loading hurts LCP.

What you can actually monitor

  • Google PageSpeed Insights API → returns LCP from field data and lab
  • Real User Monitoring via web-vitals.js → JavaScript that captures actual user LCP in browser, ships to your analytics

For agency operators monitoring 50+ client sites, PSI API is the practical tool: poll daily per domain, alert when LCP crosses 2.5s, log trend for monthly reports.

INP — interaction responsiveness

INP measures the latency between a user interaction (click, tap, key press) and the next visual update. Replaces FID (which was misleading — only measured first interaction).

What slow INP looks like

The user clicks a button or navigates a menu, and the page freezes for 300+ ms before reacting. Typical causes:

  • Heavy JavaScript on main thread. Page loaded a 500KB analytics bundle (or worse, 5x bundles from different vendors) that's chewing CPU on every interaction.
  • Long DOM trees. A WordPress page with 5000+ DOM nodes recalculates layout slowly on every state change.
  • Synchronous handlers. A click handler that does heavy computation before yielding to the browser.

What fixes it

  1. Audit third-party scripts. Most agency sites have 5-15 third-party scripts (analytics, chat, A/B testing, etc.). Each one runs on the main thread. Use Chrome DevTools → Performance tab → record a typical interaction → see which scripts are blocking.
  2. Defer non-critical JS. <script defer> on anything that's not load-blocking. async for tracking pixels.
  3. Reduce DOM size. Most WordPress themes accumulate divs unnecessarily. Page builder pages often have 8x more DOM nodes than necessary.
  4. Use requestIdleCallback for non-urgent work. Analytics that aren't time-critical should run when the main thread is idle.

INP is the metric most agency sites fail post-2024 — the FID-to-INP switch caught many sites that "passed CWV" before.

Monitoring

PSI API returns INP field data. Same flow as LCP: daily poll, alert on regression. The harder part is diagnosing regressions — you need DevTools or RUM data to see which interaction is slow.

CLS — layout shift

CLS measures how much the page jumps around as content loads. A page that loads a hero image without dimensions specified, then adds a banner that pushes everything down — high CLS. Bad CLS makes users misclick and feel like the page is broken.

What causes CLS

  • Images without width/height attributes. Browser doesn't know how tall the image will be until it loads. Reserves zero space. Image arrives → content below jumps down.
  • Web fonts loading after FOIT/FOUT. Initial render uses fallback font (different metrics), real font arrives, text reflows.
  • Ads or embeds without reserved space. YouTube embed without a fixed-height container.
  • JavaScript injecting content above existing content. Cookie banner, sticky header, "subscribe" popup that takes space.
  • Late-loading skeleton-to-content transitions. React hydration that re-renders a component to different dimensions.

What fixes it

  1. Add width and height to every <img> and <video>. Browser uses the aspect ratio to reserve space before image loads.
  2. font-display: optional or swap with proper size-adjust matched to your fallback. Or load critical fonts via <link rel="preload">.
  3. Reserve space for embeds. <iframe> with explicit width/height attributes.
  4. Insert dynamic content below existing content, not above. Cookie banners at the bottom, not at the top, unless they're modal.
  5. Avoid pop-ups that appear after page load. The newsletter signup that slides in at 3 seconds — that's CLS unless it's truly modal-overlay (which has its own UX problems).

CLS is the most fixable metric — usually a structural code change, not a performance optimization. Most sites can get CLS under 0.1 with one PR.

What CWV monitoring should look like for an agency

For each client domain monitor:

  1. PSI poll daily — mobile and desktop separately. Returns LCP / INP / CLS lab + field values.
  2. Trend over 28 days — Google's window. Show the rolling values, not single readings.
  3. Alert on regression — when any metric crosses the "good" threshold, or when it drops a grade compared to previous week.
  4. Per-page tracking — not just the homepage. The blog has different metrics than the pricing page. Hit all the top URLs your client cares about.

Manual: agency operator logs into PSI dashboard weekly, screenshots into report. Reasonable for small portfolios.

Automated: integrated monitoring tool polls PSI API daily, stores history, computes trend. Pleenx ships this as the CWV probe. Other tools: SpeedCurve, Calibre, DebugBear — all heavier and more expensive but more detailed.

The cheapest credible setup: Google PageSpeed Insights API (free, 25k requests/day with API key) hit by your monitoring tool of choice daily per domain. Average $5/mo cost across a 100-domain portfolio.

What to tell clients

The pitch:

Google measures three things about your site: how fast the biggest image loads (LCP), how fast it responds to clicks (INP), how much the page jumps around as it loads (CLS). If any of those exceed Google's thresholds, your search rankings get penalized. We monitor all three daily and tell you if any regress.

Concrete, no marketing jargon, ties to a business outcome (rankings = traffic = leads).

The deliverable in your monthly report: current LCP/INP/CLS per important page, 30-day trend, any regressions caught and resolved.

What not to optimize

Things that show up in Lighthouse audits but don't affect CWV or rankings:

  • TBT (Total Blocking Time) — was a metric, replaced by INP for ranking. Still useful for diagnosing but not a target.
  • TTFB (Time to First Byte) — useful, but a fast TTFB with slow LCP is still bad CWV. Optimize TTFB only if you've already fixed image-level issues.
  • "Speed Index" — synthetic metric, not used by Google. Ignore.
  • The Lighthouse "Performance" score itself — composite of various metrics. Useful as a single number but optimize the underlying metrics, not the composite.

When a consultant pitches your client "we'll get your Lighthouse score from 65 to 95," ask: "which of LCP, INP, CLS will improve, and by how much?" If they can't answer specifically, they're selling cosmetic changes.

TL;DR

  • Three metrics matter: LCP (loading speed), INP (responsiveness), CLS (visual stability)
  • Field data (from real users) is what Google ranks on, not lab data
  • LCP fixes: resize the hero image, use AVIF/WebP, fetchpriority="high", preload critical fonts
  • INP fixes: defer JS, reduce DOM, audit third-party scripts
  • CLS fixes: add width/height to images, reserve space for embeds, font-display tuning
  • Monitor via PSI API daily. Alert on threshold crossing. Track 28-day trend.
  • The Lighthouse "Performance" score is a composite — optimize the underlying metrics

Run a Core Web Vitals probe on any domain →

NS
written byNikolay SpangeletsCTO · founder

Building Pleenx from the engineering side. 10+ years shipping production web platforms; broke enough things in production to know which monitoring is actually useful.

/related reads