Subscription Event Technical Implementation Guide

Overview:

This document provides a comprehensive guide on how to implement subscription events using the Singular SDK. It covers in-app subscription event tracking across various platforms, server-to-server (S2S) event integration, and third-party integrations like RevenueCat and Adapty.

Singular enables you to track your subscriptions and renewals within your app, providing insights into user behavior and revenue generation. Singular's subscription attribution offers robust methods for tracking subscription events, ensuring accurate and real-time data collection. 

 

Considerations SDK S2S S2S 3P Integration
Implementation Send subscription events to Singular via the custom Revenue methods in the SDK Send subscription events managed in your backend to Singular's REST API (direct S2S implementation) with required mobile device properties S2S integrations are managed by third-party partners, and configuration is required in their respective platforms
Reliance on App Activity The app must be launched for the Singular SDK to send the subscription event Subscription events can be sent in real time, server-to-server Subscription events are sent in real time from third-party partners
Event Timing Since sending the event relies on app launch (and initialization of the Singular SDK), the event sent to Singular can have a different event time than the actual subscription time Subscription events can be sent in real time, as they are processed in your backend Subscription events can be sent in near real time, after being processed by the 3P vendor

Note:

If you choose to send subscription events via one of the S2S integrations, most customers should still integrate the Singular SDK to manage sessions and non-subscription events.

Implement Subscription State Management in App

By integrating Google's Play Billing Library and Apple's StoreKit, you can query subscription information and manage the subscription state directly on the device. This setup allows for integration with one of Singular's implementation methods. Below are sample code snippets demonstrating simple implementations of the Billing Library and StoreKit to serve as practical examples. You should modify these examples in Production to fit your App's code and subscription model.

Android: Integrating Google Play Billing Library

1. Add the Billing Library to Your Project

Add the Google Play Billing Library configuration in your build.gradle

implementation 'com.android.billingclient:billing:6.0.1'

2. Set Up In-App Products and Subscriptions

Configure your in-app products and subscription items in the Google Play Console

3. Query Subscription Information

Use the BillingClient to query purchase history and subscription status within your app.

KotlinJava
val billingClient = BillingClient.newBuilder(context)
  .setListener(purchaseUpdateListener)
  .enablePendingPurchases()
  .build()
billingClient.startConnection(object : BillingClientStateListener {
  override fun onBillingSetupFinished(billingResult: BillingResult) {
    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
        // The billing client is ready, you can now query subscription information asynchronously

        billingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS) {result, subscriptionList ->
            if (result.responseCode == BillingClient.BillingResponseCode.OK && subscriptionList != null) {
                // Handle the retrieved subscription list

                subscriptionList.forEach { purchase ->
                    // Process each subscription purchase

                }
            } else {
                // Handle error in queryPurchasesAsync

            }
        }
    } else {
       // Handle error on setup finished

    }
  }
  override fun onBillingServiceDisconnected() {
    // Retry connection after a delay if the service gets disconnected

    Handler(Looper.getMainLooper()).postDelayed({
        billingClient.startConnection(this)
    }, 3000)
  }
})
// Remember to properly disconnect the billing client in your activity/fragment lifecycle

override fun onDestroy() {
    billingClient.endConnection()
    super.onDestroy()
}

iOS: Integrating StoreKit

1. Implement StoreKit

Integrate the StoreKit Framework into your iOS app.

2. Set Up In-App Products and Subscriptions

Set up in-app products and subscription items in App Store Connect

3. Query Subscription Information

Use SKPaymentQueue and SKReceiptRefreshRequest to get the subscription status and receipt information.

Swift
import StoreKit
class YourViewController: UIViewController, SKPaymentTransactionObserver {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Add the observer for payment transactions

        SKPaymentQueue.default().add(self)
        
        // Refresh the receipt to get the latest subscription information

        refreshReceipt()
    }
    func refreshReceipt() {
        let request = SKReceiptRefreshRequest()
        request.delegate = self
        request.start()
    }
    // Implement SKPaymentTransactionObserver methods

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case .purchased, .restored:
                // Handle the purchase or restore

                // You can check the transaction.transactionReceipt for receipt information

                break
            case .failed:
                // Handle the failed transaction

                break
            case .deferred:
                // Handle the deferred transaction

                break
            case .purchasing:
                // Transaction is in progress

                break
            @unknown default:
                break
            }
        }
    }
    // Implement SKRequestDelegate method

    func requestDidFinish(_ request: SKRequest) {
        // Receipt refresh request completed

        // Now you can use the updated receipt to check subscription status

    }
    func request(_ request: SKRequest, didFailWithError error: Error) {
        // Handle the error during the receipt refresh request

    }
}

Sending Subscription Events from the Singular SDK

When the subscription state changes in the implementations above, a new custom Revenue event should be sent to Singular. DO NOT use the IAP functions and DO NOT send a receipt value to Singular. Follow the respective implementation guide for the Singular SDK you've implemented in your app to send a customRevenue() event without the receipt.

  • iOS SDK: use this method to send the "subscription" event name:

    (void)customRevenue:(NSString*)eventname currency:(NSString *)currency
            amount:(double)amount withAttributes:(NSDictionary*)attributes;
  • Android SDK use this method to send the "subscription" event name:

    Singular.customRevenue(String eventName, String currency, double
            amount, Map<String, Object> attributes)
  • React Native SDK: use this method to send the "subscription" event name:

    static customRevenueWithArgs(eventName: string, currency: string,
            amount: number, args: SerializableObject): void;
  • Unity SDK: use this method to send the "subscription" event name:

    SingularSDK.CustomRevenue(string eventName, string currency, double
            amount, Dictionary<string, object> attributes)
  • Flutter SDK: use this method to send the "subscription" event name:

    Singular.customRevenueWithAttributes(String eventName, String currency, 
            double amount, Map attributes)
  • Cordova SDK: use this method to send the "subscription" event name:

    SingularCordovaSdk.customRevenueWithArgs(String eventName, String currency, 
            double amount, JSONObject args)

Sending Subscription Events S2S

If you prefer to send subscription events in real time, and manage subscription events in your back end, you can send events to Singular's REST API. 

Use the Event Endpoint to send subscription events to Singular, and be sure to include the Revenue parameters

  • If you have implemented the Singular SDK:
    • You should not send subscription events from the SDK with this option
    • You do not need to integrate with the launch (Session) S2S endpoint 

Sending Subscription Events via 3P Integration

If you are using a 3rd party service to manage subscriptions, those vendors capture subscription data via their own integration methods. They then send subscription events to Singular's REST API, which is already integrated in their systems. These integrations require some configurations in the partner platforms - see their respective guides below:

Subscription Events

Several different subscription events can be sent to Singular. Note that Singular's standard event names are provided where applicable below (see relevant SDK documentation), but custom event names can also be used if desired. 

Subscription State Event SDK Method S2S Integration
Subscription sng_subscribe
  • customRevenue Event method (receipt validation not supported)
  • Evt request with revenue params
Trial Start sng_start_trial
  • Event Method (no revenue amount)
  • Standard evt request
Trial End sng_end_trial (not officially a standard event yet, so this will be sent as a custom event)
  • Event Method (no revenue amount)
  • Standard evt request
Refund subscription_refunded
  • customRevenue event method with negative revenue (optional)
  • Event Method (no revenue amount)
  • Evt request with revenue params & negative amt (optional)
  • Standard evt request
Cancellation subscription_cancelled
  • Event Method (no revenue amount)
  • Standard evt request
Subscription Renewal subscription_renewed
  • customRevenue Event method (receipt validation not supported)
  • Evt request with revenue params

Note:

If you choose to send subscription events via customRevenue method, be sure to only send events where isRestored is false.  

Notes on SKAN Measurement

Singular can measure subscription event data via all integration methods noted above. Note that depending on the SKAN version, event measurement may be limited depending on the SKAN postback measurement window. 

If you plan to implement the Singular SDK for lifecycle events, and use one of the S2S integration methods above to send subscription events, reach out to your CSM to enable Hybrid SKAN.