Skip to main content
Skip to navigation

AdMob SDK integration

Track AdMob events on iOS, Android, Flutter, React Native, and Unity with the RevenueCat AdMob adapters

AIAsk AIChatGPTClaude

The RevenueCat AdMob adapters wrap the standard Google Mobile Ads load calls with automatic event tracking. There is one adapter per platform; they share the same concepts, so this guide shows every platform side by side.

📘Beta feature

This feature is currently in beta.

Before integrating, install the AdMob Adapter SDK for your platform. The installation guide lists the minimum RevenueCat SDK and Google Mobile Ads versions.

Once an ad is loaded through the adapter, the following events are tracked from AdMob's callbacks with no additional code:

  • 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
  • Ad Reward Earned — The user earns a rewarded ad's reward. With reward verification it is reported as part of the verification funnel instead; without it, the Flutter, React Native and Unity adapters report it as unverified when the ad is shown through showAndTrack

The adapters can't track Rewarded Ad Prompt Shown and Rewarded Ad Prompt Accepted, because only your app knows when it offers a rewarded ad. Call those two methods yourself; see Track rewarded ad prompts.

Choose an adapter​

Pick the code tab that matches your platform and Google Mobile Ads SDK:

PlatformGoogle Mobile Ads SDKCode tab
iOSGoogle Mobile Ads SDKSwift
AndroidLegacy Google Mobile Ads SDK (play-services-ads)Kotlin (Legacy AdMob)
AndroidGoogle Mobile Ads Next-Gen SDK (ads-mobile-sdk)Kotlin (Next-Gen AdMob)
Fluttergoogle_mobile_ads pluginFlutter
React Nativereact-native-google-mobile-adsReact Native
UnityGoogle Mobile Ads Unity pluginUnity

The two Android adapters are mutually exclusive. The Next-Gen adapter is Kotlin-only; Java apps can use the base AdTracker APIs directly.

Quick start​

1. Configure the SDKs and import the adapter​

Configure Purchases and initialize the Google Mobile Ads SDK as you normally would, before the first ad loads; the adapter only tracks while Purchases is configured. On Unity, also point the adapter at your configured Purchases component once with RevenueCatAdMob.Initialize(purchases); the Unity SDK has no shared singleton. The snippets on this page use Google's test ad unit IDs (TestIds on React Native, which picks the right ID per platform); replace them with your own. The IDs hardcoded in the Flutter snippets are the iOS test IDs; on Android use the matching Android test ad unit IDs.

import RevenueCatAdMob

2. Replace load calls with the adapter​

Replace the standard AdMob load call with the adapter's loadAndTrack equivalent and pass a placement. On React Native, create the ad through RevenueCatAdMob.create... instead of createForAdRequest; the returned object is the same ad class. Show full-screen ads through the adapter as well, so it can apply a show-time placement. On iOS, every method has an async/await and a completion-handler variant:

// Before
let ad = try await InterstitialAd.load(with: adUnitID, request: Request())
ad.fullScreenContentDelegate = self
self.interstitialAd = ad

// After
self.interstitialAd = try await InterstitialAd.loadAndTrack(
withAdUnitID: adUnitID,
request: Request(),
placement: "level_complete",
fullScreenContentDelegate: self
)

The placement identifies where the ad appears and drives reporting in Ad Charts. Use stable, descriptive names like "home_banner" or "level_complete_interstitial", never dynamic values.

Implementation examples​

On Flutter the banner listener is given at construction time, so create the banner with createBannerAd or wrap your listener with trackingBannerAdListener. On React Native BannerAd is a component, so the adapter provides the useTrackingBannerAdProps hook; class components call RevenueCatAdMob.trackingBannerAdProps once per banner instance instead. On Unity attach tracking with TrackBannerView right after constructing the BannerView. With these adapters a banner refresh reports a new loaded event with the new response ID.

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​

import RevenueCatAdMob

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

func loadInterstitial() async {
do {
self.interstitialAd = try await InterstitialAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/4411468910",
request: Request(),
placement: "level_complete",
fullScreenContentDelegate: self
)
} catch {
// Handle error
}
}

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

Rewarded ads​

To verify the earned reward with RevenueCat and grant it server-side, see Granting Ad Rewards.

import RevenueCatAdMob

func loadRewardedAd() async {
do {
self.rewardedAd = try await RewardedAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/1712485313",
request: Request(),
placement: "bonus_coins",
fullScreenContentDelegate: self
)
} catch {
// Handle error
}
}

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

Rewarded interstitial ads​

import RevenueCatAdMob

func loadRewardedInterstitialAd() async {
do {
self.rewardedInterstitialAd = try await RewardedInterstitialAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/6978759866",
request: Request(),
placement: "between_levels",
fullScreenContentDelegate: self
)
} catch {
// Handle error
}
}

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

App open ads​

import RevenueCatAdMob

func loadAppOpenAd() async {
do {
self.appOpenAd = try await AppOpenAd.loadAndTrack(
withAdUnitID: "ca-app-pub-3940256099942544/5575463023",
request: Request(),
placement: "app_launch",
fullScreenContentDelegate: self
)
} catch {
// Handle error
}
}

Native ads​

On Flutter wrap the native ad listener with trackingNativeAdListener and render the loaded ad in an AdWidget with a bounded size; displayed, opened and revenue are reported once it is on screen. On React Native call RevenueCatAdMob.trackNativeAd once NativeAd.createForAdRequest resolves; the loaded event is reported immediately and the rest once the ad is rendered in NativeAdView. On Unity call TrackNativeOverlayAd on the loaded NativeOverlayAd.

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
)

Show-time placement​

For full-screen ads you can set the placement when showing instead of when loading, which helps when you preload an ad before knowing where it will appear. The show-time placement applies to Ad Displayed, Ad Opened, and Ad Revenue events; Ad Loaded and Ad Failed to Load keep the load-time placement.

// 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")

Your own callbacks​

On iOS and Android the lifecycle callback parameter of every loadAndTrack method is optional; the adapter wraps the callback you pass and forwards every event to it after tracking. If you set or replace the callback after loading, use the tracking-aware setter: setTrackingFullScreenContentDelegate on iOS, setTrackingFullScreenContentCallback on legacy Android, setTrackingAdEventCallback on Android Next-Gen (plus setTrackingBannerAdRefreshCallback for banner refreshes). On Flutter, set fullScreenContentCallback and onPaidEvent inside onAdLoaded as usual and the adapter wraps them; to assign the callback later, use setTrackingFullScreenContentCallback. On React Native listeners are additive, and RevenueCatAdMob.trackAd attaches tracking to an ad you created yourself, before load(). On Unity the Google events are multicast, so your own += handlers keep working next to the adapter's.

// Pass the full-screen content delegate when loading the ad.
InterstitialAd.loadAndTrack(
withAdUnitID: adUnitID,
request: Request(),
placement: "level_complete",
fullScreenContentDelegate: self
) { ad, error in }

// Or replace it later with the tracking-safe setter.
ad?.setTrackingFullScreenContentDelegate(myDelegate)

// Don't assign it directly. This replaces RevenueCat's tracking wrapper.
ad?.fullScreenContentDelegate = myDelegate

Reward verification​

Rewarded and rewarded interstitial ads can have their rewards verified by RevenueCat before you grant them: enable verification on the ad (an option when creating it on React Native) and show it with showWithRewardVerification. The dashboard setup and the code for every platform are in Granting Ad Rewards.

Android Next-Gen features​

The Android Next-Gen adapter supports additional Google Mobile Ads Next-Gen loading workflows. These APIs are only available in the Kotlin (Next-Gen AdMob) integration.

Suspending loads​

Interstitial, rewarded, rewarded interstitial, app open, and native helpers have suspending overloads. They return Google's original result with RevenueCat tracking installed on successful ads:

lifecycleScope.launch {
when (
val result = Purchases.sharedInstance.adTracker.loadAndTrackInterstitialAd(
adRequest = AdRequest.Builder("AD_UNIT_ID").build(),
placement = "game_interstitial",
)
) {
is AdLoadResult.Success -> interstitialAd = result.ad
is AdLoadResult.Failure -> interstitialAd = null
}
}

Direct banner loading remains callback-based because Google doesn't provide a supported suspending AdView.loadAd API.

Preloading​

All six supported formats work with Google's preloaders. Track preload success or failure with startAndTrack, then install lifecycle tracking on a buffered ad with pollAndTrackAd:

val preloadConfiguration = PreloadConfiguration(
request = AdRequest.Builder("AD_UNIT_ID").build(),
bufferSize = 2,
)

InterstitialAdPreloader.startAndTrack(
preloadId = "game-interstitial-buffer",
preloadConfiguration = preloadConfiguration,
placement = "game_interstitial_preload",
preloadCallback = object : PreloadCallback {},
)

// Later, adopt a buffered ad. Polling doesn't emit another loaded event.
interstitialAd = InterstitialAdPreloader.pollAndTrackAd(
preloadId = "game-interstitial-buffer",
placement = "game_interstitial",
adEventCallback = interstitialAdEventCallback,
)

interstitialAd?.show(this)

The placements supplied to startAndTrack and pollAndTrackAd are independent. Polling doesn't emit another loaded event. Use the corresponding preloader extensions for banner, app open, native, rewarded, and rewarded interstitial ads.

Other loading workflows​

The Next-Gen adapter also supports server-to-server ad responses for every format and single or batched native-ad loading. See the Android Next-Gen advanced loading guide for complete examples.

Migrate from the legacy Android adapter

The Next-Gen adapter isn't a drop-in binary replacement for the legacy adapter. Migrate the Google Mobile Ads SDK and RevenueCat adapter together:

  1. Replace the legacy dependencies with purchases-admob-next-gen and ads-mobile-sdk.
  2. Change RevenueCat imports from com.revenuecat.purchases.admob to com.revenuecat.purchases.admob.nextgen.
  3. Update Google imports from com.google.android.gms.ads to com.google.android.libraries.ads.mobile.sdk.
  4. Update requests and callbacks to the Next-Gen types shown in this guide.
  5. Keep existing placement values when they identify the same ad slots so reporting remains consistent.

Next-Gen requests own the ad unit ID. BannerAdRequest also owns the banner size that the legacy SDK stored on AdView. Next-Gen callbacks may run on a background thread, so dispatch to the main thread before updating UI-confined state.

Review Google's Next-Gen migration guide for SDK and mediation changes.

Platform notes​

  • iOS availability: Ad tracking requires iOS 15.0+. On older versions calls are ignored and a warning is logged, including through the Flutter, React Native and Unity adapters.
  • React Native: Requires react-native-google-mobile-ads 17.x and the New Architecture (17.0.0 needs React Native 0.76+, 17.1.0+ needs 0.86+). The library's useInterstitialAd / useRewardedAd hooks, ad pools and multi-format requests create their own ads and are not tracked; use the class API shown above. Web is not supported.
  • Flutter: Requires google_mobile_ads 8.x; 9.x isn't supported yet.
  • Unity: Requires the Google Mobile Ads Unity plugin 10.x or newer, installed from OpenUPM or the .unitypackage. Purchases creates its native wrapper in its own Start(), so with runtime setup call Configure only after that has run; RevenueCatAdMob.Initialize(purchases) just stores the reference and can be called earlier. The adapter tracks from whichever thread Google raises its callbacks on; enable MobileAds.RaiseAdEventsOnUnityMainThread only if your own callbacks touch Unity objects.

Troubleshooting​

Testing your integration​

  1. Run your app in debug mode
  2. Open the Ads page in your RevenueCat dashboard and toggle on "Sandbox data"
  3. Trigger some ads in your app and check that events appear in the sandbox events table

Events from debug builds are marked as sandbox, so you can verify the integration without affecting production data. Events are batched and sent periodically, not in real time. On iOS, backgrounding and foregrounding the app triggers a sync; Android flushes shortly after each event.

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 ads are loaded through the adapter and shown with its show methods, not the plain Google Mobile Ads calls
  4. Ensure a placement is provided and Purchases is configured before ads load
  5. Use the sandbox data view (above) to confirm events are being received

Next steps​

Was this page helpful?