EEltaCrew
Home › Blog

Why our banner ad slot was empty: a week of logging load failures, and 71% were "no fill"

Published 2026-10-26Measured 2026-10-26About 5 min readelta · EltaCrew

The bottom banner in AdDeck, our AdMob earnings app, was often empty, and we had no records to say why. We started logging every ad load failure with its reason, and after a week, 71% of banner failures were NO_FILL. What we logged and how, what we checked on a device first, and why we made banner retries longer and then shorter again.

The banner was often empty

AdDeck is an app for checking AdMob earnings, and it has one banner ad at the very bottom of the screen. On the developer's phone, that slot was often empty.

When we opened GA4 to explain why, there wasn't a single ad load failure on record. When we cleaned up failure logging across the app on October 16, the ad code had been left out. The AdMob report tells you what percentage of requests got an ad, but not what happened in any particular session.

What we logged

When an ad fails to load, the app now sends the SDK's error code and message to GA4 as one line, code:message (version 1.0.58, October 19).

Event When
ad_banner The bottom banner failed to load
ad_native_start The native ad at app start failed to load
ad_native The native ad in the exit popup failed to load
ad_init The ad SDK threw during initialization
ad_consent_info · ad_consent_form Ad consent info or form failed
giveup The short retries all failed too

Two rules:

We triggered the failures on a device first

Before shipping, we forced failures in a debug build to check that the events actually arrive.

One week of results

These are records from 110 users on versions 1.0.58 to 1.0.63, from October 19 to the morning of October 26.

Bottom banner (41 failure events · 18 users)

Reason Events Share
NO_FILL (No fill.) 29 71%
NETWORK_ERROR (host not found, connection failed, timed out) 8 20%
TIMEOUT (waiting for the JavaScript engine to load) 3 7%
INVALID_REQUEST (Ad size will not fit on screen.) 1 2%

Native ads

Placement Failure events NO_FILL Network TIMEOUT
Exit popup 31 68% 23% 10%
App start 16 44% 38% 19%

The network column also includes HTTP 504 responses (3 in the exit popup, 1 at app start).

For the same period (October 19 to 25), the AdMob report shows 1,015 banner requests, a 57.0% match rate, and a 92.1% show rate. GA4 counts once per session and AdMob counts every request, so the numbers can't be the same, but they point the same way. The biggest reason the banner was empty wasn't the app. There was no ad to fill it at that moment. When a request did get an ad, 92% of them actually appeared on screen.

The network errors included these shapes:

There were 10 ad consent info failures, and 8 of them were the same 2:Error making request. we saw in the network-off test.

We made retries longer, then shorter

Banner retries had already changed several times before this logging.

When On failure
First version, September 6 No retry
September 24 5 tries, 2 seconds apart
October 21 5 tries, 3 seconds apart, then every 30 seconds
October 23 2 tries, 3 seconds apart, then stop

What we confirmed in the logs on September 25 became the baseline. The auto refresh we had turned on in the AdMob console keeps running even after a failed load: about 110 seconds after the last NO_FILL, the banner filled. If the app also asks again every 30 seconds, the app is doing a second time what the SDK is already doing. So the app now only covers the first few seconds of empty space and leaves the rest to the SDK's refresh.

The logs also show how much the short retries rescue. In the same period, 24 banner events say the short retries all failed (21 giveup, plus 3 slow from the October 21 version). The 41 failure events are one per reason per session, so the banner failed in at most 41 sessions. That means in more than half of the sessions where the banner failed once, asking again a few seconds later still didn't get an ad. NO_FILL rarely changes within a few seconds.

What we don't know yet

Takeaways

The app in this post is AdDeck, our AdMob earnings app (Google Play).

AndroidAdMobGA4AdsMeasurement

Related

Why our lottery ticket QR scanner showed zero successes: a path you don't log looks like a failureIn our lottery app's weekly report, 19 people had opened the QR screen and GA4 showed zero successful scans. The scanner wasn't broken. The path that real ticket QR codes took had no logging at all. How we found the measurement gap, what four similar apps do, why we switched to the bundled scanning engine, and the numbers one week after the fix.Tapping the logo in the map's corner crashed the app: Naver Map SDK and the AppCompat themeFour "You need to use a Theme.AppCompat theme" crashes showed up in Crashlytics for our lottery store map app. They came not from users but from the Play pre-launch report's test robot tapping the NAVER logo in the bottom-left corner of the map. The cause, a fix that wraps only the map instead of changing the whole app theme, and a second problem that appeared in dark mode.Requesting ads before the SDK finishes initializing: why the same crash came back three times after we added a guardAfter we first fixed the "MobileAds.initialize must be called" crash in our live apps, the same crash came back three more times in different shapes. We had a guard that waited for initialization to finish, but a flag set at the start, a flag set on consent alone, and new ad slots that skipped the guard all left gaps. The cause of each case and the results of checking all 23 apps.