Testing ads in a mobile game: rewarded, interstitial, mediation and edge cases
In a free-to-play game, ads aren’t “a banner at the bottom” — they’re the main source of revenue and one of the most edge-case-rich parts of the product. Here QA answers a question that converts directly into money and store reviews: was the reward granted exactly once, and did we break the player’s session with a badly placed ad.
Let’s break down what and how to test in a mobile game’s ad monetization — by format, state, and mediation.
Formats and what breaks in each
- Rewarded video — the player watches a clip for a reward. The main risk zone (see below).
- Interstitial — a full-screen insert between screens. Risk — the moment of display: not over a loading screen, a dialog, or during gameplay.
- Banner — a persistent banner. Risk — UI overlap, safe area, refresh, taps on the edge of the play field.
- App-open — an ad on cold/warm start. Risk — showing over the splash, on return from the IAP flow, on a deep link.
- Native / playable — embedded formats. Risk — layout across screens and clicks.
The main risk — the reward (rewarded): exactly once
The player must receive the reward exactly once — not zero, not twice. This is idempotency at the product level. Test cases:
- Clip watched to completion → reward granted once.
- Ad closed at the 2nd second (before the reward threshold) → reward NOT granted, progress untouched.
- App backgrounded during the clip and returned → correct state, no double reward.
- Network lost mid-display → reward doesn’t get “stuck”, UI doesn’t hang, the player isn’t punished.
- Double callback from the SDK (a repeated
onRewarded) → reward isn’t double-counted (dedup by ad instance). - Server-Side Verification (SSV): the reward is credited on the server, not just in the client — otherwise it’s a trivial cheat. Verify the signature/validation of the callback.
- App killed right after completion, before crediting → on the next launch the reward either lands or is honestly not granted, with no duplication.
If the reward lives only in the client, it’s not a feature, it’s a hole. A rewarded reward must be confirmed by the server (SSV).
No-fill and empty inventory
There may be no ad available (no suitable ad — no-fill). This is a normal state, not an error. What to check:
- The rewarded button is unavailable/in a loading state, not “tapped — nothing happened”.
- Player progress isn’t blocked by the absence of an ad (you can’t gate progression behind an ad that doesn’t exist).
- Re-loading (preload) after a no-fill — without infinite retries that hammer network and battery.
- An interstitial on no-fill is simply skipped, the player moves on without a hang.
Mediation and waterfall
Revenue is driven by mediation: one SDK (e.g. AppLovin MAX or AdMob mediation) polls several ad networks by priority (waterfall) or via bidding. What to test:
- Network order and timeouts: if network #1 is silent, move to #2 instead of hanging.
- Fallback all the way down the waterfall without crashes or leaks.
- Test ads / test mode in every network — so you don’t serve yourself real impressions (that’s a ban).
- The SDK’s mediation debugger: which adapters are connected, which versions, where init errors are.
- Different geos/currencies, if eCPM and network availability depend on the country.
Timing of display: frequency capping, pacing, placement
- Frequency capping: don’t show interstitials more often than the limit (e.g. no more than once per N minutes / levels).
- Pacing: no two full-screens in a row, no interstitial right after a rewarded.
- Placement: ads not over a loading screen, a modal dialog, not during active gameplay, not in the first seconds of the first session (FTUE).
- Context: don’t show an interstitial before/after critical screens (payment, tutorial) where it would break the funnel.
Consent: ATT and GDPR/UMP
Without consent, ads still load, but become non-personalized. What to check:
- iOS ATT (App Tracking Transparency): the prompt appears at the right moment; on refusal IDFA is unavailable, ads are non-personalized, the app works.
- GDPR / UMP (consent via UMP): the consent form is shown in the EU; the user’s choice is propagated to all mediation networks.
- Order: consent before ad init/load, otherwise personalization leaks without consent.
- Reset consent / change region → the form is shown again, state stays consistent.
Network and device states
- Offline and slow network (throttling): the ad doesn’t load — degrade gracefully, no hangs.
- Background/return during display; incoming call; screen lock.
- Screen rotation and different aspect ratios: a full-screen ad doesn’t break layout, a banner respects safe area.
- Sound: the ad doesn’t blast over the game’s mute mode; volume returns after the clip.
- Cold start vs warm: app-open doesn’t fight with the splash and deep link.
Analytics and revenue
Ads without correct analytics are blind monetization. Verify that impression / click / reward / revenue events are sent and reconcile between the network SDK, mediation, and product analytics. Impression-level revenue (ILRD) should match the networks’ reports. A discrepancy in impressions/revenue between SDK and analytics is a common silent bug.
Tool: live traffic from ad SDKs is convenient to inspect via HTTP interception (Proxyman/Charles) — you see the real requests to networks, consent flags, reward callbacks, not just device logs.
Ad monetization testing checklist (13 points)
- The rewarded reward is granted exactly once; closing before the threshold = no reward.
- The reward is confirmed by the server (SSV), not living only in the client.
- Backgrounding/killing the app during and after the clip — no duplication or loss.
- No-fill is a valid state: the button is in loading/disabled, progress isn’t blocked.
- Preload without infinite retries, doesn’t drain battery and network.
- Waterfall/bidding: timeouts, fallback, network order work, no hangs.
- Test mode is on for all networks in QA builds (no real impressions).
- Frequency capping and pacing are respected; no two full-screens in a row.
- Placement is correct: not over loading/dialog/gameplay/FTUE.
- ATT (iOS) and UMP/GDPR (EU): consent before load, refusal doesn’t break the app.
- Offline/slow network/background/call/rotation — graceful degradation.
- Ad sound respects mute; volume is restored.
- impression/click/reward/revenue events reconcile across SDK, mediation, and analytics.
Bottom line
Ads in a game are reward idempotency + display appropriateness + correct consent + analytics reconciliation. Most of the expensive bugs here aren’t “the ad didn’t show”, but “the reward was granted twice”, “progress is locked behind a no-fill”, and “personalization without consent”. A systematic state-based checklist catches them — not a one-off “watched a clip, got coins” run.