# Analytics

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

## Overview

Analytics events are structured data objects that get automatically triggered when significant actions or states occur within components. These allow you to monitor every aspect of the payment journey.

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 should be consumed in the `PxpSdkConfig` during SDK initialisation. For example:


```kotlin
val sdkConfig = PxpSdkConfig(
    environment = Environment.TEST,
    session = SessionConfig(
        sessionId = "your_session_id",
        sessionData = "your_session_data"
    ),
    merchantShopperId = "123",
    ownerId = "UnityGroup",
    ownerType = "MerchantGroup",
    transactionData = TransactionData(
        currency = CurrencyType.USD,
        amount = payAmount,
        entryType = EntryType.Ecom,
        intent = IntentType.Authorisation,
        merchantTransactionId = "9af8af33-59d5-432d-bd35-96124930ec9f",
        merchantTransactionDate = { Instant.now().toString() }
    ),
    analyticsEvent = { analyticsEvent ->
        when (analyticsEvent) {
            is ComponentLifecycleAnalyticsEvent -> {
                // Track component lifecycle (mount/unmount)
                Log.d("Analytics", "Component ${analyticsEvent.eventType}: ${analyticsEvent.componentId}")
                analytics.track(analyticsEvent.eventName, analyticsEvent.toMap())
            }
            is ErrorTracker.ComponentErrorEvent -> {
                // Log component errors for debugging
                Log.e("Analytics", "Component error: ${analyticsEvent.message}")
                crashlytics.recordException(Exception(analyticsEvent.message))
            }
            is ErrorTracker.ComponentValidationEvent -> {
                // Track validation events
                analytics.track("component_validation", mapOf(
                    "component_id" to analyticsEvent.componentId,
                    "is_valid" to analyticsEvent.isValid,
                    "validation_message" to analyticsEvent.validationMessage
                ))
            }
            else -> {
                // Handle other analytics events
                Log.d("Analytics", "Event: ${analyticsEvent.eventName}")
                analytics.track(analyticsEvent.eventName, analyticsEvent.toMap())
            }
        }
    }
)

val pxpCheckout = PxpCheckout.builder()
    .withConfig(sdkConfig)
    .withContext(this)
    .withDebugMode(true)
    .build()
```

## Available analytics events

The Android SDK provides several types of analytics events:

### Component lifecycle events

Track when components are mounted and unmounted in your application:


```kotlin
class ComponentLifecycleAnalyticsEvent(
    val eventType: LifecycleEventType, // MOUNT or UNMOUNT
    val componentId: String,
    sessionId: String,
    val componentType: String? = null
) : BaseAnalyticsEvent("ComponentLifecycleEvent", sessionId)
```

### Component error events

Track errors that occur within components:


```kotlin
class ComponentErrorEvent(
    val code: String,
    val message: String,
    val componentId: String,
    sessionId: String
) : BaseAnalyticsEvent("ComponentErrorEvent", sessionId)
```

### Component validation events

Track validation results for components:


```kotlin
class ComponentValidationEvent(
    val componentId: String,
    val isValid: Boolean,
    val validationMessage: String?,
    sessionId: String
) : BaseAnalyticsEvent("ComponentValidationEvent", sessionId)
```

## Comprehensive analytics implementation

Here's a comprehensive example showing how to handle the available analytics events:


```kotlin
class AnalyticsManager {
    
    fun setupAnalyticsEventHandler(): (BaseAnalyticsEvent) -> Unit {
        return { analyticsEvent ->
            // Log all events for debugging (remove in production)
            Log.d("Analytics", "Event: ${analyticsEvent.eventName} at ${analyticsEvent.timestamp}")
            
            when (analyticsEvent) {
                // Component lifecycle events
                is ComponentLifecycleAnalyticsEvent -> {
                    when (analyticsEvent.eventType) {
                        LifecycleEventType.MOUNT -> {
                            trackComponentMount(analyticsEvent)
                        }
                        LifecycleEventType.UNMOUNT -> {
                            trackComponentUnmount(analyticsEvent)
                        }
                    }
                }
                
                // Error tracking
                is ErrorTracker.ComponentErrorEvent -> {
                    trackComponentError(analyticsEvent)
                    
                    // Send to crash reporting
                    crashlytics.recordException(Exception(analyticsEvent.message))
                }
                
                // Validation tracking
                is ErrorTracker.ComponentValidationEvent -> {
                    trackValidationEvent(analyticsEvent)
                }
                
                else -> {
                    // Send all events to your analytics service
                    sendToAnalyticsService(analyticsEvent)
                }
            }
        }
    }
    
    // Helper functions for tracking specific events
    private fun trackComponentMount(event: ComponentLifecycleAnalyticsEvent) {
        analytics.track("component_mounted", mapOf(
            "component_id" to event.componentId,
            "component_type" to event.componentType,
            "session_id" to event.sessionId,
            "timestamp" to event.timestamp
        ))
    }
    
    private fun trackComponentUnmount(event: ComponentLifecycleAnalyticsEvent) {
        analytics.track("component_unmounted", mapOf(
            "component_id" to event.componentId,
            "component_type" to event.componentType,
            "session_id" to event.sessionId,
            "timestamp" to event.timestamp
        ))
    }
    
    private fun trackComponentError(event: ErrorTracker.ComponentErrorEvent) {
        analytics.track("component_error", mapOf(
            "component_id" to event.componentId,
            "error_code" to event.code,
            "error_message" to event.message,
            "session_id" to event.sessionId
        ))
    }
    
    private fun trackValidationEvent(event: ErrorTracker.ComponentValidationEvent) {
        analytics.track("component_validation", mapOf(
            "component_id" to event.componentId,
            "is_valid" to event.isValid,
            "validation_message" to event.validationMessage,
            "session_id" to event.sessionId
        ))
    }
    
    private fun sendToAnalyticsService(event: BaseAnalyticsEvent) {
        // Send to your analytics service (Firebase, Mixpanel, etc.)
        firebaseAnalytics.logEvent(event.eventName, Bundle().apply {
            event.toMap().forEach { (key, value) ->
                when (value) {
                    is String -> putString(key, value)
                    is Int -> putInt(key, value)
                    is Long -> putLong(key, value)
                    is Boolean -> putBoolean(key, value)
                    is Double -> putDouble(key, value)
                    else -> putString(key, value.toString())
                }
            }
        })
    }
}
```

## Integration with analytics platforms

### Firebase Analytics


```kotlin
private fun logToFirebase(event: BaseAnalyticsEvent) {
    val bundle = Bundle().apply {
        event.toMap().forEach { (key, value) ->
            when (value) {
                is String -> putString(key, value)
                is Int -> putInt(key, value)
                is Long -> putLong(key, value)
                is Boolean -> putBoolean(key, value)
                is Double -> putDouble(key, value)
                else -> putString(key, value.toString())
            }
        }
    }
    
    firebaseAnalytics.logEvent(event.eventName, bundle)
}
```

### Custom analytics service


```kotlin
private fun logToCustomService(event: BaseAnalyticsEvent) {
    val payload = JSONObject().apply {
        put("event_name", event.eventName)
        put("session_id", event.sessionId)
        put("timestamp", event.timestamp.time)
        
        event.toMap().forEach { (key, value) ->
            put(key, value)
        }
    }
    
    // Send to your custom analytics endpoint
    analyticsApiClient.logEvent(payload)
}
```

## Best practices

### Event handling

* **Filter events:** Only track events relevant to your business needs.
* **Error handling:** Always wrap analytics calls in try-catch blocks.
* **Performance:** Avoid blocking the main thread with analytics calls.
* **Privacy:** Ensure compliance with data protection regulations.


### Implementation tips


```kotlin
// Good: Non-blocking analytics
analyticsEvent = { event ->
    GlobalScope.launch(Dispatchers.IO) {
        try {
            handleAnalyticsEvent(event)
        } catch (e: Exception) {
            Log.e("Analytics", "Failed to track event", e)
        }
    }
}

// Good: Selective event tracking
analyticsEvent = { event ->
    when (event) {
        is ComponentLifecycleAnalyticsEvent -> {
            // Only track lifecycle for specific components
            if (event.componentType in criticalComponents) {
                trackEvent(event)
            }
        }
        is ErrorTracker.ComponentErrorEvent -> {
            // Always track errors
            trackEvent(event)
        }
        // Ignore other events
    }
}
```

### Privacy considerations

* Always obtain user consent before collecting analytics data.
* Anonymise sensitive information in event payloads.
* Provide opt-out mechanisms for analytics tracking.
* Comply with GDPR, CCPA, and other relevant regulations.



```kotlin
// Example: Privacy-aware analytics
analyticsEvent = { event ->
    if (userHasConsentedToAnalytics()) {
        val sanitizedEvent = sanitizeEventData(event)
        trackEvent(sanitizedEvent)
    }
}

private fun sanitizeEventData(event: BaseAnalyticsEvent): BaseAnalyticsEvent {
    // Remove or hash sensitive data
    val sanitizedMap = event.toMap().filterKeys { key ->
        key !in sensitiveDataKeys
    }
    
    return event // Return sanitised version
}
```