Guia de Implementação de Rastreamento de Eventos de Assinatura

Guia de Implementação de Rastreamento de Eventos de Assinatura

Implemente o rastreamento abrangente de assinaturas para medir a receita de assinaturas, a retenção de usuários e o desempenho de campanhas em todas as plataformas usando o SDK da Singular, integração server-to-server ou parceiros terceiros.

A Singular possibilita a atribuição precisa de eventos de assinatura—incluindo novas assinaturas, renovações, testes, cancelamentos e reembolsos—às campanhas de marketing que geraram os usuários, oferecendo visibilidade completa do ciclo de vida da assinatura e da geração de receita.


Opções de Implementação

Escolha o método de implementação que melhor se adequa à arquitetura do seu app e aos requisitos do seu negócio.

Consideração Integração por SDK Server-to-Server (S2S) Integração com Terceiros
Implementação Envie eventos de assinatura por meio de métodos de receita personalizados no SDK da Singular Envie eventos do seu backend para a REST API da Singular com as propriedades de dispositivo móvel necessárias Configure integrações com RevenueCat, Adapty, Superwall, Xsolla ou outras plataformas de assinatura
Dependência da Atividade do App O app precisa ser iniciado para que o SDK envie os eventos Eventos enviados em tempo real, independentemente do estado do app Eventos enviados em tempo real pela plataforma parceira
Momento do Evento O horário do evento pode diferir do horário real da assinatura, dependendo da inicialização do app Rastreamento de eventos em tempo real conforme processados no backend Rastreamento em tempo quase real após o processamento do parceiro
Complexidade Implementação simples no lado do cliente Requer uma infraestrutura de backend segura Requer conta e configuração do parceiro

Importante: A maioria dos clientes que usa integrações S2S ou de terceiros para eventos de assinatura ainda deve integrar o SDK da Singular para gerenciar sessões e eventos que não são de assinatura, para um rastreamento de atribuição completo.


Android: Integração com o Google Play Billing

Integre a Google Play Billing Library 8.0.0 para consultar informações de assinatura e gerenciar o estado da assinatura diretamente no dispositivo para a integração com o SDK da Singular.

Pré-requisitos

Configurar o Google Play Console

Configure produtos in-app e itens de assinatura no Google Play Console antes de implementar o billing no seu app.

  1. Criar Produtos de Assinatura: Defina os níveis de assinatura, os períodos de cobrança e os preços no Play Console
  2. Configurar Ofertas: Configure planos base, tokens de oferta e preços promocionais
  3. Configurar Testes: Crie contas de teste e verifique a disponibilidade dos produtos

Adicionar a Dependência da Billing Library

Atualizar o build.gradle

Adicione a Google Play Billing Library 8.0.0 às dependências do seu app com as extensões Kotlin para suporte a 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")
}

Recursos da Versão 8.0.0: Esta versão introduz a reconexão automática de serviço com enableAutoServiceReconnection() , APIs de consulta de compras aprimoradas e um tratamento melhorado de transações pendentes.


Inicializar o BillingClient

Criar o Billing Manager

Configure uma classe de billing manager para lidar com todas as operações de assinatura e integrar com o SDK da Singular para o rastreamento 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"
    }
}

Recursos Principais:

  • Reconexão Automática: O enableAutoServiceReconnection() da versão 8.0.0 restabelece automaticamente as conexões quando necessário
  • Purchase Listener: Recebe callbacks para todas as atualizações de compra, incluindo renovações e transações pendentes
  • Tratamento de Erros: Tratamento abrangente para cancelamentos de usuários e erros de billing

Consultar Informações de Assinatura

Recuperar Assinaturas Ativas

Consulte assinaturas existentes usando queryPurchasesAsync() para lidar com renovações e assinaturas compradas fora do seu app.

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}")
        }
    }
}

Boa Prática: Chame queryPurchasesAsync() em onResume() para capturar renovações de assinatura que ocorreram enquanto seu app estava em segundo plano ou fechado.


Consultar Detalhes do Produto

Recupere os detalhes do produto de assinatura, incluindo preços, períodos de cobrança e tokens de oferta, antes de exibi-los aos usuários.

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}")
            }
        }
    }
}

Processar Atualizações de Compra

Tratar Eventos de Assinatura

Processe as mudanças de estado da compra e envie os eventos apropriados para a Singular com base no ciclo de vida da assinatura.

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: NÃO envie o recibo do Google Play para a Singular ao rastrear eventos de assinatura. Use o método customRevenue() sem validação de recibo. Confirme as compras dentro de 3 dias, ou elas serão reembolsadas automaticamente.


iOS: Integração com o StoreKit

Integre o framework StoreKit da Apple para gerenciar assinaturas e enviar eventos para a Singular em apps iOS.

Pré-requisitos

Configurar o App Store Connect

Configure produtos de assinatura e grupos de assinatura no App Store Connect antes de implementar o StoreKit no seu app.

  1. Criar Grupos de Assinatura: Organize as assinaturas em grupos com base nos níveis de acesso
  2. Definir Produtos de Assinatura: Configure os níveis de assinatura, as durações e os preços
  3. Configurar Ofertas: Crie ofertas introdutórias, ofertas promocionais e códigos de assinatura
  4. Ambiente de Teste: Configure contas de teste sandbox para o desenvolvimento

Implementar o StoreKit

Configurar o Transaction Observer

Implemente o SKPaymentTransactionObserver para receber notificações de compra de assinatura e renovações.

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 o Status da Assinatura

Use a validação de recibo para verificar o status atual da assinatura e tratar as renovações.

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 Integração por SDK

Envie eventos de assinatura a partir do seu app usando os métodos de receita personalizados do SDK da Singular, sem validação de recibo.

Métodos de SDK Específicos por Plataforma

Use o método de SDK apropriado para a sua plataforma para rastrear os eventos de assinatura.

SDK do 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"
    )
)

Documentação: Rastreamento de Receita do SDK do Android


SDK do 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"
    ]
)

Documentação: Rastreamento de Receita do SDK do iOS


SDK do 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"
    }
);

Documentação: Rastreamento de Receita do SDK do React Native


SDK do 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" }
    }
);

Documentação: Rastreamento de Receita do SDK do Unity


SDK do 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"
    }
);

Documentação: Rastreamento de Receita do SDK do Flutter


SDK do 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"
    }
);

Documentação: Rastreamento de Receita do SDK do Cordova

Crítico: NÃO use métodos de IAP (In-App Purchase) nem envie valores de recibo para a Singular no rastreamento de assinaturas. Use apenas os métodos customRevenue() sem recibos.


Integração Server-to-Server

Envie eventos de assinatura em tempo real do seu backend para a REST API da Singular para um rastreamento imediato, independente do estado do app.

Requisitos de Implementação

Use o Event Endpoint da Singular para enviar eventos de assinatura com parâmetros de receita a partir do seu backend seguro.

Event Endpoint

Envie requisições POST para a Event API da Singular com os dados do evento de assinatura e as propriedades de dispositivo móvel necessárias.

Endpoint:

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

Parâmetros Obrigatórios:

  • SDK Key: Sua chave SDK da Singular (parâmetro a )
  • Event Name: Nome do evento de assinatura (parâmetro n )
  • Revenue: Valor da assinatura (parâmetro amt )
  • Currency: Código de moeda ISO 4217 (parâmetro cur )
  • Device Identifiers: IDFA (iOS) ou GAID (Android) para atribuição
  • Platform: Sistema operacional (parâmetro p )

Documentação: Referência do Event Endpoint e Parâmetros de Receita


Exemplo de Requisição

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 Não Necessário: Se você usar S2S para eventos de assinatura, não precisa enviar esses eventos pelo SDK. No entanto, a maioria dos apps ainda deve integrar o SDK para o rastreamento de sessões e eventos que não são de assinatura.


Integrações com Terceiros

Configure o rastreamento de assinaturas por meio de plataformas de terceiros que gerenciam a infraestrutura de assinatura e enviam eventos diretamente para a Singular.

Parceiros Suportados

Integre com plataformas de gerenciamento de assinaturas que têm suporte nativo à Singular.

Integração com o RevenueCat

O RevenueCat gerencia a infraestrutura de assinatura e envia automaticamente os eventos de assinatura para a REST API da Singular.

Etapas de Configuração:

  1. Criar Conta no RevenueCat: Configure seu app no dashboard do RevenueCat
  2. Configurar a Integração com a Singular: Adicione a chave SDK da Singular nas configurações de integrações do RevenueCat
  3. Mapear Eventos: Configure quais eventos do RevenueCat devem ser enviados para a Singular
  4. Testar a Integração: Verifique se os eventos aparecem no dashboard da Singular

Documentação: Integração RevenueCat com Singular


Integração com o Adapty

O Adapty fornece análises de assinatura e envia eventos para a Singular por meio da integração dele.

Etapas de Configuração:

  1. Criar Conta no Adapty: Registre e configure seu app no Adapty
  2. Habilitar a Integração com a Singular: Acesse as integrações e adicione as credenciais da Singular
  3. Configurar o Mapeamento de Eventos: Selecione quais eventos de assinatura encaminhar
  4. Verificar o Fluxo de Dados: Confirme se os eventos chegam à Singular com sucesso

Documentação: Integração Adapty com Singular


Integração com o Superwall

Conecte a Singular para receber eventos de ciclo de vida de assinatura e de receita do Superwall, com suporte a SDID para uma atribuição mais robusta.

Etapas de Configuração:

  1. Integrar o SDK da Singular: Adicione o SDK da Singular ao seu app para o rastreamento de sessões e eventos
  2. Configurar o Singular SDID (Opcional): Configure o Singular SDID e atualize os atributos de usuário do Superwall com o SDID no seu app para uma atribuição mais robusta
  3. Adicionar a Integração com a Singular no Superwall: Habilite e configure a integração com a Singular no seu dashboard do Superwall

Documentação: Integração Superwall com Singular


Integração com o Xsolla

O Xsolla envia informações sobre compras no Web Shop para a Singular como eventos in-app móveis, que a Singular então atribui a instalações de aplicativos móveis, aquisição de usuários e campanhas de re-engajamento.

Etapas de Configuração:

  1. Integrar a Singular nos Seus Apps Móveis: Adicione o SDK da Singular aos seus apps móveis
  2. Configurar um Evento In-App: Envie um evento in-app para a Singular, por exemplo, login, ou qualquer outro evento que inclua o CUID
  3. Configurar a Partner Configuration da Singular: Configure a partner configuration da Singular para o Xsolla
  4. Adicionar a Singular na Sua Conta Xsolla: Habilite a Singular na sua conta Xsolla

Documentação: Integração Xsolla com Singular

Observação: As integrações com terceiros são gerenciadas pelas plataformas parceiras. A configuração deve ser concluída nos respectivos dashboards delas. O SDK da Singular ainda deve ser integrado para o rastreamento de sessões e de eventos que não são de assinatura.


Tipos de Eventos de Assinatura

Rastreie diversos eventos do ciclo de vida da assinatura para medir o engajamento dos usuários, a retenção e a receita ao longo de toda a jornada de assinatura.

Nomes de Eventos Padrão

Use os nomes de eventos padrão da Singular para relatórios consistentes entre plataformas, ou defina nomes de eventos personalizados com base nos seus requisitos de rastreamento.

Estado da Assinatura Nome do Evento Método do SDK Integração S2S
Nova Assinatura sng_subscribe customRevenue() com valor de receita (sem recibo) Event endpoint com parâmetros de receita
Início do Teste sng_start_trial método event() sem receita Event endpoint padrão sem receita
Fim do Teste sng_end_trial método event() sem receita Event endpoint padrão sem receita
Renovação da Assinatura subscription_renewed customRevenue() com valor de receita (sem recibo) Event endpoint com parâmetros de receita
Cancelamento subscription_cancelled método event() sem receita Event endpoint padrão sem receita
Reembolso subscription_refunded customRevenue() com valor negativo (opcional) OU event() sem receita Event endpoint com receita negativa (opcional) OU evento padrão

Importante: Ao enviar eventos de assinatura via customRevenue(), envie apenas eventos em que isRestored seja false . Compras restauradas representam assinaturas existentes, não uma nova receita.


Exemplos de Implementação de Eventos

Nova Assinatura

Rastreie quando os usuários compram uma nova assinatura pela primeira 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"
    )
)

Início do Teste

Rastreie quando os usuários iniciam um período de teste gratuito, sem receita.

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

Renovação da Assinatura

Rastreie renovações automáticas de assinatura com o valor de receita.

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

Cancelamento

Rastreie quando os usuários cancelam a assinatura (evento sem receita).

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

Medição pelo SKAdNetwork

Meça eventos de assinatura por meio do SKAdNetwork da Apple para uma atribuição no iOS em conformidade com a privacidade.

Suporte a Assinaturas no SKAN

A Singular pode medir dados de eventos de assinatura por todos os métodos de integração (SDK, S2S e terceiros). A medição de eventos pode ser limitada pelas janelas de tempo dos postbacks do SKAN, dependendo da versão do SKAN.

Implementação de SKAN Híbrido

Para apps que usam o SDK da Singular para eventos de ciclo de vida e integrações S2S/de terceiros para assinaturas, habilite o SKAN Híbrido para combinar as duas fontes de dados.

Entre em Contato com o Suporte: Fale com seu Customer Success Manager (CSM) para habilitar o SKAN Híbrido para o seu app. Isso garante que os eventos de assinatura de fontes de backend sejam devidamente atribuídos aos conversion values do SKAN.

Janelas de Postback do SKAN:

  • SKAN 4.0: Três janelas de postback (0-2 dias, 3-7 dias, 8-35 dias) possibilitam a medição de eventos de assinatura iniciais e renovações de curto prazo
  • SKAN 3.0: Uma única janela de postback de 24 horas limita a medição apenas às assinaturas imediatas
  • Conversion Values: Configure eventos de assinatura no seu esquema de conversion value do SKAN para priorizar eventos de alto valor

Boas Práticas e Validação

Siga as boas práticas de implementação e verifique se o rastreamento de assinaturas está funcionando corretamente antes da implantação em produção.

Boas Práticas de Implementação

Diretrizes Principais

  • Sem Validação de Recibo: Nunca envie recibos da plataforma (Google Play, App Store) para a Singular ao rastrear assinaturas—use customRevenue() sem recibos
  • Filtrar Compras Restauradas: Envie apenas eventos em que isRestored seja false, para evitar relatórios de receita duplicados
  • Verificação no Backend: Sempre verifique as compras no seu backend seguro antes de enviar os eventos para a Singular
  • Confirmação Oportuna: Confirme as compras do Google Play dentro de 3 dias para evitar reembolsos automáticos
  • Consultar no Resume: Chame queryPurchasesAsync() em onResume() para capturar renovações que ocorreram enquanto o app estava fechado
  • Nomes de Eventos Consistentes: Use os nomes de eventos padrão da Singular (sng_subscribe, subscription_renewed) para relatórios unificados
  • Incluir Metadados: Adicione atributos como subscription_tier, billing_period e product_id para uma análise detalhada

Testes e Validação

Checklist de Testes

  1. Configuração do Ambiente de Teste: Use contas sandbox/de teste para o Google Play e a App Store
  2. Nova Assinatura: Verifique se o evento sng_subscribe é enviado corretamente, com o valor e a moeda adequados
  3. Fluxo de Teste: Teste os eventos de início e fim do teste sem receita
  4. Tratamento de Renovação: Confirme que as renovações disparam eventos subscription_renewed com a receita correta
  5. Rastreamento de Cancelamento: Verifique se os eventos de cancelamento disparam quando os usuários cancelam as assinaturas
  6. Filtragem de Restauração: Garanta que as compras restauradas não enviem eventos duplicados
  7. Dashboard da Singular: Verifique se os eventos aparecem na Singular com a atribuição correta
  8. Entre Dispositivos: Teste a sincronização de assinaturas em vários dispositivos

Problemas Comuns

  • Eventos Ausentes: Verifique se a conexão do billing client está ativa e se queryPurchasesAsync() é chamado ao retomar o app
  • Eventos Duplicados: Verifique se as compras restauradas estão devidamente filtradas com a verificação de isRestored
  • Receita Incorreta: Garanta que a extração de preço do ProductDetails divide corretamente os micros por 1.000.000
  • Problemas de Atribuição: Confirme que os identificadores de dispositivo (IDFA/GAID) estão devidamente incluídos nas requisições S2S
  • Falhas de Confirmação: Verifique se a validação de recibo no backend é concluída antes da confirmação

Recursos de Suporte: Para assistência na resolução de problemas, entre em contato com o Suporte da Singular com a versão do SDK, os detalhes da plataforma, payloads de eventos de exemplo e capturas de tela do dashboard da Singular mostrando o problema.