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

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.

:::warning 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.
:::

## Overview

Manual integration gives you full control over ad event tracking and works with any mediation platform that supports ILRD, including:

- AppLovin MAX
- ironSource
- Unity Ads
- Any custom mediation setup

Hook into your mediation platform's callbacks and call the appropriate `AdTracker` methods.

## How it works

1. **Your mediation platform fires a callback** (e.g., ad loaded, ad displayed, revenue generated)
2. **You call the corresponding AdTracker method** with the event data
3. **RevenueCat records the event** and makes it available in Charts

## Prerequisites

- **SDK Version**:
  - Android: `purchases-android` 8.0.0+
  - iOS: `purchases-ios` 5.0.0+
  - Flutter: `purchases_flutter` 10.2.0+
  - Unity: `purchases-unity` 9.1.0+
  - React Native: `react-native-purchases` 10.2.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](https://admob.google.com/) under **Settings**.
- **Experimental API**: Ad monetization APIs are marked as experimental

## Android integration

### 1. Access the AdTracker

*Interactive content is available in the web version of this doc.*

### 2. Import event types

*Interactive content is available in the web version of this doc.*

### 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:

*Interactive content is available in the web version of this doc.*

#### Track ad revenue

Call when your mediation platform reports revenue for an impression:

*Interactive content is available in the web version of this doc.*

#### 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 ad
- **`trackAdFailedToLoad(AdFailedToLoadData)`** - Call when ad fails to load (doesn't require `networkName` or `impressionId`)

See the [Event data reference](#event-data-reference) section below for complete parameter details.

## iOS integration

### 1. Access the AdTracker

*Interactive content is available in the web version of this doc.*

:::info iOS availability
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:

*Interactive content is available in the web version of this doc.*

#### Track ad revenue

Call when your mediation platform reports revenue for an impression:

*Interactive content is available in the web version of this doc.*

#### 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 ad
- **`trackAdFailedToLoad(_:)`** - Call when ad fails to load (doesn't require `networkName` or `impressionId`)

See the [Event data reference](#event-data-reference) section below for complete parameter details.

## Flutter integration

### 1. Add the dependency

```yaml
# pubspec.yaml
dependencies:
  purchases_flutter: ^10.2.0
```

### 2. Access the AdTracker

*Interactive content is available in the web version of this doc.*

:::info iOS availability
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:

*Interactive content is available in the web version of this doc.*

#### Track ad revenue

Call when your mediation platform reports revenue for an impression:

*Interactive content is available in the web version of this doc.*

#### 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 ad
- **`trackAdFailedToLoad(AdFailedToLoadData)`** - Call when ad fails to load (doesn't require `networkName` or `impressionId`)

See the [Event data reference](#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

*Interactive content is available in the web version of this doc.*

:::info iOS availability
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:

*Interactive content is available in the web version of this doc.*

#### Track ad revenue

Call when your mediation platform reports revenue for an impression:

*Interactive content is available in the web version of this doc.*

#### 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 ad
- **`TrackAdFailedToLoad(AdFailedToLoadData)`** - Call when ad fails to load (doesn't require `networkName` or `impressionId`)

See the [Event data reference](#event-data-reference) section below for complete parameter details.

## React Native integration

### 1. Add the dependency

```bash
npm install react-native-purchases@^10.2.0
# or
yarn add react-native-purchases@^10.2.0
```

### 2. Access the AdTracker

*Interactive content is available in the web version of this doc.*

:::info Web and iOS availability
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:

*Interactive content is available in the web version of this doc.*

#### Track ad revenue

Call when your mediation platform reports revenue for an impression:

*Interactive content is available in the web version of this doc.*

#### 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 ad
- **`trackAdFailedToLoad(AdFailedToLoadData)`** - Call when ad fails to load (doesn't require `networkName` or `impressionId`)

See the [Event data reference](#event-data-reference) section below for complete parameter details.

## Event data reference

### Common parameters

All event types 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) |

### 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` |
| Custom       | `AdMediatorName.fromString("x")` | `.init(value: "x")` | `AdMediatorName("x")`     | `new AdTracker.MediatorName("x")` | any string                |

### 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,000` micros
- €0.25 EUR → `250,000` micros

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)

### Error handling

Track failed ad loads to understand fill rate issues:

*Interactive content is available in the web version of this doc.*

### 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                                   |

## Example projects

Complete working examples are available:

- **Android**: [purchases-android/examples/admob-sample](https://github.com/RevenueCat/purchases-android/tree/main/examples/admob-sample) - Shows AdMob integration patterns
- **iOS**: [purchases-ios/Examples/AdMobIntegrationSample](https://github.com/RevenueCat/purchases-ios/tree/main/Examples/AdMobIntegrationSample) - Shows AdMob integration patterns

These examples use AdMob's helper methods, but the event tracking patterns apply to manual integration with any mediation platform.

## View your data

See the [Ad Monetization overview](/ad-monetization#data-availability) for details on where your ad data appears in the dashboard.

## 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

RevenueCat automatically marks events from debug builds as sandbox, so you can verify your integration without affecting production data.

### Events not appearing in Charts

1. Verify you've opted in via the Ads page in your RevenueCat dashboard
2. Check that you're calling the correct `track*` methods with all required parameters
3. Ensure `impressionId` is unique for each ad instance
4. Verify your mediation platform is providing ILRD callbacks
5. Check that `revenueMicros` is calculated correctly (multiply by 1,000,000)
6. 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](#example-projects) for complete implementations
- View your ad data in [Ad Charts](/dashboard-and-metrics/charts/ads)
- Learn about the [AdMob SDK Integration](/ad-monetization/admob) for simplified integration with Google AdMob
