Core Web Vitals fail for predictable reasons. In support tickets I handled, the usual culprits were unoptimized images, render-blocking scripts, and cheap shared hosting with high server response times. Google's 2026 thresholds haven't changed from 2024, but the tooling got stricter and the field data collection window tightened. Sites that squeaked by before now fail.
This post walks through six changes that moved real sites from red to green in Google Search Console. Each fix targets one of the three CWV metrics: Largest Contentful Paint, Interaction to Next Paint, and Cumulative Layout Shift. You'll see the hosting-side changes, the front-end adjustments, and the verification commands.
1. Preconnect to critical third-party origins
LCP often tanks because the browser spends 300-600 ms establishing connections to font providers, analytics scripts, or CDN origins. Every HTTPS handshake—DNS lookup, TCP, TLS—adds latency before the first byte of your hero image or web font arrives.
Add <link rel="preconnect"> tags in your document <head> for any origin that delivers above-the-fold resources. For Google Fonts:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
For a CDN serving your hero image:
<link rel="preconnect" href="https://cdn.example.com">
The crossorigin attribute is required when the resource uses CORS, like fonts. I've seen LCP drop by 200-400 ms on mid-tier shared hosting just from preconnecting to two origins. Measure before and after with Chrome DevTools Performance tab or WebPageTest.
Don't preconnect to more than three origins. Each connection consumes memory and socket descriptors; too many and you'll hurt performance instead of helping it.
2. Switch to modern image formats and explicit dimensions
JPEG and PNG are heavy. A 1200px hero image at 85% JPEG quality might be 300 KB; the same image as WebP drops to 80-120 KB, and AVIF can hit 50-70 KB with better visual fidelity. Smaller files mean faster LCP.
Convert images to WebP or AVIF with cwebp or avifenc:
cwebp -q 85 hero.jpg -o hero.webp
avifenc --min 20 --max 40 hero.jpg hero.avif
Serve them with a <picture> element so older browsers fall back to JPEG:
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero image" width="1200" height="675">
</picture>
Notice the width and height attributes. They prevent layout shift by reserving space before the image loads. Even if you use CSS to make the image responsive, the browser calculates the aspect ratio from those attributes and holds the correct box size. Missing dimensions are a top CLS culprit.
On WordPress, plugins like ShortPixel or Imagify automate conversion and add the <picture> tags. If you're on shared hosting, check your PHP memory limit—batch processing thousands of images can hit the 128 MB default.
3. Defer non-critical JavaScript
Render-blocking scripts delay LCP and INP. If your <head> loads analytics, chatbots, or social widgets synchronously, the browser must download, parse, and execute each one before painting content. That's wasted time.
Move scripts to the bottom of <body>, or add defer to keep them in <head> without blocking:
<script src="analytics.js" defer></script>
<script src="chatbot.js" defer></script>
defer downloads the script in parallel with HTML parsing and executes it after the DOM is ready. For scripts that don't need the DOM at all—pure tracking beacons—use async instead. Just know that async scripts execute the moment they arrive, in unpredictable order.
For inline scripts, wrap them in a function and call it after DOMContentLoaded:
<script>
document.addEventListener('DOMContentLoaded', function() {
// your code
});
</script>
I've seen INP improve from 400 ms to under 200 ms by deferring three third-party scripts. Interactions feel snappier because the main thread isn't jammed parsing unused code.
4. Upgrade to HTTP/2 or HTTP/3 hosting
HTTP/1.1 opens one request per TCP connection, so browsers open six connections in parallel and queue the rest. A page with 40 resources—CSS, JS, images, fonts—suffers from head-of-line blocking and connection overhead. HTTP/2 multiplexes all requests over a single connection and compresses headers. HTTP/3 uses QUIC to eliminate TCP handshake latency altogether.
Check your server's protocol in Chrome DevTools Network tab. Look at the Protocol column. If it says "http/1.1", you're leaving performance on the table.
Enabling HTTP/2 depends on your hosting stack. On Apache with mod_http2:
sudo a2enmod http2
Then add to your virtual host:
Protocols h2 h2c http/1.1
On Nginx, HTTP/2 is enabled per listen directive:
listen 443 ssl http2;
HTTP/3 requires Nginx compiled with QUIC support or a CDN like Cloudflare. Cloudflare enables HTTP/3 by default for all plans; just turn on the toggle in the Network tab. I've measured 10-20% LCP improvement on high-latency mobile connections after switching from HTTP/1.1 to HTTP/3.
Shared hosting often doesn't expose protocol settings. If you're stuck on HTTP/1.1 and CWV keeps failing, consider upgrading to a VPS or managed host that supports HTTP/2 minimum.
5. Reserve space for ads and embeds
Cumulative Layout Shift spikes when an ad, YouTube embed, or social widget loads and pushes content down. Users click a link, the page shifts, and they hit the wrong target. Google penalizes this hard.
The fix is to reserve the exact space each dynamic element will occupy. For an ad slot, wrap it in a container with an aspect ratio:
<div style="width: 100%; padding-top: 56.25%; position: relative;">
<!-- ad script -->
</div>
The padding-top: 56.25% creates a 16:9 box. Adjust the percentage to match your ad dimensions. For a 300×250 ad, that's (250 / 300) * 100 = 83.33%.
For YouTube embeds, use the same aspect-ratio trick or the modern CSS property:
<div style="aspect-ratio: 16 / 9;">
<iframe src="https://www.youtube.com/embed/..." style="width: 100%; height: 100%;" frameborder="0" allowfullscreen></iframe>
</div>
WordPress themes that load ads via plugins (AdInserter, Ad Inserter Pro) often don't reserve space. You'll need to edit the theme's functions.php or add custom CSS to wrap the ad output. Check your CLS score in PageSpeed Insights after every change—sometimes the ad network delivers a different size than expected and you have to adjust the reserved space.
So what about server response time?
LCP can't start until the server sends the HTML. If your Time to First Byte is over 600 ms, no amount of front-end optimization will save you. TTFB reflects database queries, plugin overhead, and server CPU contention.
Run a quick test:
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" https://yoursite.com/
If TTFB is above 0.6 seconds, you've got a backend problem. On WordPress, install Query Monitor and profile slow database queries. A single unindexed query can add 300 ms. For cPanel shared hosting, check your resource usage in the Metrics section—if you're hitting I/O or entry process limits, you're throttled.
Page caching cuts TTFB dramatically. WP Rocket, LiteSpeed Cache, or even a simple Nginx fastcgi_cache will serve static HTML instead of running PHP on every request. I've seen TTFB drop from 1.2 seconds to 0.15 seconds after enabling FastCGI cache on a VPS.
6. Enable compression and minify assets
Brotli compression shrinks HTML, CSS, and JS by 20-30% more than gzip. Smaller payloads mean faster downloads and earlier LCP. Most modern browsers accept Brotli; the server just needs to send it.
On Nginx, install the Brotli module and add to your config:
brotli on;
brotli_types text/css application/javascript application/json image/svg+xml;
On Apache, mod_brotli does the same:
<IfModule mod_brotli.c>
AddOutputFilterByType BROTLI_COMPRESS text/html text/css application/javascript
</IfModule>
Cloudflare enables Brotli automatically, even on the free plan. If you're behind Cloudflare, you're already covered.
Minification removes whitespace and comments from CSS and JS. A 200 KB unminified bundle might drop to 140 KB minified. Build tools like Vite, Webpack, or Parcel minify by default in production mode. For WordPress, WP Rocket and Autoptimize handle minification without touching your build process.
Combine minification with Brotli and you'll see a 40-50% reduction in total page weight. That translates directly to better LCP on slower connections.
Verifying your changes
After making changes, clear your cache—server cache, CDN cache, browser cache. Then test with PageSpeed Insights and check the field data in Google Search Console.
PageSpeed Insights gives you lab data immediately, but Search Console shows real-user field data collected over 28 days. If you fix everything today, expect to see green CWV scores in Search Console 4-6 weeks later. The delay is frustrating but unavoidable.
For faster feedback, use Chrome User Experience Report API or install the Web Vitals extension. It shows CWV metrics as you browse your own site. Not perfect, but better than waiting a month.
Retest on mobile. CWV thresholds are the same for desktop and mobile, but mobile scores are almost always worse due to slower CPUs, higher latency, and smaller caches. A site that passes on desktop can easily fail on mobile. PageSpeed Insights lets you toggle between the two.
Common questions
Do I need to fix all three metrics to pass?
Yes. Google requires LCP under 2.5 seconds, INP under 200 ms, and CLS under 0.1 for at least 75% of page views. Fail one and you fail overall.
Will a CDN alone fix Core Web Vitals?
A CDN improves TTFB and asset delivery, but it won't fix render-blocking scripts, missing image dimensions, or layout shift. You need both hosting improvements and front-end changes.
What if my shared hosting can't enable HTTP/2?
Put Cloudflare in front. Cloudflare terminates HTTP/2 and HTTP/3 at the edge, even if your origin server only speaks HTTP/1.1. You get the protocol upgrade without changing hosts.
How do I know which third-party script is slowing INP?
Use Chrome DevTools Performance panel. Record an interaction, then look for long tasks in the flame graph. Scripts that block the main thread for more than 50 ms hurt INP.
Does WordPress hosting matter for CWV?
Yes. Managed WordPress hosts (Kinsta, WP Engine, Rocket.net) include server-level caching, CDN, and HTTP/2 by default. Cheap shared hosting often runs outdated PHP, no opcode cache, and HTTP/1.1. The stack matters.
What to measure next
Core Web Vitals are a baseline, not the finish line. After you pass, measure First Contentful Paint and Time to Interactive. Track field data month over month in Search Console and correlate CWV improvements with organic traffic changes. Google confirmed CWV is a ranking factor, but the weight is small compared to content relevance and backlinks.
If you made all six changes and still fail, the bottleneck is likely hosting infrastructure—shared CPU throttling, low RAM, or high disk I/O wait. Run top and iostat on your VPS, or check resource usage graphs in cPanel. Sometimes the only fix is an upgrade.
