* chore(ads): remove ads experimental annotations * fix: remove duplicate import * fix: regenerate api baseliens * fix: os gate for public apis * fix(ads): add api documentation * fix(ads): doc was outdated * fix(ads): val to let * fix(ads): restore documentation * fix: remove objc support * fix: remove objc support * Update baseline swiftinterface files (#7625) --------- Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
Vanilla Ad Tracking Sample
This sample app demonstrates how to track Google AdMob ad events with RevenueCat by calling Purchases.shared.adTracker.trackXxx(...) directly in each AdMob callback.
Overview
Architecture
┌─────────────┐
│ AdMob SDK │
│ (Load Ads) │
└──────┬──────┘
│
│ Ad callbacks (delegate, completion, paidEventHandler)
▼
┌─────────────────────────┐
│ Your App Code │
│ (Manual tracking) │
│ │
│ Purchases.shared │
│ .adTracker │
│ .trackAdLoaded(...) │
│ .trackAdDisplayed(...)│
│ .trackAdOpened(...) │
│ .trackAdRevenue(...) │
│ .trackAdFailedToLoad(...)│
└──────┬──────────────────┘
│
│ RevenueCat events
▼
┌────────────────────────┐
│ RevenueCat Dashboard │
│ (Analytics) │
└────────────────────────┘
5 tracked events
| Event | When to call |
|---|---|
| Ad Loaded | Ad successfully loads (completion handler / delegate callback) |
| Ad Displayed | Ad impression is recorded (adDidRecordImpression / bannerViewDidRecordImpression) |
| Ad Opened | User clicks/interacts with ad (adDidRecordClick / bannerViewDidRecordClick) |
| Ad Revenue | Ad generates revenue (paidEventHandler) |
| Ad Failed to Load | Ad fails to load (error callback) |
Code example — manual interstitial tracking
import GoogleMobileAds
import RevenueCat
// Load
InterstitialAd.load(withAdUnitID: adUnitID, request: Request()) { [weak self] ad, error in
guard let self else { return }
if let error {
Purchases.shared.adTracker.trackAdFailedToLoad(AdFailedToLoad(
mediatorName: .adMob,
adFormat: .interstitial,
placement: "my_placement",
adUnitId: adUnitID,
mediatorErrorCode: (error as NSError).code
))
return
}
guard let ad else { return }
let responseInfo = ad.responseInfo
// Track loaded
Purchases.shared.adTracker.trackAdLoaded(AdLoaded(
networkName: responseInfo?.loadedAdNetworkResponseInfo?.adNetworkClassName ?? "",
mediatorName: .adMob,
adFormat: .interstitial,
placement: "my_placement",
adUnitId: adUnitID,
impressionId: responseInfo?.responseIdentifier ?? ""
))
// Track revenue
ad.paidEventHandler = { adValue in
Purchases.shared.adTracker.trackAdRevenue(AdRevenue(
networkName: responseInfo?.loadedAdNetworkResponseInfo?.adNetworkClassName ?? "",
mediatorName: .adMob,
adFormat: .interstitial,
placement: "my_placement",
adUnitId: adUnitID,
impressionId: responseInfo?.responseIdentifier ?? "",
revenueMicros: Int(adValue.value.multiplying(by: 1_000_000).int64Value),
currency: adValue.currencyCode,
precision: .estimated // map from adValue.precision
))
}
// Set delegate for impression/click tracking
ad.fullScreenContentDelegate = self
}
Ad formats demonstrated
This sample uses Google Mobile Ads SDK v13 Swift API:
- Banner —
BannerViewwithBannerViewDelegate - Interstitial —
InterstitialAd.load(...)withFullScreenContentDelegate - App Open —
AppOpenAd.load(...)withFullScreenContentDelegate - Rewarded —
RewardedAd.load(...)withFullScreenContentDelegate - Rewarded Interstitial —
RewardedInterstitialAd.load(...)withFullScreenContentDelegate - Native —
AdLoaderwithNativeAdLoaderDelegate+NativeAdDelegate - Native Video — native loader with a video-oriented ad unit ID
- Error Handling — intentionally invalid ad unit ID to validate failed-to-load tracking
Key files
Sources/App.swift— initializesGoogleMobileAds.MobileAdsandPurchasesSources/HomeView.swift— UI for loading/showing each ad format and statusSources/AdMobManager.swift— all manual ad tracking codeSources/Constants.swift— RevenueCat API key and AdMob ad unit IDs
Mediator name
This sample uses .adMob as the MediatorName in all tracking calls since it uses the AdMob SDK directly. If you use a different ad network or mediation platform, substitute the appropriate value:
.appLovinfor AppLovin MAXMediatorName(rawValue: "YourNetwork")for custom networks
Requirements
- Xcode 16+ recommended
- iOS Simulator or device (iOS 15+)
- Ad tracking APIs are available on iOS 15.0+.
- A valid RevenueCat API key
- AdMob test ad unit IDs (included in this sample)
- Google Mobile Ads SDK v13 (Swift API; this sample uses v13 naming)
RevenueCatfrom thepurchases-iospackageGoogleMobileAdsfrom the Google Mobile Ads SPM package
Setup & Run
1. Prerequisites
-
Get a RevenueCat API key
- Sign up at revenuecat.com
- Get your API key from the RevenueCat Dashboard
-
AdMob setup (optional for testing)
- This sample uses Google's official test ad unit IDs (see below)
- No AdMob account is required to run the sample as-is
- For production validation, create an AdMob account and replace IDs
2. Configure the app
- Open
Sources/Constants.swift. - Replace
YOUR_REVENUECAT_API_KEYwith your real RevenueCat API key. - Keep the default AdMob test ad unit IDs for local testing.
3. Build and run
- From the repository root, run
tuist generateto generate the Xcode workspace. - Open the generated workspace and select the
VanillaAdTrackingSamplescheme. - Run on an iPhone simulator or device.
4. Verify ad events
In the app:
- Tap an ad format from the list.
- Tap Load and wait for status to become
Ready. - Tap Show (where applicable).
- Interact with the ad and dismiss it.
The sample prints diagnostics in the Xcode console and emits RevenueCat ad events for each format. For dashboard verification, background the app after testing to trigger SDK flush.
Test ad unit IDs used by this sample
| Ad Format | Ad Unit ID | Status |
|---|---|---|
| Banner | ca-app-pub-3940256099942544/2435281174 |
Working |
| Interstitial | ca-app-pub-3940256099942544/4411468910 |
Working |
| Rewarded | ca-app-pub-3940256099942544/1712485313 |
Working |
| Rewarded Interstitial | ca-app-pub-3940256099942544/6978759866 |
Working |
| App Open | ca-app-pub-3940256099942544/5575463023 |
Working |
| Native | ca-app-pub-3940256099942544/2247696110 |
Unreliable |
| Native Video | ca-app-pub-3940256099942544/1044960115 |
Unreliable |
| Error Testing | invalid-ad-unit-id |
Working |
These are official Google test IDs and are safe for development.
Native ads and test IDs
Native and native video test IDs can be less reliable than other formats depending on environment. For more reliable native testing:
- Create ad units in your AdMob account
- Replace test IDs in
Sources/Constants.swift - Configure your device as a test device in AdMob
- Keep test mode enabled during validation
Error testing
AdMob does not provide an official "error trigger" test ad unit ID. This sample uses invalid-ad-unit-id to intentionally fail ad load requests and validate failed-to-load tracking.
Use the Error Testing section in the sample UI:
- Tap Trigger Ad Load Error.
- This uses
Constants.AdMob.invalidAdUnitIDto intentionally fail load. - Confirm failure is logged and failure tracking is emitted.
Troubleshooting
"Missing RevenueCat API key" or build fails at startup
Make sure revenueCatAPIKey in Sources/Constants.swift is set to your real RevenueCat API key (replace the YOUR_REVENUECAT_API_KEY placeholder).
Ads not loading
- No internet connection — ensure simulator/device has internet access
- AdMob SDK still initializing — wait a few seconds after launch
- Test device not configured — simulator is typically treated as test; real devices may require explicit setup in AdMob
- Ad unit mismatch — start with Google's test IDs before custom IDs
"Invalid request" on real device
Your device may not yet be recognized as a test device. Configure it in AdMob and retry after propagation.
Revenue events not visible
- Verify
Purchases.configure(withAPIKey:)is called (Sources/App.swift) - Keep
Purchases.logLevel = .debugduring troubleshooting - Confirm you are calling
adTracker.trackAdRevenue(...)in each ad'spaidEventHandler - Background the app after interactions so events flush sooner
Revenue callbacks missing in test mode
AdMob test ads may not always trigger paidEventHandler. Revenue tracking is more reliable with production ad units on configured test devices.
Tracking calls not appearing in console
- Confirm you're running on iOS 15+ (ad tracking APIs require
@available(iOS 15.0, *)) - Verify
Purchases.isConfiguredistruebefore tracking calls execute
AdMob SDK version note
This sample uses Google Mobile Ads v13; no compiler flag is required.