---
id: "ad-monetization/admob"
title: "AdMob SDK integration"
description: "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."
permalink: "/docs/ad-monetization/admob"
slug: "admob"
version: "current"
original_source: "docs/ad-monetization/admob.mdx"
---

> **AI agents:** This is the Markdown version of a RevenueCat documentation page. For the complete documentation index, see [llms.txt](https://www.revenuecat.com/docs/llms.txt).

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.

:::info\[Beta feature]
This feature is currently in beta.
:::

**Before integrating, [install the AdMob Adapter SDK](https://www.revenuecat.com/docs/getting-started/adapter-sdks/admob) 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

```swift
@_spi(Experimental) import RevenueCatAdMob
```

```kotlin
import com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.admob.* // AdMob helper extensions
```

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. On iOS, every `loadAndTrack` method offers both an `async/await` and a completion-handler variant — pick whichever matches your code style:

**Swift (async/await)**

```swift
// 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
)
```

```swift
// 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
}
```

```kotlin
// Before
RewardedAd.load(context, adUnitId, adRequest, callback)

// After
Purchases.sharedInstance.adTracker.loadAndTrackRewardedAd(
    context = context,
    adUnitId = adUnitId,
    adRequest = adRequest,
    placement = "bonus_coins",
    loadCallback = callback
)
```

## Implementation examples

### Banner ads

```swift
@_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"
)
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
@Composable
fun BannerAdView() {
    AndroidView(
        factory = { context ->
            AdView(context).apply {
                adUnitId = "ca-app-pub-3940256099942544/9214589741"
                setAdSize(AdSize.BANNER)

                // Load with tracking
                Purchases.sharedInstance.adTracker.loadAndTrackBannerAd(
                    adView = this,
                    adRequest = AdRequest.Builder().build(),
                    placement = "home_banner"
                )
            }
        }
    )
}
```

### Interstitial ads

**Swift (async/await)**

```swift
@_spi(Experimental) 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)
    }
}
```

```swift
@_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)
    }
}
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
class MyActivity : AppCompatActivity() {
    private var interstitialAd: InterstitialAd? = null

    fun loadInterstitial() {
        Purchases.sharedInstance.adTracker.loadAndTrackInterstitialAd(
            context = this,
            adUnitId = "ca-app-pub-3940256099942544/1033173712",
            adRequest = AdRequest.Builder().build(),
            placement = "level_complete",
            loadCallback = object : InterstitialAdLoadCallback() {
                override fun onAdLoaded(ad: InterstitialAd) {
                    interstitialAd = ad
                }

                override fun onAdFailedToLoad(error: LoadAdError) {
                    interstitialAd = null
                }
            }
        )
    }

    fun showInterstitial() {
        interstitialAd?.show(this)
    }
}
```

### Rewarded ads

**Swift (async/await)**

```swift
@_spi(Experimental) 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
    }
}
```

```swift
@_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
    }
}
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
fun loadRewardedAd(context: Context) {
    Purchases.sharedInstance.adTracker.loadAndTrackRewardedAd(
        context = context,
        adUnitId = "ca-app-pub-3940256099942544/5224354917",
        adRequest = AdRequest.Builder().build(),
        placement = "bonus_coins",
        loadCallback = object : RewardedAdLoadCallback() {
            override fun onAdLoaded(ad: RewardedAd) {
                // Ad loaded successfully
                ad.show(activity) { reward ->
                    // User earned reward
                    grantCoins(reward.amount)
                }
            }

            override fun onAdFailedToLoad(error: LoadAdError) {
                // Handle error
            }
        }
    )
}
```

### Rewarded interstitial ads

**Swift (async/await)**

```swift
@_spi(Experimental) 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
    }
}
```

```swift
@_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
    }
}
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
fun loadRewardedInterstitialAd(context: Context) {
    Purchases.sharedInstance.adTracker.loadAndTrackRewardedInterstitialAd(
        context = context,
        adUnitId = "ca-app-pub-3940256099942544/5354046379",
        adRequest = AdRequest.Builder().build(),
        placement = "between_levels",
        loadCallback = object : RewardedInterstitialAdLoadCallback() {
            override fun onAdLoaded(ad: RewardedInterstitialAd) {
                ad.show(activity) { reward ->
                    // User earned reward
                }
            }

            override fun onAdFailedToLoad(error: LoadAdError) {
                // Handle error
            }
        }
    )
}
```

### App open ads

**Swift (async/await)**

```swift
@_spi(Experimental) 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
    }
}
```

```swift
@_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
    }
}
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
fun loadAppOpenAd(context: Context) {
    Purchases.sharedInstance.adTracker.loadAndTrackAppOpenAd(
        context = context,
        adUnitId = "ca-app-pub-3940256099942544/9257395921",
        adRequest = AdRequest.Builder().build(),
        placement = "app_launch",
        loadCallback = object : AppOpenAd.AppOpenAdLoadCallback() {
            override fun onAdLoaded(ad: AppOpenAd) {
                // Ad loaded successfully
            }

            override fun onAdFailedToLoad(error: LoadAdError) {
                // Handle error
            }
        }
    )
}
```

### Native ads

```swift
@_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
)
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
val adLoader = AdLoader.Builder(context, "ca-app-pub-3940256099942544/2247696110")
    // Use forNativeAdWithTracking in place of the standard forNativeAd
    .forNativeAdWithTracking(
        adUnitId = "ca-app-pub-3940256099942544/2247696110",
        placement = "feed",
    ) { nativeAd ->
        // Use the loaded native ad
    }
    .build()

// Load as usual with the standard AdLoader.loadAd() call
adLoader.loadAd(AdRequest.Builder().build())
```

## Placement parameter

The `placement` parameter identifies where ads appear in your app and is used for reporting and segmentation in [Ad Charts](https://www.revenuecat.com/docs/dashboard-and-metrics/charts/ads).

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:

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

```kotlin
// Load once, without a specific placement
Purchases.sharedInstance.adTracker.loadAndTrackInterstitialAd(
    context = context,
    adUnitId = adUnitId,
    adRequest = AdRequest.Builder().build(),
    loadCallback = object : InterstitialAdLoadCallback() {
        override fun onAdLoaded(ad: InterstitialAd) {
            cachedAd = ad
        }
    }
)

// Show with placement depending on where the user is
cachedAd?.show(activity, "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:

```swift
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
}
```

```kotlin
Purchases.sharedInstance.adTracker.loadAndTrackInterstitialAd(
    context = context,
    adUnitId = adUnitId,
    adRequest = adRequest,
    placement = "level_complete", // Optional: for reporting
    loadCallback = callback,      // Optional: your load callback
    fullScreenContentCallback = contentCallback, // Optional: for ad lifecycle
    onPaidEventListener = paidListener          // Optional: your paid event listener
)
```

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:

```swift
// ✅ 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
```

```kotlin
import com.revenuecat.purchases.admob.setTrackingFullScreenContentCallback

// ✅ Set callback at load time
Purchases.sharedInstance.adTracker.loadAndTrackInterstitialAd(
    context = context,
    adUnitId = adUnitId,
    adRequest = adRequest,
    placement = "level_complete",
    fullScreenContentCallback = myCallback
)

// ✅ Or set/change callback after load — safe
ad.setTrackingFullScreenContentCallback(myCallback)

// ❌ Don't do this — overwrites tracking
ad.fullScreenContentCallback = myCallback
```

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](https://support.google.com/admob/answer/11322405))
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:

```swift
@_spi(Experimental) import RevenueCatAdMob
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
```

## Next steps

- Explore the example projects: [iOS](https://github.com/RevenueCat/purchases-ios-admob/tree/main/Examples/AdMobIntegrationSample) and [Android](https://github.com/RevenueCat/purchases-android/tree/main/examples/admob-sample)
- View your ad data in [Ad Charts](https://www.revenuecat.com/docs/dashboard-and-metrics/charts/ads), and see the [Ad Monetization overview](https://www.revenuecat.com/docs/ad-monetization#data-availability) for where it appears across the dashboard
- [Connect your Google AdMob account](https://www.revenuecat.com/docs/integrations/third-party-integrations/google-admob) to sync ad unit names for more readable charts — no code changes required
- Learn about [Manual Integration](https://www.revenuecat.com/docs/ad-monetization/manual-integration) for other mediation platforms
