Skip to content

Events

Overview

The Google Pay button component emits events based on user interaction and payment processing stages. You can implement callback functions to inject your own business logic and customise the user experience at critical moments throughout the payment flow. While the SDK handles the complex technical aspects of payment processing, you retain full control over the customer experience and can seamlessly integrate payments into your broader business workflows.

Callbacks enable you to:

  • Validate business rules before payments proceed.
  • Display custom error, failure, or success messages.
  • Integrate with fraud detection systems.
  • Control the payment flow based on transaction data.
  • Handle 3D Secure authentication.
  • Collect and validate additional security data (CVC).
  • Manage consent for payment tokens and recurring payments.
  • Track analytics and monitor payment performance.
  • Implement retry logic for soft declines.

Payment flow events

onPreAuthorisation

This callback is triggered before payment authorisation, allowing you to provide transaction initialisation data or control whether to proceed.

You can use it to:

  • Integrate with Kount or other fraud detection services.
  • Apply business rules based on transaction amount or customer history.
  • Check product availability before processing payment.
  • Provide risk screening data for fraud prevention.
  • Configure PSD2 SCA exemptions for the transaction.
  • Cancel the payment if business rules aren't met.

Callback signature

onPreAuthorisation: (suspend (PreAuthorisationData?) -> GooglePayTransactionInitData?)?

Event data

ParameterDescription
data
PreAuthorisationData?
Pre-authorisation data containing token identifiers.
data.gatewayTokenId
String?
The gateway token identifier for the payment. Use this ID to retrieve full token details from the Unity backend.
data.schemeTokenId
String?
The scheme token identifier for the payment (e.g., Visa Token Service, Mastercard Digital Enablement Service).

Return value

Return typeDescription
GooglePayTransactionInitDataTransaction initialisation data to proceed with payment.
GooglePayTransactionInitData.psd2DataPSD2 data including SCA exemption configuration.
GooglePayTransactionInitData.psd2Data.scaExemptionSCA exemption type: ANONYMOUS_CARD, LOW_VALUE, SECURE_CORPORATE, TRANSACTION_RISK_ANALYSIS, TRUSTED_BENEFICIARY.
GooglePayTransactionInitData.riskScreeningDataRisk screening data for fraud detection (Kount).
GooglePayTransactionInitData.riskScreeningData.performRiskScreeningWhether to perform risk screening (Boolean).
GooglePayTransactionInitData.riskScreeningData.excludeDeviceDataWhether to exclude device data from risk screening (Boolean).
nullReturn null to cancel the authorisation.

Example implementation

import com.pxp.checkout.components.googlepay.types.GooglePayTransactionInitData
import com.pxp.checkout.services.kount.*
import com.pxp.checkout.services.models.transaction.ScaExemptionType

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onPreAuthorisation = suspend { data ->
        Log.d("GooglePay", "Pre-authorisation started")
        Log.d("GooglePay", "Gateway Token ID: ${data?.gatewayTokenId}")
        Log.d("GooglePay", "Scheme Token ID: ${data?.schemeTokenId}")
        
        // Perform pre-payment validation
        val isHighRisk = checkCustomerRiskProfile()
        val customerTier = getCustomerTier()
        
        // Check inventory before proceeding
        val inventoryAvailable = checkInventoryAvailability()
        if (!inventoryAvailable) {
            showError("Some items are no longer available")
            return@suspend null // Cancel payment
        }
        
        // Check business rules
        val cartTotal = getCurrentCartTotal()
        if (cartTotal > 10000.0 && isHighRisk) {
            showError("Transaction requires additional verification")
            return@suspend null // Cancel payment for manual review
        }
        
        GooglePayTransactionInitData(
            riskScreeningData = RiskScreeningData(
                performRiskScreening = true,
                excludeDeviceData = false,
                userIp = "192.168.1.100",
                account = RiskScreeningAccount(
                    id = "user_12345678",
                    creationDateTime = "2024-01-15T10:30:00.000Z"
                ),
                transaction = RiskScreeningTransaction(
                    subtotal = cartTotal
                ),
                items = cartItems.map { item ->
                    RiskScreeningItem(
                        price = item.price,
                        quantity = item.quantity,
                        category = item.category,
                        sku = item.sku
                    )
                },
                fulfillments = listOf(
                    RiskScreeningFulfillment(
                        type = FulfillmentType.SHIPPED,
                        shipping = RiskScreeningShipping(
                            shippingMethod = ShippingMethod.STANDARD
                        ),
                        recipientPerson = RiskScreeningRecipientPerson(
                            phoneNumber = "+1234567890"
                        )
                    )
                )
            ),
            psd2Data = GooglePayTransactionInitData.Psd2Data(
                scaExemption = if (cartTotal < 30.0) {
                    ScaExemptionType.LOW_VALUE
                } else {
                    ScaExemptionType.TRANSACTION_RISK_ANALYSIS
                }
            )
        )
    }
}

onPostAuthorisation

This callback is triggered after the payment is authorised, providing the transaction result and payment data.

You can use it to:

  • Handle successful or declined payments.
  • Navigate to success or failure screens.
  • Update inventory and order status.
  • Send order confirmation emails.
  • Record transactions for business intelligence.
  • Display custom success or error messages.
  • Process shipping information collected from Google Pay.
  • Save transaction details for customer account history.
  • Update UI based on payment outcome.

Callback signature

onPostAuthorisation: ((SubmitResult?, AuthorisationPaymentData) -> Unit)?

Event data

ParameterDescription
result
SubmitResult?
The transaction result: either MerchantSubmitResult (success) or FailedSubmitResult (failure).
result.merchantTransactionId
String
Your unique transaction identifier (present in both success and failure).
result.systemTransactionId
String
PXP system transaction identifier (only in MerchantSubmitResult).
result.errorCode
String
Error code (only in FailedSubmitResult).
result.errorReason
String
Error description (only in FailedSubmitResult).
result.correlationId
String
Correlation ID for tracking (only in FailedSubmitResult).
result.httpStatusCode
Int
HTTP status code (only in FailedSubmitResult).
paymentData
AuthorisationPaymentData
required
Google Pay payment data collected during checkout.
paymentData.email
String?
Customer email address (if email collection was enabled).
paymentData.shippingAddress
Map<String, String?>?
Shipping address (if shipping address collection was enabled).
paymentData.shippingOption
Map<String, String?>?
Selected shipping option (if shipping options were provided).

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onPostAuthorisation = { result, paymentData ->
        Log.d("GooglePay", "Payment completed: $result")
        
        when (result) {
            is MerchantSubmitResult -> {
                // Payment successful
                Log.d("GooglePay", "Payment authorised successfully")
                Log.d("GooglePay", "Merchant Transaction ID: ${result.merchantTransactionId}")
                Log.d("GooglePay", "System Transaction ID: ${result.systemTransactionId}")
                
                // Extract payment data
                val email = paymentData.email
                val shippingAddress = paymentData.shippingAddress
                val shippingOption = paymentData.shippingOption
                
                // Use your Activity's lifecycleScope or CoroutineScope
                lifecycleScope.launch {
                    try {
                        // Update inventory
                        updateInventory(result.merchantTransactionId)
                        
                        // Create order record
                        createOrder(
                            transactionId = result.merchantTransactionId,
                            systemTransactionId = result.systemTransactionId,
                            email = email,
                            shippingAddress = shippingAddress,
                            shippingMethod = shippingOption?.get("id"),
                            status = "confirmed"
                        )
                        
                        // Send confirmation email
                        sendConfirmationEmail(
                            transactionId = result.merchantTransactionId,
                            email = email,
                            shippingAddress = shippingAddress
                        )
                        
                        // Track successful payment
                        analyticsTracker.trackEvent("google_pay_success") {
                            put("transaction_id", result.merchantTransactionId)
                            put("cart_value", getCurrentCartValue())
                            put("shipping_method", shippingOption?.get("id"))
                        }
                        
                        // Update customer account
                        updateCustomerPurchaseHistory(result.merchantTransactionId)
                        
                        // Navigate to success screen
                        withContext(Dispatchers.Main) {
                            navController.navigate(
                                "payment_success/${result.merchantTransactionId}"
                            )
                        }
                    } catch (e: Exception) {
                        Log.e("GooglePay", "Error in post-authorisation", e)
                        showError("Payment succeeded but order processing failed")
                    }
                }
            }
            
            is FailedSubmitResult -> {
                // Payment declined
                Log.e("GooglePay", "Payment declined: ${result.errorReason}")
                Log.e("GooglePay", "Error code: ${result.errorCode}")
                Log.e("GooglePay", "Correlation ID: ${result.correlationId}")
                
                // Log failure for monitoring
                logPaymentFailure(
                    errorCode = result.errorCode,
                    errorReason = result.errorReason,
                    correlationId = result.correlationId,
                    merchantTransactionId = result.merchantTransactionId
                )
                
                // Show user-friendly error message
                val errorMessage = getErrorMessage(result.errorCode)
                showError("Payment declined: $errorMessage")
                
                // Track failed payment
                analyticsTracker.trackEvent("google_pay_declined") {
                    put("error_code", result.errorCode)
                    put("correlation_id", result.correlationId)
                }
                
                // Offer alternatives
                showAlternativePaymentMethods()
            }
            
            else -> {
                // Unexpected result
                Log.e("GooglePay", "Unexpected result: $result")
                showError("Payment processing error. Please contact support.")
                analyticsTracker.trackEvent("google_pay_exception") {
                    put("result", result.toString())
                }
            }
        }
    }
}

Google Pay sheet interaction events

onPaymentDataChanged

This callback is triggered when payment data changes in the Google Pay sheet, such as shipping address or shipping option selection.

You can use it to:

  • Calculate shipping costs based on selected address.
  • Update transaction amounts dynamically.
  • Validate addresses and show errors for unserviceable locations.
  • Add or remove line items based on selections.
  • Calculate taxes based on shipping destination.
  • Apply discounts based on shipping method selection.
  • Check delivery availability for specific locations.

When updating transaction amounts, use the SDK's updateAmount() method to synchronise the amount with the backend session.

Callback signature

onPaymentDataChanged: ((Any) -> Any?)?

Event data

ParameterDescription
intermediatePaymentData
Any
required
Google Pay intermediate payment data containing shipping address and option selections. This is a dynamic object from the Google Pay API that you'll need to parse based on Google Pay's structure.

The intermediatePaymentData object contains fields like callbackTrigger, shippingAddress, and shippingOptionData that follow Google Pay's API structure. You'll need to cast and parse this Any object to access these properties.

Return value

Return a Map structure representing updated payment data to display in the Google Pay sheet. The structure should follow Google Pay's PaymentDataRequestUpdate format with the following fields:

Return fieldDescription
newTransactionInfoMap containing updated transaction information.
newTransactionInfo.totalPriceUpdated total price as a string.
newTransactionInfo.totalPriceStatusPrice status: "FINAL" or "ESTIMATED".
newTransactionInfo.displayItemsList of Maps representing line items with label, type, and price fields.
newShippingOptionParametersMap containing updated shipping options (optional).
errorMap containing error information for invalid addresses or options (optional).
error.reasonError reason: "SHIPPING_ADDRESS_INVALID", "SHIPPING_ADDRESS_UNSERVICEABLE", "SHIPPING_OPTION_INVALID".
error.messageUser-friendly error message.
error.intentThe callback intent that triggered the error: "SHIPPING_ADDRESS", "SHIPPING_OPTION".

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    paymentDataRequest = PaymentDataRequest(
        // ... other configuration
        shippingAddressRequired = true,
        shippingOptionRequired = true
    )
    
    onPaymentDataChanged = { intermediatePaymentData ->
        Log.d("GooglePay", "Payment data changed")
        
        // Parse the intermediate payment data
        // Note: You'll need to cast/parse based on Google Pay's structure
        
        val baseAmount = 20.00
        var tax = 5.00
        var shippingCost = 0.0
        var errorMap: Map<String, String>? = null
        
        // Example: Handle shipping address or option changes
        // The structure depends on Google Pay's IntermediatePaymentData format
        
        // Calculate new total
        val newTotal = baseAmount + tax + shippingCost
        
        // Update SDK amount
        pxpCheckout.updateAmount(newTotal)
        
        // Return updated payment data as Map
        mapOf(
            "newTransactionInfo" to mapOf(
                "totalPrice" to newTotal.toString(),
                "totalPriceStatus" to "FINAL",
                "displayItems" to listOf(
                    mapOf(
                        "label" to "Subtotal",
                        "type" to "SUBTOTAL",
                        "price" to baseAmount.toString()
                    ),
                    mapOf(
                        "label" to "Shipping",
                        "type" to "LINE_ITEM",
                        "price" to shippingCost.toString()
                    ),
                    mapOf(
                        "label" to "Tax",
                        "type" to "TAX",
                        "price" to tax.toString()
                    )
                )
            ),
            "error" to errorMap // Include error if validation failed
        ).filterValues { it != null } // Remove null values
    }
}

onGooglePaymentButtonClicked

This callback is triggered when the Google Pay button is tapped, before the payment sheet opens.

You can use it to:

  • Track button click events for analytics.
  • Show loading indicators or progress dialogs.
  • Perform final validation before opening payment sheet.
  • Update cart totals or recalculate amounts.
  • Check inventory availability one last time.
  • Prepare data for the payment flow.

Callback signature

onGooglePaymentButtonClicked: (() -> kotlinx.coroutines.Deferred<Unit>?)?

Event data

This callback receives no parameters.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onGooglePaymentButtonClicked = {
        Log.d("GooglePay", "Google Pay button clicked")
        
        // Track button click
        analyticsTracker.trackEvent("google_pay_button_clicked") {
            put("timestamp", System.currentTimeMillis())
            put("cart_value", getCurrentCartValue())
            put("item_count", getCartItemCount())
        }
        
        // Show loading indicator
        withContext(Dispatchers.Main) {
            showLoadingDialog()
        }
        
        // Final inventory check
        val inventoryOk = checkInventoryAvailability()
        if (!inventoryOk) {
            withContext(Dispatchers.Main) {
                hideLoadingDialog()
                showError("Some items are no longer available")
            }
            throw IllegalStateException("Inventory unavailable")
        }
        
        // Prepare checkout data
        prepareCheckoutData()
        
        // Update cart totals
        recalculateCartTotals()
        
        withContext(Dispatchers.Main) {
            hideLoadingDialog()
        }
        
        CompletableDeferred(Unit)
    }
}

Validation and error events

onCustomValidation

This callback is executed before opening the Google Pay payment sheet, allowing custom validation of other form fields.

You can use it to:

  • Validate required form fields before payment.
  • Check terms and conditions acceptance.
  • Verify customer information completeness.
  • Prevent payment sheet from opening if validation fails.
  • Validate minimum order amounts.
  • Check age verification requirements.

Callback signature

onCustomValidation: (() -> suspend Boolean)?

Event data

This callback receives no parameters.

Return value

Return valueDescription
BooleanReturn true to proceed with opening payment sheet, false to prevent opening.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onCustomValidation = suspend {
        var isValid = true
        
        // Validate email
        val email = emailField.text.toString()
        if (email.isEmpty() || !email.contains('@')) {
            showError("Please enter a valid email address")
            highlightField(emailField)
            isValid = false
        }
        
        // Validate phone number (if required)
        val phone = phoneField.text.toString()
        if (phone.isEmpty() || phone.length < 10) {
            showError("Please enter a valid phone number")
            highlightField(phoneField)
            isValid = false
        }
        
        // Validate terms acceptance
        val termsAccepted = termsCheckbox.isChecked
        if (!termsAccepted) {
            showError("Please accept the terms and conditions")
            highlightField(termsCheckbox)
            isValid = false
        }
        
        // Validate age verification (if required)
        val ageVerified = ageVerifyCheckbox.isChecked
        if (!ageVerified) {
            showError("You must be 18 or older to complete this purchase")
            isValid = false
        }
        
        // Validate minimum order amount
        val cartTotal = getCurrentCartTotal()
        if (cartTotal < 10.00) {
            showError("Minimum order amount is £10.00")
            isValid = false
        }
        
        // Final inventory check
        if (isValid) {
            val inventoryAvailable = checkInventory()
            if (!inventoryAvailable) {
                showError("Some items are no longer available. Please review your cart.")
                isValid = false
            }
        }
        
        isValid // Return validation result
    }
}

onError

This callback is triggered when an error occurs during the Google Pay payment process.

You can use it to:

  • Log errors for debugging and monitoring.
  • Display user-friendly error messages.
  • Offer alternative payment methods.
  • Implement automatic retry for transient errors.
  • Send error notifications to support teams.
  • Track error rates for quality monitoring.

Callback signature

onError: ((BaseSdkException) -> Unit)?

Event data

Event dataDescription
error
BaseSdkException
required
The SDK exception containing error details.
error.message
String?
A human-readable error description.
error.ErrorCode
String
The error code for programmatic handling.
error.cause
Throwable?
The underlying cause of the error, if available.

Exception types

ExceptionCodeDescription
GooglePayNotReadyExceptionSDK0701Google Pay not available on device.
GooglePayPaymentFailedExceptionSDK0702Payment processing failed.
GooglePayClientNotInitializedExceptionSDK0703Client not properly initialised.
GooglePayLoadFailedExceptionSDK0704Failed to load Google Pay API.
GooglePayConfigurationValidationFailedExceptionSDK0705Invalid configuration.
GooglePayDecryptAndTokenVaultFailedExceptionSDK0706Token processing failed.
UnsupportedFundingTypeGooglePaySdkExceptionSDK0110Google Pay not in allowed funding types.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onError = { error ->
        Log.e("GooglePay", "Error occurred", error)
        
        // Log error for debugging
        logError("google-pay-error") {
            put("message", error.message ?: "Unknown error")
            put("code", error.ErrorCode)
            put("timestamp", System.currentTimeMillis())
            put("user_id", getCurrentUserId())
        }
        
        // Handle specific error types
        when (error) {
            is GooglePayNotReadyException -> {
                Log.e("GooglePay", "Google Pay not available")
                showError("Google Pay is not available on this device. Please use another payment method.")
                showAlternativePaymentMethods()
                analyticsTracker.trackEvent("google_pay_not_available")
            }
            
            is GooglePayConfigurationValidationFailedException -> {
                Log.e("GooglePay", "Configuration validation failed")
                showError("Payment system temporarily unavailable. Please try again later.")
                notifySupport("Configuration error", error)
            }
            
            is GooglePayClientNotInitializedException -> {
                Log.e("GooglePay", "Client not initialised")
                showError("Payment system not ready. Please refresh and try again.")
                notifySupport("Client initialisation error", error)
            }
            
            is GooglePayLoadFailedException -> {
                Log.e("GooglePay", "Failed to load Google Pay")
                showError("Unable to load payment system. Please check your connection.")
                offerRetryOption()
            }
            
            is GooglePayPaymentFailedException -> {
                Log.e("GooglePay", "Payment processing failed")
                showError("Payment failed. Please check your payment information.")
                offerRetryOption()
            }
            
            is GooglePayDecryptAndTokenVaultFailedException -> {
                Log.e("GooglePay", "Token vault error")
                showError("Payment processing error. Please try again.")
                notifySupport("Token vault error", error)
            }
            
            else -> {
                Log.e("GooglePay", "Unexpected error: ${error.message}")
                showError("An unexpected error occurred. Please try again.")
                analyticsTracker.trackEvent("google_pay_error") {
                    put("error_type", error::class.simpleName ?: "Unknown")
                    put("error_code", error.ErrorCode)
                }
            }
        }
    }
}

onCancel

This callback is triggered when the customer cancels the Google Pay payment flow.

You can use it to:

  • Track cancellation rates for conversion optimisation.
  • Show helpful messages or alternative options.
  • Save the customer's cart for later completion.
  • Trigger abandoned cart workflows.
  • Understand drop-off points in the payment flow.
  • Offer assistance or support.

Callback signature

onCancel: (() -> Unit)?

Event data

This callback receives no parameters.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onCancel = {
        Log.d("GooglePay", "Payment cancelled by user")
        
        // Track cancellation
        analyticsTracker.trackEvent("google_pay_cancelled") {
            put("timestamp", System.currentTimeMillis())
            put("cart_value", getCurrentCartValue())
            put("item_count", getCartItemCount())
        }
        
        // Preserve cart for later
        saveCartForLater()
        
        // Show helpful message
        showMessage(
            "No worries! Your items are saved. You can complete your purchase anytime.",
            isError = false
        )
        
        // Offer support for high-value carts
        if (getCartValue() > 100.0) {
            showSupportDialog("Need help completing your purchase?")
        }
        
        // Schedule abandoned cart notification
        lifecycleScope.launch {
            scheduleAbandonedCartNotification(
                customerId = getCurrentCustomerId(),
                cartData = getCurrentCartData(),
                delayMinutes = 60
            )
        }
    }
}

3D Secure authentication events

useUnityAuthenticationStrategy

This configuration parameter controls which authentication strategy is used for 3DS authentication.

Configuration

useUnityAuthenticationStrategy: Boolean = false

When true, uses Unity's automatic authentication strategy. When false or not specified, uses manual authentication callbacks.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    // Enable Unity authentication strategy
    useUnityAuthenticationStrategy = true
    
    // Simplified callbacks when using Unity strategy
    onPreInitiateAuthentication = {
        PreInitiateIntegratedAuthenticationData(
            providerId = "pxpfinancial",
            timeout = 12
        )
    }
    
    onPreAuthentication = suspend {
        InitiateIntegratedAuthenticationData(
            merchantCountryNumericCode = "840",
            merchantLegalName = "Your Store Name",
            challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,
            requestorChallengeIndicator = RequestorChallengeIndicatorType.NO_PREFERENCE,
            timeout = 180
        )
    }
}

onPreInitiateAuthentication

This callback is triggered before initiating the 3DS pre-authentication check.

You can use it to:

  • Configure 3DS provider settings.
  • Set authentication request preferences.
  • Specify timeout values for authentication requests.
  • Control the initial authentication flow.

Callback signature

onPreInitiateAuthentication: (() -> PreInitiateIntegratedAuthenticationData?)?

Event data

This callback receives no parameters.

Return value

Return valueDescription
PreInitiateIntegratedAuthenticationDataConfiguration for 3DS pre-authentication.
PreInitiateIntegratedAuthenticationData.providerIdYour 3DS provider identifier. Optional.
PreInitiateIntegratedAuthenticationData.requestorAuthenticationIndicatorThe authentication indicator. Optional.

Possible values:
  • PAYMENT_TRANSACTION (01)
  • RECURRING_TRANSACTION (02)
  • INSTALLMENT_TRANSACTION (03)
  • ADD_CARD (04)
  • MAINTAIN_CARD (05)
  • CARD_HOLDER_VERIFICATION (06)
  • BILLING_AGREEMENT (07)
  • DEVICE_BINDING (08)
  • SPLIT_DELAYED_SHIPMENT (09)
  • TOP_UP (10)
PreInitiateIntegratedAuthenticationData.timeoutThe timeout to get the fingerprint result, in seconds (max 600). Optional.
nullReturn null to skip 3DS authentication.

Example implementation

import com.pxp.checkout.services.models.authentication.PreInitiateIntegratedAuthenticationData
import com.pxp.checkout.models.RequestorAuthenticationIndicatorType

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onPreInitiateAuthentication = {
        Log.d("GooglePay", "Initiating 3DS pre-authentication")
        
        // Track 3DS initiation
        analyticsTracker.trackEvent("3ds_pre_initiate")
        
        PreInitiateIntegratedAuthenticationData(
            providerId = "your-3ds-provider-id", // Optional
            requestorAuthenticationIndicator = RequestorAuthenticationIndicatorType.PAYMENT_TRANSACTION,
            timeout = 300 // 5 minutes
        )
    }
}

onPostInitiateAuthentication

This callback is triggered after the 3DS pre-authentication check completes.

You can use it to:

  • Read authenticationId and threeDSecureSupported from the success result.
  • Retrieve authentication assessment results from your backend using the authenticationId.
  • Determine if full authentication is required.
  • Log authentication initiation for compliance.
  • Check SCA requirements and exemptions.
  • Decide whether to proceed with challenge.

Callback signature

onPostInitiateAuthentication: ((AuthenticationResult) -> Unit)?

Event data

ParameterDescription
result
AuthenticationResult
Authentication initiation result. Success is MerchantAuthenticationResult; failure is FailedAuthenticationResult.
result.authenticationId
String?
Unique identifier for this 3DS session. May be null when 3DS isn't required. Use this to retrieve full pre-authentication results from your backend.
result.threeDSecureSupported
Boolean
Whether 3DS authentication is supported for this transaction.

When both authenticationId is absent and threeDSecureSupported is false, the SDK skips the remaining 3DS flow and doesn't invoke onPreAuthentication. This early-exit check applies when useUnityAuthenticationStrategy is false. When useUnityAuthenticationStrategy is true, the SDK uses Unity's authentication strategy API instead. Use the authenticationId with the Get 3DS pre-initiate authentication details API to retrieve SCA mandates, exemptions, and state.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onPostInitiateAuthentication = { result ->
        when (result) {
            is FailedAuthenticationResult -> {
                Log.e("GooglePay", "3DS pre-initiation failed: ${result.errorReason}")
            }
            is MerchantAuthenticationResult -> {
                Log.d("GooglePay", "Pre-authentication complete: ${result.authenticationId}")
                Log.d("GooglePay", "3DS supported: ${result.threeDSecureSupported}")

                if (result.authenticationId.isNullOrEmpty() && !result.threeDSecureSupported) {
                    return@onPostInitiateAuthentication
                }

                val authId = result.authenticationId ?: return@onPostInitiateAuthentication

                lifecycleScope.launch {
                    try {
                        val authResult = fetchAuthenticationResultFromBackend(authId)

                        if (authResult.state == "PendingClientData") {
                            Log.d("GooglePay", "Waiting for client data collection")
                        }

                        if (authResult.scaMandated) {
                            Log.d("GooglePay", "SCA is required - 3DS must complete successfully")
                            withContext(Dispatchers.Main) {
                                showMessage("Additional verification required")
                            }
                        }

                        evaluateAuthenticationAndUpdateSession(authResult)
                    } catch (e: Exception) {
                        Log.e("GooglePay", "Error retrieving authentication result", e)
                    }
                }
            }
        }
    }
}

onPreAuthentication

This callback is triggered before full 3DS authentication begins, allowing you to provide authentication configuration.

You can use it to:

  • Specify merchant details for authentication.
  • Configure challenge window preferences.
  • Set challenge indicators based on risk assessment.
  • Provide country-specific merchant information.
  • Control the authentication user experience.

Callback signature

onPreAuthentication: (suspend () -> InitiateIntegratedAuthenticationData?)?

Event data

This callback receives no parameters.

Return value

Return valueDescription
InitiateIntegratedAuthenticationDataConfiguration for 3DS authentication.
InitiateIntegratedAuthenticationData.merchantCountryNumericCodeYour merchant location, as an ISO numeric country code (e.g., "840" for USA, "826" for UK). Optional.
InitiateIntegratedAuthenticationData.merchantLegalNameYour legal business name. Optional.
InitiateIntegratedAuthenticationData.challengeWindowSizeThe challenge window size. Optional.

Possible values:
  • FULL_SCREEN (01 - Fullscreen)
  • IFRAME_250x400 (02 - 250x400 px)
  • IFRAME_390x400 (03 - 390x400 px)
  • IFRAME_500x600 (04 - 500x600 px)
  • IFRAME_600x400 (05 - 600x400 px)
InitiateIntegratedAuthenticationData.requestorChallengeIndicatorThe challenge preference indicator. Optional.

Possible values:
  • NO_PREFERENCE (01)
  • NO_CHALLENGE_REQUESTED (02)
  • CHALLENGE_REQUESTED_3DS_REQUESTOR_PREFERENCE (03)
  • CHALLENGE_REQUESTED_MANDATE (04)
  • NO_CHALLENGE_REQUESTED_TRA_PERFORMED (05)
  • NO_CHALLENGE_REQUESTED_LOW_VALUE_EXEMPTION (10)
InitiateIntegratedAuthenticationData.timeoutTimeout to get the challenge result, in seconds (max 600). Optional.
InitiateIntegratedAuthenticationData.billingAddressBilling address for authentication. Optional.
InitiateIntegratedAuthenticationData.shopperShopper information. Optional.
nullReturn null to skip authentication.

Example implementation

import com.pxp.checkout.services.models.authentication.InitiateIntegratedAuthenticationData
import com.pxp.checkout.models.RequestorChallengeIndicatorType
import com.pxp.checkout.components.threeds.ChallengeWindowSize

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onPreAuthentication = suspend {
        Log.d("GooglePay", "Configuring 3DS authentication")
        
        // Get authentication decision from backend
        val decision = getAuthenticationDecision()
        
        if (decision == null) {
            Log.d("GooglePay", "Skipping authentication based on backend decision")
            return@suspend null
        }
        
        // Assess transaction risk
        val amount = getTransactionAmount()
        val customerHistory = getCustomerHistory()
        val isHighRisk = amount > 500.0 || customerHistory.chargebacks > 0
        
        // Determine challenge indicator
        val challengeIndicator = when {
            isHighRisk -> RequestorChallengeIndicatorType.CHALLENGE_REQUESTED_MANDATE
            amount < 30.0 && customerHistory.successfulTransactions > 10 -> 
                RequestorChallengeIndicatorType.NO_CHALLENGE_REQUESTED
            else -> RequestorChallengeIndicatorType.NO_PREFERENCE
        }
        
        Log.d("GooglePay", "Challenge indicator: $challengeIndicator")
        
        InitiateIntegratedAuthenticationData(
            merchantCountryNumericCode = "826", // United Kingdom
            merchantLegalName = "Your Store Limited",
            challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,
            requestorChallengeIndicator = challengeIndicator,
            timeout = if (decision.scaMandated) 600 else 300,
            billingAddress = getBillingAddress()?.let {
                BillingAddress(
                    city = it.city,
                    countryNumericCode = it.countryCode,
                    line1 = it.streetAddress,
                    postalCode = it.postalCode
                )
            },
            shopper = ShopperData(
                email = getCurrentCustomerEmail(),
                homePhoneNumber = getCurrentCustomerPhone()
            )
        )
    }
}

onPostAuthentication

This callback is triggered after 3DS authentication completes, providing the authentication result.

You can use it to:

  • Retrieve authentication results.
  • Log authentication outcomes for compliance.
  • Track authentication success rates.
  • Handle authentication failures gracefully.
  • Record ECI values and authentication indicators.

Callback signature

onPostAuthentication: ((AuthenticationResult) -> Unit)?

Event data

ParameterDescription
data
MerchantAuthenticationResult
required
Authentication result containing the authentication ID.
data.authenticationId
String
required
Unique identifier for the authentication attempt. Use this to retrieve full authentication details from your backend.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onPostAuthentication = { data ->
        Log.d("GooglePay", "3DS authentication completed: ${data.authenticationId}")
        
        lifecycleScope.launch {
            try {
                // Retrieve authentication result from backend
                val authResult = fetchAuthenticationResultFromBackend(data.authenticationId)
                
                Log.d("GooglePay", "Authentication result: $authResult")
                
                // Check transaction status
                when (authResult.transactionStatus) {
                    "Y" -> {
                        Log.d("GooglePay", "Authentication successful - no challenge needed")
                        showMessage("Card verified successfully")
                    }
                    "C" -> {
                        if (authResult.state == "AuthenticationSuccessful") {
                            Log.d("GooglePay", "Challenge completed successfully")
                            showMessage("Verification completed")
                        } else {
                            Log.e("GooglePay", "Challenge failed")
                            showError("Verification failed. Please try again.")
                            return@launch // Stop payment
                        }
                    }
                    "N" -> {
                        Log.e("GooglePay", "Authentication failed")
                        showError("Card verification failed")
                        return@launch // Stop payment
                    }
                    "R" -> {
                        Log.e("GooglePay", "Authentication rejected")
                        showError("Payment was rejected by your bank")
                        return@launch // Stop payment
                    }
                }
                
                // Evaluate and update authorisation decision
                evaluateAuthenticationAndUpdateAuthorization(authResult)
                
                Log.d("GooglePay", "Proceeding to final authorisation...")
            } catch (e: Exception) {
                Log.e("GooglePay", "Error processing authentication result", e)
                showError("Authentication processing error")
            }
        }
    }
}

onGetConsent

This callback is called to determine if the customer has given consent to store their payment token for future use.

The primary use case is to set a default consent value (true or false) when you're not rendering the google-pay-consent checkbox component. This allows you to control token storage behaviour without requiring explicit customer interaction.

When both googlePayConsentComponent and onGetConsent are provided, the consent component value takes priority. The onGetConsent callback will not be called if a consent component is linked.

You can use it to:

  • Set a default consent value when not using the consent checkbox component.
  • Check custom consent checkbox status from your own UI.
  • Verify terms and conditions acceptance for stored payments.
  • Control token storage behaviour based on business logic.
  • Implement opt-in/opt-out for recurring payments.
  • Respect customer privacy preferences.

Callback signature

onGetConsent: (() -> Boolean)?

Event data

This callback receives no parameters.

Return value

Return TypeDescription
Boolean
required
Return true if consent was given, false otherwise.

Example implementation

Example 1: Set default consent value without checkbox

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    // ... payment configuration
    
    onGetConsent = {
        // Return a default value when not using consent checkbox
        // Set to true to always store tokens, false to never store
        Log.d("GooglePay", "Setting default consent: true")
        true // Always save payment method for this merchant
    }
    
    onPostAuthorisation = { result, paymentData ->
        when (result) {
            is MerchantSubmitResult -> {
                Log.d("GooglePay", "Payment successful, token will be stored")
                // Token storage is handled automatically based on consent
            }
            else -> { /* Handle failure */ }
        }
    }
}

Example 2: Use custom consent checkbox from your UI

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    // ... payment configuration
    
    onGetConsent = {
        // Check your own custom checkbox
        val consentGiven = customConsentCheckbox.isChecked
        
        if (consentGiven) {
            Log.d("GooglePay", "Customer consented to save payment method")
            
            // Track consent
            analyticsTracker.trackEvent("payment_consent_given") {
                put("timestamp", System.currentTimeMillis())
                put("payment_method", "google-pay")
            }
        } else {
            Log.d("GooglePay", "Customer did not consent to save payment method")
        }
        
        consentGiven
    }
}

Example 3: With consent component (component value takes priority)

// Create consent component
val consentComponent = pxpCheckout.createComponent<
    GooglePayConsentComponent,
    GooglePayConsentConfig
>(
    type = ComponentType.GOOGLE_PAY_CONSENT,
    config = GooglePayConsentConfig(
        label = "Save this payment method for future purchases",
        initialChecked = false
    )
)

// Create Google Pay button with consent
val googlePayConfig = GooglePayButtonComponentConfig().apply {
    // ... payment configuration
    
    // Link the consent component
    googlePayConsentComponent = consentComponent
    
    // This callback will NOT be called because consent component is linked
    onGetConsent = {
        Log.d("GooglePay", "This callback is ignored when component is linked")
        true // This is ignored when consent component is present
    }
}

// The consent component's checked state will be used for token storage

CVC collection callbacks

The Google Pay Button Component can request CVV/CVC codes for additional security. While there's no specific callback for CVC collection, you can configure the behaviour:

CVC collection configuration

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    // CVC collection strategy
    collectCvc = GooglePayButtonComponentConfig.CvcCollectionStrategy.DEFAULT
    
    // Custom CVC dialog configuration (optional)
    cvcVerificationPopupConfig = CvcVerificationDialogConfig(
        title = "Security Verification",
        description = "Please enter your card's CVV code",
        submitButtonText = "Confirm Payment",
        cancelButtonText = "Go Back",
        
        // Custom styling
        titleStyles = TextStyle(
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            color = Color(0xFF1A237E)
        ),
        
        // CVC input configuration
        cvcComponentConfig = CardCvcComponentConfig().apply {
            label = "CVV"
            showHintIcon = true
            showValidIcon = true
            showMaskToggle = true
        }
    )
}

CVC collection strategies

enum class CvcCollectionStrategy {
    ALWAYS,   // Always show CVC dialog for FPAN
    NEVER,    // Never show CVC dialog
    DEFAULT   // Show CVC only when 3DS not available/skipped
}

Risk screening events

onKountCollectStart

This callback is triggered when Kount fraud detection data collection begins.

You can use it to:

  • Track fraud detection start time.
  • Show loading indicators during fraud screening.
  • Log fraud detection events.
  • Monitor fraud detection performance.

Callback signature

onKountCollectStart: ((Any) -> Unit)?

Event data

ParameterDescription
data
Any
Kount collection start data.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onKountCollectStart = { data ->
        Log.d("GooglePay", "Kount fraud detection started")
        
        // Track fraud detection start
        analyticsTracker.trackEvent("kount_collection_start") {
            put("timestamp", System.currentTimeMillis())
        }
        
        // Show fraud check indicator (optional)
        lifecycleScope.launch(Dispatchers.Main) {
            showFraudCheckIndicator()
        }
    }
}

onKountCollectEnd

This callback is triggered when Kount fraud detection data collection completes.

You can use it to:

  • Track fraud detection completion time.
  • Hide loading indicators.
  • Log fraud detection completion.
  • Calculate fraud detection duration.

Callback signature

onKountCollectEnd: ((Any) -> Unit)?

Event data

ParameterDescription
data
Any
Kount collection completion data.

Example implementation

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onKountCollectStart = { data ->
        val startTime = System.currentTimeMillis()
        
        // Store start time for duration calculation
        fraudDetectionStartTime = startTime
        
        Log.d("GooglePay", "Kount collection started at $startTime")
    }
    
    onKountCollectEnd = { data ->
        val endTime = System.currentTimeMillis()
        val duration = endTime - fraudDetectionStartTime
        
        Log.d("GooglePay", "Kount collection completed in ${duration}ms")
        
        // Track fraud detection completion
        analyticsTracker.trackEvent("kount_collection_end") {
            put("timestamp", endTime)
            put("duration_ms", duration)
        }
        
        // Hide fraud check indicator
        lifecycleScope.launch(Dispatchers.Main) {
            hideFraudCheckIndicator()
        }
    }
}

private var fraudDetectionStartTime: Long = 0

Soft decline retry events

onPreRetrySoftDecline

This callback is triggered before retrying a soft-declined payment with different authentication parameters.

You can use it to:

  • Configure retry attempts with alternative challenge indicators.
  • Implement custom retry logic for soft declines.
  • Track soft decline occurrences.
  • Adjust authentication parameters for better success rates.
  • Decide whether to retry or abort.

Callback signature

onPreRetrySoftDecline: ((SubmitResult) -> RetryConfiguration?)?

Event data

ParameterDescription
result
SubmitResult
required
Transaction result containing decline information.
result.errorCode
String
Error code indicating decline type.
result.errorReason
String
Human-readable decline reason.
result.correlationId
String
Correlation ID for tracking.
result.merchantTransactionId
String
Your transaction identifier.
result.systemTransactionId
String?
System transaction identifier (if available).

Return value

PropertyDescription
retry
Boolean
required
Whether to retry the payment.
updatedConfigs
UpdatedConfigs?
Updated callback configurations for retry attempt. Contains optional onPreInitiateAuthentication, onPreAuthentication, and onPreAuthorisation callbacks.

Example implementation

import com.pxp.checkout.components.googlepay.types.GooglePayButtonComponentConfig
import com.pxp.checkout.services.models.authentication.*
import com.pxp.checkout.models.*
import com.pxp.checkout.components.threeds.ChallengeWindowSize

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    onPreRetrySoftDecline = { result ->
        Log.w("GooglePay", "Soft decline detected, preparing retry")
        Log.w("GooglePay", "Error code: ${result.errorCode}")
        Log.w("GooglePay", "Decline reason: ${result.errorReason}")
        Log.w("GooglePay", "Correlation ID: ${result.correlationId}")
        
        // Track soft decline
        analyticsTracker.trackEvent("payment_soft_decline") {
            put("error_code", result.errorCode)
            put("error_reason", result.errorReason)
            put("correlation_id", result.correlationId)
            put("transaction_id", result.merchantTransactionId)
        }
        
        // Show message to user
        showMessage("Processing payment with additional verification...")
        
        // Retry with forced 3DS challenge
        GooglePayButtonComponentConfig.RetryConfiguration(
            retry = true,
            updatedConfigs = GooglePayButtonComponentConfig.RetryConfiguration.UpdatedConfigs(
                onPreInitiateAuthentication = {
                    PreInitiateIntegratedAuthenticationData(
                        providerId = "pxpfinancial",
                        timeout = 12
                    )
                },
                onPreAuthentication = suspend {
                    InitiateIntegratedAuthenticationData(
                        merchantCountryNumericCode = "826",
                        merchantLegalName = "Your Store Ltd",
                        challengeWindowSize = ChallengeWindowSize.FULL_SCREEN,
                        requestorChallengeIndicator = 
                            RequestorChallengeIndicatorType.CHALLENGE_REQUESTED_MANDATE,
                        timeout = 300
                    )
                }
            )
        )
        
        // Alternative: Don't retry
        // GooglePayButtonComponentConfig.RetryConfiguration(retry = false)
    }
}

Complete implementation example

Here's a comprehensive example showing multiple callbacks working together:

import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.pxp.PxpCheckout
import com.pxp.checkout.components.googlepay.*
import com.pxp.checkout.components.googlepay.types.*
import com.pxp.checkout.models.*
import com.pxp.checkout.services.kount.*
import com.pxp.checkout.types.ComponentType
import kotlinx.coroutines.CompletableDeferred

@Composable
fun GooglePayPaymentScreen(
    pxpCheckout: PxpCheckout,
    amount: Double,
    onSuccess: (String) -> Unit,
    onError: (String) -> Unit
) {
    var errorMessage by remember { mutableStateOf<String?>(null) }
    var isProcessing by remember { mutableStateOf(false) }
    
    val googlePayComponent = remember {
        pxpCheckout.createComponent<
            GooglePayButtonComponent,
            GooglePayButtonComponentConfig
        >(
            type = ComponentType.GOOGLE_PAY_BUTTON,
            config = GooglePayButtonComponentConfig().apply {
                
                // Payment configuration
                style = GooglePayButtonStyle(
                    type = GooglePayButtonType.PAY,
                    theme = GooglePayButtonTheme.DARK,
                    cornerRadius = 8
                )
                
                paymentDataRequest = PaymentDataRequest(
                    allowedPaymentMethods = listOf(
                        PaymentMethodSpecification(
                            parameters = PaymentMethodParameters(
                                allowedAuthMethods = listOf(
                                    CardAuthMethod.PAN_ONLY,
                                    CardAuthMethod.CRYPTOGRAM_3DS
                                ),
                                allowedCardNetworks = listOf(
                                    CardNetwork.VISA,
                                    CardNetwork.MASTERCARD,
                                    CardNetwork.AMEX
                                )
                            )
                        )
                    ),
                    transactionInfo = TransactionInfo(
                        currencyCode = "GBP",
                        totalPriceStatus = TotalPriceStatus.FINAL,
                        totalPrice = amount.toString(),
                        countryCode = "GB"
                    ),
                    emailRequired = true
                )
                
                // Enable 3DS with Unity strategy
                useUnityAuthenticationStrategy = true
                collectCvc = GooglePayButtonComponentConfig.CvcCollectionStrategy.DEFAULT
                
                // Button click callback
                onGooglePaymentButtonClicked = {
                    Log.d("GooglePay", "Button clicked")
                    isProcessing = true
                    errorMessage = null
                    CompletableDeferred(Unit)
                }
                
                // Pre-authorisation callback
                onPreAuthorisation = suspend { data ->
                    Log.d("GooglePay", "Pre-authorisation: ${data?.gatewayTokenId}")
                    
                    GooglePayTransactionInitData(
                        riskScreeningData = RiskScreeningData(
                            performRiskScreening = true,
                            excludeDeviceData = false,
                            userIp = "192.168.1.100",
                            account = RiskScreeningAccount(
                                id = "user_12345678",
                                creationDateTime = "2024-01-15T10:30:00.000Z"
                            ),
                            fulfillments = listOf(
                                RiskScreeningFulfillment(
                                    type = FulfillmentType.SHIPPED,
                                    recipientPerson = RiskScreeningRecipientPerson(
                                        phoneNumber = "+1234567890"
                                    )
                                )
                            )
                        )
                    )
                }
                
                // Post-authorisation callback
                onPostAuthorisation = { result, paymentData ->
                    isProcessing = false
                    
                    when (result) {
                        is MerchantSubmitResult -> {
                            Log.d("GooglePay", "Payment successful")
                            onSuccess(result.merchantTransactionId)
                        }
                        is FailedSubmitResult -> {
                            Log.e("GooglePay", "Payment failed: ${result.errorReason}")
                            errorMessage = result.errorReason
                            onError(result.errorReason)
                        }
                    }
                }
                
                // Error callback
                onError = { error ->
                    Log.e("GooglePay", "Error: ${error.message}", error)
                    isProcessing = false
                    errorMessage = error.message
                    onError(error.message ?: "Payment error")
                }
                
                // Cancel callback
                onCancel = {
                    Log.d("GooglePay", "Payment cancelled")
                    isProcessing = false
                    errorMessage = "Payment cancelled"
                }
            }
        )
    }
    
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Complete Your Payment",
            style = MaterialTheme.typography.headlineMedium
        )
        
        Spacer(modifier = Modifier.height(16.dp))
        
        Text(
            text = "£${amount}",
            style = MaterialTheme.typography.displaySmall
        )
        
        Spacer(modifier = Modifier.height(24.dp))
        
        // Render Google Pay button
        googlePayComponent?.Content(
            modifier = Modifier.fillMaxWidth()
        )
        
        // Error message
        errorMessage?.let { error ->
            Spacer(modifier = Modifier.height(16.dp))
            Text(
                text = error,
                color = MaterialTheme.colorScheme.error,
                style = MaterialTheme.typography.bodyMedium
            )
        }
        
        // Processing indicator
        if (isProcessing) {
            Spacer(modifier = Modifier.height(16.dp))
            CircularProgressIndicator()
        }
    }
}

Analytics events

The SDK automatically tracks key events throughout the Google Pay payment flow. These analytics events help you monitor payment performance, identify issues, and optimise the user experience.

Automatic event tracking

The following events are tracked automatically without any additional configuration:

EventDescription
GooglePayButtonClickAnalyticsEventTriggered when the user taps the Google Pay button. Helps track button engagement and conversion funnel entry.
GooglePayReadinessCheckAnalyticsEventTriggered when the SDK checks if Google Pay is available on the device. Useful for understanding device compatibility.
GooglePaySheetOpenedAnalyticsEventTriggered when the Google Pay payment sheet opens. Indicates successful button interaction and sheet loading.
GooglePaySheetCompletedAnalyticsEventTriggered when the Google Pay payment sheet closes (either completed or cancelled). Helps track sheet completion rates.
GooglePayTokenReceivedAnalyticsEventTriggered when a payment token is successfully received from Google Pay. Indicates successful tokenisation.
GooglePayFlowCancelledAnalyticsEventTriggered when the user cancels the payment flow. Helps identify drop-off points and cancellation patterns.
ComponentErrorAnalyticsEventTriggered when an error occurs during the payment flow. Essential for monitoring error rates and types.

Event data structure

Each analytics event contains:

  • Event name: The type of event that occurred.
  • Timestamp: When the event was triggered.
  • Component type: Always GOOGLE_PAY_BUTTON for Google Pay events.
  • Additional context: Event-specific data (e.g., error details, token information).

Accessing analytics data

Analytics events are automatically sent to the PXP backend and can be viewed in the Unity Portal analytics dashboard. You can use this data to:

  • Monitor conversion rates: Track how many users complete payments after clicking the button.
  • Identify technical issues: Detect patterns in error events and readiness check failures.
  • Optimise user experience: Understand where users drop off in the payment flow.
  • Track performance metrics: Measure average time from button click to payment completion.

Custom analytics integration

If you want to integrate with your own analytics platform (e.g., Firebase Analytics, Google Analytics), you can track events using the callback functions:

import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase

val analytics = Firebase.analytics

val googlePayConfig = GooglePayButtonComponentConfig().apply {
    
    onGooglePaymentButtonClicked = {
        // Track button click
        analytics.logEvent("google_pay_button_clicked", Bundle().apply {
            putLong("timestamp", System.currentTimeMillis())
            putString("currency", "GBP")
            putDouble("amount", 99.99)
        })
        CompletableDeferred(Unit)
    }
    
    onPostAuthorisation = { result, paymentData ->
        when (result) {
            is MerchantSubmitResult -> {
                // Track successful payment
                analytics.logEvent("google_pay_payment_success", Bundle().apply {
                    putString("transaction_id", result.merchantTransactionId)
                    putString("system_transaction_id", result.systemTransactionId)
                })
            }
            is FailedSubmitResult -> {
                // Track failed payment
                analytics.logEvent("google_pay_payment_failed", Bundle().apply {
                    putString("error_code", result.errorCode)
                    putString("error_reason", result.errorReason)
                    putString("correlation_id", result.correlationId)
                })
            }
        }
    }
    
    onError = { error ->
        // Track errors
        analytics.logEvent("google_pay_error", Bundle().apply {
            putString("error_type", error::class.simpleName)
            putString("error_message", error.message)
        })
    }
    
    onCancel = {
        // Track cancellations
        analytics.logEvent("google_pay_cancelled", Bundle().apply {
            putLong("timestamp", System.currentTimeMillis())
        })
    }
}