React Native SDK - Ad Revenue Tracking

Ad Revenue Attribution

Connect ad revenue to specific marketing campaigns that brought users to your app, providing complete visibility into campaign costs, in-app revenue, and ad revenue for accurate ROI measurement.

Overview

What is Ad Revenue Attribution

Ad Revenue Attribution ties mobile app ad revenue to the marketing campaigns that generated users, enabling you to measure true campaign performance by connecting user acquisition costs with lifetime revenue including ad monetization.

  • Campaign ROI: View campaign cost, in-app purchases, and ad revenue in unified reports to calculate true return on ad spend
  • Network Optimization: Send ad revenue data back to ad networks to improve bidding algorithms and campaign performance
  • Data Sources: Supports user-level and impression-level data from mediation platforms including AdMob, AppLovin MAX, Unity LevelPlay (IronSource), and TradPlus

For complete details, see the Ad Revenue Attribution FAQ.

Important Considerations:

  1. Currency Codes: Use ISO 4217 three-letter currency codes (USD, EUR, INR). Most mediation platforms report in USD—verify your platform's currency before implementation
  2. Data Accuracy: Validate revenue and currency data before sending to Singular. Incorrect data cannot be corrected retroactively

Implementation Requirements

Ad revenue tracking requires integration with your mediation platform SDK and configuration of revenue callbacks.

  1. SDK Version: Update to the latest Singular React Native SDK version
  2. Mediation Platform: Integrate the React Native SDK for your mediation platform (AdMob, AppLovin MAX, IronSource, or TradPlus)
  3. Revenue Callbacks: Implement platform-specific paid event handlers to capture impression-level revenue data
  4. Validation Logic: Add revenue and currency validation before sending data to Singular

SDK Method

Singular.adRevenue

Report ad revenue data to Singular with platform, currency, and revenue amount for attribution to the user's acquisition campaign.

Method Signature:

static adRevenue(data: {
    adPlatform: string;
    currency: string;
    revenue: number;
}): void

Parameters:

  • adPlatform: Mediation platform name (e.g., "AdMob", "AppLovin", "IronSource", "TradPlus")
  • currency: ISO 4217 three-letter currency code (e.g., "USD", "EUR")
  • revenue: Revenue amount in the specified currency (must be greater than 0)

For complete method documentation, see adRevenue reference.


Platform Integrations

AdMob Integration

Implement AdMob ad revenue tracking using the Google Mobile Ads SDK paid event callbacks for impression-level revenue reporting.

Prerequisites


Implementation Overview

When loading ad formats (App Open, Banner, Interstitial, Native, Rewarded), configure a paid event handler that triggers when ads generate revenue. Extract the revenue value and currency from the event data, validate both values, and send to Singular.

Platform Difference: AdMob reports revenue differently by platform. Android reports revenue in micros (e.g., $0.005 appears as 5000), requiring division by 1,000,000. iOS reports revenue in dollars directly (0.005). Adjust conversion logic based on platform detection.


AdMob Rewarded Ad Example

Load a rewarded ad with AdMob and capture paid events for revenue tracking.

New ArchitectureOld Architecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import React, { useEffect } from 'react';
import NativeSingular from 'singular-react-native/js/NativeSingular';
import { RewardedAd, AdEventType } from 'react-native-google-mobile-ads';
import { Platform } from 'react-native';

const AD_UNIT_ID = 'ca-app-pub-xxxxxxxxxxxxx/yyyyyyyyyy';

export default function AdMobRevenueTracker() {
  useEffect(() => {
    loadRewardedAd();
  }, []);

  const loadRewardedAd = () => {
    // Create RewardedAd instance
    const rewardedAd = RewardedAd.createForAdRequest(AD_UNIT_ID);

    // Set up event listener for ad events
    rewardedAd.addAdEventListener((type, error, data) => {
      if (type === AdEventType.LOADED) {
        console.log('Rewarded ad loaded');
      } else if (type === AdEventType.ERROR) {
        console.error('Rewarded ad failed to load:', error);
      } else if (type === AdEventType.PAID_EVENT) {
        // Handle paid event with revenue data
        handleAdRevenue(data);
      }
    });

    // Load the ad
    rewardedAd.load();
  };

  const handleAdRevenue = (data) => {
    const { value, currencyCode } = data;

    // Validate revenue and currency
    if (!value || value <= 0) {
      console.error('Invalid ad revenue value:', value);
      return;
    }

    if (!currencyCode || currencyCode.trim() === '') {
      console.error('Invalid currency code:', currencyCode);
      return;
    }

    // Convert revenue based on platform
    let revenue;
    if (Platform.OS === 'android') {
      // Android reports in micros - convert to dollars
      revenue = value / 1_000_000.0;
    } else {
      // iOS reports in dollars directly
      revenue = value;
    }

    const adRevenueData = {
      adPlatform: 'AdMob',
      currency: currencyCode,
      revenue: revenue
    };

    // Send to Singular
    NativeSingular.adRevenue(adRevenueData);

    console.log('Ad Revenue reported to Singular:', adRevenueData);
  };

  return null;
}

Implementation Notes:

  • Platform Detection: Use Platform.OS to determine conversion logic (Android divides by 1,000,000, iOS uses value directly)
  • Revenue Validation: Ensure revenue is greater than 0 before sending
  • Currency Validation: Verify currency code is non-empty
  • Error Logging: Log invalid data for debugging without sending to Singular

AppLovin MAX Integration

Implement AppLovin MAX ad revenue tracking using the Impression-Level User Revenue API for real-time revenue reporting across all ad formats.

Prerequisites

  • Integrate the AppLovin MAX React Native SDK. See Getting Started Guide
  • Enable Impression-Level User Revenue API in your AppLovin dashboard

Implementation Overview

Configure ad revenue listeners for each ad format (Interstitial, Rewarded, Banner, MRec, App Open) to capture revenue events. Extract revenue from adInfo.revenue and send to Singular with platform-specific currency (typically USD).


AppLovin MAX Revenue Tracking

Set up global revenue listeners for all AppLovin MAX ad formats.

New ArchitectureOld Architecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import NativeSingular from 'singular-react-native/js/NativeSingular';
import {
  InterstitialAd,
  RewardedAd,
  BannerAd,
  MRecAd,
  AppOpenAd
} from 'react-native-applovin-max';

// Currency constant - AppLovin typically reports in USD
const CURRENCY = 'USD';

// Generic handler for ad revenue
const handleAdRevenue = (adInfo) => {
  if (!adInfo) {
    console.error('AdInfo is null or undefined');
    return;
  }

  const revenue = adInfo.revenue;

  // Validate revenue
  if (!revenue || revenue <= 0) {
    console.error('Invalid revenue value:', revenue);
    return;
  }

  const adRevenueData = {
    adPlatform: 'AppLovin',
    currency: CURRENCY,
    revenue: revenue
  };

  // Send to Singular
  NativeSingular.adRevenue(adRevenueData);

  console.log('AppLovin ad revenue reported:', adRevenueData);
};

// Set up listeners for each ad type
export const setupAppLovinRevenueTracking = () => {
  InterstitialAd.addAdRevenuePaidListener(handleAdRevenue);
  RewardedAd.addAdRevenuePaidListener(handleAdRevenue);
  BannerAd.addAdRevenuePaidListener(handleAdRevenue);
  MRecAd.addAdRevenuePaidListener(handleAdRevenue);
  AppOpenAd.addAdRevenuePaidListener(handleAdRevenue);

  console.log('AppLovin MAX revenue tracking initialized');
};

Implementation Notes:

  • All Ad Formats: Register listeners for all ad types your app uses (Interstitial, Rewarded, Banner, MRec, App Open)
  • Currency: AppLovin typically reports revenue in USD—verify in your dashboard
  • Shared Handler: Use a single revenue handler function for all ad formats to ensure consistent validation

Unity LevelPlay (IronSource) Integration

Implement IronSource ad revenue tracking using the Impression Level Revenue (ILR) SDK API for impression-level data from IronSource Ads and mediated networks.

Prerequisites


Implementation Overview

Subscribe to the onImpressionDataSuccess event emitter to receive impression data. Extract revenue from impressionData.revenue and send to Singular with USD currency.


IronSource Revenue Tracking

Configure event listener for IronSource impression data callbacks.

New ArchitectureOld Architecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import { NativeModules, NativeEventEmitter } from 'react-native';
import NativeSingular from 'singular-react-native/js/NativeSingular';

const { IronSourceModule } = NativeModules;
const ironSourceEventEmitter = new NativeEventEmitter(IronSourceModule);

const AD_PLATFORM = 'IronSource';
const CURRENCY = 'USD'; // IronSource typically reports in USD

export const setupIronSourceRevenueTracking = () => {
  ironSourceEventEmitter.addListener('onImpressionDataSuccess', (impressionData) => {
    // Validate impression data
    if (!impressionData) {
      console.error('No impression data available');
      return;
    }

    const revenue = impressionData.revenue;

    // Validate revenue value
    if (!revenue || revenue <= 0) {
      console.error('Invalid revenue value:', revenue);
      return;
    }

    const adRevenueData = {
      adPlatform: AD_PLATFORM,
      currency: CURRENCY,
      revenue: revenue
    };

    // Send to Singular
    NativeSingular.adRevenue(adRevenueData);

    console.log('IronSource ad revenue reported:', adRevenueData);
  });

  console.log('IronSource revenue tracking initialized');
};

Implementation Notes:

  • Native Event Emitter: IronSource uses React Native's native event system for impression callbacks
  • ARM Postbacks: Verify ARM SDK Postbacks Flag is enabled in IronSource dashboard
  • Event Subscription: Set up listener before initializing IronSource SDK

TradPlus Integration

Implement TradPlus ad revenue tracking using global impression listeners to capture eCPM data from ad impressions.

Prerequisites

  • Integrate the TradPlus React Native SDK with your app
  • Configure TradPlus ad units in your dashboard

Implementation Overview

Subscribe to the onImpressionSuccess event to receive ad impression data. Extract eCPM value from tpAdInfo.ecpm, convert from millis to dollars (divide by 1000), and send to Singular.

eCPM Conversion: TradPlus reports eCPM in milli-units. Divide the eCPM value by 1000 to convert to dollar amounts before sending to Singular.


TradPlus Revenue Tracking

Configure event listener for TradPlus impression success callbacks.

New ArchitectureOld Architecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import { NativeModules, NativeEventEmitter } from 'react-native';
import NativeSingular from 'singular-react-native/js/NativeSingular';

const { TradPlusModule } = NativeModules;
const tradPlusEventEmitter = new NativeEventEmitter(TradPlusModule);

const AD_PLATFORM = 'TradPlus';
const CURRENCY = 'USD'; // TradPlus typically reports in USD

export const setupTradPlusRevenueTracking = () => {
  tradPlusEventEmitter.addListener('onImpressionSuccess', (tpAdInfo) => {
    // Validate ad info
    if (!tpAdInfo) {
      console.error('AdInfo is null');
      return;
    }

    // eCPM is reported in milli-units - convert to dollars
    if (!tpAdInfo.ecpm || typeof tpAdInfo.ecpm !== 'number') {
      console.error('Invalid eCPM value:', tpAdInfo.ecpm);
      return;
    }

    const revenue = tpAdInfo.ecpm / 1000.0;

    // Validate revenue after conversion
    if (revenue <= 0) {
      console.error('Revenue out of expected range:', revenue);
      return;
    }

    const adRevenueData = {
      adPlatform: AD_PLATFORM,
      currency: CURRENCY,
      revenue: revenue
    };

    // Send to Singular
    NativeSingular.adRevenue(adRevenueData);

    console.log('TradPlus ad revenue reported:', adRevenueData);
  });

  console.log('TradPlus revenue tracking initialized');
};

Implementation Notes:

  • eCPM Format: TradPlus reports eCPM in milli-units—always divide by 1000 before sending to Singular
  • Type Checking: Verify eCPM is a number before conversion
  • Post-Conversion Validation: Validate revenue is greater than 0 after division

Generic Integration

Implement ad revenue tracking for custom mediation platforms or direct integrations using the generic adRevenue() method.

When to Use Generic Integration

  • Custom mediation platforms not covered by standard integrations
  • Direct ad network integrations without mediation
  • Server-side ad revenue calculations forwarded to the app
  • Testing ad revenue tracking with mock data

Generic Implementation Example

Create a reusable function to report ad revenue from any source with proper validation.

New ArchitectureOld Architecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import NativeSingular from 'singular-react-native/js/NativeSingular';

/**
 * Report ad revenue to Singular with validation
 * 
 * @param {string} adPlatform - Name of the ad platform or mediation provider
 * @param {string} currency - ISO 4217 three-letter currency code (e.g., 'USD', 'EUR')
 * @param {number} revenue - Revenue amount in the specified currency
 */
export const reportAdRevenue = (adPlatform, currency, revenue) => {
  // Validate platform
  if (!adPlatform || adPlatform.trim() === '') {
    console.error('Invalid ad platform:', adPlatform);
    return;
  }

  // Validate currency code
  if (!currency || currency.trim() === '' || currency.length !== 3) {
    console.error('Invalid currency code:', currency);
    return;
  }

  // Validate revenue
  if (typeof revenue !== 'number' || revenue <= 0 || !isFinite(revenue)) {
    console.error('Invalid revenue value:', revenue);
    return;
  }

  const adRevenueData = {
    adPlatform: adPlatform.trim(),
    currency: currency.toUpperCase().trim(),
    revenue: revenue
  };

  // Send to Singular
  NativeSingular.adRevenue(adRevenueData);

  console.log('Ad Revenue reported to Singular:', adRevenueData);
};

// Example usage
export const trackCustomAdRevenue = () => {
  // Example: Custom mediation platform
  reportAdRevenue('CustomPlatform', 'USD', 0.05);

  // Example: Direct network integration
  reportAdRevenue('FacebookAudienceNetwork', 'EUR', 0.03);
};

Validation Features:

  • Platform Validation: Ensures platform name is non-empty and trimmed
  • Currency Validation: Verifies three-letter ISO 4217 code format and converts to uppercase
  • Revenue Validation: Checks for positive number, excludes NaN and Infinity
  • Type Safety: TypeScript interface ensures compile-time type checking

Best Practices

Data Validation

Implement robust validation to prevent incorrect data from reaching Singular analytics.

  • Positive Revenue: Always verify revenue is greater than zero before sending
  • Valid Currency: Use ISO 4217 codes and verify non-empty strings
  • Platform Consistency: Use consistent platform names across your app (e.g., always "AdMob", not "Admob" or "ADMOB")
  • Type Checking: Verify data types match expected values (number for revenue, string for currency/platform)
  • Null Checks: Handle null, undefined, and empty values appropriately

Critical: Incorrect ad revenue data cannot be corrected retroactively in Singular. Always validate data before calling Singular.adRevenue().


Currency Handling

Ensure accurate currency reporting for multi-region apps and diverse ad networks.

  • Verify Platform Currency: Check your mediation platform documentation for default currency (most use USD)
  • Consistent Format: Always use uppercase three-letter ISO 4217 codes
  • No Conversion: Report revenue in the currency provided by the ad network—do not convert currencies
  • Currency Per Network: Different ad networks may report in different currencies—verify each separately

Platform-Specific Considerations

Handle platform differences in revenue reporting formats and units.

  • AdMob Android: Revenue reported in micros—divide by 1,000,000 to convert to dollars
  • AdMob iOS: Revenue reported in dollars—use value directly without conversion
  • TradPlus: eCPM reported in milli-units—divide by 1,000 to convert to dollars
  • AppLovin: Revenue reported in dollars—use value directly
  • IronSource: Revenue reported in dollars—use value directly

Error Handling and Logging

Implement comprehensive logging for debugging and monitoring ad revenue tracking.

  • Validation Failures: Log detailed error messages when validation fails, including actual values received
  • Success Logging: Log successful revenue reports in development with platform, currency, and amount
  • Production Monitoring: Use error tracking services (Sentry, Bugsnag) to monitor validation failures in production
  • Revenue Anomalies: Alert on unusually high or low revenue values that may indicate integration issues
  • Platform Coverage: Monitor which ad platforms are reporting revenue to ensure all are integrated correctly

Testing Strategy

Verify ad revenue tracking implementation before production deployment.

  1. Test Ads: Use test ad units from your mediation platform during development
  2. Validate Events: Check Singular dashboard for ad revenue events after test ad impressions
  3. Verify Currency: Confirm currency codes appear correctly in Singular reports
  4. Platform Accuracy: Ensure platform names are consistent and recognizable in reports
  5. Revenue Amounts: Verify revenue amounts match expected ranges for test ad units
  6. Multi-Platform: Test on both iOS and Android to verify platform-specific conversion logic

Performance Optimization

Minimize performance impact of ad revenue tracking on your app.

  • Asynchronous Processing: Revenue callbacks execute asynchronously—no blocking of main thread
  • Minimal Validation: Keep validation logic simple and fast (type checks, range checks)
  • Batch Consideration: For high-volume apps, consider batching if supported by your analytics backend
  • Error Handling: Use try-catch blocks to prevent revenue tracking errors from crashing your app

Verification and Troubleshooting

Verify Implementation

Confirm ad revenue data is flowing correctly to Singular.

  1. Enable Test Ads: Configure test mode in your mediation platform
  2. Trigger Impressions: Display test ads and trigger paid events
  3. Check Logs: Verify revenue tracking logs appear in console with correct values
  4. Dashboard Verification: Check Singular dashboard for ad revenue events (may take 15-30 minutes)
  5. Event Details: Verify currency, platform, and revenue amounts in Singular event details

Common Issues

  • No Revenue Events: Verify paid event handlers are registered before loading ads and mediation SDK is initialized correctly
  • Zero Revenue: Check platform-specific conversion logic (micros to dollars for Android AdMob, millis to dollars for TradPlus)
  • Wrong Currency: Verify currency code matches what your mediation platform reports—check platform documentation
  • Platform Name Mismatch: Use consistent platform names that match Singular's recognized platforms
  • Missing Events: Ensure Singular SDK is initialized before ad revenue events occur
  • Duplicate Events: Verify paid event handlers are registered only once, not on every ad load

Additional Resources: For detailed information, see the Ad Revenue Attribution FAQ and React Native SDK Methods Reference.