Why your site is slow: Core Web Vitals problems you can find in code
Core Web Vitals measure loading (LCP, good under 2.5 s), responsiveness (INP, under 200 ms) and visual stability (CLS, under 0.1). Most bad scores trace back to a few code decisions: an unoptimised hero image, fonts and scripts that block rendering, a large client bundle, unsized media and slow data fetching on the server.
Last reviewed by the Forge team
What goes wrong
What it costs when this is missed
High
Visitors leave
Every extra second before the page shows something loses people, on mobile most of all.
High
Slow server responses
Queries in loops and uncached pages make every visit wait for the database before anything can render.
Medium
Weaker rankings
Core Web Vitals are part of Google's page experience signals. Between similar pages, the faster one has the edge.
Medium
Pages that jump
Layout shift makes people tap the wrong thing, and it counts against you in CLS.
Common problems
What to look for in your code
Each one: why it hurts, and how to spot it in your own project.
01An unoptimised hero image
The largest image above the fold is usually what LCP measures. A 3 MB PNG, or one the browser finds late, delays it.
How to spot it: Check the hero image's size and format, and that it's preloaded or marked as priority.
loading="lazy" on the hero image tells the browser to wait, which is exactly wrong for the LCP element.
How to spot it: Search for loading="lazy" on images in hero sections and page headers.
03Render-blocking scripts and fonts
Analytics, chat widgets and tag managers in <head>, and fonts loaded without font-display, hold the first paint back.
How to spot it: Look at your layout's <head>: third-party scripts should load after the page (async, defer or the framework's lazy strategy), and fonts should be self-hosted with font-display: swap.
04A large client bundle
Marking whole pages as client components, or importing heavy libraries for one function, ships JavaScript every visitor must download and run.
How to spot it: Run your bundler's analyser. Look for 'use client' at the top of pages and layouts, and for large libraries used once.
Risky
"use client"; // the whole page, for one dropdown
import moment from "moment";
Better
// the page renders on the server; only the dropdown is a client component
import { Dropdown } from "./Dropdown";
05Media without dimensions
Images, video and embeds without width and height push content down as they load. That's what CLS measures.
How to spot it: Look for <img>, <video> and <iframe> tags without width and height, or without a fixed aspect ratio.
06Long tasks in event handlers
Heavy work on click or input (filtering big lists, re-rendering everything) blocks the main thread, which INP measures.
How to spot it: Profile a slow interaction in the browser's Performance panel, then find the handler that runs during it.
07Queries in loops
Fetching related rows one by one (the N+1 problem) turns one page load into hundreds of database round trips.
How to spot it: Look for awaits inside loops over query results, and for list endpoints without pagination.
Risky
for (const order of orders) {
order.customer = await db.customer.find(order.customerId);
}
Example findingSEOMediumConfirmed in codeHero image lazy-loaded and unsizedcomponents/Hero.tsx:18<img src="/hero.png" loading="lazy" />the largest element above the fold waits for lazy loading and shifts the layout
Questions
Lab data or field data?
Lighthouse is a lab test on one simulated device. Google ranks on field data from real Chrome users (CrUX), at the 75th percentile. Use the lab to find causes and the field to confirm the fix.
Do Core Web Vitals affect rankings?
They're part of Google's page experience signals. Relevance matters more, but between similar pages the faster one has the edge, and visitors leave slow pages either way.
Can a code review find performance problems?
Many, yes: the causes are in the code (image setup, script loading, queries in loops). Measuring then tells you which ones matter most.