Skip to main content
YollaMEDIA

Lazy Loading Ads: Performance Gains vs Revenue Trade-offs

Lazy loading ads improves page speed and Core Web Vitals, but some impressions never fire. How the trade-off works and how to implement it on gaming sites.

RM

Remel Mendoza

Senior Technical Product Manager · · 13 min read


On this page

Lazy loading delays ad requests until the ad slot is near the user's viewport. Instead of requesting all ads on page load, you only request ads the user is about to see. The performance benefit is clear: fewer resources loaded upfront, faster initial render, better Core Web Vitals scores. The revenue question is less obvious: if you defer ad requests, some of those requests never fire because the user leaves before scrolling to the slot.

For gaming publishers, this trade-off has a specific shape. Your pages are different from news articles or blog posts. Most of the action happens at or above the fold: the game canvas, the play button, the adjacent ad units. Below-fold content (related games, descriptions, comments) gets less scroll traffic than a typical content site.

Here is how lazy loading affects gaming sites specifically: what it does to impressions, Core Web Vitals and CPMs, how to do the math for your own site, and the implementation approach that balances both sides.

How Lazy Loading Works

Without lazy loading, your page load triggers all ad requests simultaneously. A page with 5 ad slots fires 5 ad requests (each with its own header bidding auction) within the first 1–2 seconds of page load. That is 5 sets of network requests, 5 sets of bid responses, and 5 sets of creative renders competing for bandwidth and main thread time.

With lazy loading, only ads in or near the viewport fire immediately. Ads below the fold wait. When the user scrolls within a defined distance of the ad slot (the "root margin"), the request fires.

Option 1: GPT's built-in lazy loading

If you serve through Google Ad Manager, Google Publisher Tag has lazy loading built in: call googletag.pubads().enableLazyLoad() before your ads are displayed. It takes three optional settings: fetchMarginPercent (how far away, as a percentage of the viewport, a slot must be before the ad is fetched), renderMarginPercent (how far away before it is rendered) and mobileScaling (a multiplier applied to both margins on mobile). If you omit them, GPT uses defaults that Google sets and tunes over time, so do not assume fixed values; set them explicitly if you want predictable behavior. Google also notes that with Single Request Architecture, lazy fetching only works if all slots are outside the fetching margin (GPT reference).

GPT's lazy loading controls when Ad Manager fetches and renders the ad. It does not, on its own, delay your Prebid auctions: if you request bids for every slot on page load, those bid requests still fire up front. To defer the auction as well, trigger it from your own viewport logic.

Option 2: Your own IntersectionObserver

Running the auction and the ad request from an IntersectionObserver gives you control over both:

const adObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const slot = entry.target;
      requestAd(slot); // Fire the ad request
      adObserver.unobserve(slot); // Only request once
    }
  });
}, {
  rootMargin: '100% 0px' // Start loading when the slot is one viewport height away
});

// Apply to below-fold ad slots only
document.querySelectorAll('.ad-slot[data-lazy]').forEach(slot => {
  adObserver.observe(slot);
});

The rootMargin: '100% 0px' setting tells the observer to trigger when the ad slot is within one viewport height of the visible area, not when it is already visible. The goal is for the auction to finish and the ad to render by the time the slot enters the viewport. With client-side header bidding timeouts commonly set at 800–1200 ms, the margin has to buy enough scroll distance for a full auction plus the creative render.

The Performance Gains

LCP Improvement

By deferring below-fold ad requests, you remove their JavaScript execution, network activity and DOM manipulation from the critical rendering path. The gain is usually larger on mobile, where CPU and bandwidth are more limited, than on desktop.

How much LCP improves depends on how heavy your below-fold ads are and what your LCP element is. For a gaming site sitting just above the 2.5-second "good" LCP threshold, removing below-fold ad work from the initial load can be the difference between a passing and a failing score. Measure it with a before-and-after test rather than assuming a number.

Bandwidth Savings

Each ad request involves:

  • Prebid auction: bid requests and responses are small, typically a few kilobytes per bidder, but each is a separate network round trip
  • Creative assets: roughly 50–500 KB per display creative, and 1–5 MB per video creative
  • Tracking pixels: often several additional network requests per impression

For 3 below-fold display ads that the user never scrolls to, lazy loading saves roughly 150 KB to 1.5 MB of data transfer, mostly creative assets, plus dozens of requests. On mobile networks, this matters for page load time and for users on metered data plans.

CWV Score Improvement

The direction of the effect on each Core Web Vital:

MetricExpected effect
LCPImproves, because less ad work competes with the initial render
CLSNo change, as long as slot dimensions are reserved (lazy loading does not fix CLS by itself)
INPCan improve, because fewer scripts compete for the main thread during early interactions

For a page sitting near a threshold, those improvements can move it from "Needs Improvement" to "Good" in Google's CWV assessment.

The Revenue Trade-off

Here is the honest part: lazy loading means some ad impressions never fire.

Impressions Lost

If a user visits your game page, plays a game, and leaves without scrolling below the fold, every below-fold ad slot with lazy loading generates zero impressions. Without lazy loading, those ads would have loaded (whether the user saw them or not) and would have generated impressions — low-viewability impressions, but impressions nonetheless.

Where the impression loss is largest:

  • Gaming portals (game play pages): usually the largest loss. Most user attention is on the game canvas above the fold, and many players never scroll.
  • Content pages (guides, blogs): a loss that varies widely. Some users read the full article; others leave after the first paragraph.
  • Category/listing pages: usually the smallest loss. Users browse these pages with more scrolling, so most below-fold ads still fire.

Your own analytics will tell you the real number: the share of pageviews that never reach each below-fold slot is roughly the share of that slot's impressions you will give up.

The Viewability Offset

Here is why the impression loss is less damaging than it appears: the impressions you lose are mostly ones that were never viewable anyway.

An ad that loads below the fold but is never scrolled into view counts as an impression but not a viewable impression. Advertisers increasingly buy on viewable CPM (vCPM) rather than raw CPM. An impression that was never in view either:

  • Earns nothing (if the advertiser is buying on vCPM)
  • Earns less (if the impression's low viewability history drags down future bid prices for the slot)
  • Reduces your site's overall viewability score (which SSPs and advertisers use to set bid adjustments)

By eliminating these never-seen impressions, lazy loading actually improves your viewability rate. And higher viewability leads to higher bids on the impressions that do fire.

The CPM Offset

Lazy-loaded ads tend to earn somewhat higher CPMs than eager-loaded ads in the same position. They are more likely to be viewable (they only fire when the user is near the slot), and viewable impressions attract higher bids. The CPM increase offsets part of the impression volume decrease. Whether it offsets all of it depends on how many impressions you lose.

Net Revenue Impact

Ad revenue is impressions × CPM, so the two effects multiply. Here is an illustrative example with assumed inputs, not measured results:

FactorIllustrative assumption
Impression volume−5% to −15%
Average CPM+3% to +5%
  • Best case: 0.95 × 1.05 = 0.9975, a change of about −0.25%, effectively flat
  • Worst case: 0.85 × 1.03 = 0.8755, a change of about −12.5%

So with these inputs, the direct effect on ad revenue in the first weeks ranges from about −12.5% to flat. The viewability gain is not a separate line to add on top; it is the reason CPMs rise, so it is already counted in the CPM change.

What sits on the other side of the ledger is harder to put a number on: faster pages, better Core Web Vitals, and the session depth and organic traffic that can follow from them over time. Lazy loading is worth it when the impressions you give up were mostly never seen anyway, and when your performance gains are real on your own pages. That is why the test plan below measures both revenue and user behavior.

The Right Implementation for Gaming Sites

What to Eager Load (Request Immediately)

  • Above-fold ad units: The leaderboard at the top of the page, the 300×250 next to the game canvas, and any ad unit visible on initial page load. These fire immediately because they are in the user's viewport from the start.
  • The game-adjacent 300×250 or 300×600: This is usually your highest-viewability, highest-CPM display slot. It sits next to the game canvas where the user is focused. Eager load it: it needs to render fast and earn at full CPM.

What to Lazy Load

  • Below-fold display units: Related games sections, footer leaderboards, and sidebar ads that sit below the primary content area.
  • In-content ads in long-form content: If your site has blog posts, guides, or game descriptions that are several screens long, lazy load the in-content units placed after the first screen.
  • Second and third outstream units: If you run multiple outstream video placements on a page, lazy load all except the first one.

The rootMargin Setting

The rootMargin parameter controls how early the ad request fires relative to the slot entering the viewport. This is the most important tuning parameter for lazy loading.

Too small (a few hundred pixels or less): The request fires when the slot is almost in view. If the auction runs on that trigger, a normal scroll brings the slot into view long before an 800–1200 ms auction and the creative render finish. The user sees an empty slot, which looks broken and wastes viewable time.

Too large (several viewport heights): On a short gaming page, the request fires so early that it is effectively eager loading. You get minimal performance benefit.

A sensible starting point for gaming sites: about one viewport height.

When the auction itself is triggered by the observer, start with a margin of about one viewport height ('100% 0px') on desktop. Mobile users flick-scroll faster and mobile ad loading is slower, so use a larger margin there, around 1.5–2 viewport heights. GPT's mobileScaling setting exists for the same reason. Then tune from your own data: if lazy slots are often empty when they come into view, increase the margin; if almost every lazy slot still fires on almost every pageview, you can reduce it.

const rootMargin = window.innerWidth < 768 ? '200% 0px' : '100% 0px';

const adObserver = new IntersectionObserver(callback, { rootMargin });

Handling Unfilled Lazy Slots

When a lazy-loaded slot fires a request but receives no fill, do not collapse the slot if its dimensions were reserved in CSS. Collapsing reserved space causes CLS. Instead:

  1. Show a house ad (promoting another game on your site)
  2. Leave the reserved space empty (acceptable if it is small, like a 300×250)
  3. Fill with non-ad content (a newsletter signup, a social follow widget)

Option 1 is the best practice: it maintains layout stability, serves a business purpose and avoids the visual gap.

Testing and Validation

Before Deploying

  1. Measure current CWV scores for your top 10 pages using PageSpeed Insights field data
  2. Record current impression counts and RPM for below-fold ad slots
  3. Identify which slots are below fold on both desktop and mobile viewports (they differ)

Deployment

  1. Deploy lazy loading to 20% of traffic for 14 days
  2. Compare the lazy-loaded group against the control on:
    • LCP, CLS, INP (performance)
    • Total impressions, viewability rate, CPM, RPM (revenue)
    • Bounce rate, session depth (user experience)
  3. If performance improves and the revenue change is within the range you decided in advance you would accept, scale to 50%, then 100%

Ongoing Monitoring

After full deployment, track these weekly:

  • Viewability rate by ad slot: should increase for lazy-loaded slots
  • Fill rate by ad slot: should remain stable (lazy loading does not affect fill rate for impressions that do fire)
  • CWV field data: should improve over 28 days as CrUX data updates
  • Session RPM: compare it with your control group, not just with last month

If RPM drops more than you expected in the first two weeks, check whether your root margin is too small. A margin that is too small causes slots to come into view empty (or to be scrolled past before they render), which costs impressions and viewable time. If RPM holds but performance barely improves, the margin is probably too large.

Advanced: Predictive Loading

For publishers with the engineering resources, predictive loading takes lazy loading one step further. Instead of using a fixed rootMargin, predict whether the user will scroll to the ad slot based on:

  • Session depth patterns: Users on their third game play in a session scroll more than first-visit bouncers
  • Page type: Category page users scroll more than game play page users
  • Device type: Mobile users scroll differently than desktop users
  • Scroll velocity: A user scrolling slowly through game descriptions will reach below-fold content; a user who jumped straight to the play button will not

Predictive loading fires ad requests for users likely to scroll and defers them for users likely to stay above the fold. This further reduces wasted ad requests while maintaining fill for users who will actually see the ads.

Implementation requires a lightweight model or heuristic rules. It is not trivial, so test whether the gain over standard lazy loading justifies the engineering time on your traffic.

Make the Change

Lazy loading below-fold ads is one of the more reliable performance optimizations available to gaming publishers. The performance gains are measurable. The direct revenue cost is real but bounded, and it falls mostly on impressions nobody saw.

Start by eager loading above-fold and game-adjacent ads, lazy loading everything else with a margin of about one viewport height (more on mobile), and measuring against a control group for 14 days. For the performance side of the ledger, read our guide to Core Web Vitals for gaming publishers, or see publisher results.

Ready to see what managed monetization can do for your gaming site?

Get a Revenue Estimate

Related articles

Core Web Vitals

How to Measure the CLS Impact of Your Ad Setup

CLS is the Core Web Vital ads affect most directly. How to measure it, find which ad elements cause layout shifts, and fix the common patterns on gaming sites.

Remel MendozaSenior Technical Product Manager

14 min read