Technical SEO MasteryCore Web Vitals, mobile-first indexing and security · Lesson 13 of 18
Core Web Vitals: diagnosis and fixes
Video lecture
Core Web Vitals: diagnosis and fixes
The narrated lecture is in production
Every chapter is scripted and ready. Browse the chapters and read the full transcript now — the video will appear here when it’s published.
Chapters
Transcript of the narration, chapter by chapter.
0:00 Core Web Vitals: diagnosis and fixes
Core Web Vitals are where SEO, engineering and conversion rate meet. They measure what real users experience: how fast the main content appears, how quickly the page responds when you tap, and whether things jump around. In this lecture you'll learn the three metrics and their thresholds, why field data beats lab data, the proven fixes for LCP, INP and CLS, a prioritisation workflow, and how to pull real-user data with the CrUX API.
0:32 Metrics and thresholds (p75)
The three metrics. Largest Contentful Paint measures loading: when the main content appears. Good is two point five seconds or less; poor is over four seconds. Interaction to Next Paint measures responsiveness across all interactions: good is two hundred milliseconds or less; poor is over five hundred. Cumulative Layout Shift measures visual stability: good is zero point one or less; poor is over zero point two five. Google evaluates them at the seventy-fifth percentile of page loads, split by mobile and desktop. INP replaced First Input Delay in March twenty twenty-four, and those thresholds haven't changed.
1:14 Keep perspective
Keep perspective. Google says Core Web Vitals are used by its ranking systems, but good scores don't guarantee top rankings, and relevance and helpfulness still dominate. So treat Core Web Vitals as a user experience and conversion investment with a modest search component, especially where competing pages are otherwise similar. And be wary of blog posts claiming new thresholds; check web dot dev for the current definitions.
1:43 Field vs lab
Field versus lab. Field data comes from real users: the Chrome UX Report, shown in PageSpeed Insights and Search Console's Core Web Vitals report, and your own real-user monitoring with the web-vitals JavaScript library. That's what counts. Lab data is simulated: Lighthouse, the lab section of PageSpeed Insights, Chrome DevTools. Use it to debug, not to judge success. Lab tools can't measure INP directly, because it needs real interactions. Total Blocking Time is only a rough proxy.
2:16 Fixing LCP
Fixing LCP. Break it into four parts and fix the biggest one. Time to first byte: slow servers and uncached HTML, fixed with full-page caching, edge caching and backend work. Resource load delay: the browser discovers the LCP image late, for example as a CSS background or a JavaScript-inserted image. Resource load duration: the image is too heavy. And element render delay: render-blocking CSS or JavaScript, or client-side rendering. Make the hero image discoverable with a preload and fetchpriority high, set its dimensions, and never lazy-load it.
2:54 Fixing INP (overview)
Fixing INP, briefly, because the next lesson goes deep. Poor INP almost always means long tasks on the main thread. Reduce and split JavaScript, and remove unused third-party scripts like heavy chat widgets or overloaded tag managers. Break up long tasks and yield to the main thread, using scheduler dot yield where available with a fallback. Give immediate visual feedback before heavy work. Avoid huge DOMs and forced synchronous layouts. And move heavy computation to web workers.
3:27 Fixing CLS
Fixing CLS. Always set width and height, or a CSS aspect ratio, on images, videos and iframes. Reserve space for ads, embeds and cookie banners. Don't insert content above existing content unless the user asked for it. Reduce font-swap shifts with font-display optional or size-adjusted fallback fonts. Animate with transforms, not properties that trigger layout. And check back-forward cache eligibility, because pages restored from the bfcache avoid many shifts entirely.
3:57 Prioritisation workflow
Prioritisation workflow. Open Search Console's Core Web Vitals report and list the poor and needs-improvement URL groups on mobile. Map groups to templates and weigh them by traffic and revenue. For each template, pull field data and run a lab trace to find the dominant sub-part. Write tickets with the specific fix and the expected metric movement. And after release, wait for field data to update, because CrUX uses a rolling twenty-eight-day window, and use Validate fix in Search Console to track.
4:33 Hands-on: CrUX API
Hands-on. The lesson text has a short Python function for the CrUX API. You post a URL or origin, a form factor like phone, and the three metrics, and you get back the seventy-fifth percentile for each. LCP and INP come back in milliseconds, CLS as a score. A four-oh-four means there isn't enough field data for that URL, so fall back to the origin, the Search Console group, or your own real-user monitoring. For trend charts, the CrUX History API returns weekly data.
5:10 Example 1: Abu Dhabi restaurant
Worked example one, simple. An Abu Dhabi restaurant site has poor LCP on mobile. The trace shows the hero photo is a four-megabyte JPEG, lazy-loaded by the theme. The fixes: serve a compressed AVIF or WebP at sensible sizes with srcset, remove lazy-loading from the hero, and add fetchpriority high. Field LCP moves into good once the twenty-eight-day window rolls over.
5:37 Watch me do it: poor mobile LCP
Watch me do it. I'll diagnose poor mobile LCP on a category template. Step one: I open Search Console's Core Web Vitals report, mobile, and see a poor URL group of category pages. Step two: I run the CrUX script for three category URLs and the origin. The URLs have p75 LCP around four seconds; INP and CLS are fine. Step three: in PageSpeed Insights for one URL, I check that field data agrees, then look at the lab diagnostics to identify the LCP element. It's the hero banner image. Step four: in Chrome DevTools, I run a performance trace with network throttling and CPU slowdown. The LCP breakdown shows resource load delay is the biggest part. The hero image is only requested after a JavaScript carousel initialises. Step five: I check the image itself: a large JPEG, lazy-loaded by the theme. Step six: I write the ticket. Output the first slide as a normal image in the HTML, with width and height, fetchpriority high and no lazy-loading; serve AVIF or WebP with srcset; initialise the carousel afterwards. Expected effect: LCP moves towards good in the lab, and field data confirms it after the twenty-eight-day window. I annotate the release date.
7:04 Example 2: Lahore news site (illustrative)
Worked example two, with illustrative details. A Lahore news site fails CLS on mobile article pages. A DevTools trace with layout shift regions shows two culprits: ad slots that collapse and expand as ads load, and a web font swap that reflows headlines. Fixes: fixed-height ad containers with a sensible fallback when no ad fills, font-display optional with a size-adjusted fallback font, and moving the cookie banner to a bottom overlay. Field CLS moves into good after the window rolls over, confirmed via the CrUX API and Validate fix.
7:43 Recap and try this now
Recap. Know the thresholds: two point five seconds, two hundred milliseconds, zero point one, at the seventy-fifth percentile. Trust field data, debug with lab tools, fix the dominant sub-part per template, and wait for the twenty-eight-day window. Common mistakes: chasing a Lighthouse score of one hundred while field data is fine, lazy-loading the hero, and ignoring third-party scripts. Try this now. Run the CrUX script for your top five templates on phone, and write one ticket for the worst metric on the highest-revenue template.
The three metrics
Core Web Vitals measure real-user experience. Google evaluates them at the 75th percentile of page loads, split by mobile and desktop.
| Metric | Measures | Good | Needs improvement | Poor |
|---|---|---|---|---|
| LCP Largest Contentful Paint | Loading: when the main content appears | ≤ 2.5 s | ≤ 4.0 s | > 4.0 s |
| INP Interaction to Next Paint | Responsiveness across all interactions | ≤ 200 ms | ≤ 500 ms | > 500 ms |
| CLS Cumulative Layout Shift | Visual stability | ≤ 0.1 | ≤ 0.25 | > 0.25 |
INP replaced First Input Delay (FID) as a Core Web Vital in March 2024. The thresholds above are unchanged as of September 2026 — beware blog posts claiming otherwise, and check web.dev's Core Web Vitals pages for the current definitions. Lesson 6.2 goes deep on INP.
Keep perspective: Google says Core Web Vitals are used by its ranking systems, but good scores do not guarantee top rankings, and relevance and helpfulness still dominate. Treat CWV as a user-experience and conversion investment with a modest search component, especially where competing pages are otherwise similar.
Field data versus lab data
- Field data (real users): Chrome UX Report (CrUX), shown in PageSpeed Insights and the Search Console Core Web Vitals report, and your own RUM using the
web-vitalsJavaScript library. This is what counts. - Lab data (simulated): Lighthouse, PageSpeed Insights lab section, Chrome DevTools. Use it to debug, not to judge success. Lab tools cannot measure INP directly (Total Blocking Time is a rough proxy).
The Search Console report groups similar URLs, so fixes are usually template-level.
Fixing LCP
Break LCP into four parts and fix the largest one:
- Time to First Byte — slow servers, uncached HTML, far-away origins. Fixes: full-page caching, CDN edge caching, database and backend optimisation.
- Resource load delay — the browser discovers the LCP image late (for example a CSS background, or JS-inserted image).
- Resource load duration — the image is too heavy.
- Element render delay — render-blocking CSS/JS or client-side rendering delays paint.
<!-- Make the hero image discoverable and prioritised -->
<link rel="preload" as="image" href="/img/hero-1200.avif" fetchpriority="high">
<img src="/img/hero-1200.avif" width="1200" height="600" alt="Team reviewing an SEO audit"
fetchpriority="high" decoding="async">
<!-- Never lazy-load the LCP image -->Other LCP levers: modern formats (AVIF/WebP) with responsive srcset, inlining critical CSS, deferring non-critical JS, self-hosting key fonts, and avoiding client-side rendering for above-the-fold content.
Fixing INP
INP measures the delay from a user interaction (click, tap, key press) to the next frame painted. Poor INP almost always means long tasks on the main thread.
- Reduce and split JavaScript; remove unused third-party scripts (chat widgets, tag managers loaded with dozens of tags, heavy A/B testing tools).
- Break up long tasks and yield to the main thread:
async function processItems(items) {
for (const item of items) {
doWork(item);
// Yield so the browser can respond to input
if (globalThis.scheduler?.yield) await scheduler.yield();
else await new Promise(r => setTimeout(r, 0));
}
}- Give immediate visual feedback, then do heavy work afterwards.
- Avoid large DOM sizes and forced synchronous layouts (reading layout properties right after writing styles).
- Debounce input handlers; move heavy computation to Web Workers.
Use Chrome DevTools' Performance panel and RUM attribution (the web-vitals library's attribution build reports which element and script caused slow interactions).
Fixing CLS
- Always set
widthandheight(or CSSaspect-ratio) on images, videos and iframes. - Reserve space for ads, embeds and cookie banners; do not push content down after load.
- Avoid inserting content above existing content, except in response to user interaction.
- Font swaps: use
font-display: optionalor matched fallbacks (size-adjust) to reduce shift. - Animate with
transform, not properties that trigger layout (top,height). - Check back/forward cache eligibility; pages restored from bfcache avoid many shifts.
Prioritisation workflow
- Open the Search Console Core Web Vitals report; list poor and needs-improvement URL groups on mobile.
- Map groups to templates and weigh by traffic and revenue.
- For each template, pull PageSpeed Insights field data and run a lab trace to find the dominant sub-part.
- Write tickets with the specific fix and expected metric movement.
- After release, wait for field data to update (CrUX uses a rolling 28-day window) before declaring success. Use the "Validate fix" button in Search Console to track.
Hands-on: pull field data with the CrUX API (Python)
The Chrome UX Report (CrUX) API returns 75th-percentile field data for an origin or URL (where there's enough traffic). Create an API key in Google Cloud, keep it in an environment variable, and:
import os, requests
KEY = os.environ["CRUX_API_KEY"]
ENDPOINT = f"https://chromeuxreport.googleapis.com/v1/records:queryRecord?key={KEY}"
METRICS = ["largest_contentful_paint", "interaction_to_next_paint", "cumulative_layout_shift"]
def p75(target, form_factor="PHONE", kind="url"):
body = {kind: target, "formFactor": form_factor, "metrics": METRICS}
r = requests.post(ENDPOINT, json=body, timeout=20)
if r.status_code == 404:
return None # not enough field data for this URL/origin
r.raise_for_status()
m = r.json()["record"]["metrics"]
return {k: m[k]["percentiles"]["p75"] for k in METRICS if k in m}
for url in ["https://www.example.com/", "https://www.example.com/collections/cushions/"]:
print(url, p75(url) or p75("https://www.example.com", kind="origin"))LCP and INP come back in milliseconds and CLS as a unitless score (sometimes as a string — cast before comparing). A 404 means CrUX has insufficient data for that URL; fall back to the origin, the Search Console group, or your own RUM. The CrUX History API (records:queryHistoryRecord) returns weekly trend data for charts.
Worked example 2: a Lahore news site's CLS
A Lahore news site (illustrative) fails CLS on mobile article templates. A DevTools performance trace with Layout Shift regions shows two culprits: ad slots that collapse and expand as ads load, and a web font swap that reflows headlines. Fixes: reserve fixed-height ad containers (with a sensible fallback when no ad fills), font-display: optional plus a size-adjusted fallback font, and moving the cookie banner to a bottom overlay that doesn't push content. Field CLS moves into "good" after the 28-day window rolls over, confirmed via the CrUX API and Search Console's "Validate fix".
Common mistakes
- Chasing a Lighthouse score of 100 while field data is fine (or vice versa).
- Lazy-loading everything including the hero image.
- Ignoring third-party scripts because "marketing needs them" — audit their value.
Key takeaways
- Good thresholds at the 75th percentile: LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1; INP replaced FID in March 2024.
- Judge success with field data (CrUX, Search Console, RUM); use lab tools to debug.
- LCP: fix TTFB, discovery, weight and render delay; INP: break long tasks; CLS: reserve space.
- CWV are a ranking input but not a shortcut to top positions; prioritise by template and business value.
Check your understanding
Quick questions to lock in the lesson. They don’t count towards your certificate.
Put it into practice
Run PageSpeed Insights on your three highest-traffic templates, record field LCP/INP/CLS, and identify the dominant cause for the worst metric on each.
Enrol for free to save your progress
Reading is always free. Enrol to keep your place, take the final assessment and earn a verifiable certificate.