Skip to main content

AdMob SDK integration

Quick setup for AdMob ad monetization on iOS and Android with RevenueCat

AIAsk AIChatGPTClaude

The RevenueCat AdMob integration provides helper methods that wrap standard AdMob ad loading calls. Use loadAndTrack methods to automatically track all ad events across every major AdMob format — Banner, Interstitial, Rewarded, Rewarded Interstitial, App Open, and Native.

📘Beta feature — opt-in required

This feature is currently in beta. To enable it, visit the Ads page in your RevenueCat dashboard to opt in.

Before integrating, install the AdMob Adapter SDK and complete the required AdMob configuration. Requires purchases-ios 5.0+ (iOS 15+) or purchases-android 8.0+, plus the Google Mobile Ads SDK.

The loadAndTrack methods automatically track the following events, captured from AdMob's callbacks with no additional code required:

  • Ad Loaded — Ad successfully loads
  • Ad Displayed — Ad impression is recorded
  • Ad Opened — Customer clicks the ad
  • Ad Revenue — Ad generates revenue (via AdMob's paid event handler)
  • Ad Failed to Load — Ad fails to load

Quick start

1. Import the module

@_spi(Experimental) import RevenueCatAdMob

These APIs are experimental and require explicit opt-in. iOS opts in through the @_spi(Experimental) attribute on the import (shown above). On Android, annotate each class or function that calls loadAndTrack with @OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class), as shown in the examples below.

2. Replace load calls with loadAndTrack

Replace standard AdMob load calls with loadAndTrack methods:

// Before
InterstitialAd.load(with: adUnitID, request: Request()) { ad, error in
ad?.fullScreenContentDelegate = self
self.interstitialAd = ad
}

// After
InterstitialAd.loadAndTrack(
withAdUnitID: adUnitID,
request: Request(),
placement: "level_complete",
fullScreenContentDelegate: self
) { ad, error in
self.interstitialAd = ad
}

Implementation examples

@_spi(Experimental) import RevenueCatAdMob

let bannerView = BannerView(adSize: AdSize(size: CGSize(width: 320, height: 50), flags: 0))
bannerView.adUnitID = "ca-app-pub-3940256099942544/2435281174"

bannerView.loadAndTrack(
request: Request(),
placement: "home_banner"
)

Interstitial ads

@_spi(Experimental) import RevenueCatAdMob

class MyViewController: UIViewController, FullScreenContentDelegate {
private var interstitialAd: InterstitialAd?

func loadInterstitial() {
InterstitialAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/4411468910",
request: Request(),
placement: "level_complete",
fullScreenContentDelegate: self
) { [weak self] ad, error in
if let error { return }
self?.interstitialAd = ad
}
}

func showInterstitial() {
interstitialAd?.present(from: self)
}
}

Rewarded ads

@_spi(Experimental) import RevenueCatAdMob

func loadRewardedAd() {
RewardedAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/1712485313",
request: Request(),
placement: "bonus_coins",
fullScreenContentDelegate: self
) { [weak self] ad, error in
if let error { return }
self?.rewardedAd = ad
}
}

func showRewardedAd() {
rewardedAd?.present(from: self) {
// User earned reward
}
}

Rewarded interstitial ads

@_spi(Experimental) import RevenueCatAdMob

func loadRewardedInterstitialAd() {
RewardedInterstitialAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/6978759866",
request: Request(),
placement: "between_levels",
fullScreenContentDelegate: self
) { [weak self] ad, error in
if let error { return }
self?.rewardedInterstitialAd = ad
}
}

func showRewardedInterstitialAd() {
rewardedInterstitialAd?.present(from: self) {
// User earned reward
}
}

App open ads

@_spi(Experimental) import RevenueCatAdMob

func loadAppOpenAd() {
AppOpenAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/5575463023",
request: Request(),
placement: "app_launch",
fullScreenContentDelegate: self
) { [weak self] ad, error in
if let error { return }
self?.appOpenAd = ad
}
}

Native ads

@_spi(Experimental) import RevenueCatAdMob

let adLoader = AdLoader(
adUnitID: "ca-app-pub-3940256099942544/3986624511",
rootViewController: self,
adTypes: [.native],
options: nil
)
adLoader.delegate = self

adLoader.loadAndTrack(
Request(),
placement: "feed",
nativeAdDelegate: self
)

Placement parameter

The placement parameter identifies where ads appear in your app and is used for reporting and segmentation in Ad Charts.

Use consistent, descriptive names like "home_banner" or "level_complete_interstitial". Avoid dynamic values or timestamps.

Show-time placement override

For full-screen ads, you can set the placement when showing the ad instead of at load time. This is useful when you preload an ad before knowing where it will be shown:

// Load once, without a specific placement
InterstitialAd.loadAndTrack(
withAdUnitID: adUnitID,
request: Request(),
fullScreenContentDelegate: self
) { [weak self] ad, error in
self?.cachedAd = ad
}

// Show with placement depending on where the user is
cachedAd?.present(from: self, placement: "level_complete")

The show-time placement applies to Ad Displayed, Ad Opened, and Ad Revenue events. Ad Loaded and Ad Failed to Load always use the load-time placement.

Optional parameters and callbacks

Beyond placement, all loadAndTrack methods accept optional parameters — a load completion/callback, a full-screen content delegate/callback, and a paid-event handler/listener:

InterstitialAd.loadAndTrack(
withAdUnitID: adUnitID,
request: Request(),
placement: "level_complete", // Optional: for reporting
fullScreenContentDelegate: self, // Optional: ad lifecycle callbacks
paidEventHandler: { adValue in
// Optional: your custom paid event handling
}
) { ad, error in
// Optional: your load completion handler
}

RevenueCat wraps your full-screen content delegate (iOS) or callback (Android) at load time to add tracking before forwarding events to your handlers. If you need to set or change it after loading, use the tracking-aware setter instead of assigning it directly:

// ✅ Set delegate at load time
InterstitialAd.loadAndTrack(
withAdUnitID: adUnitID,
request: Request(),
placement: "level_complete",
fullScreenContentDelegate: self
) { ad, error in }

// ✅ Or set/change delegate after load — safe
ad?.setTrackingFullScreenContentDelegate(myDelegate)

// ❌ Don't do this — overwrites tracking
ad?.fullScreenContentDelegate = myDelegate

The tracking-aware setter — setTrackingFullScreenContentDelegate on iOS and setTrackingFullScreenContentCallback on Android — is available on all full-screen ad types: InterstitialAd, AppOpenAd, RewardedAd, and RewardedInterstitialAd.

The delegate/callback parameter on loadAndTrack methods is optional and defaults to none, so you can omit it at load time and set it later with the tracking-aware setter.

Troubleshooting

Testing your integration

Before troubleshooting, verify your events are being tracked:

  1. Run your app in debug mode
  2. Navigate to the Ads page in your RevenueCat dashboard
  3. Toggle on "Sandbox data"
  4. Trigger some ads in your app
  5. Check that events appear in the sandbox events table

Events from debug builds are automatically marked as sandbox. This lets you verify your integration without affecting production data.

Note on event timing: Ad events are not synced to the dashboard in real-time. The SDK batches and sends events periodically. If you've triggered several ads and don't see events immediately, try putting your app in the background and bringing it back to the foreground to trigger a sync. This is normal behavior and doesn't indicate an integration issue.

Events not appearing in charts

  1. Verify that "Impression-level ad revenue" is enabled in your AdMob account (instructions)
  2. Verify you've opted in via the Ads page in your RevenueCat dashboard
  3. Check that you're using loadAndTrack methods (not standard AdMob methods)
  4. Ensure placement parameter is provided
  5. Verify ads are actually loading and showing (check AdMob callbacks)
  6. Use the sandbox data view (above) to confirm events are being received

Compilation errors

Make sure you've added the experimental opt-in — the @_spi(Experimental) import on iOS, or the @OptIn annotation on Android:

@_spi(Experimental) import RevenueCatAdMob

Next steps

Was this page helpful?