Manual Integration
Track ad events from any mediation platform that provides ILRD
Track ad events from any mediation platform that provides impression-level revenue data (ILRD) by calling AdTracker methods from your SDK callbacks. Ad impressions, clicks, and revenue appear alongside your subscription data in RevenueCat Charts.
This feature is currently in beta.
Overview
Manual integration gives you full control over ad event tracking and works with any mediation platform that supports ILRD, including:
- AppLovin MAX
- Unity LevelPlay (formerly ironSource)
- Unity Ads
- Any custom mediation setup
Hook into your mediation platform's callbacks and call the appropriate AdTracker methods.
How it works
- Your mediation platform fires a callback (e.g., ad loaded, ad displayed, revenue generated)
- You call the corresponding AdTracker method with the event data
- RevenueCat records the event and makes it available in Charts
Prerequisites
- SDK Version:
- Android:
purchases-android10.19.0+ - iOS:
purchases-ios5.89.0+ - Flutter:
purchases_flutter10.10.1+ - Unity:
purchases-unity9.9.0+ - React Native:
react-native-purchases10.8.1+
- Android:
- Rewarded ad prompt events (
trackRewardedAdPromptShownandtrackRewardedAdPromptAccepted) requirepurchases-ios5.92.0+,purchases-android10.24.0+,purchases_flutter10.15.0+,react-native-purchases10.12.0+,purchases-unity9.13.0+, orpurchases-kmp3.12.0+. - iOS Availability: Ad tracking requires iOS 15.0+ / tvOS 15.0+ / macOS 12.0+ / watchOS 8.0+. On older OS versions, calls are silently ignored and a warning is logged.
- ILRD Support: Your mediation platform must provide impression-level revenue data. If using Google AdMob, you must enable "Impression-level ad revenue" in your AdMob dashboard under Settings.
Android integration
1. Access the AdTracker
- Kotlin
import com.revenuecat.purchases.Purchases
val adTracker = Purchases.sharedInstance.adTracker
2. Import event types
- Kotlin
import com.revenuecat.purchases.ads.events.types.*
3. Track events from mediation callbacks
All track methods follow a similar pattern. Here are the two main examples:
Track ad loaded
Call when an ad successfully loads:
- Kotlin
fun onAdLoaded(ad: YourAdType) {
adTracker.trackAdLoaded(
AdLoadedData(
networkName = ad.networkName, // e.g., "Google Ads"
mediatorName = AdMediatorName.APP_LOVIN, // or custom: AdMediatorName.fromString("YourMediator")
adFormat = AdFormat.REWARDED, // BANNER, INTERSTITIAL, etc.
placement = "home_screen", // Your custom placement ID
adUnitId = ad.adUnitId, // Ad unit identifier
impressionId = ad.impressionId // Unique impression ID
)
)
}
Track ad revenue
Call when your mediation platform reports revenue for an impression:
- Kotlin
fun onAdRevenue(ad: YourAdType, revenue: Double, currency: String) {
adTracker.trackAdRevenue(
AdRevenueData(
networkName = ad.networkName,
mediatorName = AdMediatorName.APP_LOVIN,
adFormat = AdFormat.REWARDED,
placement = "home_screen",
adUnitId = ad.adUnitId,
impressionId = ad.impressionId,
revenueMicros = (revenue * 1_000_000).toLong(), // Convert to micros
currency = currency, // e.g., "USD"
precision = AdRevenuePrecision.EXACT // Or ESTIMATED, PUBLISHER_DEFINED
)
)
}
Other track methods
The remaining methods follow the same pattern as trackAdLoaded:
trackAdDisplayed(AdDisplayedData)- Call when ad impression is recorded (ad shown on screen)trackAdOpened(AdOpenedData)- Call when user clicks/taps the adtrackAdFailedToLoad(AdFailedToLoadData)- Call when ad fails to load (doesn't requirenetworkNameorimpressionId)trackRewardedAdPromptShown/trackRewardedAdPromptAccepted- Rewarded ads only; see Track rewarded ad prompts
See the Event data reference section below for complete parameter details.
iOS integration
1. Access the AdTracker
- Swift
import RevenueCat
let adTracker = Purchases.shared.adTracker
Ad tracking requires iOS 15.0+, tvOS 15.0+, macOS 12.0+, and watchOS 8.0+. On older OS versions, calls are silently ignored and a warning is logged.
2. Track events from mediation callbacks
All track methods follow a similar pattern. Here are the two main examples:
Track ad loaded
Call when an ad successfully loads:
- Swift
func onAdLoaded(ad: YourAdType) {
Purchases.shared.adTracker.trackAdLoaded(.init(
networkName: ad.networkName, // e.g., "Google Ads"
mediatorName: .appLovin, // or custom: .init(value: "YourMediator")
adFormat: .rewarded, // .banner, .interstitial, etc.
placement: "home_screen", // Your custom placement ID
adUnitId: ad.adUnitId, // Ad unit identifier
impressionId: ad.impressionId // Unique impression ID
))
}
Track ad revenue
Call when your mediation platform reports revenue for an impression:
- Swift
func onAdRevenue(ad: YourAdType, revenue: Double, currency: String) {
Purchases.shared.adTracker.trackAdRevenue(.init(
networkName: ad.networkName,
mediatorName: .appLovin,
adFormat: .rewarded,
placement: "home_screen",
adUnitId: ad.adUnitId,
impressionId: ad.impressionId,
revenueMicros: Int(revenue * 1_000_000), // Convert to micros
currency: currency, // e.g., "USD"
precision: .exact // Or .estimated, .publisherDefined
))
}
Other track methods
The remaining methods follow the same pattern as trackAdLoaded:
trackAdDisplayed(_:)- Call when ad impression is recorded (ad shown on screen)trackAdOpened(_:)- Call when user clicks/taps the adtrackAdFailedToLoad(_:)- Call when ad fails to load (doesn't requirenetworkNameorimpressionId)trackRewardedAdPromptShown(_:)/trackRewardedAdPromptAccepted(_:)- Rewarded ads only; see Track rewarded ad prompts
See the Event data reference section below for complete parameter details.
Flutter integration
1. Add the dependency
# pubspec.yaml
dependencies:
purchases_flutter: ^10.2.0
2. Access the AdTracker
- Flutter
import 'package:purchases_flutter/purchases_flutter.dart';
final adTracker = Purchases.adTracker;
Ad tracking requires iOS 15.0+, tvOS 15.0+, macOS 12.0+, and watchOS 8.0+. On older OS versions, calls are silently ignored and a warning is logged. Android has no version restriction.
3. Track events from mediation callbacks
All track methods follow a similar pattern. Here are the two main examples:
Track ad loaded
Call when an ad successfully loads:
- Flutter
void onAdLoaded(YourAdType ad) {
Purchases.adTracker.trackAdLoaded(
AdLoadedData(
networkName: ad.networkName, // e.g., "Google Ads"
mediatorName: AdMediatorName.adMob, // or custom: AdMediatorName('YourMediator')
adFormat: AdFormat.rewarded, // .banner, .interstitial, etc.
placement: 'home_screen', // Your custom placement ID
adUnitId: ad.adUnitId, // Ad unit identifier
impressionId: ad.impressionId, // Unique impression ID
),
);
}
Track ad revenue
Call when your mediation platform reports revenue for an impression:
- Flutter
void onAdRevenue(YourAdType ad, double revenue, String currency) {
Purchases.adTracker.trackAdRevenue(
AdRevenueData(
networkName: ad.networkName,
mediatorName: AdMediatorName.adMob,
adFormat: AdFormat.rewarded,
placement: 'home_screen',
adUnitId: ad.adUnitId,
impressionId: ad.impressionId,
revenueMicros: (revenue * 1_000_000).toInt(), // Convert to micros
currency: currency, // e.g., "USD"
precision: AdRevenuePrecision.exact, // or .estimated, .publisherDefined
),
);
}
Other track methods
The remaining methods follow the same pattern as trackAdLoaded:
trackAdDisplayed(AdDisplayedData)- Call when ad impression is recorded (ad shown on screen)trackAdOpened(AdOpenedData)- Call when user clicks/taps the adtrackAdFailedToLoad(AdFailedToLoadData)- Call when ad fails to load (doesn't requirenetworkNameorimpressionId)trackRewardedAdPromptShown/trackRewardedAdPromptAccepted- Rewarded ads only; see Track rewarded ad prompts
See the Event data reference section below for complete parameter details.
Unity integration
1. Add the dependency
Import com.revenuecat.purchases 9.1.0 via the Unity Package Manager.
2. Access the AdTracker
- Unity
using RevenueCat;
var adTracker = purchases.AdTracker; // 'purchases' is the Purchases MonoBehaviour on a GameObject
Ad tracking requires iOS 15.0+. On older iOS versions, calls are silently ignored and a warning is logged. The C# code compiles and runs on all platforms — the guard is applied in the native bridge layer.
3. Track events from mediation callbacks
All track methods follow a similar pattern. Here are the two main examples:
Track ad loaded
Call when an ad successfully loads:
- Unity
void OnAdLoaded(YourAdType ad)
{
purchases.AdTracker.TrackAdLoaded(new AdLoadedData(
mediatorName: AdTracker.MediatorName.AdMob, // or new AdTracker.MediatorName("YourMediator")
adFormat: AdTracker.Format.Rewarded, // .Banner, .Interstitial, etc.
adUnitId: ad.adUnitId, // Ad unit identifier
impressionId: ad.impressionId, // Unique impression ID
networkName: ad.networkName, // e.g., "Google Ads" (optional)
placement: "home_screen" // Your custom placement ID (optional)
));
}
Track ad revenue
Call when your mediation platform reports revenue for an impression:
- Unity
void OnPaidEvent(YourAdType ad, double revenue, string currency)
{
purchases.AdTracker.TrackAdRevenue(new AdRevenueData(
mediatorName: AdTracker.MediatorName.AdMob,
adFormat: AdTracker.Format.Rewarded,
adUnitId: ad.adUnitId,
impressionId: ad.impressionId,
revenueMicros: (long)(revenue * 1_000_000), // Convert to micros
currency: currency, // e.g., "USD"
precision: AdTracker.Precision.Exact // or .Estimated, .PublisherDefined
));
}
Other track methods
The remaining methods follow the same pattern as TrackAdLoaded:
TrackAdDisplayed(AdDisplayedData)- Call when ad impression is recorded (ad shown on screen)TrackAdOpened(AdOpenedData)- Call when user clicks/taps the adTrackAdFailedToLoad(AdFailedToLoadData)- Call when ad fails to load (doesn't requirenetworkNameorimpressionId)TrackRewardedAdPromptShown/TrackRewardedAdPromptAccepted- Rewarded ads only; see Track rewarded ad prompts
See the Event data reference section below for complete parameter details.
React Native integration
1. Add the dependency
npm install react-native-purchases@^10.2.0
# or
yarn add react-native-purchases@^10.2.0
2. Access the AdTracker
- React Native
import Purchases, {
AdMediatorName,
AdFormat,
AdRevenuePrecision,
} from "react-native-purchases";
const adTracker = Purchases.adTracker;
Ad tracking is not supported on web — calls are silently ignored. On iOS < 15.0, calls are also silently ignored and a warning is logged. Android has no version restriction.
3. Track events from mediation callbacks
All track methods follow a similar pattern. Here are the two main examples:
Track ad loaded
Call when an ad successfully loads:
- React Native
async function onAdLoaded(ad: YourAdType) {
await Purchases.adTracker.trackAdLoaded({
networkName: ad.networkName, // e.g., "Google Ads" (optional)
mediatorName: AdMediatorName.adMob, // or any string
adFormat: AdFormat.rewarded, // AdFormat.banner, .interstitial, etc.
placement: "home_screen", // Your custom placement ID (optional)
adUnitId: ad.adUnitId, // Ad unit identifier
impressionId: ad.impressionId, // Unique impression ID
});
}
Track ad revenue
Call when your mediation platform reports revenue for an impression:
- React Native
async function onAdRevenue(ad: YourAdType, revenue: number, currency: string) {
await Purchases.adTracker.trackAdRevenue({
networkName: ad.networkName,
mediatorName: AdMediatorName.adMob,
adFormat: AdFormat.rewarded,
placement: "home_screen",
adUnitId: ad.adUnitId,
impressionId: ad.impressionId,
revenueMicros: Math.round(revenue * 1_000_000), // Convert to micros
currency: currency, // e.g., "USD"
precision: AdRevenuePrecision.exact, // or .estimated, .publisherDefined
});
}
Other track methods
The remaining methods follow the same pattern as trackAdLoaded:
trackAdDisplayed(AdDisplayedData)- Call when ad impression is recorded (ad shown on screen)trackAdOpened(AdOpenedData)- Call when user clicks/taps the adtrackAdFailedToLoad(AdFailedToLoadData)- Call when ad fails to load (doesn't requirenetworkNameorimpressionId)trackRewardedAdPromptShown/trackRewardedAdPromptAccepted- Rewarded ads only; see Track rewarded ad prompts
See the Event data reference section below for complete parameter details.
Track rewarded ad prompts
Rewarded ads usually start with a prompt in your UI, such as a "Watch an ad to earn coins" button. Track that prompt to measure how many users see the offer and how many accept it before the ad loads:
- Rewarded Ad Prompt Shown - Call
trackRewardedAdPromptShownwhen the prompt appears. - Rewarded Ad Prompt Accepted - Call
trackRewardedAdPromptAcceptedwhen the user accepts the prompt (for example, taps the button).
Both events are manual-only: the AdMob adapter never emits them, because only your app knows when the prompt is presented or accepted. Call them even if you use the adapter for the rest of the ad lifecycle.
Both events are rewarded-only: adFormat is always rewarded and is set for you. They take only mediatorName, adUnitId, and an optional placement — there is no networkName or impressionId, because the ad has not loaded yet.
- Swift
- Kotlin
- Flutter
- Unity
- React Native
// When the "Watch an ad to earn coins" prompt appears
func onRewardPromptShown() {
Purchases.shared.adTracker.trackRewardedAdPromptShown(.init(
mediatorName: .appLovin, // or custom: .init(value: "YourMediator")
placement: "bonus_coins_rewarded", // Your custom placement ID
adUnitId: rewardedAdUnitId // Ad unit identifier
))
}
// When the user taps the prompt to watch the ad
func onRewardPromptAccepted() {
Purchases.shared.adTracker.trackRewardedAdPromptAccepted(.init(
mediatorName: .appLovin,
placement: "bonus_coins_rewarded",
adUnitId: rewardedAdUnitId
))
}
// When the "Watch an ad to earn coins" prompt appears
fun onRewardPromptShown() {
adTracker.trackRewardedAdPromptShown(
AdRewardPromptShownData(
mediatorName = AdMediatorName.APP_LOVIN, // or custom: AdMediatorName.fromString("YourMediator")
placement = "bonus_coins_rewarded", // Your custom placement ID
adUnitId = rewardedAdUnitId // Ad unit identifier
)
)
}
// When the user taps the prompt to watch the ad
fun onRewardPromptAccepted() {
adTracker.trackRewardedAdPromptAccepted(
AdRewardPromptAcceptedData(
mediatorName = AdMediatorName.APP_LOVIN,
placement = "bonus_coins_rewarded",
adUnitId = rewardedAdUnitId
)
)
}
// When the "Watch an ad to earn coins" prompt appears
void onRewardPromptShown() {
Purchases.adTracker.trackRewardedAdPromptShown(
AdRewardPromptShownData(
mediatorName: AdMediatorName.appLovin, // or custom: AdMediatorName('YourMediator')
placement: 'bonus_coins_rewarded', // Your custom placement ID
adUnitId: rewardedAdUnitId, // Ad unit identifier
),
);
}
// When the user taps the prompt to watch the ad
void onRewardPromptAccepted() {
Purchases.adTracker.trackRewardedAdPromptAccepted(
AdRewardPromptAcceptedData(
mediatorName: AdMediatorName.appLovin,
placement: 'bonus_coins_rewarded',
adUnitId: rewardedAdUnitId,
),
);
}
// When the "Watch an ad to earn coins" prompt appears
void OnRewardPromptShown()
{
purchases.AdTracker.TrackRewardedAdPromptShown(new AdRewardPromptShownData(
mediatorName: AdTracker.MediatorName.AppLovin, // or new AdTracker.MediatorName("YourMediator")
adUnitId: rewardedAdUnitId, // Ad unit identifier
placement: "bonus_coins_rewarded" // Your custom placement ID (optional)
));
}
// When the user taps the prompt to watch the ad
void OnRewardPromptAccepted()
{
purchases.AdTracker.TrackRewardedAdPromptAccepted(new AdRewardPromptAcceptedData(
mediatorName: AdTracker.MediatorName.AppLovin,
adUnitId: rewardedAdUnitId,
placement: "bonus_coins_rewarded"
));
}
// When the "Watch an ad to earn coins" prompt appears
async function onRewardPromptShown() {
await Purchases.adTracker.trackRewardedAdPromptShown({
mediatorName: AdMediatorName.appLovin, // or any string
placement: "bonus_coins_rewarded", // Your custom placement ID (optional)
adUnitId: rewardedAdUnitId, // Ad unit identifier
});
}
// When the user taps the prompt to watch the ad
async function onRewardPromptAccepted() {
await Purchases.adTracker.trackRewardedAdPromptAccepted({
mediatorName: AdMediatorName.appLovin,
placement: "bonus_coins_rewarded",
adUnitId: rewardedAdUnitId,
});
}
Event data reference
Common parameters
The ad lifecycle events (loaded, displayed, opened, revenue, and failed to load) share these common parameters:
| Parameter | Type | Description | Required |
|---|---|---|---|
networkName | String | Ad network that served the ad (e.g., "Google Ads", "Meta Audience Network") | No (null allowed) |
mediatorName | AdMediatorName | Your mediation platform | Yes |
adFormat | AdFormat | Type of ad | Yes |
placement | String | Your custom placement identifier | No (null allowed) |
adUnitId | String | Ad unit identifier from mediation platform | Yes |
impressionId | String | Unique identifier for this ad instance | Yes (except for failed events) |
Rewarded ad prompt events accept only mediatorName, adUnitId, and an optional placement. They have no adFormat, networkName, or impressionId parameter; the SDK sets adFormat to rewarded for you.
AdFormat values
| Format | Android | iOS | Flutter | Unity | React Native |
|---|---|---|---|---|---|
| Banner | AdFormat.BANNER | .banner | AdFormat.banner | AdTracker.Format.Banner | AdFormat.banner |
| Interstitial | AdFormat.INTERSTITIAL | .interstitial | AdFormat.interstitial | AdTracker.Format.Interstitial | AdFormat.interstitial |
| Rewarded | AdFormat.REWARDED | .rewarded | AdFormat.rewarded | AdTracker.Format.Rewarded | AdFormat.rewarded |
| Rewarded Interstitial | AdFormat.REWARDED_INTERSTITIAL | .rewardedInterstitial | AdFormat.rewardedInterstitial | AdTracker.Format.RewardedInterstitial | AdFormat.rewardedInterstitial |
| Native | AdFormat.NATIVE | .native | AdFormat.native_ | AdTracker.Format.Native | AdFormat.native |
| App Open | AdFormat.APP_OPEN | .appOpen | AdFormat.appOpen | AdTracker.Format.AppOpen | AdFormat.appOpen |
| Other | AdFormat.OTHER | .other | AdFormat.other | AdTracker.Format.Other | AdFormat.other |
| Custom | AdFormat.fromString("x") | .init(value: "x") | AdFormat("x") | new AdTracker.Format("x") | any string |
AdMediatorName values
| Mediator | Android | iOS | Flutter | Unity | React Native |
|---|---|---|---|---|---|
| Google AdMob | AdMediatorName.AD_MOB | .adMob | AdMediatorName.adMob | AdTracker.MediatorName.AdMob | AdMediatorName.adMob |
| AppLovin MAX | AdMediatorName.APP_LOVIN | .appLovin | AdMediatorName.appLovin | AdTracker.MediatorName.AppLovin | AdMediatorName.appLovin |
| Unity LevelPlay | AdMediatorName.LEVEL_PLAY | .init(value: "LevelPlay") | AdMediatorName("LevelPlay") | new AdTracker.MediatorName("LevelPlay") | "LevelPlay" |
| Custom | AdMediatorName.fromString("x") | .init(value: "x") | AdMediatorName("x") | new AdTracker.MediatorName("x") | any string |
On Android SDK versions that don't expose AdMediatorName.LEVEL_PLAY, use AdMediatorName.fromString("LevelPlay").
AdRevenuePrecision values
| Precision | Android | iOS | Flutter | Unity | React Native |
|---|---|---|---|---|---|
| Exact | AdRevenuePrecision.EXACT | .exact | AdRevenuePrecision.exact | AdTracker.Precision.Exact | AdRevenuePrecision.exact |
| Estimated | AdRevenuePrecision.ESTIMATED | .estimated | AdRevenuePrecision.estimated | AdTracker.Precision.Estimated | AdRevenuePrecision.estimated |
| Publisher Defined | AdRevenuePrecision.PUBLISHER_DEFINED | .publisherDefined | AdRevenuePrecision.publisherDefined | AdTracker.Precision.PublisherDefined | AdRevenuePrecision.publisherDefined |
| Unknown | AdRevenuePrecision.UNKNOWN | .unknown | AdRevenuePrecision.unknown | AdTracker.Precision.Unknown | AdRevenuePrecision.unknown |
Revenue in micros
The revenueMicros parameter expects revenue in micros (millionths of the currency unit). Multiply the revenue value from your mediation platform by 1,000,000:
- $1.50 USD →
1,500,000micros - €0.25 EUR →
250,000micros
The conversion in each platform's code examples above shows the exact formula for that language.
Best practices
Placement naming
Use consistent, descriptive placement names:
- ✅ Good:
"home_banner","level_complete_interstitial","bonus_coins_rewarded" - ❌ Avoid:
"ad1","test", timestamps, or dynamic values
Impression IDs
- Use unique IDs provided by your mediation platform
- Use the same impression ID across all events for a single ad instance (loaded → displayed → opened → revenue)
- Prompt events have no impression ID because they fire before the ad loads
Error handling
Track failed ad loads to understand fill rate issues:
- Kotlin
adTracker.trackAdFailedToLoad(
AdFailedToLoadData(
mediatorName = AdMediatorName.fromString("YourMediator"),
adFormat = AdFormat.REWARDED,
placement = "home_screen",
adUnitId = adUnitId,
mediatorErrorCode = errorCode // Include platform error code
)
)
When to track each event
| Event | When to Call |
|---|---|
trackAdLoaded | After ad successfully loads in memory |
trackAdDisplayed | When ad impression is recorded (ad shown on screen) |
trackAdOpened | When user clicks/taps the ad |
trackAdRevenue | When mediation platform reports ILRD for the impression |
trackAdFailedToLoad | When ad request fails |
trackRewardedAdPromptShown | When your UI shows a prompt offering a rewarded ad |
trackRewardedAdPromptAccepted | When the user accepts the prompt to watch the ad |
Example projects
Complete working examples are available:
- Android: Unity LevelPlay manual integration — Tracks banner, interstitial, rewarded, and failed-load events without an adapter
- iOS: AdMob integration — Shows AdMob integration patterns
View your data
See the Ad Monetization overview for details on where your ad data appears in the dashboard.
Troubleshooting
Testing your integration
Before troubleshooting, verify your events are being tracked:
- Run your app in debug mode
- Navigate to the Ads page in your RevenueCat dashboard
- Toggle on "Sandbox data"
- Trigger some ads in your app
- Check that events appear in the sandbox events table
RevenueCat automatically marks events from debug builds as sandbox, so you can verify your integration without affecting production data.
Events not appearing in Charts
- Verify you've opted in via the Ads page in your RevenueCat dashboard
- Check that you're calling the correct
track*methods with all required parameters - Ensure
impressionIdis unique for each ad instance (prompt events have noimpressionId) - Verify your mediation platform is providing ILRD callbacks
- Check that
revenueMicrosis calculated correctly (multiply by 1,000,000) - Use the sandbox data view (above) to confirm events are being received
Revenue values seem incorrect
- Ensure you're converting to micros: multiply by 1,000,000
- Verify the currency code is correct (e.g., "USD", "EUR")
- Check that the revenue value from your mediation platform is already in the correct currency unit
Next steps
- Review the example projects for complete implementations
- View your ad data in Ad Charts
- Learn about the AdMob SDK Integration for simplified integration with Google AdMob