How to Fix a Slow Website: A Practical Guide to Core Web Vitals
Google uses page speed as a ranking signal. Here's how to diagnose slow Core Web Vitals and fix them.
Page speed is a documented ranking signal in Google Search, measured through the Core Web Vitals programme. Slow pages also tend to have higher bounce rates, as users leave before the page finishes loading.
This guide walks you through the most common causes of slow websites and the practical fixes for each one.
Understanding Core Web Vitals
Before diving into fixes, it helps to understand what you are actually measuring. Google's Core Web Vitals are three metrics that assess real-world user experience:
Largest Contentful Paint (LCP) measures how long it takes for the largest visible element — usually a hero image or headline — to load. A good LCP is under 2.5 seconds.
Cumulative Layout Shift (CLS) measures how much the page jumps around as it loads. You have seen this when text moves just as you are about to click something and you tap the wrong thing. A good CLS score is under 0.1.
Interaction to Next Paint (INP) replaced First Input Delay (FID) in 2024. It measures how quickly your page responds to user interactions like clicks and taps. A good INP is under 200 milliseconds.
You can check your current Core Web Vitals scores using the AuditZap Core Web Vitals checker — it runs a free, instant check without needing to install anything.
Fix 1: Optimise Your Images
Images are one of the most common contributors to slow LCP scores.
Convert to modern formats. WebP and AVIF produce smaller file sizes than JPEG at comparable quality, and both are supported in all modern browsers. If your CMS does not handle conversion automatically, tools like Squoosh or Sharp (for Node.js pipelines) can batch-convert your image library.
Lazy-load below-the-fold images. Adding loading="lazy" to <img> tags tells the browser not to download images until the user scrolls near them. Do not apply this to your hero image — that one should load as fast as possible.
Add explicit width and height attributes. When the browser does not know image dimensions before the image loads, it cannot reserve space for it. The result is layout shift (bad CLS). Always include width and height on every <img> tag, even if you are overriding the display size with CSS.
Use a CDN. Serving images from a CDN means users download them from a server geographically close to them. Most modern hosting platforms (Cloudflare, Vercel, Netlify) do this automatically.
Fix 2: Eliminate Render-Blocking Resources
When a browser encounters a <script> or <link rel="stylesheet"> tag in the <head>, it stops building the page until that resource has downloaded and processed. These are render-blocking resources, and they directly delay your LCP.
Defer non-critical JavaScript. Add defer or async to script tags that are not needed for the initial render. Third-party scripts — analytics, live chat, A/B testing tools — are common offenders. Loading multiple marketing scripts synchronously delays the browser from rendering anything until they have all downloaded and executed.
Inline critical CSS. The CSS required to render what is visible above the fold (your hero section, navigation, and first viewport) can be inlined directly in the <head>. This removes the stylesheet download from the critical path. Tools like Critical or PurgeCSS can automate extracting and inlining critical CSS.
Preload key resources. Use <link rel="preload"> to tell the browser to download your LCP image, web fonts, and critical scripts early, before the browser would normally discover them.
Fix 3: Reduce Server Response Time
If your server takes a long time to respond to the initial request, every other metric suffers. The technical term is Time to First Byte (TTFB), and it should be under 800ms.
Enable caching. If your pages are generated dynamically from a database, implement server-side caching so repeated requests are served from memory rather than rebuilding the page from scratch. For WordPress sites, plugins like WP Rocket or W3 Total Cache handle this. For custom apps, tools like Redis or Varnish are the standard approach.
Use a CDN for HTML too.Edge networks can cache your HTML responses and serve them from servers near your users. Cloudflare's caching or Vercel's Edge Network make this relatively straightforward.
Reduce database query complexity. Slow database queries are a common TTFB culprit. Use query profiling tools to identify queries that take more than 100ms and add appropriate indexes.
Fix 4: Fix Layout Shift (CLS)
A poor CLS score is often caused by a handful of specific issues.
Reserve space for ads and embeds. If you run display ads or embed third-party content (videos, social feeds, widgets), reserve the correct dimensions in your CSS before the content loads. Use min-height or aspect-ratio containers.
Avoid injecting content above existing content. Banners, cookie consent notices, and newsletter popups that push content down when they appear are the most common CLS culprits. Consider using position: fixed for these so they overlay rather than push content, or ensure they are rendered server-side so their space is reserved from the start.
Preload fonts and use font-display: optional or font-display: swap. When web fonts load late, the browser can switch from a fallback font to the custom font mid-render, causing a visible text shift. font-display: optional prevents the swap entirely if the font is not ready in time.
Fix 5: Improve Interaction Responsiveness (INP)
INP measures responsiveness to every interaction throughout the page lifetime, not just the first one. A poor INP score usually points to JavaScript doing too much work on the main thread.
Break up long tasks.Any JavaScript task that takes over 50ms is considered a “long task” and will make the page feel unresponsive. Use setTimeout or requestIdleCallback to break up large chunks of work and yield control back to the browser.
Reduce third-party JavaScript. This is a recurring theme because it is a recurring problem. Each third-party script you load adds JavaScript execution time to the main thread. Audit your third-party scripts and remove any that are not generating measurable value.
Debounce input handlers. If you have event listeners on scroll, resize, or input fields that do expensive calculations, make sure they are debounced or throttled so they do not fire on every event.
How to Measure Your Progress
After making changes, verify the impact. Field data (from real users) takes 28 days to update in Google Search Console. For instant feedback, use lab tools:
- AuditZap's Core Web Vitals checker gives you a free instant measurement
- Google PageSpeed Insights provides both lab data and real-world CrUX data
- Chrome DevTools Performance panel lets you profile specific interactions
Google's PageSpeed Insights report identifies which specific issues are affecting your scores and lists them in order of estimated impact — use that as your starting point.