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.
- Crear productos de suscripción: Define niveles de suscripción, periodos de facturación y precios en Play Console.
- Configurar ofertas: Configura planes base, tokens de oferta y precios promocionales
- 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.
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.
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.
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.
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.
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.
- Crear grupos de suscripción: Organiza las suscripciones en grupos en función de los niveles de acceso.
- Definir productos de suscripción: Configura niveles de suscripción, duraciones y precios.
- Configurar ofertas: Crear ofertas de lanzamiento, ofertas promocionales y códigos de suscripción
- 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.
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.
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
// 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
// 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
// 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
// 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
// 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
// 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ámetro
a) -
Nombre del evento: Nombre del evento de suscripción ( parámetro
n) -
Ingreso: Importe de la suscripción (
amtparameter) -
Divisa: Código de moneda ISO 4217 ( parámetro
cur) - Identificadores de dispositivo: IDFA (iOS) o GAID (Android) para atribución
-
Plataforma: Sistema operativo ( parámetro
p)
Documentación: Referencia de punto final de eventoy parámetros de ingresos
Ejemplo de solicitud
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:
- Cree una cuenta RevenueCat: Configure su aplicación en el panel de RevenueCat.
- Configure la integración de Singular: Añada la clave del SDK de Singular en la configuración de integraciones de RevenueCat.
- Mapear Eventos: Configure qué eventos de RevenueCat deben enviarse a Singular
- 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:
- Cree una cuenta de Adapty: Regístrese y configure su aplicación en Adapty
- Habilita la integración con Singular: Navega hasta integraciones y añade las credenciales de Singular
- Configurar mapeo de eventos: Selecciona qué eventos de suscripción reenviar
- 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.
// 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.
// 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.
// 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).
// 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
- Configuración del entorno de prueba: Utilice cuentas sandbox/de prueba tanto para Google Play como para App Store.
- Nueva suscripción: Compruebe que el evento sng_subscribe se envía correctamente con el importe y la divisa adecuados.
- Flujo de prueba: Pruebe los eventos de inicio y fin de prueba sin ingresos
- Gestión de renovaciones: Confirmar que las renovaciones activan los eventos subscription_renewed con los ingresos correctos
- Seguimiento de cancelaciones: Verificar que los eventos de cancelación se activan cuando los usuarios cancelan suscripciones
- Filtrado de restauración: Asegúrese de que las compras restauradas no envían eventos duplicados
- Panel de Singular: Compruebe que los eventos aparecen en Singular con la atribución correcta
- 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.