Skip to main content
YollaMEDIA

Core Web Vitals for Gaming Publishers: Running Ads Without Hurting Performance

Core Web Vitals feed into Google Search, and ads affect all three. How gaming publishers can run ads without wrecking LCP, CLS, and INP.

YW

Yen Wang

SVP, Tech & Operations · · 11 min read


On this page

Google uses three Core Web Vitals metrics — LCP, CLS, and INP — as part of its page experience signals in search. INP replaced FID (First Input Delay) as the responsiveness metric on March 12, 2024. If your gaming site fails these metrics, you lose organic traffic. If you lose organic traffic, you lose ad revenue. The irony: the ads you run to generate revenue are often what push your Core Web Vitals into the red.

For gaming sites, the stakes are doubled. Bad CWV scores hurt your SEO rankings and bad performance hurts player experience. A game page that takes 5 seconds to load, shifts layout while the game canvas is rendering, or lags during play because ad scripts are hogging the main thread is losing you users from both directions.

Here is how each CWV metric is affected by ads, what the thresholds are, and the specific solutions that work for gaming sites.

The Three Metrics

LCP — Largest Contentful Paint

What it measures: The time from navigation start to when the largest visible image or text block in the viewport finishes rendering. On a gaming site, that is typically a game thumbnail or cover image, a hero image, or a large heading. A <canvas> element is not an LCP candidate, so the game area itself does not count toward LCP, but everything it loads competes with the element that does.

Target: ≤ 2.5 seconds

How ads hurt LCP: Ad scripts loaded in the <head> or early in the body block the main thread during page load. Time spent parsing, compiling, and executing ad JavaScript before the LCP element renders delays LCP. A header bidding setup with several demand partners, plus the ad server library and any partner scripts, can add hundreds of milliseconds to LCP, and more on slow mobile devices.

The problem is compounded on gaming sites because you are already loading a game engine (Unity WebGL, Phaser, Construct, or custom HTML5). The page has two heavy loads competing for the same resources: the game and the ads.

CLS: Cumulative Layout Shift

What it measures: The largest burst of unexpected layout shifts during the page's lifetime. Shifts that happen less than 1 second apart are grouped into a session window (capped at 5 seconds), and CLS is the score of the worst window. A layout shift occurs when a visible element changes position without recent user input, typically because something above it loaded late and pushed it down.

Target: ≤ 0.1

How ads hurt CLS: Ads are one of the most common causes of CLS on publisher sites. When an ad slot does not have reserved dimensions and the ad creative loads 1–3 seconds after the page renders, everything below that slot shifts. On a gaming site, the consequences are specific:

  • A top leaderboard ad (728×90) loading late pushes the game canvas down by 90 pixels
  • A sidebar slot growing from 300×250 to 300×600 pushes the content below it down
  • An outstream video expanding in-content pushes all subsequent content down
  • An unfilled slot collapsing pulls the content below it up, which is also a shift

Each of these shifts registers in CLS. Shifts that land within a second of each other add up in the same session window, and a burst of ad loads right after page load is often the worst window of the visit.

INP: Interaction to Next Paint

What it measures: The delay between a user interaction (click, tap, keypress) and the next visual update on screen. Unlike FID, which only looked at the first input, INP reflects the slowest interactions across the whole visit.

Target: ≤ 200 ms

How ads hurt INP: Ad refresh scripts, bidding auctions, and creative rendering run on the main thread. When these operations coincide with a user interaction, the interaction is delayed. On a gaming site, this is particularly damaging because:

  • Players are interacting constantly (clicking, tapping, using keyboard)
  • Any delay between input and visual response is immediately noticeable during gameplay
  • Ad refresh triggers every 30–60 seconds, and each refresh involves multiple network requests and DOM manipulations

A player tapping a game control at the moment an ad refresh fires a Prebid auction can see a noticeable delay, sometimes hundreds of milliseconds on slower devices. That delay is measurable, and it shows up in INP.

Solutions for Gaming Sites

1. Lazy Load Below-Fold Ads

The fix for LCP: do not load ads that are not visible at page load.

How to implement:

  • Ads in the viewport on initial load (above the fold): load immediately
  • Ads below the fold: load when the slot is within 200px of the viewport

Use the Intersection Observer API or your ad library's built-in lazy loading:

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadAdSlot(entry.target);
      observer.unobserve(entry.target);
    }
  });
}, { rootMargin: '200px' });

document.querySelectorAll('.ad-slot-lazy').forEach(slot => {
  observer.observe(slot);
});

Impact on LCP: Removing two or three below-fold ad requests from the initial page load frees network and main-thread time for the LCP element. For gaming sites already loading heavy game assets, this can be the difference between passing and failing the 2.5-second threshold.

Revenue trade-off: Minimal. Below-fold ads on gaming sites have low viewability anyway. Lazy loading defers the request but does not eliminate it; the ad still loads when the user scrolls.

2. Reserve Ad Slot Dimensions in CSS

The fix for CLS: tell the browser exactly how much space the ad will occupy before the ad loads.

How to implement:

.ad-slot-leaderboard {
  width: 728px;
  min-height: 90px;
}

.ad-slot-medium-rectangle {
  width: 300px;
  min-height: 250px;
}

.ad-slot-half-page {
  width: 300px;
  min-height: 600px;
}

.ad-slot-outstream {
  width: 100%;
  min-height: 250px; /* minimum height for outstream container */
}

Critical detail: Use min-height, not a fixed height. A fixed height clips or overflows a creative that comes back larger than expected. min-height reserves the space while still letting the container grow. A creative that fits inside the reserved space moves nothing; one that grows beyond it pushes content down and counts as a shift. If a slot can serve several sizes, reserve the height of the largest one you expect to win most often.

For responsive/mobile layouts: Use aspect-ratio or percentage-based sizing that maintains the proportion:

.ad-slot-responsive {
  width: 100%;
  aspect-ratio: 300 / 250;
  min-height: 200px;
}

Impact on CLS: Proper dimension reservation removes most ad-caused CLS for fixed-size display units, as long as the creative fits the space. Outstream video is trickier. Animating the player open with a CSS transition still moves the content below it, and each frame counts as a shift. Either reserve the player's full height up front, or expand it only in response to a user action (shifts within 500 ms of a tap, click, or keypress are excluded from CLS).

3. Use requestIdleCallback for Refresh Logic

The fix for INP: keep ad refresh work out of the way of player input. requestIdleCallback still runs on the main thread, but only when the browser is idle, so the refresh is less likely to land in the middle of an interaction.

How to implement:

Instead of firing ad refresh on a strict timer:

// Bad: fires regardless of main thread state
setInterval(() => {
  refreshAdSlot(slot);
}, 30000);

Use requestIdleCallback to defer refresh to idle periods:

function scheduleRefresh(slot, interval) {
  setTimeout(() => {
    requestIdleCallback(() => {
      if (isSlotInView(slot)) {
        refreshAdSlot(slot);
      }
      scheduleRefresh(slot, interval);
    }, { timeout: 5000 }); // max 5s delay
  }, interval);
}

scheduleRefresh(adSlot, 30000);

This ensures the refresh fires during idle time, not while the user is actively interacting with the game. The timeout: 5000 parameter ensures the refresh still happens within 5 seconds even if the main thread stays busy.

Impact on INP: Fewer refreshes land in the middle of a player's input, so fewer interactions compete with ad auction JavaScript for main-thread time. Measure INP before and after to see how much it helps on your pages.

Important caveat: requestIdleCallback isn't reliably available in every browser (check Safari), so fall back to setTimeout:

const scheduleIdle = window.requestIdleCallback || 
  ((cb) => setTimeout(cb, 1));

4. Prefer Server-Side Bidding for Heavy Pages

The nuclear option for LCP: move the header bidding auction from the browser to a server.

Client-side header bidding (Prebid.js) runs in the user's browser. Each demand partner's adapter adds code to the Prebid bundle, makes its own network request, and processes its response on the main thread. On a gaming site already loading a game engine, this is a heavy additional burden.

Server-side bidding (Prebid Server, Amazon TAM, or equivalent) moves the auction to a server. The browser makes a single request to the server, which runs the auction across all demand partners simultaneously and returns the winning bid. The browser makes one auction request instead of one per bidder, and ships a smaller Prebid bundle.

Impact on LCP: Moving bidders server-side reduces the JavaScript and network work competing with the LCP element, which helps most on heavy pages. The trade-off is that server-side bids can be worth less, because the server loses some browser-side signals such as cookie matching.

When to use it: If your gaming site loads a heavy game engine (Unity WebGL, for example) and your LCP is above 3 seconds, server-side bidding may be the only way to pass CWV thresholds without removing ad slots.

Measuring Your Current State

Before optimizing, measure. Here are the tools:

Chrome DevTools Performance Panel

  1. Open Chrome DevTools (F12)
  2. Go to the Performance tab; its live metrics view shows LCP, CLS and INP as you load and play the page
  3. Record a page load and the first 30 seconds of interaction
  4. Find the LCP marker in the Timings track, individual layout shifts in the Layout shifts track, and your clicks and taps in the Interactions track
  5. Identify which ad scripts are running around each of them

Web Vitals Extension

Install the Web Vitals Chrome extension. It shows real-time LCP, CLS, and INP values as you browse your site. Useful for quick spot-checking after changes.

PageSpeed Insights

Run your key pages through PageSpeed Insights (pagespeed.web.dev). It shows both lab data (simulated) and field data (real user metrics from Chrome User Experience Report). Field data is what Google uses for ranking.

Important distinction: Lab data runs on a simulated throttled connection. Field data reflects your actual users. Your LCP might pass in lab data but fail in field data if a significant portion of your users are on slow mobile connections.

Google Search Console

The Core Web Vitals report in Search Console shows which URLs pass and fail, grouped by status. It is based on the same field data (from the Chrome User Experience Report) that Google uses in search.

Check this report monthly. If you see URLs moving from "Good" to "Needs Improvement," investigate immediately.

Benchmark Targets for Gaming Sites

MetricGoodNeeds ImprovementPoor
LCP≤ 2.5 s2.5–4.0 s> 4.0 s
CLS≤ 0.10.1–0.25> 0.25
INP≤ 200 ms200–500 ms> 500 ms

For gaming sites specifically, we suggest aiming for a margin below Google's thresholds:

  • LCP < 2.0 s (gives you margin for ad scripts)
  • CLS < 0.05 (gaming sites should have near-zero layout shift since the game canvas is the dominant element)
  • INP < 150 ms (gaming requires responsive interaction; the standard 200 ms threshold is too loose for games)

The Performance-Revenue Balance

Every solution here involves a trade-off. Lazy loading defers impressions. Server-side bidding can reduce bid values. Deferred refresh means fewer refresh cycles per session.

The key insight: the revenue you lose from performance optimizations is usually less than the revenue you gain from maintaining strong search rankings and good user experience. For example, losing 5% of impressions to lazy loading is cheaper than losing 15% of your traffic by falling off page 1 in Google.

Measure both sides. Optimize for total revenue, not per-impression revenue.

What to Do Next

If your gaming site's Core Web Vitals are in the red, your ad setup is a likely cause. The fixes above are specific and measurable, and none of them require removing ad slots. Start with reserved slot sizes and lazy loading, measure again, and work down the list. If you want to see how other gaming publishers balance revenue and performance, see publisher results.

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

Get a Revenue Estimate

Related articles

Core Web Vitals

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.

Remel MendozaSenior Technical Product Manager

13 min read

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