~/wiki / ux-i-interfeisy / pagespeed-lighthouse-core-web-vitals-audit

Site audit through PageSpeed, Lighthouse and Core Web Vitals: step-by-step analysis

Main chat

A chat for vibe coders: news, guides, live cases, marketplace, and finding executors.

$ cd section/ $ join vibe dev
Site audit through PageSpeed, Lighthouse and Core Web Vitals: step-by-step analysis - обложка

Three instruments and their roles

Before we run to check something, let’s figure out what kind of tools exist and how they differ.

PageSpeed Insights (PSI)

Link: pagespeed.web. dev

This is an online tool from Google. Analyzes one page and gives a score of 0 to 100 for mobile and desktop separately.

What’s important to understand is that PSI shows two types of data.

Lab data - Lighthouse runs on Google servers under controlled conditions. It's a synthetic test: a fixed iron, a fixed network, one particular moment in time.

Field data (CrUX) - real data from real Chrome users over the past 28 days. Chrome User Experience Report (CrUX) If the site is not visited enough, there may be no field data.

The difference is fundamental: laboratory data is needed to diagnose problems. Field data is needed to understand how the site feels to real users.

Lighthouse

Where to run: Chrome DevTools → Lighthouse tab (F12 → Lighthouse)

The same engine that is used in PSI, but runs in your browser. It analyzes not only performance, but also accessibility, SEO, best practices.

Advantage over PSI: you can test local builds, staging environments, pages for authorization. The PSI cannot reach closed pages.

Core Web Vitals

These are three specific metrics that Google considers key to user experience:

  • **LCP (Largest Contentful Paint) - when the main content is downloaded
  • **INP (Interaction to Next Paint)
  • CLS (Cumulative Layout Shift) - How stable is the layout when loading

These three metrics are found in PSI, Lighthouse, and Google Search Console.


How to Read PageSpeed Insights Report

You open pagespeed.web.dev, insert a URL, click "Analysis". In 20-30 seconds, report. Take it down from top to bottom.

First screen: assessments and field data

At the top are two numbers: the score for mobile and for desktop. Mobile is almost always lower because it is tested on an emulated slow device (Moto G4) with a slow connection (4G).

** Color coding:**

  • 90-100 - good
  • 50–89 ий – requires improvements
  • 0-49 - bad

Below is field data, if any. These are real users. This is the same color coding for each of the three Core Web Vitals metrics.

**Important: ** The estimate is an aggregate number. Two pages can have a score of 65 for very different reasons. Don’t look at metrics, look at specific metrics.

Productivity metrics

Under the field data is the Performance Diagnostics section with six metrics:

**FCP (First Contentful Paint) ** When the first piece of content (text or image) appears Normal: < 1.8 seconds.

*LCP (Largest Contentful Paint) When the largest item on a page (usually a hero image or title) loads. Normal: < 2.5 seconds. This is one of Core Web Vitals.

TBT (Total Blocking Time) is the total lock time of the main JavaScript stream. Laboratory proxy for the INP. Normal: < 200 ms.

CLS (Cumulative Layout Shift) – How much do elements “jump” when booting. Norm: < 0.1. This is Core Web Vitals.

*Speed Index – How fast is the screen filling up? Normal: < 3.4 seconds.

INP (Interaction to Next Paint) - the time from the user's action to the next rendered frame. This is the key metric for interactivity in 2024+. Norm: <200 ms. Core Web Vitals.

Section "Opportunities" (Opportunities)

These are specific actions that will improve LCP and other metrics – with an estimate of potential savings in seconds.

Prioritize your potential winnings here. “Delete unused JavaScript” with a saving of 2.3 seconds is more important than “Use the WebP format” with a saving of 0.1 seconds.

Section "Diagnostics" (Diagnostics)

More detailed recommendations do not directly affect the assessment, but affect the quality.


Core Web Vitals: A breakdown of each metric

LCP (Largest Contentful Paint)

**The moment the largest visible element of the page loaded. Usually this:

  • Hero-image
  • Large block of text (header on the text page)
  • Video poster

Norms:

  • < 2.5 seconds - good
  • 2.5-4 seconds – requires improvement
  • 4 seconds - bad

How to find out what the LCP element is:**

In Chrome DevTools → Performance → Run a record → Reboot the page → in the Timings section, find the LCP marker → click → see which element.

Or the Lighthouse report -- the details of LCP say what it is.

**Why LCP is Slow - Typical Causes

  1. Slow server (TTFB) - the browser waits a long time for the first byte from the server. Everything else is pointlessly optimized if TTFB > 600 ms. Solution: CDN, server caching, hosting upgrade.

  2. LCP image is not preloaded - the browser only detects the image when CSS parsite or renders HTML. If this is a hero picture, it should be loaded from the beginning. Solution: <link rel="preload" as="image" href="hero.webp"> in <head>.

  3. ** Image not optimized** PNG 2MB instead of WebP 200KB Solution: conversion to WebP/AVIF, correct dimensions (do not load a 3000px image width if 800px is displayed).

  4. Render-blocking resources - CSS and JS in <head> without defer/async block rendering. Solution: critical CSS - inline in <head>, non-critical - with media="print" and JS-switching, JavaScript - with defer or async.

  5. Slow fonts - the browser waits for the font to load before showing the text. Solution: font-display: swap + preload critical fonts.


INP (Interaction to Next Paint)

What it is: time from any user interaction (click, tap, keystroke) to the moment when the browser drew the next frame in response. Replaced FID (First Input Delay) as a metric for interactivity in 2024.

Norms:

  • < 200 ms - good
  • 200–500 ms – needs improvement
  • 500 ms - bad

Why the INP is slow:

INP suffers when the main thread is occupied. Reasons:

  • Heavy JavaScript problems blocking the flow
  • Many event handlers
  • Complicated Style Recalculations (layout thrashing)
  • Synchronous operations in the Click Processor

How to diagnose:

Chrome DevTools → Performance → record 5-10 seconds of interaction → find in the track “Main” long yellow / red tasks (Long Tasks) – this is what blocks the flow.

LoAF (Long Animation Frames) — a new section in Chrome 123+ — shows specific animations and scripts that create latency.

How to fix:

  • Break down long tasks using setTimeout(0) or scheduler.yield()
  • Use Web Workers for heavy computing
  • Debounce/throttle for frequent events (scroll, resize, input)
  • Long list virtualization (react-virtual, tanstack-virtual)

CLS (Cumulative Layout Shift)

** What is this: * The total "instability" of the layout when loading. When elements “jump” – the user accidentally clicks the wrong thing, loses space in the text, feels irritation.

Norms:

  • < 0.1 - good
  • 0.1–0.25 – requires improvements
  • 0.25 - bad

**Every unexpected layout shift has an impact fraction × distance fraction. CLS is the sum of all such events per session.

Typical causes of CLS:

1. Images without dimensions

html
<!-- ❌ Плохо: браузер не знает сколько места зарезервировать -->
<img src="hero.jpg" alt="Hero">

<!-- ✅ Хорошо: резервирует место заранее -->
<img src="hero.jpg" alt="Hero" width="1200" height="600">

Or through CSS: aspect-ratio: 16/9.

2. Advertising and embed content without reserved space

The ad block appears after the page loads and shifts the content. Solution: Reserve space through min-height for the ad unit.

3. Dynamically inserted content

The “accept cookies” banner appears on top of the content and shifts it. Solution: Fixed positioning (position: fixed) instead of flow displacement.

4. Fonts calling FOUT/FOIT

The text is first shown in the system font, then replaced by custom - and slightly shifted (different letter sizes). Solution: font-display: optional (does not show custom font if not loaded) or size-adjust, ascent-override for maximum coincidence with the fallback font.

How to diagnose:

Chrome DevTools → Performance → enable “Web Vitals” in settings → record when rebooting → in the track “Experience” you can see CLS events with elements.

Or, in the Lighthouse report in the details of the CLS, a list of specific items that have shifted.


Complete audit algorithm: step by step

Step 1: Field data from Search Console

Start with Google Search Console → Core Web Vitals.

There you can see real data on all pages of the site with a breakdown of “good / needs improvement / bad”. This allows you to prioritize which pages and which metrics are problematic for real users.

URL: search.google.com/search-console → Core Web Vitals (on the left menu)

Step 2: Lab Analysis of Problem Pages

For every problem page from Search Console, run a PSI. Look at this:

  1. What is an LCP element
  2. TBT (proxy for INP)
  3. CLS infringers
  4. Top 5 Opportunities for potential savings

Step 3: Deep Analysis in DevTools

For difficult cases – Chrome DevTools → Performance.

plaintext
F12 → Performance →  ️ settings:
CPU throttling: 4x slowdown (emulation of the average smartphone)
- Network: Fast 4G
Click Record → Reload the page → in 5-7 seconds Stop

What to watch in Trayce:

  • Main thread: Long Tasks > 50 ms is TBT/INP
  • Network: waterfall resource loading – that loads sequentially instead of parallel
  • Timings: Tokens FCP, LCP, DCL (DOMContentLoaded)
  • Frames: Where style recalculations (purple blocks) occur

Step 4: Network Panel Analysis

DevTools → Network → reload the page → sort by Size.

Look for:

  • Images > 500 KB (optimization candidates)
  • JavaScript bands > 300 KB (code splitting candidates)
  • CSS files > 100 KB (possibly a lot of unused)
  • Cache-free resources (no Cache-Control headers)
  • Resources from another domain that block rendering

Step 5: Coverage – Unused Code

DevTools → Ctrl+Shift+P → “Show Coverage” → Record → reboots.

The percentage of unused JavaScript and CSS. 50-70% of unused JavaScript on the first download is the norm for complex SPA. But >80% means something is clearly wrong with code splitting.


Prioritization: What to fix first

Not everything is equally important. Here's the order by influence:

TTFB (Time to First Byte) - server response time

If TTFB > 600 ms, everything else is pointlessly optimized. The browser waits for the server before doing anything.

How to check: Network → First query → Timing → “Waiting (TTFB)” tab.

How to improve:

  • CDN (Content Delivery Network) – The answer comes from the nearest server
  • Server cache – do not recalculate the page for each request
  • Database optimization (slow queries)
  • Hosting upgrade

2. LCP Image: The Most Influential Perception

  • WebP or AVIF format (average 30-50% less PNG at the same quality)
  • fetchpriority="high" on LCP image
  • The correct srcset to avoid loading 2000px on your phone
  • Preload: <link rel="preload" as="image" fetchpriority="high" href="hero.webp">

3. Render-blocking resources

CSS in <head> without the media attribute blocks rendering. JavaScript in <head> without defer blocks rendering.

html
<!-- ❌ Блокирует рендеринг -->
<script src="analytics.js"></script>

<!-- ✅ Загружается параллельно, выполняется после HTML -->
<script src="analytics.js" defer></script>

<!-- ✅ Загружается и выполняется параллельно (порядок не гарантирован) -->
<script src="widget.js" async></script>

4. JavaScript bundle size

Large bundles are the main cause of high TBT and slow INP.

  • Code splitting: download only what you need for the current page
  • Tree Shaking: Remove unused code from libraries
  • Lazy loading: components below fold loads delayed

5. Images below fold

All images that are not visible at the first download:

html
<img src="photo.jpg" alt="..." loading="lazy">

loading="lazy" attribute – the browser does not load the image until it approaches viewport. For images on the first screen, do not use (LCP will delay).


Typical scenarios and solutions

Scenario: High CLS on mobile due to banner

The cookie banner appears on top of the content and moves it.

css
/* ❌ Плохо: баннер в потоке документа */
.cookie-banner {
  position: relative;
}

/* ✅ Хорошо: фиксированный, не сдвигает поток */
.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1000;
}

Scenario: Slow LCP due to hero image

Hero image 1.2 MB in PNG, loaded after CSS.

Correction checklist:

  1. Convert to WebP: cwebp -q 80 hero.png -o hero.webp
  2. Add srcset for different sizes
  3. Add preload to <head>:
html
<link rel="preload" as="image" href="hero.webp" 
      imagesrcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
      imagesizes="100vw"
      fetchpriority="high">
  1. On img add fetchpriority="high"

High TBT due to heavy JavaScript

TBT 1800 ms. Coverage shows that 60% of the bundle is not used on the current page.

Checklist:

  1. Analysis through Webpack Bundle Analyzer or Rollup Visualizer
  2. Dynamic importation of components that are not needed immediately
  3. Check if there are any duplicate dependencies
  4. Replace heavy libraries with lightweight alternatives (moment.js → date-fns, lodash → lodash-es with tree shaking)

Real-time monitoring tools

A one-time audit is good. Regular monitoring is better.

Google Search Console - free, real data from Chrome users, alerts when deteriorating. A mandatory tool for each website.

web-vitals.js is a library from Google to collect CWV analytics:

javascript
import {onLCP, onINP, onCLS} from 'web-vitals';

onLCP(console.log);
onINP(console.log);
onCLS(console.log);

Connect to your analytics (GA4, Amplitude) – get real data from your users.

Lighthouse CI – Start Lighthouse automatically in CI/CD at every depletion. If the estimate falls below the threshold, the assembly falls.

Vercel Speed Insights, Netlify Analytics are built-in tools for popular hosting sites.

WebPageTest (webpagetest.org) - More detailed than PSI, allows you to test from different locations, different devices, with video recording of the download.


Frequently asked questions

** "A score of 100 = website fast?" **

Nope. A score of 100 at Lighthouse means you performed well on a synthetic test. Real users on real devices with real internet is another story. Look at the field data in CrUX.

**My assessment is different every time - why? **

Laboratory tests have a variability of ±10-15% due to server load, processor noise, and parallel tasks. To be precise, run a few times and look at the average. Or use WebPageTest with multiple runs.

“Site is fast on desktop, but slow on mobile in PSI” **

Lighthouse for mobile is testing on an emulated Moto G4 (slow CPU) with an emulated 4G connection. These are deliberately pessimistic conditions. Real-world experiences depend on your audience – if most are on 5G flagships, a score of 55 for mobile doesn’t mean a bad experience.

Advertising drops CWV - what to do? **

Reserve space for the ad unit even before the ad loads: min-height: 250px (standard banner). Use position: sticky or fixed for blocks that appear on top of content.


AI and Performance Audit: How Claude Helps

Prompt: interpreting the PSI report

plaintext
Here is the data from PageSpeed Insights for our website:

Mobile: estimate [number]
LCP: [value] sec
INP/TBT: [value] ms
CLS: [meaning]
FCP: [value] sec

Top 5 recommendations from the Opportunities section:
[Saving time list]

Analyze:
1. What metrics are critical (affecting Core Web Vitals and ranking)?
2. What to fix first, in terms of influence and complexity?
3. Which of the Opportunities list can be solved quickly (1-2 days)?
4. What problems require deep technical work?

Prompt: an optimization plan for the developer

plaintext
We need to improve the following website indicators:
- LCP: [current] → goal [targeted]
- CLS: [current] → goal < 0. 1st
— TBT: [current] → target < 200 ms

Stack: [React/Vue/Next.js/WordPress/Other]
Hosting: [Description]
Main issues from Lighthouse: [list]

Create a technical optimization plan:
1. Quick wins (up to 1 day of work) – which will give a quick result
2. Medium (1-3 days) - more complex changes
3. Long-term (week+) - architectural improvements

For each item: what to do (specific changes in code or configuration).

Prompt: explain the results to stakeholders

plaintext
We need to explain the results of the performance audit to the management/client.

Current situation:
- PSI mobile score: [number]
- Main issues: [list]
- Load time: [seconds]

Write an explanation for a non-technical audience:
1. What do these indicators mean in simple words?
2. How it affects users (specifically)
3. How it affects business (conversion, SEO, retention)
4. What we plan to fix and what outcome we expect

No technical jargon. Page 1 maximum.

Prompt: Code Review for Performance

plaintext
Check this code for performance issues (LCP, CLS, INP):

[insert HTML/CSS/JavaScript]

Context: This is [page/component description].

Find:
1. What Can Cause Slow LCP
2. What Can Cause CLS
3. What can block the main thread (affects the INP)
4. Suboptimal resource utilization

For each problem: a specific fix with the code.

Performance audit checklist

** Tools:**

  • Verified Core Web Vitals in Google Search Console
  • Launched PSI for main and key landing pages (mobile!)
  • Launched Lighthouse in DevTools for pages beyond authorization
  • Tested by TTFB in Network Panel

LCP:

  • Defined LCP element (what exactly)
  • Image in WebP/AVIF with the correct dimensions
  • Preload for LCP image in <head>
  • fetchpriority="high" on LCP image
  • TTFB < 600 ms

CLS:

  • All images have width and height attributes
  • Advertising and embed space reserved
  • Dynamically appearing content does not shift the flow (position: fixed)
  • Fonts with font-display: swap and fallback close in size

INP/TBT:

  • No Long Tasks > 50ms in main thread (DevTools Performance)
  • JavaScript Bands < 300 KB for the First Download
  • Third-party scripts are loaded with defer or async
  • Heavy handlers with debounce/throttle

Resources:

  • Images below fold with loading="lazy"
  • Critical CSS inline or preload
  • Uncritical JavaScript with defer
  • Cache-Control headlines on static resources
  • Gzip or Brotli compression enabled on the server
$ cd ../ ← back to UX and interfaces