How to Run Ads Without Hurting Core Web Vitals
Reserve space, size images correctly, lazy-load below the fold and skip third-party scripts: a practical guide to banner ads that keep LCP, INP and CLS healthy.
On this page
Ads hurt Core Web Vitals in three main ways: they push content around when they load (CLS), their scripts make the page slow to respond (INP), and they compete with your main content for bandwidth (LCP). You can avoid most of the damage by reserving each ad's space in advance, setting width and height or a CSS aspect-ratio, lazy-loading ads below the fold, serving compressed WebP or AVIF images, and using script-free embeds instead of third-party ad JavaScript.
Key takeaways
- Google's "good" thresholds are LCP within 2.5 seconds, INP of 200 milliseconds or less, and CLS of 0.1 or less, measured at the 75th percentile of page loads.
- Reserve every ad's space before it loads, and never collapse an empty slot.
- Lazy-load ads below the fold, but never the ones visible when the page opens.
- Serve small WebP or AVIF images at the size the slot actually needs.
- Every ad script adds main-thread work. A linked image needs no JavaScript at all.
Core Web Vitals at a glance
According to web.dev's Core Web Vitals overview, there are three metrics, and the target is to hit the "good" threshold for at least 75% of page loads, segmented across mobile and desktop. INP replaced First Input Delay (FID) as a Core Web Vital on March 12, 2024.
| Metric | What it measures | Good | Poor | How ads affect it |
|---|---|---|---|---|
| Largest Contentful Paint (LCP) | Time to render the largest image or text block in the viewport | 2.5 s or less | Over 4.0 s | A large ad image above the fold can become the LCP element, and ad requests compete for bandwidth |
| Interaction to Next Paint (INP) | How quickly the page responds to clicks, taps, and key presses | 200 ms or less | Over 500 ms | Ad scripts keep the main thread busy |
| Cumulative Layout Shift (CLS) | How much content moves unexpectedly | 0.1 or less | Over 0.25 | Ads that load without reserved space push content down |
Why it matters for search: Google says it highly recommends good Core Web Vitals for success with Search, and its page experience guidance also asks whether your content avoids an excessive amount of ads that distract from or interfere with the main content. Good scores don't guarantee top rankings, but poor ones make your site worse for readers and for the advertisers paying to reach them.
1. Reserve space so ads never shift content
Ads are a classic cause of layout shift. The page renders, the reader starts reading, then a banner arrives and shoves the paragraph down. Web.dev's guide to optimizing CLS recommends always including width and height on images, or reserving the space with CSS aspect-ratio, min-height, or similar.
For a fixed-size banner, the attributes alone do the job:
<div class="ad-slot">
<a href="https://advertiser.example.com/" target="_blank" rel="sponsored noopener">
<img src="https://yoursite.example.com/ads/sidebar-300x250.webp"
width="300" height="250"
alt="Acme Analytics: see every campaign in one dashboard">
</a>
</div>
For a responsive slot that scales with its container, reserve the shape with aspect-ratio:
.ad-slot {
max-width: 300px;
aspect-ratio: 300 / 250;
}
.ad-slot img {
display: block;
width: 100%;
height: auto;
}
Three more rules from the same web.dev guidance:
- Don't collapse empty slots. Removing reserved space causes as much shift as inserting content. Show a placeholder when no ad is running. An "Advertise here" banner does that job and doubles as a sales tool.
- Place late-loading content lower. Content injected near the top of the viewport usually causes bigger shifts than content injected further down.
- Prefer one exact size per slot. Slots that accept several sizes force you to guess how much space to reserve.
If you show different slots on mobile and desktop, such as a 320×50 banner on phones and a 728×90 leaderboard on desktop, hide the unused one with display: none in a media query and add loading="lazy" to both images. Web.dev notes that Chrome, Safari, and Firefox don't load lazy images hidden with display: none, so phones won't download the desktop banner.
2. Keep ads from slowing your largest content
LCP measures when the largest image or text block in the viewport renders. If a big banner sits above the fold and outweighs your headline or hero image, it can become the LCP element, so its file size directly affects your score.
- Keep above-the-fold ads modest in size and weight so your own content stays the largest element.
- Never lazy-load an ad that's visible when the page opens. Web.dev advises against lazy-loading images likely to be in the initial viewport, because the browser fetches them later than it otherwise would.
- Limit the number of ad requests early in the page load, since each one competes with your own content for bandwidth.
3. Lazy-load ads below the fold
For ads further down the page, add loading="lazy" to the image. The browser then waits until the ad approaches the viewport before downloading it. Native lazy loading works in all major browsers and needs no JavaScript.
Lazy loading saves bandwidth for readers who never scroll that far, and it makes impression counts more meaningful, since below-the-fold ads are only requested when readers get close to them. Keep the width and height attributes on lazy images too, or they'll cause a shift when they finally load.
4. Serve small, modern image formats
Ad images are often the heaviest thing an ad adds to a page, so treat them like any other performance budget item.
- WebP works in all current major browsers and offers much better compression than PNG or JPEG, according to MDN's image format guide.
- AVIF compresses slightly better still and is supported in current versions of Chrome, Edge, Firefox, and Safari. MDN suggests providing a fallback format for older browsers.
- Export at the right size. For sharp results on high-density screens, export at twice the slot's dimensions, then compress. Don't upload a 3,000-pixel image for a 300-pixel slot.
- Avoid heavy animation. Animated GIFs are usually far heavier than a static WebP of the same banner.
- Set a file-size limit in your creative specs so advertisers know the rules before they upload.
5. Skip third-party ad JavaScript where you can
Most ad networks deliver ads through JavaScript. The script loads more scripts, runs auctions, measures viewability, and sometimes refreshes ads, all on the main thread your page needs for responding to readers. That's how ads end up hurting INP even when they look harmless.
The lightest possible ad is a plain linked image, as described in our guide to adding a banner ad with plain HTML. It makes one image request and runs no code, so it adds nothing to the main thread.
If you do need ad scripts, load them with async or defer, keep them out of the top of the page, and cap how many run on each page.
6. Measure before and after
- Field data: PageSpeed Insights shows real-user Core Web Vitals for your URLs when enough data exists, and Search Console's Core Web Vitals report groups affected pages.
- Lab tests: Lighthouse and the Performance panel in Chrome DevTools show layout shifts and long tasks, including which element moved.
- Test both states: check pages with an ad running and with the slot empty, on a mid-range phone as well as your desktop.
A copy-paste checklist
[ ] Every ad image has width and height (or the slot uses aspect-ratio)
[ ] Empty slots show a placeholder instead of collapsing
[ ] Ads visible on load are NOT lazy-loaded
[ ] Ads below the fold use loading="lazy"
[ ] Images are WebP or AVIF (or optimized JPEG/PNG), exported at 2x and compressed
[ ] One exact size per slot
[ ] No third-party ad scripts, or scripts loaded async/defer and capped
[ ] Tested with ad and without ad, on mobile and desktop
Not sure which slot sizes to offer? Our banner ad sizes guide covers the common ones.
A lightweight setup that sells itself
You can build all of this by hand, or use an embed designed around it. Spreadiom gives each ad slot a one-line <a><img></a> embed with no JavaScript and no cookies, and ads are served from a CDN. When no campaign is running, the slot shows an "Advertise here" banner that links to the slot's booking page, so the reserved space stays filled instead of collapsing and becomes a way for advertisers to find you.
FAQ
Do ads affect Core Web Vitals?
Yes, they can affect all three. Ads that load without reserved space cause layout shift, which hurts CLS. Ad scripts add main-thread work that slows responses to clicks and taps, which hurts INP. Large ad images above the fold can delay or become the largest contentful paint. Reserving space, lazy-loading below-the-fold ads, compressing images, and avoiding ad scripts prevent most of the damage.
How do I stop ads from causing layout shift?
Reserve the ad's space before it loads. For image banners, set width and height attributes that match the slot. For responsive slots, give the container a CSS aspect-ratio or min-height. Keep the space reserved when no ad is running by showing a placeholder, because collapsing an empty slot shifts content just like inserting an ad does. Fixed, single-size slots make all of this easier.
Should I lazy-load ads?
Lazy-load ads that sit below the fold by adding loading="lazy" to the image. The browser then fetches them only as readers scroll near them, which saves bandwidth and makes impression counts more meaningful. Don't lazy-load ads that are visible when the page first loads, because that delays them and can hurt your Largest Contentful Paint. Keep width and height on every lazy image.
What is a good CLS score?
According to web.dev, a good Cumulative Layout Shift score is 0.1 or less, and anything above 0.25 is considered poor. Google recommends measuring at the 75th percentile of page loads, separately for mobile and desktop, so most of your visitors get a stable page. Ads without reserved space are one of the most common reasons sites miss this threshold.
Sell ad space on your site — start free
Give every ad slot its own booking page. Advertisers pick dates, upload a banner and pay by card or PayPal — straight into your own account. No subscription; 5% only on completed bookings.