You've run PageSpeed Insights. The scores are poor. You've optimised images, minified CSS, and still LCP stays red. Or CLS keeps spiking on client sites. Or users complain that clicks feel sluggish even though the page "loads fast". The problem isn't always obvious—some of the worst Core Web Vitals mistakes look like best practice at first glance. Here are five that we see again and again, why they hurt, and how to fix them.
1. Lazy-loading the LCP image
Lazy-loading saves bandwidth. It delays loading images until they're near the viewport. So lazy-load everything, right? Wrong. The single most damaging thing you can do to LCP is to lazy-load your hero image, banner, or whatever element the browser identifies as the largest contentful paint.
Why it hurts: The LCP element is usually above the fold. Lazy-loading it gives the image low priority and defers its fetch until after layout or until the user scrolls near it. That delays the very element that defines "page is ready" for both users and Google. Field data from web.dev shows that image download time is rarely the main LCP bottleneck—resource load delay and TTFB are. Adding loading="lazy" to the LCP image creates delay that no amount of compression can fix.
Fix: Remove loading="lazy" from any above-the-fold image that could be the LCP element. Preload it instead: <link rel="preload" as="image" href="/hero.webp" /> and add fetchpriority="high" on the <img> tag. Keep the LCP image in the HTML—don't load it via JavaScript or a CSS background, or the browser discovers it too late.
2. Images without width and height
You've seen it: images load in, the page jumps, text shifts down. That's CLS—cumulative layout shift. One of the simplest and most common causes is images (and videos, iframes, ads) without explicit dimensions.
Without width and height, the browser doesn't know how much space to reserve. It renders the text, then the image arrives, and the layout recalculates. Every shift counts toward your CLS score. Ads, embedded videos, and lazy-loaded content below the fold all contribute, but the quick win is your own images.
Fix: Add width and height to every <img> (and equivalent attributes to <video> and <iframe>). Use the intrinsic dimensions—the actual pixel size of the image file. With responsive images, pair srcset with width and height so the browser can compute the correct aspect ratio. Reserve space for dynamically injected content (ads, widgets) with CSS placeholders or a known container height.
3. Render-blocking CSS and JavaScript
The browser must parse HTML, then CSS, then execute JavaScript before it can paint. If critical CSS or JS blocks the parser, nothing above the fold renders until those files download and run. That directly delays LCP and often FCP.
Common culprits: synchronous scripts in <head>, large CSS files that block first paint, and font loading that holds up text. CMS themes and page builders often ship with dozens of render-blocking resources by default.
Fix: Inline critical CSS—the minimal styles needed for above-the-fold content—and load the rest asynchronously. Use media="print" with onload="this.media='all'" to load non-critical CSS without blocking. Defer or async non-critical JavaScript: defer for scripts that need the DOM, async for independent scripts like analytics. Preload fonts with <link rel="preload"> and use font-display: swap so text renders immediately with a fallback font.
4. Third-party scripts running unconstrained
Analytics, chat widgets, ads, and social embeds run on the main thread. When they block for hundreds of milliseconds—or seconds—user interactions stall. That's INP: interaction to next paint. Chrome's Lighthouse audit flags pages where third-party code blocks the main thread for over 250ms; the HTTP Archive points to these scripts as a primary cause of poor INP.
Tag managers can balloon to 500KB+ when loaded with multiple pixels and tracking scripts. Chat widgets often pull in 200–500KB of JavaScript. Each script competes for CPU and bandwidth; together they delay not just interactions but often the initial paint too.
Fix: Load third-party scripts after the main content. Use defer or load them in a requestIdleCallback or setTimeout so they don't block the critical path. For chat widgets and similar, delay loading until user intent (e.g. scroll, hover near a help icon). Audit with Lighthouse's "Reduce the impact of third-party code" and Chrome DevTools' Performance tab to see which scripts block longest.
5. Ignoring server response time (TTFB)
LCP breaks down into four phases: TTFB, resource load delay, resource load duration, and element render delay. Real user data shows that TTFB alone often accounts for about half of LCP; resource load delay adds another quarter or more. If your server takes 2 seconds to send the first byte, LCP cannot possibly meet the 2.5s "Good" threshold, no matter how small your hero image is.
Shared hosting, distant servers, and uncached database queries all inflate TTFB. A CDN alone won't fix origin latency, but it helps for static assets and can cache HTML at the edge when configured correctly.
Fix: Profile your backend—slow queries, heavy middleware, and cold starts all add up. Use a CDN for static assets and consider edge caching for HTML where it makes sense. Enable server-side caching (Redis, Memcached) for expensive operations. If you're on shared hosting and TTFB stays high, upgrading to a faster tier or a closer region often yields the biggest gain for the least code.
Catch regressions before they hurt
These five mistakes are fixable. But fixing them once isn't enough. A new plugin, a deployed change, or a client's content update can reintroduce any of them. Manual PageSpeed runs don't catch regressions the day they happen.
Apogee Watcher runs automated PageSpeed tests, lets you set performance budgets, and sends alerts when LCP, INP, or CLS cross your thresholds. Add a site and we discover pages and test on schedule; when something goes out of budget you get a digest—not a flood of emails. Use a repeatable agency checklist to set things up, and our guide to setting thresholds to define what "good" means for each site.
FAQ
What is the biggest PageSpeed mistake?
Lazy-loading the LCP image. It sounds efficient, but the LCP element is usually above the fold. Delaying its load directly worsens your largest-contentful-paint score and contradicts how the metric is defined.
Do I need to fix all five mistakes at once?
No. Tackle them in order of impact. Start with the LCP image (remove lazy-load, add preload) and images without dimensions—both are quick wins. Then address render-blocking resources, third-party scripts, and TTFB based on what your diagnostics show.
How do I know which image is the LCP element?
Run PageSpeed Insights or Lighthouse; the LCP element is listed in the diagnostics. It's usually the largest above-the-fold image (hero, banner) or a text block. On e-commerce sites it's often the product image. If you're unsure, test by temporarily hiding suspect elements and re-running—when LCP improves, you've found it.
Should I remove third-party scripts entirely?
Not necessarily. Analytics and chat have business value. The fix is to load them after the main content—defer them, use requestIdleCallback, or delay chat widgets until user intent (e.g. scroll). Keep them; just don't let them block the critical path.
Does TTFB affect mobile and desktop differently?
Yes. Mobile networks add latency, so TTFB on 4G or 3G is often worse than on desktop. If your server is already slow, mobile users feel it more. Optimise your origin first; a CDN helps for static assets but can't fix a sluggish backend.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.