Ad Revenue Attribution Support

Understanding Ad Revenue Attribution

Ad Revenue Attribution helps you connect your ad revenue to the specific campaigns that brought users to your app. This gives you a clear picture of how well your ads are performing by showing the campaign cost, in-app revenue, and ad revenue all in one place. This feature also lets you send ad revenue data back to your ad networks to improve your ad performance.

Key Points:

  • What It Does: Ad Revenue Attribution ties mobile app ad revenue to the marketing campaigns that generated users for your app. This way, you can see how much you earned from each campaign and how it affects your overall ad ROI.
  • Data Source: This data usually comes from your mediation platform and can be at the user level or impression level. Singular supports different ways to get this attribution data.
  • Read More: For more details, check out the FAQ and Troubleshooting article on Singular Ad Revenue Attribution.

Important Notes:

  1. Currency Codes: Use three-letter ISO 4217 currency codes (e.g., "USD" for US Dollars, "EUR" for Euros, "INR" for Indian Rupees). Many mediation platforms use "USD", so make sure your code matches this if you're using it. If you use a different currency, update the validation code accordingly.
  2. Data Accuracy: Always check that your revenue and currency data are correct before sending it to Singular. Incorrect data can't be fixed later, so it’s crucial to ensure it’s accurate.

Implementing Ad Revenue Attribution

  1. Update the SDK: Make sure you have the latest version of the Singular SDK.
  2. Add Code Snippets: Depending on your mediation platform, add the right code snippets to your Singular SDK setup.

Following these steps will help you set up Ad Revenue Attribution correctly and get the most out of your ad data.

AdMob
Partner Notes
  • This feature needs to be enabled in your AdMob account.

    See AdMob Support.

  • When you load an ad format (such as "App Open," "Banner," "Interstitial," "Native," or "Rewarded"), set up a paidEventHandler as a callback function that is triggered whenever an ad generates revenue. The Google Mobile Ads SDK tracks impression events and calls this handler with the Ad generated revenue.

    To do this, modify the "load" function of the ad format to include the paidEventHandler. Inside this callback, you manage the ad revenue data, validate it, and send it to Singular using the Singular.adRevenue function.

    For example, when a "Rewarded ad" loads successfully, the paidEventHandler will receive the ad's revenue information (adValue). In this function, handle the revenue data and send it to Singular.

    For more details, check the AdMob documentation.

    IMPORTANT: The AdMob SDK reports revenue differently depending on the platform. For instance, 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.
Select the code base for your SDK implementation:
SwiftObjective-CKotlinJavaFlutterCordovaReact NativeUnity
How it works:
  • Implement the Google AdMob Mobile Ads SDK (iOS): See the Getting Started Guide.
  • AdMob Integration: Load the ad from AdMob and set a setOnPaidEventListener to handle ad revenue events.
  • Revenue Validation: Add a check to ensure that revenue is greater than 0. This prevents sending zero or negative revenue values.
  • Currency Validation: Ensure that the currency is not nil or empty before sending data to Singular.
  • Logging Invalid Data: If the data fails validation, print a log message for debugging, and do not send the data to Singular.
import Singular

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 with error: \(error.localizedDescription)")
            return
        }
        
        self.rewardedAd = ad
        self.rewardedAd?.paidEventHandler = { adValue in
            // Ensure valid revenue data
            let revenue = adValue.value
            let currency = adValue.currencyCode
            
            // Validate the revenue and currency before sending to Singular
            guard revenue > 0, let currency = currency, !currency.isEmpty else {
                print("Invalid ad revenue data: revenue = \(revenue), currency = \(String(describing: currency))")
                return
            }
            
            let data = SingularAdData(
                adPlatform: "Admob",
                currency: currency,
                revenue: revenue
            )
            
            // Send Ad Revenue data to Singular
            Singular.adRevenue(data: data)
            
            // Log the data for debugging
            print("Ad Revenue reported to Singular: \(data)")
        }
    }
}
AppLovinMax
Partner Notes
  • Share impression-level ad revenue data using the Applovin Impression-Level User Revenue API.
Select the code base for your SDK implementation:
SwiftObjective-CKotlinJavaFlutterCordovaReact NativeUnity
How it works:
  • Uses the AppLovin Impression-Level User Revenue API (iOS): See the Getting Started Guide.
  • AppLovin Integration: Load a rewarded ad from AppLovin MAX and use the didReceive function to handle ad revenue events.
  • Revenue Validation: Add a check to ensure that revenue is greater than 0. This prevents sending zero or negative revenue values.
  • Currency Validation: In the sample below, the currency is hard coded to "USD". Ensure that the currency is accurate and not nil or empty before sending data to Singular.
  • Logging Invalid Data: If the data fails validation, print a log message for debugging, and do not send the data to Singular.
import Singular

func didReceive(_ message: ALCMessage) { if "max_revenue_events" == message.topic { // Safely unwrap values from the message data guard let revenueValue = message.data["revenue"] as? Double, revenueValue > 0 else { print("Failed to parse valid revenue value from message data or revenue is not greater than 0") return } let data = SingularAdData( adPlatform: "AppLovin", currency: "USD", // Update this if a different currency is needed revenue: revenueValue ) // Send the revenue data to Singular Singular.adRevenue(data) } }
Unity LevelPlay (IronSource)
Partner Notes
  • The Impression Level Revenue (ILR) SDK API provides impression level data for ironSource Ads and other mediated networks, using the ironSource SDK. Read more on [developers.is.com]
  • Ensure that the ARM SDK Postbacks Flag in IronSource is turned on
Select the code base for your SDK implementation:
SwiftObjective-CKotlinJavaFlutterCordovaReact NativeUnity
How it works:
  • Uses the ironSource SDK to get Impression-Level User Revenue (iOS): See the Getting Started Guide.
  • Ironsource Integration: Load a rewarded ad from Ironsource and use the impressionDataDidSucceed function to handle Ad Revenue events.
  • Revenue Validation: Add a check to ensure that revenue is greater than 0. This prevents sending zero or negative revenue values.
  • Currency Validation: In the sample below, the currency is hard coded to "USD". Ensure that the currency is accurate and not nil or empty before sending data to Singular.
  • Logging Invalid Data: If the data fails validation, print a log message for debugging, and do not send the data to Singular.
import Singular

class IronSourceRewardedAdViewController: UIViewController {

    func impressionDataDidSucceed(impressionData: ISImpressionData?) {
        logCallback(#function)

        // Ensure impressionData is not nil
        guard let impressionData = impressionData else {
            print("No impression data available.")
            return
        }

        // Ensure revenue value is valid
        let revenue = impressionData.revenue
        guard revenue > 0 else {
            print("Invalid revenue value: \(revenue)")
            return
        }

        // Create SingularAdData object with appropriate values
        let data = SingularAdData(
            adPlatform: "IronSource",
            currency: "USD",
            revenue: revenue
        )

        // Send the Ad Revenue data to Singular
        Singular.adRevenue(data)

        // Log the data for debugging
        print("Ad Revenue reported to Singular: AdPlatform: \(data.adPlatform), Currency: \(data.currency), Revenue: \(data.revenue)")
    }

    private func logCallback(_ functionName: String) {
        // Implement logging if needed
        print("Function called: \(functionName)")
    }
}
TradPlus
Partner Notes
  • Set the impressionDelegate
  • Add Singular to the TradPlusAdImpression Callback
Select the code base for your SDK implementation:
SwiftObjective-CKotlinJavaFlutterCordovaReact NativeUnity
How it works:
  • TradPlus Integration: Load a rewarded ad from TradPlus and use the tradPlusAdImpression function to handle Ad Revenue events.
  • Revenue Validation: Add a check to ensure that revenue is greater than 0. This prevents sending zero or negative revenue values. The adInfo dictionary contains an "ecpm" key with a valid NSNumber value. It converts this value to a Double and scales it (typically ecpm is given in milli-units, so dividing by 1000.0 converts it to dollars).
  • Currency Validation: In the sample below, the currency is hard coded to "USD". Ensure that the currency is accurate and not nil or empty before sending data to Singular.
  • Logging Invalid Data: If the data fails validation, print a log message for debugging, and do not send the data to Singular.
import Singular

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

// Delegate method for handling ad impressions
func tradPlusAdImpression(_ adInfo: [String: Any]) {
    let currency = "USD" // Assuming USD, adjust if necessary

    // Ensure adInfo contains the necessary key and its value is valid
    if let ecpmValue = adInfo["ecpm"] as? NSNumber {
        let revenue = ecpmValue.doubleValue / 1000.0
        
        // Validate the revenue value
        guard revenue > 0 else {
            print("Ad Revenue value out of expected range: \(revenue)")
            return
        }

        // Create SingularAdData object with required fields
        let data = SingularAdData(
            adPlatform: "TradPlus",
            currency: currency,
            revenue: revenue
        )

        // Send the Ad Revenue data to Singular
        Singular.adRevenue(data)

        print("Ad Revenue reported to Singular: \(data)")
    } else {
        // Log the issue for debugging
        print("No eCPM data available in adInfo")
    }
}
Other (Generic)
Partner Notes
  • Generic Integration: Initialize a SingularAdData object and pass the required data. Data should include the adPlatform as a String, currency as a String, and revenue as a Double.
  • Revenue Reporting: Check that your revenue and currency data are correct before sending it to Singular. Incorrect data can NOT be fixed later, so it’s crucial to ensure it’s accurate.
  • Tip: Log information for debugging purposes.
Select the code base for your SDK implementation:
SwiftObjective-CKotlinJavaFlutterCordovaReact NativeUnity
import Singular

// Function to send Ad Revenue data to Singular
func reportAdRevenue(adPlatform: String, currency: String, revenue: Double) {
    // Validate the revenue value
    guard revenue > 0 else {
        print("Invalid revenue value: \(revenue)")
        return
    }
    
    // Create a SingularAdData object with the provided fields
    let data = SingularAdData(
        adPlatform: adPlatform,
        currency: currency,
        revenue: revenue
    )
    
    // Send the Ad Revenue data to Singular
    Singular.adRevenue(data)
    
    // Log the data for debugging
    print("Ad Revenue reported to Singular: AdPlatform: \(data.adPlatform), Currency: \(data.currency), Revenue: \(data.revenue)")
}