SDK de Flutter - Seguimiento de los ingresos publicitarios

Documento

Atribución de ingresos publicitarios

Realice un seguimiento de los ingresos publicitarios de las plataformas de mediación y atribúyalos a las campañas de marketing específicas que llevaron a los usuarios a su aplicación, lo que permite un análisis exhaustivo del ROI.

Ad Revenue Attribution conecta los ingresos publicitarios de las aplicaciones móviles con las campañas de marketing que generaron usuarios, combinando el coste de la campaña, los ingresos dentro de la aplicación y los ingresos publicitarios en un informe unificado. Estos datos también se transmiten a las redes publicitarias para optimizar el rendimiento de las campañas.

Más información: Consulte Singular Ad Revenue Attribution FAQ para obtener información detallada sobre la metodología de atribución y las plataformas de mediación compatibles.


Cómo funciona la atribución de ingresos publicitarios

Flujo de atribución

Su plataforma de mediación comunica los datos de ingresos a nivel de impresión o a nivel de usuario a través de callbacks, que usted valida y envía a Singular para el análisis de atribución.

  • Atribución de campaña: Vincula los ingresos publicitarios a las campañas específicas que adquirieron cada usuario, mostrando el verdadero ROI por campaña.
  • Fuentes de datos: Los datos de ingresos proceden de su plataforma de mediación, ya sea a nivel de usuario o de impresión.
  • Optimización de la red: Singular transmite los datos de ingresos a las redes publicitarias para mejorar las estrategias de segmentación y pujas.

Requisitos de implementación

Asegúrese de la exactitud de los datos antes de implementar el seguimiento de ingresos publicitarios, ya que los datos de ingresos incorrectos no se pueden corregir después de la transmisión.

Requisitos críticos:

  • Códigos de moneda: Utilice códigos ISO 4217 de tres letras (USD, EUR, INR). La mayoría de las plataformas de mediación utilizan USD por defecto.
  • Validación de datos: Valide siempre que los valores de los ingresos sean positivos y que los códigos de moneda no estén vacíos antes de enviarlos a Singular.
  • Conversión de unidades: Algunas plataformas informan de los ingresos en micros (1.000.000 = 1,00 $). Convertir a dólares antes de enviar a Singular

Pasos de configuración

Siga estos pasos para implementar la atribución de ingresos publicitarios con su plataforma de mediación.

  1. Actualice el SDK: Asegúrese de que está ejecutando la última versión del SDK de Singular Flutter.
  2. Configure la plataforma: Habilite los informes de ingresos publicitarios en el panel de su plataforma de mediación (AdMob, AppLovin, etc.)
  3. Implemente retrollamadas: Añada escuchadores de eventos de ingresos desde su SDK de mediación para capturar los datos de impresión.
  4. Valide los datos: Compruebe que los ingresos sean superiores a 0 y que la divisa sea válida antes de reenviarlos a Singular.
  5. Pruebe la integración: Compruebe que los datos de ingresos aparecen en los informes de Singular en 24 horas

Integración con AdMob

Requisitos previos

Habilite los informes de ingresos publicitarios en su cuenta de AdMob e implemente el SDK de Google Mobile Ads para Flutter antes de la integración con Singular.

  • Configuración de AdMob: Habilite los ingresos publicitarios a nivel de impresión en su panel de AdMob. Consulte Soporte de AdMob
  • Paquete Flutter: instale el paquete google_mobile_ads. Consulte la Guía de introducción

Diferencias entre plataformas: AdMob informa de los ingresos de forma diferente según la plataforma. Android devuelve los ingresos en micros (5000 = 0,005 $), mientras que iOS devuelve valores decimales (0,005 = 0,005 $). Convierta los valores de Android dividiéndolos por 1.000.000 antes de enviarlos a Singular.


Pasos de implementación

Configure la devolución de llamada onPaidEvent al cargar anuncios para capturar los datos de ingresos de las impresiones de anuncios correctas.

  1. Cargar anuncio: Cree y cargue un bloque de anuncios (recompensado, intersticial, banner, etc.).
  2. Establecer devolución de llamada: Asigne onPaidEvent callback para capturar AdValue cuando el anuncio genere ingresos
  3. Convertir unidades: Divida valueMicros entre 1.000.000 para convertir a dólares.
  4. Validar: Compruebe que los ingresos sean > 0 y que la divisa no esté vacía
  5. Enviar a Singular: Llamar a Singular.adRevenue() con los datos validados

Ejemplo de anuncio con recompensa

Capture ingresos publicitarios de anuncios de vídeo con recompensa configurando la devolución de llamada onPaidEvent una vez finalizada la carga del anuncio.

Dart
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:singular_flutter_sdk/singular.dart';

const String adUnitId = 'YOUR_AD_UNIT_ID';

class AdManager {
  RewardedAd? _rewardedAd;

  void loadRewardedAd() {
    RewardedAd.load(
      adUnitId: adUnitId,
      request: AdRequest(),
      rewardedAdLoadCallback: RewardedAdLoadCallback(
        onAdLoaded: (RewardedAd ad) {
          _rewardedAd = ad;
          print('Rewarded ad loaded successfully');

          // Set up full screen content callback
          _rewardedAd?.fullScreenContentCallback = FullScreenContentCallback(
            onAdShowedFullScreenContent: () {
              print('Rewarded ad displayed');
            },
            onAdFailedToShowFullScreenContent: (AdError adError) {
              print('Rewarded ad failed to show: ${adError.message}');
            },
            onAdDismissedFullScreenContent: () {
              print('Rewarded ad dismissed');
              _rewardedAd = null;
            },
          );

          // Set up paid event callback for revenue tracking
          _rewardedAd?.onPaidEvent = (AdValue adValue) {
            // Convert revenue from micros to dollars
            double revenue = adValue.valueMicros / 1_000_000.0;
            String? currency = adValue.currencyCode;

            // Validate revenue and currency before sending
            if (revenue > 0 && currency != null && currency.isNotEmpty) {
              final adData = {
                'adPlatform': 'AdMob',
                'currency': currency,
                'revenue': revenue,
              };

              // Send ad revenue data to Singular
              Singular.adRevenue(adData);

              // Log for debugging
              print('Ad Revenue reported: $revenue $currency');
            } else {
              print('Invalid ad revenue: revenue=$revenue, currency=$currency');
            }
          };
        },
        onAdFailedToLoad: (LoadAdError loadAdError) {
          print('Rewarded ad failed to load: ${loadAdError.message}');
        },
      ),
    );
  }

  void showRewardedAd() {
    if (_rewardedAd != null) {
      _rewardedAd!.show(
        onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {
          print('User earned reward: ${reward.amount} ${reward.type}');
        },
      );
    } else {
      print('Rewarded ad not ready');
    }
  }
}

Ejemplo de anuncio intersticial

Realice un seguimiento de los ingresos de los anuncios intersticiales utilizando el mismo patrón onPaidEvent.

Dart
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:singular_flutter_sdk/singular.dart';

const String interstitialAdUnitId = 'YOUR_INTERSTITIAL_AD_UNIT_ID';

class InterstitialAdManager {
  InterstitialAd? _interstitialAd;

  void loadInterstitialAd() {
    InterstitialAd.load(
      adUnitId: interstitialAdUnitId,
      request: AdRequest(),
      adLoadCallback: InterstitialAdLoadCallback(
        onAdLoaded: (InterstitialAd ad) {
          _interstitialAd = ad;
          print('Interstitial ad loaded');

          // Set paid event callback
          _interstitialAd?.onPaidEvent = (AdValue adValue) {
            double revenue = adValue.valueMicros / 1_000_000.0;
            String? currency = adValue.currencyCode;

            if (revenue > 0 && currency != null && currency.isNotEmpty) {
              Singular.adRevenue({
                'adPlatform': 'AdMob',
                'currency': currency,
                'revenue': revenue,
              });
              
              print('Interstitial revenue: $revenue $currency');
            }
          };

          // Set full screen callback
          _interstitialAd?.fullScreenContentCallback = FullScreenContentCallback(
            onAdDismissedFullScreenContent: () {
              _interstitialAd = null;
              loadInterstitialAd(); // Load next ad
            },
          );
        },
        onAdFailedToLoad: (LoadAdError error) {
          print('Interstitial ad failed to load: ${error.message}');
        },
      ),
    );
  }

  void showInterstitialAd() {
    _interstitialAd?.show();
  }
}

Ejemplo de anuncio de banner

Realice un seguimiento de los ingresos procedentes de los banners publicitarios mostrados en su interfaz de usuario de Flutter.

Dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:singular_flutter_sdk/singular.dart';

const String bannerAdUnitId = 'YOUR_BANNER_AD_UNIT_ID';

class BannerAdWidget extends StatefulWidget {
  @override
  _BannerAdWidgetState createState() => _BannerAdWidgetState();
}

class _BannerAdWidgetState extends State<BannerAdWidget> {
  BannerAd? _bannerAd;
  bool _isBannerAdReady = false;

  @override
  void initState() {
    super.initState();
    _loadBannerAd();
  }

  void _loadBannerAd() {
    _bannerAd = BannerAd(
      adUnitId: bannerAdUnitId,
      size: AdSize.banner,
      request: AdRequest(),
      listener: BannerAdListener(
        onAdLoaded: (Ad ad) {
          setState(() {
            _isBannerAdReady = true;
          });
          print('Banner ad loaded');

          // Set paid event callback
          (ad as BannerAd).onPaidEvent = (AdValue adValue) {
            double revenue = adValue.valueMicros / 1_000_000.0;
            String? currency = adValue.currencyCode;

            if (revenue > 0 && currency != null && currency.isNotEmpty) {
              Singular.adRevenue({
                'adPlatform': 'AdMob',
                'currency': currency,
                'revenue': revenue,
              });
              
              print('Banner revenue: $revenue $currency');
            }
          };
        },
        onAdFailedToLoad: (Ad ad, LoadAdError error) {
          ad.dispose();
          print('Banner ad failed to load: ${error.message}');
        },
      ),
    );

    _bannerAd?.load();
  }

  @override
  void dispose() {
    _bannerAd?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_isBannerAdReady && _bannerAd != null) {
      return Container(
        alignment: Alignment.center,
        width: _bannerAd!.size.width.toDouble(),
        height: _bannerAd!.size.height.toDouble(),
        child: AdWidget(ad: _bannerAd!),
      );
    }
    return SizedBox.shrink();
  }
}

Integración de AppLovin MAX

Requisitos previos

Implemente el complemento AppLovin MAX Flutter y configure el seguimiento de ingresos a nivel de impresión antes de integrarlo con Singular.

  • Configuración MAX: Configure su aplicación en el panel de AppLovin MAX.
  • Plugin Flutter: Instala el paquete applovin_max. Consulte la Guía de introducción
  • API de ingresos: Habilita Impression-Level User Revenue API en la configuración del panel MAX.

Descripción general de la implementación

Configure onAdRevenuePaidCallback listeners para cada formato de anuncio para capturar ingresos cuando las impresiones generen ganancias.

  1. Inicializar MAX: Configure AppLovin MAX SDK con su clave SDK.
  2. Configurar escuchas: Añadir onAdRevenuePaidCallback para cada formato de anuncio
  3. Extraer ingresos: Obtenga ingresos de la propiedad ad.revenue
  4. Manejo de divisas: AppLovin normalmente informa en USD, pero verifíquelo con ad.currency
  5. Enviar a Singular: Envía los datos validados a Singular.adRevenue()

Implementación completa de MAX

Capture los ingresos de todos los formatos publicitarios MAX (Rewarded, Interstitial, Banner, MREC) utilizando un gestor unificado.

Dart
import 'package:flutter/material.dart';
import 'package:applovin_max/applovin_max.dart';
import 'package:singular_flutter_sdk/singular.dart';

class AppLovinMaxManager extends StatefulWidget {
  @override
  _AppLovinMaxManagerState createState() => _AppLovinMaxManagerState();
}

class _AppLovinMaxManagerState extends State<AppLovinMaxManager> {
  @override
  void initState() {
    super.initState();
    _initializeAppLovinMax();
  }

  Future<void> _initializeAppLovinMax() async {
    // Initialize AppLovin MAX SDK
    await AppLovinMAX.initialize('YOUR_SDK_KEY');

    // Set up revenue listeners for all ad formats
    _setupRewardedAdListeners();
    _setupInterstitialAdListeners();
    _setupBannerAdListeners();
    _setupMRecAdListeners();

    print('AppLovin MAX initialized with revenue tracking');
  }

  void _setupRewardedAdListeners() {
    AppLovinMAX.setRewardedAdListener(RewardedAdListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'Rewarded');
      },
      onAdLoadedCallback: (ad) {
        print('Rewarded ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('Rewarded ad failed to load: $error');
      },
    ));
  }

  void _setupInterstitialAdListeners() {
    AppLovinMAX.setInterstitialListener(InterstitialListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'Interstitial');
      },
      onAdLoadedCallback: (ad) {
        print('Interstitial ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('Interstitial ad failed to load: $error');
      },
    ));
  }

  void _setupBannerAdListeners() {
    AppLovinMAX.setBannerListener(AdViewAdListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'Banner');
      },
      onAdLoadedCallback: (ad) {
        print('Banner ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('Banner ad failed to load: $error');
      },
    ));
  }

  void _setupMRecAdListeners() {
    AppLovinMAX.setMRecListener(AdViewAdListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'MREC');
      },
      onAdLoadedCallback: (ad) {
        print('MREC ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('MREC ad failed to load: $error');
      },
    ));
  }

  void _handleAdRevenuePaid(Ad ad, String adType) {
    // Extract revenue and currency from ad object
    final double revenueValue = ad.revenue ?? 0.0;
    final String currency = ad.revenueCurrency ?? 'USD';

    // Validate revenue before sending
    if (revenueValue > 0) {
      final adData = {
        'adPlatform': 'AppLovin',
        'currency': currency,
        'revenue': revenueValue,
      };

      // Send ad revenue to Singular
      Singular.adRevenue(adData);

      // Log for debugging
      print('[$adType] Revenue: $revenueValue $currency');
    } else {
      print('[$adType] Invalid revenue: $revenueValue');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('AppLovin MAX Revenue Tracking'),
      ),
      body: Center(
        child: Text('MAX revenue tracking active'),
      ),
    );
  }
}

Práctica recomendada: Configure los receptores de ingresos publicitarios durante la inicialización de la aplicación antes de cargar los anuncios para garantizar que no se pierda ninguna impresión.


Integración con IronSource (Unity LevelPlay)

Requisitos previos

Habilite Impression Level Revenue (ILR) en su panel de IronSource e implemente el plugin IronSource Flutter antes de integrar con Singular.

  • Configuración de IronSource: Habilite ARM SDK Postbacks Flag en el cuadro de mandos de IronSource
  • Plugin Flutter: Instale el paquete ironsource_mediation. Consulte la Guía de introducción
  • API ILR: Configure el seguimiento de ingresos a nivel de impresión para su aplicación

Ejemplo de implementación

Utilice la devolución de llamada onImpressionDataSuccess para capturar datos de ingresos a nivel de impresión de la mediación IronSource.

Dart
import 'package:ironsource_mediation/ironsource_mediation.dart';
import 'package:singular_flutter_sdk/singular.dart';

void setupIronSourceRevenueTracking() {
  // Set up impression data listener
  IronSource.setImpressionDataListener((ISImpressionData? impressionData) {
    onImpressionDataSuccess(impressionData);
  });
}

void onImpressionDataSuccess(ISImpressionData? impressionData) {
  // Ensure impression data is not null
  if (impressionData == null) {
    print('No impression data available');
    return;
  }

  // Extract and validate revenue
  final revenue = impressionData.revenue?.toDouble() ?? 0.0;
  
  if (revenue <= 0) {
    print('Invalid revenue value: $revenue');
    return;
  }

  // Create ad revenue data for Singular
  final adData = {
    'adPlatform': 'IronSource',
    'currency': 'USD',
    'revenue': revenue,
  };

  // Send to Singular
  Singular.adRevenue(adData);

  // Log for debugging
  print('IronSource Revenue: $revenue USD');
}

Integración de TradPlus

Requisitos previos

Configure el delegado de impresiones de TradPlus para capturar datos de eCPM cuando los anuncios generen ingresos.

  • Configuración de TradPlus: Configure su aplicación en el panel de TradPlus.
  • Delegado de impresión: Habilite el seguimiento a nivel de impresión en los ajustes de TradPlus

Conversión eCPM: TradPlus suele informar del eCPM en mili-unidades. Divídalo por 1000,0 para convertirlo a dólares antes de enviarlo a Singular.


Ejemplo de implementación

Utilice la escucha de impresiones global para capturar los datos de ingresos de todos los formatos de anuncios de TradPlus.

Dart
import 'package:singular_flutter_sdk/singular.dart';

void setupTradPlusImpressionListener() {
  // Set up global impression listener
  TradPlusSdk.setGlobalImpressionListener((tpAdInfo) {
    if (tpAdInfo == null) {
      print('AdInfo is null');
      return;
    }

    // Ensure eCPM is available
    if (tpAdInfo.ecpm == null) {
      print('eCPM value is null');
      return;
    }

    // Convert eCPM from milli-units to dollars
    double revenue = tpAdInfo.ecpm! / 1000.0;

    // Validate revenue
    if (revenue <= 0) {
      print('Invalid revenue: $revenue');
      return;
    }

    // Create ad revenue data
    final adData = {
      'adPlatform': 'TradPlus',
      'currency': 'USD',
      'revenue': revenue,
    };

    // Send to Singular
    Singular.adRevenue(adData);

    // Log for debugging
    print('TradPlus Revenue: $revenue USD');
  });
}

void main() {
  // Initialize TradPlus SDK
  setupTradPlusImpressionListener();
  
  runApp(MyApp());
}

Integración genérica (otras plataformas)

Implementación personalizada

Para plataformas de mediación no cubiertas explícitamente anteriormente, implemente un gestor de ingresos personalizado utilizando el método de ingresos de anuncios de Singular.

Dart
import 'package:singular_flutter_sdk/singular.dart';

/// Generic function to report ad revenue to Singular
/// Use this for any mediation platform not explicitly supported above
void reportAdRevenue({
  required String adPlatform,
  required String currency,
  required double revenue,
}) {
  // Validate revenue value
  if (revenue <= 0) {
    print('Invalid revenue value: $revenue');
    return;
  }

  // Validate currency code
  if (currency.isEmpty) {
    print('Currency code is empty');
    return;
  }

  // Create ad revenue data
  final adData = {
    'adPlatform': adPlatform,
    'currency': currency,
    'revenue': revenue,
  };

  // Send to Singular
  Singular.adRevenue(adData);

  // Log for debugging
  print('Ad Revenue reported: $revenue $currency from $adPlatform');
}

// Example usage with a custom mediation platform
void onCustomAdImpression(Map<String, dynamic> impressionData) {
  reportAdRevenue(
    adPlatform: 'CustomNetwork',
    currency: impressionData['currency'] ?? 'USD',
    revenue: impressionData['revenue'] ?? 0.0,
  );
}

Mejores prácticas y resolución de problemas

Validación de datos

  • Validar siempre: compruebe que los ingresos sean superiores a 0 y que la divisa no esté vacía antes de enviar los datos a Singular.
  • Conversión de unidades: Verifique si su plataforma informa en micros o en dólares y convierta en consecuencia
  • Códigos de moneda: Utilice códigos ISO 4217 de tres letras (USD, EUR, JPY) de forma coherente
  • Pruebe a fondo: Verifique que los datos de ingresos aparecen en los informes de Singular antes del lanzamiento de producción

Problemas comunes

  • Falta de ingresos: Asegúrese de que los ingresos a nivel de impresión están habilitados en el panel de su plataforma de mediación.
  • Valores incorrectos: Compruebe la conversión de unidades (micros vs dólares) para su plataforma específica
  • No hay datos en los informes: Espere de 24 a 48 horas para que los datos aparezcan en los informes de Singular después de la implementación
  • Ingresos nulos: Compruebe que las devoluciones de llamada de los anuncios están correctamente configuradas antes de que se complete la carga del anuncio.

Importante: Los datos de ingresos por anuncios no se pueden corregir después de la transmisión. Valide siempre la exactitud de los datos antes de llamar a Singular.adRevenue().