Ad Revenue Attribution
Track ad revenue from mediation platforms and attribute it to the marketing campaigns that acquired your users, providing complete ROI visibility across campaign costs, in-app purchases, and advertising monetization.
Overview
What Is Ad Revenue Attribution
Ad Revenue Attribution connects mobile app advertising revenue to the user acquisition campaigns that drove app installs, enabling you to measure true campaign profitability including ad monetization.
Key Benefits:
- Unified ROI View: See campaign costs, in-app revenue, and ad revenue in a single dashboard
- Campaign Optimization: Send ad revenue data back to ad networks to improve bidding and targeting
- LTV Measurement: Calculate complete user lifetime value including advertising monetization
Data Sources: Ad revenue data typically comes from your mediation platform (e.g., AdMob, AppLovin MAX, IronSource) at either the user level or impression level. Singular supports multiple integration methods to receive this data.
Learn More: See the Ad Revenue Attribution FAQ for comprehensive details on setup, reporting, and troubleshooting.
Implementation Requirements
Critical Guidelines
Data Accuracy Is Critical:
- Currency Codes: Use three-letter ISO 4217 currency codes (e.g., USD, EUR, INR). Many mediation platforms report in USD—verify your platform's currency before implementation
-
Validate Before Sending: Always validate revenue
and currency data before calling
SingularSDK.AdRevenue(). Incorrect data cannot be corrected after submission - Platform Differences: AdMob reports revenue in micros on Unity and Android (divide by 1,000,000) but in standard units on iOS. Check your platform's documentation
Setup Steps
Follow these steps to implement ad revenue attribution:
- Update SDK: Ensure you're using the latest Singular SDK version
- Choose Integration: Select the mediation platform integration below that matches your setup
- Implement Callbacks: Add platform-specific paid event listeners to capture revenue data
- Validate Data: Test revenue reporting and verify data appears in Singular dashboard
Platform Integrations
AdMob Integration
Track ad revenue from Google AdMob using the paid event listener for impression-level revenue reporting.
Requirements:
- Enable paid event tracking in your AdMob account (see AdMob Support)
- Implement Google Mobile Ads SDK for Unity (see Getting Started Guide)
Platform Revenue Reporting: AdMob reports revenue differently by platform. Ad revenue of $0.005 will be returned as 5000 on Unity and Android platforms but as 0.005 on iOS. For iOS, send 0.005 directly to the Singular SDK. On other platforms, convert adValue from micros to dollars before sending it to Singular.
Implementation
Register an OnAdPaid event handler when loading ads to capture
revenue data and send it to Singular.
using UnityEngine;
using Singular;
using GoogleMobileAds.Api;
public class AdMobRevenueTracking : MonoBehaviour
{
private const string AD_UNIT_ID = "YOUR_AD_UNIT_ID";
private RewardedAd rewardedAd;
void Start()
{
// Initialize Mobile Ads SDK
MobileAds.Initialize(initStatus =>
{
Debug.Log("AdMob initialized");
LoadRewardedAd();
});
}
private void LoadRewardedAd()
{
// Create ad request
AdRequest adRequest = new AdRequest();
// Load rewarded ad
RewardedAd.Load(AD_UNIT_ID, adRequest, (RewardedAd ad, LoadAdError error) =>
{
if (error != null || ad == null)
{
Debug.LogError($"Rewarded ad failed to load: {error}");
return;
}
Debug.Log("Rewarded ad loaded");
rewardedAd = ad;
// Register event handlers
RegisterEventHandlers(ad);
});
}
private void RegisterEventHandlers(RewardedAd ad)
{
// Raised when the ad is estimated to have earned money
ad.OnAdPaid += (AdValue adValue) =>
{
// Validate and ensure revenue data is within an expected range
float revenue = adValue.Value / 1_000_000f; // Convert micros to dollars
string currency = adValue.CurrencyCode;
// Check if revenue is positive and currency is valid
if (revenue > 0 && !string.IsNullOrEmpty(currency))
{
// Construct and send the Singular Ad Revenue Event
SingularAdData data = new SingularAdData(
"AdMob",
currency,
revenue
);
SingularSDK.AdRevenue(data);
// Log the revenue data for debugging purposes
Debug.Log($"Ad Revenue reported to Singular: {data}");
}
else
{
Debug.LogError($"Invalid ad revenue data: revenue = {revenue}, currency = {currency}");
}
};
// Additional event handlers
ad.OnAdFullScreenContentOpened += () =>
{
Debug.Log("Rewarded ad full screen content opened");
};
ad.OnAdFullScreenContentClosed += () =>
{
Debug.Log("Rewarded ad full screen content closed");
// Load next ad
LoadRewardedAd();
};
ad.OnAdFullScreenContentFailed += (AdError error) =>
{
Debug.LogError($"Rewarded ad failed to show: {error}");
// Load next ad
LoadRewardedAd();
};
}
public void ShowRewardedAd()
{
if (rewardedAd != null && rewardedAd.CanShowAd())
{
rewardedAd.Show((Reward reward) =>
{
Debug.Log($"User earned reward: {reward.Type} - {reward.Amount}");
});
}
else
{
Debug.Log("Rewarded ad is not ready yet");
}
}
}
AppLovin MAX Integration
Track impression-level ad revenue using the AppLovin Impression-Level User Revenue API.
Requirements:
- Implement AppLovin MAX SDK for Unity (see Getting Started Guide)
- Attach revenue paid callbacks to all ad formats you are using
Implementation
Register OnAdRevenuePaidEvent callbacks to capture and send
revenue data to Singular.
using UnityEngine;
using Singular;
public class AppLovinRevenueTracking : MonoBehaviour
{
void Start()
{
// Attach callbacks based on the ad format(s) you are using
MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
MaxSdkCallbacks.Rewarded.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
MaxSdkCallbacks.Banner.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
MaxSdkCallbacks.MRec.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
}
private void OnAdRevenuePaidEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
{
double revenue = adInfo.Revenue;
if (revenue > 0)
{
// Create a SingularAdData object with relevant information
SingularAdData adData = new SingularAdData(
"AppLovin",
"USD", // AppLovin typically reports in USD
revenue
);
// Send ad revenue data to Singular
SingularSDK.AdRevenue(adData);
Debug.Log($"Ad Revenue reported to Singular: {revenue} USD from {adUnitId}");
}
else
{
Debug.LogError("Failed to parse valid revenue value from ad info or revenue is not greater than 0");
}
}
void OnDestroy()
{
// Detach callbacks to prevent memory leaks
MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent -= OnAdRevenuePaidEvent;
MaxSdkCallbacks.Rewarded.OnAdRevenuePaidEvent -= OnAdRevenuePaidEvent;
MaxSdkCallbacks.Banner.OnAdRevenuePaidEvent -= OnAdRevenuePaidEvent;
MaxSdkCallbacks.MRec.OnAdRevenuePaidEvent -= OnAdRevenuePaidEvent;
}
}
Unity LevelPlay (IronSource) Integration
Track impression-level revenue from ironSource and mediated networks using the IronSource SDK.
Requirements:
- Implement ironSource Unity SDK (see Getting Started Guide)
- Enable ARM SDK Postbacks flag in your IronSource dashboard
- Set impression data listener to receive revenue callbacks
Learn More: See IronSource Ad Revenue Documentation for complete setup details.
Implementation
Subscribe to the ImpressionDataReadyEvent to capture and
send revenue data.
using UnityEngine;
using Singular;
public class IronSourceRevenueTracking : MonoBehaviour
{
void Start()
{
// Ensure the listener is added before initializing the SDK
IronSourceEvents.onImpressionDataReadyEvent += ImpressionDataReadyEvent;
// Initialize the IronSource SDK here if not already done
// IronSource.Agent.init("YOUR_IRONSOURCE_APP_KEY");
}
private void ImpressionDataReadyEvent(IronSourceImpressionData impressionData)
{
if (impressionData != null)
{
// Ensure revenue value is valid
double? revenue = impressionData.revenue;
if (revenue.HasValue && revenue.Value > 0)
{
// Create SingularAdData object with appropriate values
SingularAdData adData = new SingularAdData(
"IronSource",
"USD", // IronSource typically reports in USD
revenue.Value
);
// Send the Ad Revenue data to Singular
SingularSDK.AdRevenue(adData);
// Log the data for debugging
Debug.Log($"Ad Revenue reported to Singular: AdPlatform: {adData.AdPlatform}, " +
$"Currency: {adData.Currency}, Revenue: {adData.Revenue}");
}
else
{
Debug.LogError($"Invalid revenue value: {revenue}");
}
}
else
{
Debug.LogError("Impression data is null");
}
}
void OnDestroy()
{
// Detach the callback to prevent memory leaks
IronSourceEvents.onImpressionDataReadyEvent -= ImpressionDataReadyEvent;
}
}
TradPlus Integration
Capture ad revenue from TradPlus mediation using the global impression listener.
Requirements:
-
Add global ad impression listener via
TradplusAds.Instance().AddGlobalAdImpression() -
Handle
OnGlobalAdImpressioncallback to receive revenue data - Convert eCPM from milli-units to standard currency (divide by 1000)
Implementation
Register a global impression listener to track all ad impressions and revenue.
using UnityEngine;
using Singular;
using System.Collections.Generic;
using System.Globalization;
public class TradPlusRevenueTracking : MonoBehaviour
{
private const string TAG = "TradPlusRevenue";
void Start()
{
// Add Global Ad Impression Listener
TradplusAds.Instance().AddGlobalAdImpression(OnGlobalAdImpression);
}
void OnGlobalAdImpression(Dictionary<string, object> adInfo)
{
// Ensure adInfo is not null
if (adInfo == null)
{
Debug.LogError($"{TAG}: AdInfo is null");
return;
}
// Ensure eCPM is present and valid
if (!adInfo.ContainsKey("ecpm") || adInfo["ecpm"] == null)
{
Debug.LogError($"{TAG}: eCPM value is null or missing");
return;
}
// Parse the eCPM value
if (!double.TryParse(adInfo["ecpm"].ToString(), NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture, out double revenue))
{
Debug.LogError($"{TAG}: Failed to parse eCPM value");
return;
}
// Convert eCPM to revenue (eCPM is in milli-units)
revenue = revenue / 1000.0;
// Validate the revenue value
if (revenue <= 0)
{
Debug.LogError($"{TAG}: Ad Revenue value out of expected range: {revenue}");
return;
}
// Create SingularAdData object with the necessary fields
SingularAdData data = new SingularAdData(
"TradPlus",
"USD",
revenue
);
// Send the Ad Revenue data to Singular
SingularSDK.AdRevenue(data);
// Log the data for debugging purposes
Debug.Log($"{TAG}: Ad Revenue reported to Singular: AdPlatform: {data.AdPlatform}, " +
$"Currency: {data.Currency}, Revenue: {data.Revenue}");
}
}
Generic Integration (Other Platforms)
Integrate any mediation platform using the generic
SingularAdData interface.
Requirements:
- Access to impression-level revenue data from your mediation platform
- Revenue amount in standard currency units (not micros)
- ISO 4217 currency code (e.g., USD, EUR, INR)
Data Accuracy: Validate revenue and currency data before sending to Singular. Incorrect data cannot be corrected after submission.
Implementation
Create a SingularAdData object with platform name, currency,
and revenue, then call SingularSDK.AdRevenue().
using UnityEngine;
using Singular;
public class GenericAdRevenueTracking : MonoBehaviour
{
// Function to report ad revenue to Singular
public void ReportAdRevenue(string adPlatform, string currency, float revenue)
{
// Validate the input: ensure revenue is positive and currency is not null or empty
if (revenue > 0 && !string.IsNullOrEmpty(currency))
{
// Create a SingularAdData object with the validated data
SingularAdData data = new SingularAdData(
adPlatform,
currency,
revenue
);
// Send the ad revenue data to Singular
SingularSDK.AdRevenue(data);
// Log the reported data for debugging
Debug.Log($"Ad Revenue reported to Singular: Platform = {adPlatform}, " +
$"Currency = {currency}, Revenue = {revenue}");
}
else
{
// Log a warning if validation fails
Debug.LogWarning($"Invalid ad revenue data: Platform = {adPlatform}, " +
$"Revenue = {revenue}, Currency = {currency}");
}
}
// Example usage
void ExampleUsage()
{
// Report revenue from a custom mediation platform
ReportAdRevenue("MyMediationPlatform", "USD", 0.05f);
}
}
Testing and Validation
Verify Revenue Reporting
Test your ad revenue implementation to ensure data flows correctly to Singular.
- Check Logs: Verify revenue callback logs appear with correct values and currency in Unity Console
- Test Ads: Load and display test ads to trigger revenue events
- Dashboard Verification: Confirm revenue appears in Singular dashboard within 24 hours
- Data Accuracy: Validate revenue amounts match your mediation platform reports
Troubleshooting: If revenue doesn't appear in Singular, check that:
- Ad revenue attribution is enabled in your Singular account
- Revenue values are greater than 0
- Currency codes are valid ISO 4217 codes
- Platform name matches Singular's expected format
- Event handlers are properly registered before ads load