iOS SDK - Ad Revenue Tracking

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:

  1. 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
  2. Validate Before Sending: Always validate revenue and currency data before calling Singular.adRevenue(). Incorrect data cannot be corrected after submission
  3. Platform Differences: iOS receives revenue directly in standard currency units (e.g., $0.005), unlike Android which uses micros. Always check your platform's documentation for the correct format

Setup Steps

Follow these steps to implement ad revenue attribution:

  1. Update SDK: Ensure you're using the latest Singular SDK version
  2. Choose Integration: Select the mediation platform integration below that matches your setup
  3. Implement Callbacks: Add platform-specific paid event listeners to capture revenue data
  4. 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:

Platform Revenue Reporting: AdMob reports revenue differently by platform. iOS returns revenue in standard currency units (e.g., $0.005 = 0.005). Send the value directly to Singular without conversion.

Implementation

Set a paid event handler when loading ads to capture revenue data and send it to Singular.

SwiftObjective-C
import Singular
import GoogleMobileAds

private let adUnitID = "AD_UNIT_ID"
var rewardedAd: GADRewardedAd?

func loadRewardedAd() {
    let request = GADRequest()
    
    GADRewardedAd.load(withAdUnitID: adUnitID, request: request) { [weak self] ad, error in
        guard let self = self else { return }
        
        if let error = error {
            print("Rewarded ad failed to load: \(error.localizedDescription)")
            return
        }
        
        self.rewardedAd = ad
        
        // Set paid event handler for revenue tracking
        self.rewardedAd?.paidEventHandler = { adValue in
            // Extract revenue and currency from AdValue
            let revenue = adValue.value.doubleValue
            let currency = adValue.currencyCode
            
            // Validate revenue and currency before sending
            guard revenue > 0, let currency = currency, !currency.isEmpty else {
                print("Invalid ad revenue data: revenue = \(revenue), currency = \(String(describing: currency))")
                return
            }
            
            // Create ad revenue data object
            let data = SingularAdData(
                adPlatform: "AdMob",
                currency: currency,
                revenue: revenue
            )
            
            // Send to Singular
            Singular.adRevenue(data)
            print("Ad revenue sent: \(revenue) \(currency)")
        }
    }
}

AppLovin MAX Integration

Share impression-level ad revenue using the AppLovin Impression-Level User Revenue API.

Requirements:

Implementation

Handle revenue messages through the AppLovin Communicator callback.

SwiftObjective-C
import Singular
import AppLovinSDK

func didReceive(_ message: ALCMessage) {
    // Check for revenue events topic
    if message.topic == "max_revenue_events" {
        // Extract and validate revenue value
        guard let revenueValue = message.data["revenue"] as? Double,
              revenueValue > 0 else {
            print("Failed to parse valid revenue value or revenue is not greater than 0")
            return
        }
        
        // Create ad revenue data object
        let data = SingularAdData(
            adPlatform: "AppLovin",
            currency: "USD",  // AppLovin typically reports in USD
            revenue: revenueValue
        )
        
        // Send to Singular
        Singular.adRevenue(data)
        print("Ad revenue sent: \(revenueValue) USD")
    }
}

Unity LevelPlay (IronSource) Integration

Track impression-level revenue from ironSource and mediated networks using the IronSource SDK.

Requirements:

  • Implement ironSource 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

Implement the impression data success callback to capture and send revenue.

SwiftObjective-C
import Singular
import IronSource

func impressionDataDidSucceed(_ impressionData: ISImpressionData?) {
    // Validate impression data
    guard let impressionData = impressionData else {
        print("No impression data available")
        return
    }
    
    // Extract and validate revenue
    let revenue = impressionData.revenue
    guard revenue > 0 else {
        print("Invalid revenue value: \(revenue)")
        return
    }
    
    // Create ad revenue data object
    let data = SingularAdData(
        adPlatform: "IronSource",
        currency: "USD",  // IronSource typically reports in USD
        revenue: revenue
    )
    
    // Send to Singular
    Singular.adRevenue(data)
    print("Ad revenue sent: \(revenue) USD")
}

TradPlus Integration

Capture ad revenue from TradPlus mediation using the impression delegate.

Requirements:

  • Set impression delegate via TradPlus.sharedInstance().impressionDelegate
  • Handle tradPlusAdImpression callback to receive revenue data
  • Convert eCPM from milli-units to standard currency (divide by 1000)

Implementation

Register an impression delegate to track all ad impressions and revenue.

SwiftObjective-C
import Singular
import TradPlusSDK

// Set up the delegate
TradPlus.sharedInstance().impressionDelegate = self

// Delegate method for handling ad impressions
func tradPlusAdImpression(_ adInfo: [String: Any]) {
    let currency = "USD"
    
    // Extract and validate eCPM value
    guard let ecpmValue = adInfo["ecpm"] as? NSNumber else {
        print("No eCPM data available in adInfo")
        return
    }
    
    // Convert eCPM from milli-units to dollars
    let revenue = ecpmValue.doubleValue / 1000.0
    
    // Validate revenue
    guard revenue > 0 else {
        print("Ad Revenue value out of expected range: \(revenue)")
        return
    }
    
    // Create ad revenue data object
    let data = SingularAdData(
        adPlatform: "TradPlus",
        currency: currency,
        revenue: revenue
    )
    
    // Send to Singular
    Singular.adRevenue(data)
    print("Ad revenue sent: \(revenue) \(currency)")
}

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
  • 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 Singular.adRevenue().

SwiftObjective-C
import Singular

func reportAdRevenue(adPlatform: String, currency: String, revenue: Double) {
    // Validate revenue
    guard revenue > 0 else {
        print("Invalid revenue value: \(revenue)")
        return
    }
    
    // Validate currency
    guard !currency.isEmpty else {
        print("Invalid currency: \(currency)")
        return
    }
    
    // Create ad revenue data object
    let data = SingularAdData(
        adPlatform: adPlatform,
        currency: currency,
        revenue: revenue
    )
    
    // Send to Singular
    Singular.adRevenue(data)
    print("Revenue sent: \(revenue) \(currency) from \(adPlatform)")
}

// Example usage
reportAdRevenue(adPlatform: "MyMediationPlatform", currency: "USD", revenue: 0.05)

Testing and Validation

Verify Revenue Reporting

Test your ad revenue implementation to ensure data flows correctly to Singular.

  1. Check Logs: Verify revenue callback logs appear with correct values and currency
  2. Test Ads: Load and display test ads to trigger revenue events
  3. Dashboard Verification: Confirm revenue appears in Singular dashboard within 24 hours
  4. 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