Guía de implementación técnica de los eventos de suscripción

Documento

Guía de Implementación de Seguimiento de Eventos de Suscripción

Implemente un seguimiento exhaustivo de las suscripciones para medir los ingresos por suscripciones, la retención de usuarios y el rendimiento de las campañas en todas las plataformas mediante el SDK de Singular, la integración de servidor a servidor o los socios de terceros.

Singular permite la atribución precisa de eventos de suscripción -incluyendo nuevas suscripciones, renovaciones, pruebas, cancelaciones y reembolsos- a las campañas de marketing que generaron usuarios, proporcionando una visibilidad completa del ciclo de vida de la suscripción y la generación de ingresos.


Opciones de implantación

Elija el método de implementación que mejor se adapte a la arquitectura de su aplicación y a sus requisitos empresariales.

Consideración Integración SDK Servidor a servidor (S2S) Integración de terceros
Implementación Enviar eventos de suscripción a través de métodos de ingresos personalizados en el SDK de Singular Enviar eventos desde su backend a la API REST de Singular con las propiedades requeridas del dispositivo móvil Configurar integraciones con RevenueCat, Adapty u otras plataformas de suscripción
Dependencia de la actividad de la aplicación La aplicación debe ser lanzada para que el SDK envíe eventos Eventos enviados en tiempo real, independientemente del estado de la aplicación Eventos enviados en tiempo real desde una plataforma asociada
Cronología de eventos La hora del evento puede diferir de la hora de suscripción real en función del lanzamiento de la aplicación. Seguimiento de eventos en tiempo real cuando se procesan en el backend Seguimiento casi en tiempo real tras el procesamiento del socio
Complejidad Implementación sencilla del lado del cliente Requiere una infraestructura backend segura Requiere cuenta de socio y configuración

Importante: La mayoría de los clientes que utilizan S2S o integraciones de terceros para los eventos de suscripción deben integrar el SDK de Singular para gestionar las sesiones y los eventos no relacionados con la suscripción para un seguimiento completo de la atribución.


Android: Integración de facturación de Google Play

Integre Google Play Billing Library 8.0.0 para consultar la información de suscripción y gestionar el estado de suscripción directamente en el dispositivo para la integración de Singular SDK.

Requisitos previos

Configurar Google Play Console

Configure los productos integrados en la aplicación y los elementos de suscripción en Google Play Consoleantes de implementar la facturación en su aplicación.

  1. Crear productos de suscripción: Define niveles de suscripción, periodos de facturación y precios en Play Console.
  2. Configurar ofertas: Configura planes base, tokens de oferta y precios promocionales
  3. Configuración de prueba: Crear cuentas de prueba y verificar la disponibilidad del producto

Añadir dependencia de la biblioteca de facturación

Actualizar build.gradle

Añade Google Play Billing Library 8.0.0 a las dependencias de tu aplicación con extensiones Kotlin para compatibilidad con coroutines.

Kotlin DSL
dependencies {
    val billingVersion = "8.0.0"
    
    // Google Play Billing Library
    implementation("com.android.billingclient:billing:$billingVersion")
    
    // Kotlin extensions and coroutines support
    implementation("com.android.billingclient:billing-ktx:$billingVersion")
}

Características de la versión 8.0.0 Esta versión introduce la reconexión automática de servicios con enableAutoServiceReconnection(), API de consulta de compras mejoradas y gestión de transacciones pendientes mejorada.


Inicializar BillingClient

Crear gestor de facturación

Configure una clase de gestor de facturación para gestionar todas las operaciones de suscripción e integrar con Singular SDK para el seguimiento de eventos.

Kotlin
class SubscriptionManager(private val context: Context) {
    
    private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases ->
        when (billingResult.responseCode) {
            BillingResponseCode.OK -> {
                purchases?.forEach { purchase ->
                    handlePurchaseUpdate(purchase)
                }
            }
            BillingResponseCode.USER_CANCELED -> {
                Log.d(TAG, "User canceled the purchase")
            }
            else -> {
                Log.e(TAG, "Purchase error: ${billingResult.debugMessage}")
            }
        }
    }
    
    private val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases() // Required for all purchases
        .enableAutoServiceReconnection() // NEW in 8.0.0 - handles reconnection automatically
        .build()
    
    fun initialize() {
        billingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                if (billingResult.responseCode == BillingResponseCode.OK) {
                    Log.d(TAG, "Billing client ready")
                    // Query existing subscriptions
                    queryExistingSubscriptions()
                } else {
                    Log.e(TAG, "Billing setup failed: ${billingResult.debugMessage}")
                }
            }
            
            override fun onBillingServiceDisconnected() {
                // With enableAutoServiceReconnection(), SDK handles reconnection
                // Manual retry is no longer required
                Log.d(TAG, "Billing service disconnected - auto-reconnection enabled")
            }
        })
    }
    
    companion object {
        private const val TAG = "SubscriptionManager"
    }
}

Características principales:

  • Reconexión automática: La versión 8.0.0 de enableAutoServiceReconnection() restablece automáticamente las conexiones cuando es necesario.
  • Receptor de compras: Recibe llamadas de retorno para todas las actualizaciones de compra, incluidas las renovaciones y las transacciones pendientes.
  • Gestión de errores: Gestión exhaustiva de cancelaciones de usuarios y errores de facturación.

Consulta de información de suscripción

Recuperación de suscripciones activas

Consulte las suscripciones existentes utilizando queryPurchasesAsync()para gestionar las renovaciones y las suscripciones adquiridas fuera de su aplicación.

Kotlin
private suspend fun queryExistingSubscriptions() {
    val params = QueryPurchasesParams.newBuilder()
        .setProductType(BillingClient.ProductType.SUBS)
        .build()
    
    withContext(Dispatchers.IO) {
        val result = billingClient.queryPurchasesAsync(params)
        
        if (result.billingResult.responseCode == BillingResponseCode.OK) {
            result.purchasesList.forEach { purchase ->
                when (purchase.purchaseState) {
                    Purchase.PurchaseState.PURCHASED -> {
                        // Active subscription - process it
                        handleSubscriptionPurchase(purchase)
                    }
                    Purchase.PurchaseState.PENDING -> {
                        // Pending payment - notify user
                        Log.d(TAG, "Subscription pending: ${purchase.products}")
                    }
                }
            }
        } else {
            Log.e(TAG, "Query failed: ${result.billingResult.debugMessage}")
        }
    }
}

Práctica recomendada: Llame a queryPurchasesAsync()en onResume() para detectar renovaciones de suscripciones que se hayan producido mientras su aplicación estaba en segundo plano o cerrada.


Consultar detalles del producto

Recupere los detalles del producto de suscripción, incluidos los precios, los períodos de facturación y los tokens de oferta antes de mostrarlos a los usuarios.

Kotlin
private suspend fun querySubscriptionProducts() {
    val productList = listOf(
        QueryProductDetailsParams.Product.newBuilder()
            .setProductId("premium_monthly")
            .setProductType(BillingClient.ProductType.SUBS)
            .build(),
        QueryProductDetailsParams.Product.newBuilder()
            .setProductId("premium_yearly")
            .setProductType(BillingClient.ProductType.SUBS)
            .build()
    )
    
    val params = QueryProductDetailsParams.newBuilder()
        .setProductList(productList)
        .build()
    
    withContext(Dispatchers.IO) {
        val productDetailsResult = billingClient.queryProductDetails(params)
        
        if (productDetailsResult.billingResult.responseCode == BillingResponseCode.OK) {
            // Process successfully retrieved product details
            productDetailsResult.productDetailsList?.forEach { productDetails ->
                // Extract subscription offers
                productDetails.subscriptionOfferDetails?.forEach { offer ->
                    val price = offer.pricingPhases.pricingPhaseList.firstOrNull()
                    Log.d(TAG, "Product: ${productDetails.productId}, Price: ${price?.formattedPrice}")
                }
            }
            
            // Handle unfetched products
            productDetailsResult.unfetchedProductList?.forEach { unfetchedProduct ->
                Log.w(TAG, "Unfetched: ${unfetchedProduct.productId}")
            }
        }
    }
}

Procesar actualizaciones de compras

Gestión de eventos de suscripción

Procese los cambios de estado de compra y envíe los eventos apropiados a Singular en función del ciclo de vida de la suscripción.

Kotlin
private fun handlePurchaseUpdate(purchase: Purchase) {
    when (purchase.purchaseState) {
        Purchase.PurchaseState.PURCHASED -> {
            if (!purchase.isAcknowledged) {
                // Verify purchase on your backend first
                verifyPurchaseOnBackend(purchase) { isValid ->
                    if (isValid) {
                        // Send subscription event to Singular
                        trackSubscriptionToSingular(purchase)
                        
                        // Grant entitlement to user
                        grantSubscriptionAccess(purchase)
                        
                        // Acknowledge purchase to Google
                        acknowledgePurchase(purchase)
                    }
                }
            }
        }
        Purchase.PurchaseState.PENDING -> {
            // Notify user that payment is pending
            Log.d(TAG, "Purchase pending approval: ${purchase.products}")
            notifyUserPendingPayment(purchase)
        }
    }
}

private fun trackSubscriptionToSingular(purchase: Purchase) {
    // Get cached product details for pricing information
    val productDetails = getCachedProductDetails(purchase.products.first())
    
    productDetails?.let { details ->
        val subscriptionOffer = details.subscriptionOfferDetails?.firstOrNull()
        val pricingPhase = subscriptionOffer?.pricingPhases?.pricingPhaseList?.firstOrNull()
        
        val price = pricingPhase?.priceAmountMicros?.div(1_000_000.0) ?: 0.0
        val currency = pricingPhase?.priceCurrencyCode ?: "USD"
        
        // Determine event name based on purchase type
        val eventName = if (isNewSubscription(purchase)) {
            "sng_subscribe"
        } else {
            "subscription_renewed"
        }
        
        // Send to Singular WITHOUT receipt
        Singular.customRevenue(
            eventName,
            currency,
            price,
            mapOf(
                "subscription_id" to purchase.products.first(),
                "order_id" to (purchase.orderId ?: ""),
                "purchase_time" to purchase.purchaseTime.toString()
            )
        )
        
        Log.d(TAG, "Tracked $eventName to Singular: $price $currency")
    }
}

private fun acknowledgePurchase(purchase: Purchase) {
    val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
        .setPurchaseToken(purchase.purchaseToken)
        .build()
    
    lifecycleScope.launch {
        val ackResult = withContext(Dispatchers.IO) {
            billingClient.acknowledgePurchase(acknowledgePurchaseParams)
        }
        
        if (ackResult.responseCode == BillingResponseCode.OK) {
            Log.d(TAG, "Purchase acknowledged successfully")
        } else {
            Log.e(TAG, "Acknowledgement failed: ${ackResult.debugMessage}")
        }
    }
}

Crítico: NO envíe el recibo de Google Play a Singular cuando rastree eventos de suscripción. Utilice el método customRevenue() sin validación de recibo. Acuse recibo de las compras en un plazo de 3 días o se reembolsarán automáticamente.


iOS: Integración con StoreKit

Integra el framework StoreKit de Apple para gestionar suscripciones y enviar eventos a Singular para apps iOS.

Requisitos previos

Configurar App Store Connect

Configura los productos de suscripción y los grupos de suscripción en App Store Connectantes de implementar StoreKit en tu app.

  1. Crear grupos de suscripción: Organiza las suscripciones en grupos en función de los niveles de acceso.
  2. Definir productos de suscripción: Configura niveles de suscripción, duraciones y precios.
  3. Configurar ofertas: Crear ofertas de lanzamiento, ofertas promocionales y códigos de suscripción
  4. Entorno de prueba: Configurar cuentas de prueba sandbox para el desarrollo

Implementar StoreKit

Configurar el observador de transacciones

Implementar SKPaymentTransactionObserver para recibir notificaciones de compra de suscripciones y renovaciones.

Swift
import StoreKit

class SubscriptionManager: NSObject, SKPaymentTransactionObserver {
    
    static let shared = SubscriptionManager()
    
    private override init() {
        super.init()
        // Add transaction observer
        SKPaymentQueue.default().add(self)
    }
    
    deinit {
        SKPaymentQueue.default().remove(self)
    }
    
    // MARK: - SKPaymentTransactionObserver
    
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case .purchased:
                // New subscription or renewal
                handlePurchasedTransaction(transaction)
                
            case .restored:
                // Subscription restored from another device
                handleRestoredTransaction(transaction)
                
            case .failed:
                // Purchase failed
                handleFailedTransaction(transaction)
                
            case .deferred:
                // Purchase awaiting approval (family sharing)
                print("Transaction deferred: \(transaction.payment.productIdentifier)")
                
            case .purchasing:
                // Transaction in progress
                break
                
            @unknown default:
                break
            }
        }
    }
    
    private func handlePurchasedTransaction(_ transaction: SKPaymentTransaction) {
        // Verify receipt with your backend
        verifyReceipt { isValid in
            if isValid {
                // Send to Singular
                self.trackSubscriptionToSingular(transaction)
                
                // Grant entitlement
                self.grantSubscriptionAccess(transaction)
                
                // Finish transaction
                SKPaymentQueue.default().finishTransaction(transaction)
            }
        }
    }
    
    private func trackSubscriptionToSingular(_ transaction: SKPaymentTransaction) {
        // Get product details for pricing
        let productId = transaction.payment.productIdentifier
        
        // You should cache product details from SKProductsRequest
        if let product = getCachedProduct(productId) {
            let price = product.price.doubleValue
            let currency = product.priceLocale.currencyCode ?? "USD"
            
            // Determine event name
            let eventName = isNewSubscription(transaction) ? "sng_subscribe" : "subscription_renewed"
            
            // Send to Singular WITHOUT receipt
            Singular.customRevenue(
                eventName,
                currency: currency,
                amount: price,
                withAttributes: [
                    "subscription_id": productId,
                    "transaction_id": transaction.transactionIdentifier ?? "",
                    "transaction_date": transaction.transactionDate?.timeIntervalSince1970 ?? 0
                ]
            )
        }
    }
}

Consultar el estado de la suscripción

Utilice la validación de recibos para comprobar el estado actual de la suscripción y gestionar las renovaciones.

Swift
func refreshSubscriptionStatus() {
    let request = SKReceiptRefreshRequest()
    request.delegate = self
    request.start()
}

extension SubscriptionManager: SKRequestDelegate {
    func requestDidFinish(_ request: SKRequest) {
        // Receipt refreshed successfully
        if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
           FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
            
            // Send receipt to your backend for validation
            validateReceiptOnServer()
        }
    }
    
    func request(_ request: SKRequest, didFailWithError error: Error) {
        print("Receipt refresh failed: \(error.localizedDescription)")
    }
}

Método de integración SDK

Envíe eventos de suscripción desde su aplicación utilizando los métodos de ingresos personalizados de Singular SDK sin validación de recibos.

Métodos SDK específicos de la plataforma

Utilice el método SDK apropiado para su plataforma para realizar el seguimiento de los eventos de suscripción.

SDK para Android

Kotlin
// Track subscription without receipt
Singular.customRevenue(
    "sng_subscribe",  // Event name
    "USD",            // Currency
    9.99,             // Amount
    mapOf(            // Additional attributes
        "subscription_id" to "premium_monthly",
        "billing_period" to "monthly"
    )
)

Documentación: SDK de Android Revenue Tracking


SDK para iOS

Swift
// Track subscription without receipt
Singular.customRevenue(
    "sng_subscribe",  // Event name
    currency: "USD",  // Currency
    amount: 9.99,     // Amount
    withAttributes: [ // Additional attributes
        "subscription_id": "premium_monthly",
        "billing_period": "monthly"
    ]
)

Documentación: Seguimiento de ingresos del SDK de iOS


SDK de React Native

JavaScript
// Track subscription without receipt
Singular.customRevenueWithArgs(
    "sng_subscribe",  // Event name
    "USD",            // Currency
    9.99,             // Amount
    {                 // Additional attributes
        subscription_id: "premium_monthly",
        billing_period: "monthly"
    }
);

Documentación: Seguimiento de ingresos del SDK de React Native


SDK de Unity

C#
// Track subscription without receipt
SingularSDK.CustomRevenue(
    "sng_subscribe",  // Event name
    "USD",            // Currency
    9.99,             // Amount
    new Dictionary<string, object> { // Additional attributes
        { "subscription_id", "premium_monthly" },
        { "billing_period", "monthly" }
    }
);

Documentación: Seguimiento de ingresos del SDK de Unity


SDK de Flutter

Dart
// Track subscription without receipt
Singular.customRevenueWithAttributes(
    "sng_subscribe",  // Event name
    "USD",            // Currency
    9.99,             // Amount
    {                 // Additional attributes
        "subscription_id": "premium_monthly",
        "billing_period": "monthly"
    }
);

Documentación: Seguimiento de ingresos del SDK de Flutter


SDK de Cordova

JavaScript
// Track subscription without receipt
cordova.plugins.SingularCordovaSdk.customRevenueWithArgs(
    "sng_subscribe",  // Event name
    "USD",            // Currency
    9.99,             // Amount
    {                 // Additional attributes
        subscription_id: "premium_monthly",
        billing_period: "monthly"
    }
);

Documentación: Seguimiento de ingresos de SDK de Cordova

Crítico: NO utilice métodos IAP (In-App Purchase) ni envíe valores de recibos a Singular para el seguimiento de suscripciones. Utilice únicamente métodos customRevenue() sin recibos.


Integración de servidor a servidor

Envíe eventos de suscripción en tiempo real desde su backend a la API REST de Singular para un seguimiento inmediato independiente del estado de la aplicación.

Requisitos de implementación

Utilice el punto final de eventos de Singular para enviar eventos de suscripción con parámetros de ingresos desde su backend seguro.

Punto final de eventos

Envíe solicitudes POST a la API de eventos de Singular con datos de eventos de suscripción y las propiedades requeridas del dispositivo móvil.

Punto final:

POST https://api.singular.net/api/v1/evt

Parámetros requeridos:

  • Clave SDK: Su clave del SDK de Singular (parámetroa )
  • Nombre del evento: Nombre del evento de suscripción ( parámetron)
  • Ingreso: Importe de la suscripción (amt parameter)
  • Divisa: Código de moneda ISO 4217 ( parámetrocur)
  • Identificadores de dispositivo: IDFA (iOS) o GAID (Android) para atribución
  • Plataforma: Sistema operativo ( parámetrop )

Documentación: Referencia de punto final de eventoy parámetros de ingresos


Ejemplo de solicitud

cURL
curl -X POST 'https://api.singular.net/api/v1/evt' \
  -H 'Content-Type: application/json' \
  -d '{
    "a": "YOUR_SDK_KEY",
    "n": "sng_subscribe",
    "r": 9.99,
    "pcc": "USD",
    "idfa": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "p": "iOS",
    "install_time": 1697000000000,
    "extra": {
      "subscription_id": "premium_monthly",
      "order_id": "GPA.1234.5678.9012"
    }
  }'

SDK no necesario: Si utiliza S2S para eventos de suscripción, no necesita enviar estos eventos desde el SDK. Sin embargo, la mayoría de las aplicaciones deberían integrar el SDK para el seguimiento de sesiones y eventos no relacionados con suscripciones.


Integraciones de terceros

Configure el seguimiento de suscripciones a través de plataformas de terceros que gestionen la infraestructura de suscripciones y envíen los eventos directamente a Singular.

Socios compatibles

Integre con plataformas de gestión de suscripciones que tienen soporte incorporado para Singular.

Integración con RevenueCat

RevenueCat gestiona la infraestructura de suscripción y envía automáticamente los eventos de suscripción a la API REST de Singular.

Pasos de configuración:

  1. Cree una cuenta RevenueCat: Configure su aplicación en el panel de RevenueCat.
  2. Configure la integración de Singular: Añada la clave del SDK de Singular en la configuración de integraciones de RevenueCat.
  3. Mapear Eventos: Configure qué eventos de RevenueCat deben enviarse a Singular
  4. Pruebe la integración: Compruebe que los eventos aparecen en el panel de control de Singular

Documentación: RevenueCat Singular Integration


Integración de Adapty

Adapty proporciona análisis de suscripciones y envía eventos a Singular a través de su integración.

Pasos de configuración:

  1. Cree una cuenta de Adapty: Regístrese y configure su aplicación en Adapty
  2. Habilita la integración con Singular: Navega hasta integraciones y añade las credenciales de Singular
  3. Configurar mapeo de eventos: Selecciona qué eventos de suscripción reenviar
  4. Verificar el flujo de datos: Confirmar que los eventos llegan a Singular correctamente

Documentación: Integración de Adapty Singular

Nota: Las integraciones de terceros son gestionadas por plataformas asociadas. La configuración debe completarse en sus respectivos cuadros de mando. Singular SDK debe seguir integrándose para el seguimiento de eventos de sesión y no de suscripción.


Tipos de eventos de suscripción

Realice el seguimiento de varios eventos del ciclo de vida de la suscripción para medir el compromiso, la retención y los ingresos de los usuarios a lo largo de todo el proceso de suscripción.

Nombres de eventos estándar

Utilice los nombres de eventos estándar de Singular para obtener informes coherentes en todas las plataformas, o defina nombres de eventos personalizados en función de sus requisitos de seguimiento.

Estado de la suscripción Nombre del evento Método SDK Integración S2S
Nueva Suscripción sng_subscribe customRevenue() con importe de ingresos (sin recibo) Punto final de evento con parámetros de ingresos
Inicio de prueba sng_start_trial método event() sin ingresos Punto final de evento estándar sin ingresos
Fin de prueba sng_end_trial Método event() sin ingresos Punto final de evento estándar sin ingresos
Renovación de suscripción subscription_renewed customRevenue() con importe de ingresos (sin recibo) Punto final de evento con parámetros de ingresos
Cancelación subscription_cancelled Método event() sin ingresos Punto final de evento estándar sin ingresos
Reembolso subscription_refunded customRevenue() con importe negativo (opcional) O evento() sin ingresos Endpoint de evento con importe negativo (opcional) O evento estándar

Importante: Al enviar eventos de suscripción mediante customRevenue(), sólo envíe eventos en los que isRestored sea falso. Las compras restauradas representan suscripciones existentes, no nuevos ingresos.


Ejemplos de implementación de eventos

Nueva suscripción

Realiza un seguimiento cuando los usuarios adquieren una nueva suscripción por primera vez.

Kotlin
// New subscription purchase
Singular.customRevenue(
    "sng_subscribe",
    "USD",
    9.99,
    mapOf(
        "subscription_tier" to "premium",
        "billing_period" to "monthly",
        "product_id" to "premium_monthly"
    )
)

Inicio de prueba

Realiza un seguimiento cuando los usuarios comienzan un período de prueba gratuito sin ingresos.

Kotlin
// Trial start (no revenue)
Singular.event(
    "sng_start_trial",
    mapOf(
        "trial_duration" to "7_days",
        "subscription_tier" to "premium"
    )
)

Renovación de Suscripción

Seguimiento de las renovaciones automáticas de suscripciones con importe de ingresos.

Kotlin
// Subscription renewal
Singular.customRevenue(
    "subscription_renewed",
    "USD",
    9.99,
    mapOf(
        "subscription_tier" to "premium",
        "renewal_count" to 3,
        "product_id" to "premium_monthly"
    )
)

Cancelación

Seguimiento de los usuarios que cancelan su suscripción (sin ingresos).

Kotlin
// Subscription cancelled (no revenue)
Singular.event(
    "subscription_cancelled",
    mapOf(
        "cancellation_reason" to "too_expensive",
        "days_active" to 45,
        "subscription_tier" to "premium"
    )
)

Medición de SKAdNetwork

Mida los eventos de suscripción a través de SKAdNetwork de Apple para una atribución compatible con la privacidad de iOS.

Soporte de suscripción SKAN

Singular puede medir datos de eventos de suscripción a través de todos los métodos de integración (SDK, S2S y terceros). La medición de eventos puede estar limitada por las ventanas de tiempo de postback de SKAN dependiendo de la versión de SKAN.

Implementación híbrida de SKAN

Para aplicaciones que utilizan Singular SDK para los eventos del ciclo de vida e integraciones S2S/de terceros para las suscripciones, habilite Hybrid SKAN para combinar ambas fuentes de datos.

Póngase en contacto con el servicio de asistencia: Póngase en contacto con su Customer Success Manager (CSM) para activar SKAN híbrido para su aplicación. Esto garantiza que los eventos de suscripción de las fuentes de backend se atribuyan correctamente en los valores de conversión de SKAN.

SKAN Postback Windows:

  • SKAN 4.0: Tres ventanas de postback (0-2 días, 3-7 días, 8-35 días) permiten la medición de eventos de suscripción temprana y renovaciones a corto plazo.
  • SKAN 3.0: La ventana única de 24 horas limita la medición a las suscripciones inmediatas.
  • Valores de conversión: Configure los eventos de suscripción en su esquema de valores de conversión de SKAN para dar prioridad a los eventos de alto valor.

Mejores prácticas y validación

Siga las mejores prácticas de implementación y verifique que el seguimiento de suscripciones funciona correctamente antes de la implementación en producción.

Mejores prácticas de implementación

Directrices clave

  • Sin validación de recibos: Nunca envíe recibos de plataforma (Google Play, App Store) a Singular cuando realice el seguimiento de suscripciones; utilice customRevenue() sin recibos.
  • Filtrar compras restauradas: Envíe únicamente eventos en los que isRestored sea falso para evitar la duplicación de informes de ingresos.
  • Verificación de backend: Verifique siempre las compras en su backend seguro antes de enviar eventos a Singular
  • Reconocimiento oportuno: Confirme las compras de Google Play en un plazo de 3 días para evitar reembolsos automáticos.
  • Consulta en reanudación: Llame a queryPurchasesAsync() en onResume() para capturar las renovaciones que se produjeron mientras la aplicación estaba cerrada
  • Nombres de eventos coherentes: Utilice nombres de eventos Singular estándar (sng_subscribe, subscription_renewed) para obtener informes unificados
  • Incluya metadatos: Añada atributos como subscription_tier, billing_period y product_id para un análisis detallado.

Pruebas y validación

Lista de comprobación de pruebas

  1. Configuración del entorno de prueba: Utilice cuentas sandbox/de prueba tanto para Google Play como para App Store.
  2. Nueva suscripción: Compruebe que el evento sng_subscribe se envía correctamente con el importe y la divisa adecuados.
  3. Flujo de prueba: Pruebe los eventos de inicio y fin de prueba sin ingresos
  4. Gestión de renovaciones: Confirmar que las renovaciones activan los eventos subscription_renewed con los ingresos correctos
  5. Seguimiento de cancelaciones: Verificar que los eventos de cancelación se activan cuando los usuarios cancelan suscripciones
  6. Filtrado de restauración: Asegúrese de que las compras restauradas no envían eventos duplicados
  7. Panel de Singular: Compruebe que los eventos aparecen en Singular con la atribución correcta
  8. Dispositivos cruzados: Pruebe la sincronización de suscripciones en varios dispositivos

Problemas comunes

  • Ausencia de eventos: Compruebe que la conexión con el cliente de facturación está activa y que se llama a queryPurchasesAsync() al reanudar la aplicación.
  • Eventos duplicados: Comprobar que las compras restauradas se filtran correctamente con la comprobación isRestored
  • Ingresos incorrectos: Asegúrese de que la extracción de precios de ProductDetails divide correctamente los micros entre 1.000.000
  • Problemas de atribución: Confirmar que los identificadores de dispositivo (IDFA/GAID) se incluyen correctamente en las solicitudes S2S
  • Fallos de acuse de recibo: Compruebe que la validación de recepción del backend se completa antes del acuse de recibo

Recursos de asistencia: Para obtener asistencia en la resolución de problemas, póngase en contacto con el servicio de asistencia de Singular e indíquenos la versión del SDK, los detalles de la plataforma, ejemplos de cargas útiles de eventos y capturas de pantalla del panel de control de Singular que muestren el problema.