Most Unity developers treat AdMob integration as a one-hour checkbox task. They paste in an App ID, slap a banner at the bottom of the screen, and call it monetized.
Then they wonder why their published game earns $0.03 a day.
The gap between a game that earns $0.03/day and one that earns $30/day is not the ad network. It is the integration strategy — where ads fire, in what format, with what frequency, and whether the game's architecture was built to support any of that cleanly.
This guide covers the complete AdMob integration process from SDK setup through revenue optimization, with a specific focus on Unity game templates — and why templates give you a structural head start that from-scratch builds do not.
If you are looking for the companion piece on budget templates and C# architecture patterns, read Budget Unity Templates in 2026: 8 Projects Under $19 That Ship Real Mobile Games first. This article builds directly on that foundation.
Why Templates Are the Right Foundation for AdMob
Before touching a line of AdMob code, the most important decision is your starting architecture.
Developers who build from scratch spend the first month wiring together scene management, game loops, and UI flows — all before they can think about where a rewarded ad should actually fire. By the time the game feels playable, the monetization architecture is an afterthought bolted onto systems that were never designed to support it.
Templates built for mobile publishing solve this differently. The scene transitions, game-over flows, level progression, and retry loops already exist — and they exist in the exact places where ads earn the most. You are not finding space for AdMob. You are plugging into hooks that were designed for it.
The full breakdown of why this matters is in the How to Integrate AdMob into a Unity Game Template guide on the Unity Source Code blog. That article covers the complete integration flow and the genre-specific template recommendations in detail. What follows here is the technical architecture layer that goes alongside it.
Step 1: AdMob Account Setup — Do Not Skip the IDs
Before adding any SDK, you need two things from your AdMob account at admob.google.com:
App ID — formatted as ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX
Ad Unit IDs — one per format (banner, interstitial, rewarded, app open)
Create separate Ad Unit IDs for Android and iOS from the start. Setting this up now avoids a painful refactor when you add iOS later.
Using test IDs in production is the single most common reason developers see zero revenue despite real impressions. Real IDs only — in production builds.
Step 2: SDK Installation
Google's official plugin is the only supported path. No third-party wrappers.
- Download GoogleMobileAds.unitypackage from the Google Mobile Ads GitHub releases page
- Unity → Assets → Import Package → Custom Package
- Import all assets
- Assets → Google Mobile Ads → Settings
- Enter Android App ID and iOS App ID
After import, verify your AndroidManifest.xml was updated correctly:
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX"/>
If this block is missing or uses a placeholder, your app will crash on launch on Android. Not a graceful fail — a hard crash.
Step 3: Initialize Before Requesting Any Ads
This is where most integrations lose revenue silently. Requesting ads before the SDK is fully initialized produces failed loads that look like working code.
`pusing GoogleMobileAds.Api;
using System.Collections.Generic;
using UnityEngine;
public class AdsManager : MonoBehaviour
{
void Start()
{
MobileAds.Initialize(initStatus =>
{
Dictionary map = initStatus.getAdapterStatusMap();
foreach (KeyValuePair keyValuePair in map)
{
string className = keyValuePair.Key;
AdapterStatus status = keyValuePair.Value;
switch (status.InitializationState)
{
case AdapterState.NotReady:
Debug.Log("Adapter: " + className + " not ready.");
break;
case AdapterState.Ready:
Debug.Log("Adapter: " + className + " is initialized.");
break;
}
}
// Only load ads AFTER this callback fires
LoadInterstitialAd();
LoadRewardedAd();
});
}
}`
Make AdsManager a singleton with DontDestroyOnLoad. In a template project with multiple scenes per level, this is not optional — it is required for the manager to survive scene transitions.
Step 4: Implement Each Format Correctly
Banner Ads
Banners have the lowest eCPM but the highest fill rate. They belong on menus, results screens, and shop UIs — not during active gameplay, where they damage retention.
Use Anchored Adaptive Banners in 2026. Fixed-size 320x50 banners earn significantly less than adaptive variants that fill the full device width.
`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);
var adRequest = new AdRequest();
bannerView.LoadAd(adRequest);
}`
Interstitial Ads
Interstitials are the highest-volume format for casual and puzzle games. The money is in placement, not frequency. Showing them too often is the most common revenue-destroying mistake.
Natural placement triggers in Unity templates:
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 after a session
`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;
RegisterInterstitialEvents(interstitialAd);
});
}
public void ShowInterstitialAd()
{
if (interstitialAd != null && interstitialAd.CanShowAd())
{
interstitialAd.Show();
}
else
{
LoadInterstitialAd(); // Pre-load the next one
}
}
private void RegisterInterstitialEvents(InterstitialAd ad)
{
ad.OnAdFullScreenContentClosed += () =>
{
Debug.Log("Interstitial closed.");
LoadInterstitialAd(); // Always pre-load after dismiss
};
}`
Always pre-load the next interstitial immediately after dismiss. If you wait until the next trigger to load, the ad will not be ready in time and you will show nothing.
Rewarded Ads
Rewarded ads are the highest-eCPM format available. They are also opt-in — players choose to watch — which means zero retention penalty when placed at the right moment.
The strongest placement moments in template-based games: the "continue after game over" offer, hint unlocks in puzzle games, and extra lives or currency in runners.
`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: " + loadError);
return;
}
rewardedAd = ad;
});
}
public void ShowRewardedAd(System.Action onRewarded)
{
if (rewardedAd != null && rewardedAd.CanShowAd())
{
rewardedAd.Show(reward =>
{
Debug.Log("Rewarded: " + reward.Amount + " " + reward.Type);
onRewarded?.Invoke(); // Grant reward inside callback only
});
rewardedAd.OnAdFullScreenContentClosed += () =>
{
LoadRewardedAd(); // Pre-load next
};
}
}`
Never grant the in-game reward before the callback fires. The callback is the proof of completion.
App Open Ads
App Open Ads show when the player returns from the background. They earn high eCPM because re-entry is a natural, non-intrusive moment — and most Unity developers are not using them at all.
In 2026, App Open Ads typically add 10–25% to total ad revenue for games that retain players across multiple sessions.
`private AppOpenAd appOpenAd;
private 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 = DateTime.UtcNow;
});
}
public bool IsAdAvailable()
{
// App Open Ads expire after 4 hours
return appOpenAd != null && (DateTime.UtcNow - loadTime).TotalHours < 4;
}`
Step 5: Slot AdMob Into a Template's Architecture Cleanly
If you are working with a template that already has a GameManager and LevelManager, do not scatter ad calls across multiple scripts. One centralized AdsManager called through events keeps the logic auditable and easy to tune.
`// In LevelManager.cs
void OnLevelComplete()
{
levelCount++;
if (levelCount % 3 == 0)
{
AdsManager.Instance.ShowInterstitialAd();
}
LoadNextLevel();
}
void OnGameOver()
{
AdsManager.Instance.ShowInterstitialAd();
ShowGameOverUI();
}`
This pattern — frequency logic in LevelManager, ad execution in AdsManager — means you can adjust the interstitial cadence without touching any ad code. When you are tuning Day-1 retention after launch, this separation matters enormously.
Step 6: The Four Mobile Optimization Patterns That Support Ad Revenue
Ad revenue is directly tied to session length and retention. These four patterns appear in every quality template and directly affect both numbers.
Object Pooling Over Instantiate/Destroy
`// Wrong — GC spikes cause frame drops, users quit
Instantiate(coinPrefab, spawnPoint.position, Quaternion.identity);
Destroy(coin, 3f);
// Right — pre-allocated pool, no GC pressure
var coin = CoinPool.Instance.Get();
coin.transform.SetPositionAndRotation(spawnPoint.position, Quaternion.identity);
coin.OnDeactivate += () => CoinPool.Instance.Return(coin);
Cache Component References
csharp// Wrong — GetComponent every frame is expensive
void Update()
{
GetComponent().velocity = Vector3.zero;
}
// Right — cache once in Awake
private Rigidbody _rb;
void Awake() => _rb = GetComponent();
void Update() => _rb.velocity = Vector3.zero;
FixedUpdate for Physics, Update for Input
csharpprivate float _inputDirection;
void Update()
{
// Input is polled every rendered frame
_inputDirection = Input.GetAxis("Horizontal");
}
void FixedUpdate()
{
// Physics forces applied at fixed physics timestep
_rb.AddForce(Vector3.right * _inputDirection * moveForce);
}`
ScriptableObjects for Level Data
`[CreateAssetMenu(menuName = "Game/Level Config")]
public class LevelConfig : ScriptableObject
{
public int targetScore;
public float timeLimit;
public int moveCount;
public List tileWeights;
}
// Swap configs in Inspector to change levels — zero code changes
[SerializeField] private LevelConfig currentLevel;`
These four patterns are present in every professionally built template in the Unity Source Code catalog. Reading them in a real project context teaches you why they exist — something isolated tutorials consistently fail to demonstrate.
Step 7: Revenue Optimization After Launch
Integration is the setup. These are the levers that actually move the number.
Enable AdMob Mediation
Mediation lets multiple ad networks compete for each impression in real time. Adding even one additional network through Open Bidding (Meta Audience Network, AppLovin, Unity Ads) typically lifts eCPM by 20–40%.
Tune Frequency Carefully
The default "show every level" approach destroys Day-1 retention. Start conservative:
- Puzzle games: every 3 levels
- Runner games: every 2–3 runs
- Idle games: on app open after 4+ hours away
Monitor Day-1 retention in Google Play Console. If it drops below your genre benchmark after AdMob goes live, your frequency is too high.
Use Ad Inspector Before Launch
MobileAds.OpenAdInspector(error =>
{
if (error != null) Debug.LogError("Ad Inspector error: " + error);
});
Ad Inspector (available since AdMob SDK 9.0+) lets you test real ad rendering on a physical device without enabling test mode globally. Use it to confirm every format loads before submitting to the stores.
Step 8: Pre-Launch Checklist
Run through this before submitting 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
- Interstitials pre-load immediately after dismiss
- Rewarded ads grant reward only inside the callback
- App does not crash when an ad fails to load
- Ad Inspector confirms all formats on a physical device
- Banners use Anchored Adaptive sizing
- No ads shown during active gameplay
- Frequency capping is configured
*Genre-Format Pairing: What Earns What
*
Not all genres earn equally. Here is how ad formats match to template types:
High session length → more interstitials:
Action RPG loops (Archero-style) and idle games keep players in-session longer, compounding interstitial opportunities.
High level count → perfect interstitial cadence:
Sort puzzles and match games have short levels — frequent, natural triggers.
Strong rewarded placement:
Runner games with the "revive and continue" mechanic. Puzzle games with hint systems. These are the highest-converting rewarded placements in mobile gaming.
The full template recommendations with direct links are in the AdMob integration guide on the Unity Source Code blog, where each genre recommendation includes specific rationale for why the ad-game loop fits.
Where to Go From Here
AdMob integration is one layer of a larger publish-and-earn system. The full architecture — genre selection, session design, retention tuning, and in-app purchase strategy — is covered in the Unity Source Code blog:
- Budget Unity Templates in 2026: 8 Projects Under $19 — the C# architecture deep-dive on the exact templates that work for this integration
Browse the full library of 500+ AdMob-compatible templates — including bestsellers, flash sale items, and free downloads — at Unity Source Code.
Pick a template. Read the code. Publish the game. Then come back for the next one.
Top comments (0)