How to Speed Up a Slow Website in 2026: A Practical Guide for Developers

Speed up a slow site by fixing what real users feel: pull field data from the Chrome UX Report, not Lighthouse, then target LCP under 2.5s, INP under 200ms, and CLS under 0.1. Most gains come from images, render-blocking scripts, and server response time.
Part of the complete web development guide.
On this page
- Start with field data, not Lighthouse
- The LCP problem is usually one of four things
- 1. You’re lazy-loading the hero image
- 2. Your fonts are blocking the first paint
- 3. Your server is far away from your users
- 4. Your HTML takes too long to arrive
- INP is almost always JavaScript
- CLS: reserve space for everything
- Caching and compression in 2026
- Images and video are still the biggest bytes
- Measure the change, or you’re guessing
- FAQ
- What’s a good page speed score in 2026?
- Do I need to rewrite my site to make it fast?
- How long does a speed fix take to show up in rankings?
Most slow sites aren’t slow because of one giant problem. They’re slow because of twenty small ones nobody ever measured. This is how I actually track them down and fix them, in the order that tends to matter most in 2026.
Start with field data, not Lighthouse
Lighthouse is a lab test. It runs on your machine, on your connection, with a cold cache, and it will happily give you a 98 on a page that feels terrible to real visitors on a phone in a parking lot. The numbers that count are the ones Google collects from actual users, and they live in the Chrome UX Report. You can see them in Search Console under Core Web Vitals, or pull them directly:
curl "https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=YOUR_KEY"
-H "Content-Type: application/json"
-d '{
"url": "https://example.com/pricing/",
"formFactor": "PHONE",
"metrics": ["largest_contentful_paint", "interaction_to_next_paint", "cumulative_layout_shift"]
}'
What you’re aiming for, and this hasn’t changed much in years because it’s tied to human perception:
- LCP (largest contentful paint): under 2.5s
- INP (interaction to next paint): under 200ms
- CLS (cumulative layout shift): under 0.1
If your field data is green and your Lighthouse score is 60, ignore Lighthouse. If field data is red, you have real work to do. Optimize for the 75th percentile of your users, not the median. A site that’s fast for people on fiber and slow for everyone else is just a slow site.
The LCP problem is usually one of four things
In my experience, LCP almost always traces back to the same short list. Check these before you start rewriting anything.
1. You’re lazy-loading the hero image
This is the single most common self-inflicted LCP wound. Someone adds loading="lazy" to every image on the page, including the one above the fold, and then wonders why LCP is 4 seconds. The hero should load eagerly, and it should be the highest priority resource on the page:
<img
src="/hero-1200.avif"
srcset="/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-1800.avif 1800w"
sizes="100vw"
width="1200" height="675"
fetchpriority="high"
decoding="async"
alt="Team reviewing a site audit">
Set fetchpriority="high" on exactly one image. Set loading="lazy" on everything below the fold. Don’t do both to the same image.
2. Your fonts are blocking the first paint
Self-host your fonts. Preload the one file you actually need for the first screen. And please stop loading six weights when you use two.
<link rel="preload" href="/fonts/inter-var.woff2"
as="font" type="font/woff2" crossorigin>
@font-face {
font-family: "Inter";
src: url("/fonts/inter-var.woff2") format("woff2-variations");
font-weight: 100 900;
font-display: swap;
}
font-display: swap means text renders immediately in a fallback font and swaps when yours arrives. You’ll get a brief flash, which is a much better trade than a blank screen.
3. Your server is far away from your users
If your audience is on Long Island and your origin is in a single datacenter in Frankfurt, every request pays a round trip tax. Put a CDN in front of it. Cloudflare, Fastly, Bunny, whatever fits your budget. This is the highest-use fix for geographically spread audiences, and it takes an afternoon.
4. Your HTML takes too long to arrive
Time to first byte is a real LCP input. If your homepage is doing three database queries, an API call to a CRM, and a template render before it sends a byte, no amount of image optimization will save you. Cache the rendered output. For most marketing pages, the content changes once a week and you’re rebuilding it on every request.
INP is almost always JavaScript
Interaction to Next Paint replaced First Input Delay in 2024, and it’s a stricter metric because it measures the whole interaction, not just the delay before your handler starts. The usual culprits:
- Long tasks on the main thread blocking the browser from responding
- Third-party scripts (chat widgets, tag managers, heatmap tools) doing work during interactions
- React or Vue components re-rendering large trees on every keystroke
- Event handlers that do heavy synchronous work instead of yielding
For the last one, scheduler.yield() is now widely supported and it’s the cleanest way to break up long work without the jank of setTimeout:
async function handleSearchInput(query) {
showSpinner();
// Let the browser paint the spinner and stay responsive
await scheduler.yield();
const results = await runExpensiveFilter(query);
renderResults(results);
}
For third-party scripts, audit what’s actually loading. I’ve seen sites carrying four analytics tools where the team only reads one dashboard. If a script isn’t earning its keep, delete it. If it is, load it after the page is interactive:
<script>
window.addEventListener("load", () => {
const s = document.createElement("script");
s.src = "https://example.com/widget.js";
s.async = true;
document.head.appendChild(s);
}, { once: true });
</script>
CLS: reserve space for everything
Layout shift is the easiest of the three to fix and the most annoying to debug, because it usually comes from ads, embeds, or late-loading content. The rule is simple: if something is going to appear in the layout, its slot needs to exist before it loads.
.ad-slot {
min-height: 250px; /* matches the 300x250 creative */
contain: layout size; /* isolate it from the rest of the page */
}
iframe[loading="lazy"] {
aspect-ratio: 16 / 9;
width: 100%;
height: auto;
}
Always set explicit width and height attributes on images and videos. Modern browsers use them to compute the aspect ratio and reserve the right box before the file arrives. This one habit kills most CLS on most sites.
Caching and compression in 2026
Brotli is the default compression choice now, and most CDNs and servers handle it automatically. The part people still get wrong is cache headers. Hashed assets should be cached forever. HTML should not be.
# Hashed build assets: immutable, cache for a year
location ~* .(js|css|woff2|avif|webp)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# HTML: always revalidate
location ~* .html$ {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
This pairs with a build step that fingerprints filenames (app.a3f9c1.js). Change the file, change the name, and the browser fetches it. Nothing else invalidates, so nothing else costs you a round trip.
Images and video are still the biggest bytes
AVIF and WebP are both well supported now. AVIF wins on size, WebP wins on encode speed, and you can serve both with a <picture> element. For anything larger than a thumbnail, run it through a CDN that resizes on the fly rather than pre-generating twelve variants by hand.
<picture>
<source srcset="/photo-800.avif 800w, /photo-1600.avif 1600w" type="image/avif">
<source srcset="https://i0.wp.com/www.kennykey.com/photo-800.webp 800w, https://i0.wp.com/www.kennykey.com/photo-1600.webp 1600w" type="image/webp">
<img src="https://i0.wp.com/www.kennykey.com/photo-800.jpg" width="800" height="533" alt="Workshop" loading="lazy">
</picture>
For background video, don’t autoplay a 40MB MP4 on mobile. Serve a poster image and skip the video entirely under a certain viewport width. Nobody on a phone in a parking lot wants your hero reel.
Measure the change, or you’re guessing
Every fix above is a hypothesis until you measure it. Set up Real User Monitoring so you can see LCP, INP, and CLS by page, by device, and by connection type. Then change one thing at a time and watch the p75 move. If you deploy five optimizations at once and the number improves, you’ve learned nothing about which one mattered.
If you’d rather not run this yourself, or you’re on a platform where you can’t get at the server config, this is the kind of thing I handle through custom web development work. And since speed and search rankings are the same conversation in practice, it usually makes sense to treat it as part of an ongoing Long Island SEO effort rather than a one-off cleanup. I’m based in Commack, so a lot of that work is local, but the technical fixes are the same whether you’re in Suffolk County or anywhere else.
FAQ
What’s a good page speed score in 2026?
Ignore the Lighthouse score and look at field data. You want LCP under 2.5 seconds, INP under 200 milliseconds, and CLS under 0.1 at the 75th percentile of real users. If all three are green in Search Console, you’re in good shape regardless of what any audit tool says.
Do I need to rewrite my site to make it fast?
Almost never. Most slow sites improve dramatically from caching headers, image compression and sizing, removing unused JavaScript, and putting a CDN in front of the origin. A rewrite is the last resort, not the first step.
How long does a speed fix take to show up in rankings?
Field data in Search Console updates on a 28-day rolling window, so you’ll see it move gradually over a few weeks. Expect the user experience to improve immediately and the ranking signal to follow with a lag.


