Most pages have more ad slots than the average reader scrolls past. Loading them all when the page opens spends time and data on ads nobody sees. Lazy loading waits until a slot is close to the screen before loading its ad. Done well, it makes pages faster and raises viewability. Done badly, readers reach empty slots and you lose impressions you used to sell.
What lazy loading actually does
Loading an ad has two steps, and lazy loading can delay each one:
- Fetching is the ad request: the browser asks the ad server for an ad for that slot.
- Rendering is displaying it: the creative is placed in the slot and its images and scripts are downloaded.
The viewport is the part of the page visible on screen. Lazy loading uses distance from the viewport as the trigger: when the reader scrolls close enough, the ad is fetched, and when they get closer still, it is rendered. Separating the two lets the ad be ready in advance without the cost of rendering it before it is needed.
What eager loading costs
"Eager" loading means every slot is requested at page load. The costs:
- Requests for slots readers never reach, each adding network traffic and browser work while your content is still loading.
- Impressions nobody sees. An ad at the bottom of a page the reader leaves early still counts as an impression, but not a viewable one. See our guide to ad viewability.
- Slower pages. Google's web.dev article on loading ads without hurting page speed recommends lazy loading below-the-fold ads to reduce initial load time and main-thread blocking.
Google Ad Manager's viewability best practices describe both sides: used properly, lazy loading can raise overall viewability, because below-the-fold slots do not load for readers who do not scroll; but if the reader scrolls faster than the ad loads, they will not see it.
Read the transcript
Lazy loading means your page asks for an ad only when the reader is about to reach it, not for every ad the moment the page opens. Here is the same article twice. On the left, every ad is requested as soon as the page opens. On the right, ads are requested a little ahead of the reader, and shown just before they scroll into view. This reader stops partway down and leaves. On the left, six ads were requested, but only three were seen. On the right, four were requested for the same three seen. Less wasted work, and a lighter page. The margins matter. Too small, and readers reach empty slots. Too large, and you lose the benefit. Test any change against revenue per thousand page views.
Setting it up in Google Publisher Tag
If you use Google Ad Manager, lazy loading is built into Google Publisher Tag (GPT), the script that requests and displays your ads. Ad Manager's help recommends GPT for this, because other methods can trigger ad requests that never lead to a rendered ad.
The current way to turn it on is googletag.setConfig() with a lazyLoad setting. Older code uses googletag.pubads().enableLazyLoad(), which takes the same three options but is marked deprecated in the GPT reference. This is Google's documented example:
googletag.cmd.push(() => {
// Define your ad slots first, then:
googletag.setConfig({
lazyLoad: {
fetchMarginPercent: 500, // fetch slots within 5 viewports
renderMarginPercent: 200, // render slots within 2 viewports
mobileScaling: 2.0, // double both margins on mobile
},
});
googletag.enableServices();
});
| Option | What it controls | Google's example |
|---|---|---|
fetchMarginPercent | How close a slot must be to the viewport before GPT requests its ad | 500 (five viewports) |
renderMarginPercent | How close a slot must be before GPT renders the fetched ad. Google says it should be less than or equal to the fetch margin | 200 (two viewports) |
mobileScaling | A multiplier applied to both margins on mobile devices | 2.0 (doubled on mobile) |
Options you leave out use defaults set by Google, which Google says may be tuned over time. To switch one off, set it to null; for example, a null fetch margin keeps lazy rendering without lazy fetching. Google's lazy loading sample shows a working page.
How the margins are measured
Margins are a percentage of the viewport, not pixels: 0 means "when the slot enters the viewport", 100 means "when the slot is one viewport away".
An illustrative calculation with hypothetical screen sizes: on a desktop viewport 900 pixels tall, Google's example values fetch an ad when its slot is about 4,500 pixels away and render it at about 1,800. On a phone with a 700-pixel viewport, mobileScaling: 2.0 makes the margins 1,000% and 400%, so the ad is fetched about 7,000 pixels away and rendered about 2,800 away. Google's reference gives the reason for a separate mobile multiplier: viewport sizes and scroll speeds may differ from desktop.
Lazy loading and Single Request Architecture
Single Request Architecture (SRA) bundles the requests for several slots into one ad request. Google says it is needed to guarantee that competitive exclusions and roadblocks are honored.
SRA changes lazy fetching. The GPT reference notes that with SRA on, lazy fetching only works when all slots are outside the fetch margin, and Google's sample explains that when the first slot comes within the fetch margin, all slots are requested together. So if a slot near the top of the page is inside the fetch margin at load, every slot may be requested immediately. If you rely on SRA for exclusions or roadblocks, accept this trade-off knowingly; if not, test lazy loading with and without it.
Lazy loading and header bidding
If you use header bidding (for example Prebid.js), slots that load late still need bids. GPT's lazy loading controls when GPT calls the ad server; neither Google's nor Prebid's documentation describes a setting that makes it start a Prebid auction. Prebid's documentation covers two set-ups:
- Bids collected at page load, ad rendered later. Prebid's setConfig documentation describes this case with GPT lazy loading. If Prebid has dropped the bid from its cache before the slot renders, the ad can fail to show; the
minTargetedBidCacheTTLsetting keeps bids sent to the ad server for longer. But each bid also has an expiry set by the bidder, and if the ad renders after it, the bidder may not attribute revenue. Prebid's cache setting does not change that. - An auction for each slot as it approaches. Prebid's individual ad unit refresh example, suggested for infinite scroll, requests bids for one ad unit, sets targeting for that unit, then refreshes that GPT slot.
With per-slot auctions, the auction runs while the reader is approaching, so it must finish within the distance your margin allows. See our guide to header bidding timeouts.
Choosing margins
| Setting | What tends to happen | What to check |
|---|---|---|
| Margins too small | Fast-scrolling readers reach a blank slot, or pass it before the ad appears | Impressions per page view and viewability, especially on mobile |
| Margins too large | Ads load for slots readers never reach, close to eager loading | Whether viewability or page speed changed at all |
| Fetch margin far larger than render margin | Ads are ready early, but bids may age before they render | Header bidding bid expiry, as above |
No value suits every site: it depends on page length, scrolling speed, how long ads and auctions take, and your device mix. Start from Google's example or default, then test.
How to measure the change
Lazy loading usually trades some impressions for better viewability and speed, so judge it on revenue per page view. Track, for each version:
- Page RPM (revenue per 1,000 page views), the deciding number.
- Impressions per page view, which may fall.
- Viewable impressions per page view, which should hold or rise.
- Viewability rate by slot and device.
- Page speed, including Core Web Vitals.
An A/B test is the most reliable method: assign readers at random to the current or new margins, label each group with a key-value so your ad server reports them separately, and run for at least a full week. Before-and-after comparisons are weaker, because seasonal and demand changes move RPM on their own. To check a page by hand, GPT's slotRequested and slotOnload events, used in Google's sample, show when each slot is fetched and rendered. If RPM falls, our guide to diagnosing an RPM drop helps separate lazy loading from other causes.
Common mistakes
- Lazy loading the first screen. Google's ad best practices recommend requesting above-the-fold slots as early as possible and lazy loading those below the fold.
- A render margin larger than the fetch margin. Google's reference says it should be less than or equal.
- Not reserving space for slots, so ads push content around as they appear.
- Hiding and re-showing slots as readers scroll. Ad Manager's help says this is not a proper implementation of lazy loading and does not improve viewability.
- Refreshing slots without a new auction. Prebid warns that refreshing GPT without removing old Prebid targeting can render the same bids over and over.
- Judging on viewability rate alone. A higher rate with fewer impressions can mean less revenue.
If you use AdSense
These margin settings belong to Google Publisher Tag. AdSense ad units and Auto ads use different code, and Google does not document these settings for them. AdSense policies do not permit changes to the ad code that artificially inflate ad performance or harm advertiser conversions, so read modifications of AdSense ad code before adding your own loading logic.
Common questions
Does lazy loading reduce ad revenue?
It can. Fewer ads load for readers who do not scroll, so impressions per page view usually fall. Whether revenue falls depends on whether better viewability and speed make up for it. Compare page RPM in a test.
What fetch and render margins should I use?
Google's documented example is a 500% fetch margin, a 200% render margin and a mobile multiplier of 2.0, but no single value suits every site. Start there or with Google's defaults and test against revenue per page view.
Is enableLazyLoad still supported?
Google's GPT reference marks it as deprecated and points to the lazyLoad setting of googletag.setConfig(), which takes the same three options.
Do lazy-loaded slots still get header bidding demand?
Only if your set-up provides them: collect bids at page load and make sure they have not expired by render time, or run an auction for each slot as it approaches.