Every Unity developer who ships a mobile game eventually hits the same wall: the game works, it's fun, people are playing it — and it's making almost no money. Nine times out of ten, the problem isn't the game. It's the ad integration.
AdMob is still the default monetization layer for mobile games in 2026, and it's deceptively easy to get wrong in ways that don't show up until you look at your retention charts a week after launch. This post walks through a clean, production-ready way to wire up AdMob in a Unity project — banners, interstitials, rewarded ads, and app open ads — along with the placement decisions that actually protect your Day-1 retention instead of quietly destroying it.
Why "It Compiles" Isn't the Bar
A lot of AdMob tutorials stop at "here's how to show an interstitial." That's the easy 20%. The part that actually determines whether your game earns money or gets uninstalled is:
- When an ad fires (never mid-gameplay, always at a natural break)
- How often it fires (frequency capping is not optional)
- Whether it's pre-loaded before it's needed (nothing kills a game's feel like a 2-second stall waiting for an ad to load)
- Whether the reward is only granted after the ad actually completes (grant early and you'll eventually pay out for ads nobody watched)
Keep those four things in mind as you read the code below — the architecture exists specifically to make them easy to get right.
Step 1: Account Setup — Don't Skip the Boring Part
Before touching Unity, you need from your AdMob account:
- An App ID, formatted like
ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX - One Ad Unit ID per format you're using (banner, interstitial, rewarded, app open)
Create separate ad units for Android and iOS even if you're only launching on one platform right now. Retrofitting this later, once your AdsManager is wired throughout the codebase, is far more annoying than doing it up front.
One thing worth calling out explicitly: never ship test ad unit IDs to production. It's the single most common reason developers see real impressions in their analytics but zero revenue in their AdMob dashboard.
Step 2: Install the Google Mobile Ads Unity Plugin
Google's official plugin is the only supported integration path:
- Grab the latest
GoogleMobileAds.unitypackagefrom the Google Mobile Ads GitHub releases page - In Unity:
Assets → Import Package → Custom Package - Import everything when prompted
- Go to
Assets → Google Mobile Ads → Settingsand enter your Android and iOS App IDs - Enable Delay App Measurement if Firebase Analytics is also in the project
After import, double-check AndroidManifest.xml for the auto-injected meta-data block:
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX"/>
If this is missing or still holds a placeholder value, the app will crash on launch on Android — a surprisingly common first-submission bug.
Step 3: Initialize Before You Ever Request an Ad
This is the single most-skipped step, and it's the reason a lot of "AdMob isn't working" bug reports exist. Ads should only be requested after the SDK confirms it's initialized:
using GoogleMobileAds.Api;
using System.Collections.Generic;
using UnityEngine;
public class AdsManager : MonoBehaviour
{
public static AdsManager Instance;
void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
void Start()
{
MobileAds.Initialize(initStatus =>
{
Dictionary<string, AdapterStatus> map = initStatus.getAdapterStatusMap();
foreach (KeyValuePair<string, AdapterStatus> kv in map)
{
Debug.Log($"Adapter {kv.Key}: {kv.Value.InitializationState}");
}
// Only load ads AFTER this callback fires
LoadInterstitialAd();
LoadRewardedAd();
});
}
}
Make AdsManager a singleton with DontDestroyOnLoad, as shown above — templates and games with multiple scenes need this to survive scene transitions without re-initializing.
Step 4: Implement Each Ad Format Correctly
Banner Ads
Lowest eCPM, highest fill rate. Use them on menus and results screens — never during active gameplay.
private BannerView bannerView;
public void LoadBannerAd()
{
string adUnitId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX";
if (bannerView != null) bannerView.Destroy();
AdSize adSize = AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(AdSize.FullWidth);
bannerView = new BannerView(adUnitId, adSize, AdPosition.Bottom);
bannerView.LoadAd(new AdRequest());
}
Use Anchored Adaptive Banners rather than fixed 320x50 banners — they fill more of the screen width and consistently earn a higher CPM in 2026.
Interstitial Ads
The highest-volume format for casual games, and the one most likely to tank retention if mistimed.
private InterstitialAd interstitialAd;
public void LoadInterstitialAd()
{
string adUnitId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX";
InterstitialAd.Load(adUnitId, new AdRequest(), (ad, loadError) =>
{
if (loadError != null || ad == null)
{
Debug.LogError("Interstitial failed to load: " + loadError);
return;
}
interstitialAd = ad;
interstitialAd.OnAdFullScreenContentClosed += LoadInterstitialAd; // pre-load the next one
});
}
public void ShowInterstitialAd()
{
if (interstitialAd != null && interstitialAd.CanShowAd())
interstitialAd.Show();
else
LoadInterstitialAd();
}
Good placement triggers:
- After every 3–5 level completions, not every level
- On the game-over screen, before the retry button
- When the player returns to the main menu from a session
Always re-load the next interstitial the moment the current one closes. Waiting until the next trigger point to start loading means you'll frequently have nothing ready to show.
Rewarded Ads
Highest eCPM of any format, and opt-in — players choose to watch, so the retention cost is close to zero when placed well (extra lives, hints, continues).
private RewardedAd rewardedAd;
public void LoadRewardedAd()
{
string adUnitId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX";
RewardedAd.Load(adUnitId, new AdRequest(), (ad, loadError) =>
{
if (loadError != null || ad == null)
{
Debug.LogError("Rewarded ad failed to load: " + loadError);
return;
}
rewardedAd = ad;
});
}
public void ShowRewardedAd(System.Action onRewarded)
{
if (rewardedAd == null || !rewardedAd.CanShowAd()) return;
rewardedAd.Show(reward =>
{
onRewarded?.Invoke(); // grant reward ONLY here, inside the callback
});
rewardedAd.OnAdFullScreenContentClosed += LoadRewardedAd;
}
The reward callback is the whole point of this format — never grant the in-game reward before it fires, or you'll eventually be paying out rewards for ads that were closed early or never actually watched.
App Open Ads
An underused format that shows when a player returns to the app after backgrounding it — high eCPM because the player is already re-engaging.
private AppOpenAd appOpenAd;
private System.DateTime loadTime;
public void LoadAppOpenAd()
{
string adUnitId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX";
AppOpenAd.Load(adUnitId, ScreenOrientation.Portrait, new AdRequest(), (ad, error) =>
{
if (error != null) { Debug.LogError(error); return; }
appOpenAd = ad;
loadTime = System.DateTime.UtcNow;
});
}
public bool IsAdAvailable()
{
return appOpenAd != null && (System.DateTime.UtcNow - loadTime).TotalHours < 4;
}
This format typically adds 10–25% to total ad revenue for games with strong multi-session retention, and it's rarely implemented outside of top-grossing titles.
Step 5: Keep Ad Logic Centralized
Don't scatter ShowInterstitialAd() calls across a dozen scripts. Route everything through your GameManager or LevelManager so frequency tuning is a one-line change later:
void OnLevelComplete()
{
levelCount++;
if (levelCount % 3 == 0)
{
AdsManager.Instance.ShowInterstitialAd();
}
LoadNextLevel();
}
void OnGameOver()
{
AdsManager.Instance.ShowInterstitialAd();
ShowGameOverUI();
}
Step 6: Squeeze More eCPM Once It's Live
Integration is table stakes. These are the levers that actually move revenue after launch:
- Enable mediation. Running multiple networks (AppLovin, Meta Audience Network, Unity Ads) through AdMob's Open Bidding can lift eCPM by 20–40% over AdMob alone.
- Tune interstitial frequency by genre, not by gut feel — puzzle games tend to tolerate roughly one interstitial every 3 levels, runners every 2–3 runs, idle games on return after several hours away. Watch Day-1 retention in Play Console; if it drops after ads go live, your frequency is too aggressive.
-
Use Ad Inspector (
MobileAds.OpenAdInspector(...), SDK 9.0+) to debug ad delivery on a real device without flooding it with live impressions in test mode. - Don't over-rely on geo-targeting hacks — you can't force Tier-1 eCPMs, but solid English-language ASO naturally pulls in higher-value traffic even for a globally published game.
A Note on Starting From a Template vs. From Scratch
If you're newer to Unity, there's a real temptation to build every system — including the ad layer — completely from scratch as a learning exercise. That's valuable up to a point, but it also means re-solving scene architecture, save systems, and ad placement hooks that have already been solved reasonably well elsewhere, often at the cost of weeks you could be spending on the parts of the game that are actually unique to you.
There's a good breakdown of this exact tradeoff — what's worth building yourself early on versus what's smarter to start from an existing, well-structured project — in this piece on the best Unity projects for new developers and why your first one probably shouldn't be from scratch. Worth a read if you're deciding where to spend your limited time as you're getting monetization wired up for the first time.
Pre-Launch Checklist
Before you submit to Google Play or the App Store:
- [ ] All ad unit IDs are real production IDs, not test IDs
- [ ] App ID is correctly set in
AndroidManifest.xml - [ ] AdMob initializes before the first ad request fires
- [ ] Interstitials pre-load immediately after dismissal
- [ ] Rewarded ads only grant the reward inside the reward callback
- [ ] The app doesn't crash if an ad fails to load
- [ ] Ad Inspector confirms every format loads on a physical device
- [ ] Banners use anchored adaptive sizing
- [ ] No ads appear during active gameplay — only at transitions and menus
- [ ] Frequency capping is actually configured, not defaulted to "every level"
Wrapping Up
None of this is complicated once you've done it once, but nearly every point above is something developers get wrong on their first pass — usually because a tutorial stopped at "ad shows on screen" instead of covering pre-loading, frequency, and reward integrity. Get those four fundamentals right, and the rest of your monetization stack (mediation, IAP, live-ops) has something solid to build on top of instead of fighting a leaky foundation.
If you've integrated AdMob into a Unity project recently, I'd be curious what frequency caps and placements worked for your genre — drop them in the comments.
Top comments (0)