Skip to content

Analytics

Get actionable, trackable data instantly to drive better decisions and performance.

Overview

Analytics events are structured data objects automatically triggered when significant actions or states occur during a Paze payment. Configure the analyticsEvent callback on PxpSdkConfig when you build PxpCheckout because events aren't emitted if the handler is omitted.

Analytics events allow you to:

  • Gain transparency with native transaction tracking in PXP reports.
  • Optimise conversion rates and reduce drop-offs, thanks to actionable insights.
  • Feed real-time data into your analytics and CRM systems.

Consume an event

Analytics events are delivered through the analyticsEvent callback on PxpSdkConfig when you build PxpCheckout. Configure the handler and branch on eventName or the Kotlin event type:

val sdkConfig = PxpSdkConfig(
    environment = Environment.TEST,
    session = sessionData,
    transactionData = transactionData,
    clientName = "Your merchant name",
    siteName = "Your store",
    onGetShopper = {
        Shopper(id = "shopper-123", email = "customer@example.com")
    },
    analyticsEvent = { event ->
        if (event is PazeButtonClickAnalyticsEvent) {
            Log.d("Paze", "Button clicked ${event.componentId} ${event.merchantTransactionId}")
        }

        if (event is PazeCheckoutCompletedAnalyticsEvent) {
            Log.d("Paze", "Checkout completed ${event.merchantTransactionId}")
        }

        if (event is PazeAuthorisationFailedAnalyticsEvent) {
            Log.e("Paze", "Authorisation failed ${event.additionalData}")
        }
    },
)

val checkout = PxpCheckout.builder()
    .withConfig(sdkConfig)
    .withContext(context)
    .build()

Handle every Paze-specific event through a single PazeAnalyticsEvent branch:

analyticsEvent = { event ->
    if (event is PazeAnalyticsEvent) {
        trackPazeEvent(
            name = event.eventName,
            sessionId = event.sessionId,
            componentId = event.componentId,
            merchantTransactionId = event.merchantTransactionId,
            additionalData = event.additionalData,
        )
    }
}

Custom Tab availability isn't emitted as a dedicated Paze analytics event. Instead, track it with onPresentmentResolved on the Paze button component:

config.onPresentmentResolved = { customTabAvailable ->
    trackMetric("paze_custom_tab_available", mapOf("customTabAvailable" to customTabAvailable))
}

Supported events

The following tables list events you can receive during a Paze payment. Paze-specific events extend PazeAnalyticsEvent. Shared lifecycle events use different structures, so check eventName and componentType when filtering.

Paze-specific events

Events that extend PazeAnalyticsEvent:

Event name Kotlin type Structure
PazeButtonRenderedPazeButtonRenderedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
PazeButtonClickedPazeButtonClickAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
PazePopupLaunchedPazePopupLaunchedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
PazeCheckoutCompletedPazeCheckoutCompletedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
PazeCheckoutAbandonedPazeCheckoutAbandonedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
  • additionalData
PazeDecryptionInitiatedPazeDecryptionInitiatedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
PazeDecryptionCompletedPazeDecryptionCompletedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
PazeDecryptionFailedPazeDecryptionFailedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
  • additionalData
PazeAuthorisationFailedPazeAuthorisationFailedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
  • additionalData
PazeSdkInitialisationFailedPazeSdkInitialisationFailedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
  • additionalData
PazeCheckoutFailedPazeCheckoutFailedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
  • additionalData
PazeCompleteFailedPazeCompleteFailedAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
  • additionalData

Shared lifecycle events during Paze payments

These events don't extend PazeAnalyticsEvent:

Event nameKotlin typeStructure
PreAuthorisationPreAuthorisationAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentType
  • transactionId
  • isRetry
PostAuthorisationPostAuthorisationAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentType
  • transactionId
  • isRetry
PazeTransactionInitiatedPaymentLifecycleAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentType
  • transactionId
PazeAuthorisationCancelledPaymentLifecycleAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentType
  • transactionId
PazeTokenDecryptionCancelledPazeDecryptionCancelledAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • componentId
  • merchantTransactionId
  • walletType
ComponentLifecycleEventComponentLifecycleAnalyticsEvent
  • eventName
  • timestamp
  • sessionId
  • eventType (Mount / Unmount)
  • componentId

PreAuthorisation is emitted only when you configure onPreAuthorisation and the flow proceeds (Proceed or TransactionInitData). Returning Cancel emits PazeAuthorisationCancelled instead. PostAuthorisation is emitted when you configure onPostAuthorisation and the SDK receives a MerchantSubmitResult, immediately before your callback runs. PazeAuthorisationFailed may also fire if the response reports an error state. Invalid Kount riskScreeningData throws a ValidationException surfaced through onSubmitError without a PazeAuthorisationFailed event.

Event data

All Paze analytics events extend PazeAnalyticsEvent and include:

NameDescription
eventNameThe name of the event (for example, PazeButtonClicked).
timestampMilliseconds since epoch when the event occurred.
sessionIdThe session's unique identifier.
componentIdThe Paze button component's unique identifier.
merchantTransactionIdThe merchant transaction identifier from SDK initialisation.
walletTypeAlways Paze for Paze-specific events.
additionalDataPresent on all PazeAnalyticsEvent types. Populated on failure events with PazeErrorAnalyticsData (errorCode, errorMessage) or on abandonment events with PazeReasonAnalyticsData (reason); otherwise null.

Shared lifecycle events add:

NameDescription
componentTypePaze for PreAuthorisation and PostAuthorisation; PazeButton for PazeTransactionInitiated and PazeAuthorisationCancelled.
transactionIdThe merchant transaction identifier on lifecycle events.
isRetryWhether the lifecycle event is a retry (PreAuthorisation / PostAuthorisation only).

When each event fires

The following table describes when each analytics event fires during a Paze payment:

Event nameTrigger
PazeButtonRenderedPresentment validation succeeds and the button becomes visible, when the component Content() is composed.
PazeButtonClickedAfter checkout validation passes: onPazeButtonClicked runs, then this event fires, then the SDK calls create-session and opens the Custom Tab.
PazePopupLaunchedCreate-session succeeds and the Paze checkout Custom Tab opens.
PazeCheckoutCompletedPaze checkout returns COMPLETE and the merchant approves at onCheckoutComplete.
PazeCheckoutAbandonedCheckout is incomplete, the shopper cancels, the Custom Tab closes without a redirect, or merchant validation rejects checkout.
PazeDecryptionInitiatedAfter onComplete, when the SDK enters the decryption flow — immediately before onPreDecryption. Also fires when onPreDecryption returns false (followed by PazeTokenDecryptionCancelled).
PazeDecryptionCompletedSDK decryption succeeds. Not emitted when onPreDecryption returns false.
PazeDecryptionFailedSDK decryption fails (onError with SDK1233).
PazeCompleteFailedThe complete API call fails (onError also fires).
PazeCheckoutFailedCheckout validation fails when the shopper taps the button, or the create-session API call fails. Not emitted for Custom Tab launch failures (onError only).
PazeAuthorisationFailedTransaction submission fails or the Unity response reports an error state.
PazeSdkInitialisationFailedPresentment validation fails (button hidden).
PazeTokenDecryptionCancelledonPreDecryption returns false (merchant-managed decryption). Authorisation analytics events do not follow.
PazeAuthorisationCancelledonPreAuthorisation is configured and returns Cancel.
PazeTransactionInitiatedAuthorisation request is sent to the Unity API.
PreAuthorisationonPreAuthorisation is configured and the flow proceeds (Proceed or TransactionInitData). Returning Cancel emits PazeAuthorisationCancelled instead. componentType is Paze.
PostAuthorisationonPostAuthorisation is configured and the SDK receives a MerchantSubmitResult, immediately before your callback runs. componentType is Paze. PazeAuthorisationFailed may also fire if the response reports an error state. Not emitted on the merchant-managed decryption path.
ComponentLifecycleEventThe component mounts after presentment succeeds (Mount, when Content() is composed — emitted once, before PazeButtonRendered), or unmounts when removed from the UI (Unmount).

onPazeButtonClicked runs when the shopper taps the button, after checkout validation. The PazeButtonClicked analytics event fires immediately afterwards, before the Custom Tab opens.

Event quick reference

One-line descriptions of each Paze-related analytics event:

Event name Description
PazeButtonRenderedButton became visible after presentment validation.
PazeButtonClickedShopper tapped the native Paze button.
PazePopupLaunchedPaze checkout Custom Tab opened.
PazeCheckoutCompletedCheckout returned COMPLETE and the merchant approved at onCheckoutComplete.
PazeCheckoutAbandonedCheckout incomplete, shopper cancelled, Custom Tab closed without redirect, or merchant rejected at onCheckoutComplete.
PazeDecryptionInitiatedSDK entered the decryption flow (before onPreDecryption).
PazeDecryptionCompletedSDK decrypt succeeded; not emitted on the merchant-managed path.
PazeDecryptionFailedDecrypt request failed (onError with SDK1233).
PazeTokenDecryptionCancelledMerchant returned false from onPreDecryption.
PazeCompleteFailedPaze complete API call failed (onError also fires).
PazeCheckoutFailedCheckout validation failed on tap, or create-session failed; not emitted for Custom Tab launch failures.
PazeAuthorisationFailedTransaction submission failed or Unity returned an error state.
PazeSdkInitialisationFailedPresentment validation failed (button hidden).
PazeTransactionInitiatedAuthorisation request sent to the Unity API.
PazeAuthorisationCancelledonPreAuthorisation configured and returned Cancel.
PreAuthorisationShared lifecycle event when configured onPreAuthorisation proceeds (Proceed or TransactionInitData).
PostAuthorisationShared lifecycle event when onPostAuthorisation is configured and Unity returns MerchantSubmitResult, before your callback runs.
ComponentLifecycleEventComponent mounted or unmounted (Mount / Unmount).

PazeAuthorisationInitiatedAnalyticsEvent and PazeAuthorisationCompletedAnalyticsEvent exist in the SDK but aren't emitted by the Paze button component. Use PazeTransactionInitiated and PostAuthorisation instead.

Use merchantTransactionId to correlate analytics events with server-side logs and PXP reports.

Integration examples

Firebase Analytics

Forward Paze analytics events to Firebase by type:

analyticsEvent = { event ->
    when (event) {
        is PazeButtonClickAnalyticsEvent -> {
            Firebase.analytics.logEvent("paze_button_click") {
                param("component_id", event.componentId)
                param("merchant_transaction_id", event.merchantTransactionId)
                param("session_id", event.sessionId)
            }
        }
        is PazeCheckoutCompletedAnalyticsEvent -> {
            Firebase.analytics.logEvent("paze_checkout_complete") {
                param("merchant_transaction_id", event.merchantTransactionId)
                param("session_id", event.sessionId)
            }
        }
        is PazeAuthorisationFailedAnalyticsEvent -> {
            Firebase.analytics.logEvent("paze_authorisation_failed") {
                param("merchant_transaction_id", event.merchantTransactionId)
                param("session_id", event.sessionId)
            }
        }
    }
}

Best practices

Conversion funnel tracking

Build a complete picture of your Paze conversion funnel by combining SDK analytics events with onPresentmentResolved:

val funnelStages = mutableMapOf(
    "customTabAvailable" to 0,
    "buttonRendered" to 0,
    "buttonClicked" to 0,
    "checkoutCompleted" to 0,
    "decryptionCompleted" to 0,
    "paymentAuthorised" to 0,
)

config.onPresentmentResolved = { customTabAvailable ->
    if (customTabAvailable) {
        funnelStages["customTabAvailable"] = funnelStages.getValue("customTabAvailable") + 1
    }
}

val sdkConfig = PxpSdkConfig(
    // ... session and transactionData
    analyticsEvent = { event ->
        when (event) {
            is PazeButtonRenderedAnalyticsEvent ->
                funnelStages["buttonRendered"] = funnelStages.getValue("buttonRendered") + 1
            is PazeButtonClickAnalyticsEvent ->
                funnelStages["buttonClicked"] = funnelStages.getValue("buttonClicked") + 1
            is PazeCheckoutCompletedAnalyticsEvent ->
                funnelStages["checkoutCompleted"] = funnelStages.getValue("checkoutCompleted") + 1
            is PazeDecryptionCompletedAnalyticsEvent ->
                funnelStages["decryptionCompleted"] = funnelStages.getValue("decryptionCompleted") + 1
            is PostAuthorisationAnalyticsEvent ->
                if (event.componentType == "Paze") {
                    // Only emitted when onPostAuthorisation is registered on the component config
                    funnelStages["paymentAuthorised"] = funnelStages.getValue("paymentAuthorised") + 1
                    Log.d("Paze", "Conversion funnel: $funnelStages")
                }
            else -> Unit
        }
    },
)

Error tracking and alerting

Track operational failures using Paze failure events:

Route Paze failure analytics events to your error tracking service:

analyticsEvent = { event ->
    when (event) {
        is PazeDecryptionFailedAnalyticsEvent,
        is PazeAuthorisationFailedAnalyticsEvent,
        is PazeSdkInitialisationFailedAnalyticsEvent,
        is PazeCheckoutFailedAnalyticsEvent,
        is PazeCompleteFailedAnalyticsEvent,
        -> {
            if (event is PazeAnalyticsEvent) {
                trackError("paze_flow_error", mapOf(
                    "eventName" to event.eventName,
                    "merchantTransactionId" to event.merchantTransactionId,
                    "additionalData" to event.additionalData.toString(),
                ))
            }
        }
        else -> Unit
    }
}

The SDK also emits ComponentLifecycleEvent with eventType: Mount when presentment succeeds. This is separate from PazeButtonRendered. Custom Tab launch failures surface through onError only — there's no dedicated analytics event. Types such as PazeAuthorisationInitiatedAnalyticsEvent and PazeAuthorisationCompletedAnalyticsEvent exist in the SDK but aren't emitted by the Paze button component; use PazeTransactionInitiated and PostAuthorisation instead.