3rd Party Analytics

Forward Superwall events to your own analytics stack.

Beta

The KMP SDK is in beta and its API may change between releases.

Superwall tracks events internally: paywalls opening, transactions completing, placements firing. You can forward all of them to your own analytics provider through SuperwallDelegate.

Forwarding events

Implement handleSuperwallEvent:

import com.superwall.sdk.kmp.SuperwallDelegate
import com.superwall.sdk.kmp.models.events.SuperwallEventInfo

class AnalyticsDelegate : SuperwallDelegate {
    override fun handleSuperwallEvent(eventInfo: SuperwallEventInfo) {
        analytics.track(
            name = eventInfo.eventType.name,
            properties = eventInfo.params.orEmpty(),
        )
    }
}

Superwall.delegate = AnalyticsDelegate()

handleSuperwallEvent is not guaranteed to arrive on any particular thread, and that may change between releases. Do not touch UI from it without hopping to main yourself, and do not assume it is off the main thread either. Keep the body cheap and non-blocking. See Platform differences.

The event envelope

SuperwallEventInfo is a flat envelope. eventType identifies the event, and only the fields relevant to that event are non-null:

import com.superwall.sdk.kmp.models.events.EventType

override fun handleSuperwallEvent(eventInfo: SuperwallEventInfo) {
    when (eventInfo.eventType) {
        EventType.PAYWALL_OPEN -> {
            analytics.track("paywall_open", mapOf(
                "paywall_id" to eventInfo.paywallInfo?.identifier,
                "paywall_name" to eventInfo.paywallInfo?.name,
            ))
        }
        EventType.TRANSACTION_COMPLETE -> {
            analytics.track("purchase", mapOf(
                "product_id" to eventInfo.product?.productIdentifier,
            ))
        }
        else -> analytics.track(eventInfo.eventType.name, eventInfo.params.orEmpty())
    }
}

Commonly useful fields on the envelope:

Prop

Type

Sending your identifiers to Superwall

The reverse direction matters too, since Superwall can attribute better if it knows your analytics identifiers:

import com.superwall.sdk.kmp.models.events.IntegrationAttribute

Superwall.setIntegrationAttributes(
    mapOf(
        IntegrationAttribute.AMPLITUDE_USER_ID to amplitude.userId,
        IntegrationAttribute.MIXPANEL_DISTINCT_ID to mixpanel.distinctId,
        IntegrationAttribute.APPSFLYER_ID to appsFlyer.uid,
    ),
)

Supported providers include Adjust, Amplitude, AppsFlyer, Braze, OneSignal, Meta, Firebase, Singular, Iterable, Mixpanel, mParticle, CleverTap, Airship, Kochava, Tenjin, PostHog, Customer.io, and Appstack. Passing null for a value removes it.

IntegrationAttribute.FIREBASE_INSTALLATION_ID is iOS only. Setting it on Android is skipped and logs a warning. Every other attribute works on both platforms.

Capturing SDK logs

handleLog gives you the SDK's own log stream:

override fun handleLog(
    level: LogLevel,
    scope: LogScope,
    message: String?,
    info: Map<String, Any?>?,
    error: String?,
) {
    if (level == LogLevel.ERROR) {
        crashReporter.log("Superwall/${scope.name}: $message")
    }
}

handleLog fires for every internal log line, regardless of the configured log level, which is hundreds of calls for a single register. Filter early, keep the body cheap, and never block in it.

Controlling what Superwall collects

To limit what leaves the device, set eventTrackingBehavior:

Superwall.configure(
    apiKey = "pk_your_api_key",
    options = SuperwallOptions(
        eventTrackingBehavior = EventTrackingBehavior.SUPERWALL_ONLY,
    ),
)
ValueEffect
ALLEverything is tracked. The default.
SUPERWALL_ONLYOnly internal Superwall events; your tracking calls, trigger-fire events, and user-attribute updates are suppressed.
NONENothing is sent to Superwall's servers.

How is this guide?

On this page