> ## Documentation Index
> Fetch the complete documentation index at: https://primer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Track payment in analytics

> Send payment events to your analytics platform.

Track payment success and failure events in your analytics platform (Google Analytics, Segment, etc.).

## Recipe

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    document.addEventListener('primer:payment-success', (event) => {
      const { paymentSummary, paymentMethodType } = event.detail;

      analytics.track('Payment Completed', {
        paymentId: paymentSummary.id,
        orderId: paymentSummary.orderId,
        method: paymentMethodType,
        last4: paymentSummary.paymentMethodData?.last4Digits,
      });
    });

    document.addEventListener('primer:payment-failure', (event) => {
      const { error, paymentMethodType } = event.detail;

      analytics.track('Payment Failed', {
        errorCode: error.code,
        method: paymentMethodType,
        diagnosticsId: error.diagnosticsId,
      });
    });
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    PrimerCheckoutSheet(
        checkout = checkout,
        onEvent = { event ->
            when (event) {
                is PrimerCheckoutEvent.Success -> {
                    val payment = event.checkoutData.payment
                    trackPaymentSuccess(payment.id, payment.orderId)
                }
                is PrimerCheckoutEvent.Failure -> {
                    val error = event.error
                    trackPaymentFailure(error.errorCode, error.diagnosticsId)
                }
            }
        },
    )
    ```
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    PrimerCheckout(
      clientToken: clientToken,
      scope: { checkoutScope in
        Task {
          for await state in checkoutScope.state {
            switch state {
            case .success(let result):
              Analytics.track("payment_success", properties: [
                "payment_id": result.payment?.id ?? ""
              ])
            case .failure(let error):
              Analytics.track("payment_failure", properties: [
                "error_id": error.errorId
              ])
            default:
              break
            }
          }
        }
      }
    )
    ```
  </Tab>
</Tabs>

## How it works

<Tabs>
  <Tab title="Web">
    1. Listen for `primer:payment-success` and `primer:payment-failure` DOM events
    2. Extract relevant data from `event.detail`
    3. Send to your analytics platform with meaningful event names and properties
  </Tab>

  <Tab title="Android">
    1. Use the `onEvent` callback on `PrimerCheckoutSheet` or `PrimerCheckoutHost`
    2. Map `PrimerCheckoutEvent` types to analytics events
    3. Extract relevant data from each event and send to your analytics platform

    | Checkout Event | Analytics Event      | Key Properties                 |
    | -------------- | -------------------- | ------------------------------ |
    | `Success`      | `purchase_completed` | `payment_id`, `order_id`       |
    | `Failure`      | `purchase_failed`    | `error_code`, `diagnostics_id` |
  </Tab>

  <Tab title="iOS">
    1. Use the `scope` closure to observe `checkoutScope.state` via `for await`
    2. Map `PrimerCheckoutState` cases to analytics events
    3. Extract relevant data from each state and send to your analytics platform

    | Checkout State             | Analytics Event      | Key Properties       |
    | -------------------------- | -------------------- | -------------------- |
    | `.success(result)`         | `payment_success`    | `payment_id`         |
    | `.failure(error)`          | `payment_failure`    | `error_id`           |
    | `.ready(amount, currency)` | `checkout_ready`     | `amount`, `currency` |
    | `.dismissed`               | `checkout_dismissed` | —                    |
  </Tab>
</Tabs>

## Variations

### Google Analytics 4 / Firebase Analytics

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    document.addEventListener('primer:payment-success', (event) => {
      const { paymentSummary, paymentMethodType } = event.detail;

      gtag('event', 'purchase', {
        transaction_id: paymentSummary.orderId,
        value: paymentSummary.amount / 100, // Convert from cents
        currency: paymentSummary.currencyCode,
        payment_type: paymentMethodType,
      });
    });
    ```
  </Tab>

  <Tab title="Android">
    Add the Firebase Analytics dependency:

    ```kotlin theme={"dark"}
    // build.gradle.kts
    implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
    implementation("com.google.firebase:firebase-analytics")
    ```

    Create an analytics tracker:

    ```kotlin theme={"dark"}
    class CheckoutAnalytics(
        private val firebaseAnalytics: FirebaseAnalytics,
    ) {
        fun trackPaymentSuccess(paymentId: String, orderId: String?) {
            firebaseAnalytics.logEvent("purchase_completed") {
                param("payment_id", paymentId)
                param("order_id", orderId.orEmpty())
            }
        }

        fun trackPaymentFailure(errorCode: String?, diagnosticsId: String) {
            firebaseAnalytics.logEvent("purchase_failed") {
                param("error_code", errorCode.orEmpty())
                param("diagnostics_id", diagnosticsId)
            }
        }

        fun trackPaymentMethodSelected(methodType: String) {
            firebaseAnalytics.logEvent("payment_method_selected") {
                param("payment_method_type", methodType)
            }
        }
    }
    ```

    Wire it into your checkout:

    ```kotlin theme={"dark"}
    @Composable
    fun CheckoutScreen(
        clientToken: String,
        analytics: CheckoutAnalytics,
    ) {
        val checkout = rememberPrimerCheckoutController(clientToken)
        val state by checkout.state.collectAsStateWithLifecycle()

        when (state) {
            is PrimerCheckoutState.Loading -> CircularProgressIndicator()
            is PrimerCheckoutState.Ready -> {
                PrimerCheckoutSheet(
                    checkout = checkout,
                    onEvent = { event ->
                        when (event) {
                            is PrimerCheckoutEvent.Success -> {
                                val payment = event.checkoutData.payment
                                analytics.trackPaymentSuccess(payment.id, payment.orderId)
                            }
                            is PrimerCheckoutEvent.Failure -> {
                                analytics.trackPaymentFailure(
                                    event.error.errorCode,
                                    event.error.diagnosticsId,
                                )
                            }
                        }
                    },
                )
            }
        }
    }
    ```
  </Tab>

  <Tab title="iOS">
    Add the Firebase Analytics dependency via SPM or CocoaPods, then create a tracker:

    ```swift theme={"dark"}
    class CheckoutAnalytics {
      let firebaseAnalytics: Analytics.Type = Analytics.self

      func trackState(_ state: PrimerCheckoutState) {
        switch state {
        case .ready(let totalAmount, let currencyCode):
          firebaseAnalytics.logEvent("checkout_ready", parameters: [
            "amount": totalAmount,
            "currency": currencyCode
          ])
        case .success(let result):
          firebaseAnalytics.logEvent("purchase_completed", parameters: [
            "payment_id": result.payment?.id ?? ""
          ])
        case .failure(let error):
          firebaseAnalytics.logEvent("purchase_failed", parameters: [
            "error_id": error.errorId
          ])
        default:
          break
        }
      }
    }
    ```

    Wire it into your checkout:

    ```swift theme={"dark"}
    let analytics = CheckoutAnalytics()

    PrimerCheckout(
      clientToken: clientToken,
      scope: { checkoutScope in
        Task {
          for await state in checkoutScope.state {
            analytics.trackState(state)
          }
        }
      }
    )
    ```
  </Tab>
</Tabs>

### Segment / Reusable analytics wrapper

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    document.addEventListener('primer:payment-success', (event) => {
      const { paymentSummary, paymentMethodType } = event.detail;

      analytics.track('Order Completed', {
        order_id: paymentSummary.orderId,
        total: paymentSummary.amount / 100,
        currency: paymentSummary.currencyCode,
        payment_method: paymentMethodType,
      });
    });
    ```
  </Tab>

  <Tab title="Android">
    For apps that use multiple analytics providers, create an interface that decouples checkout tracking from any specific SDK:

    ```kotlin theme={"dark"}
    interface CheckoutTracker {
        fun onPaymentSuccess(paymentId: String, orderId: String?)
        fun onPaymentFailure(errorCode: String?, diagnosticsId: String)
        fun onPaymentMethodSelected(methodType: String)
    }

    class CompositeCheckoutTracker(
        private val trackers: List<CheckoutTracker>,
    ) : CheckoutTracker {
        override fun onPaymentSuccess(paymentId: String, orderId: String?) {
            trackers.forEach { it.onPaymentSuccess(paymentId, orderId) }
        }

        override fun onPaymentFailure(errorCode: String?, diagnosticsId: String) {
            trackers.forEach { it.onPaymentFailure(errorCode, diagnosticsId) }
        }

        override fun onPaymentMethodSelected(methodType: String) {
            trackers.forEach { it.onPaymentMethodSelected(methodType) }
        }
    }
    ```

    Usage:

    ```kotlin theme={"dark"}
    fun handleEvent(event: PrimerCheckoutEvent, tracker: CheckoutTracker) {
        when (event) {
            is PrimerCheckoutEvent.Success -> {
                val payment = event.checkoutData.payment
                tracker.onPaymentSuccess(payment.id, payment.orderId)
            }
            is PrimerCheckoutEvent.Failure -> {
                tracker.onPaymentFailure(event.error.errorCode, event.error.diagnosticsId)
            }
        }
    }
    ```
  </Tab>

  <Tab title="iOS">
    For apps with multiple analytics providers, create a protocol that decouples checkout tracking:

    ```swift theme={"dark"}
    protocol CheckoutTracker {
      func onPaymentSuccess(paymentId: String)
      func onPaymentFailure(errorId: String)
    }

    class CompositeCheckoutTracker: CheckoutTracker {
      let trackers: [CheckoutTracker]

      init(trackers: [CheckoutTracker]) { self.trackers = trackers }

      func onPaymentSuccess(paymentId: String) {
        trackers.forEach { $0.onPaymentSuccess(paymentId: paymentId) }
      }

      func onPaymentFailure(errorId: String) {
        trackers.forEach { $0.onPaymentFailure(errorId: errorId) }
      }
    }
    ```

    Usage:

    ```swift theme={"dark"}
    func handleState(_ state: PrimerCheckoutState, tracker: CheckoutTracker) {
      switch state {
      case .success(let result):
        tracker.onPaymentSuccess(paymentId: result.payment?.id ?? "")
      case .failure(let error):
        tracker.onPaymentFailure(errorId: error.errorId)
      default:
        break
      }
    }
    ```
  </Tab>
</Tabs>

### Track payment method selection

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    document.addEventListener('primer:payment-start', (event) => {
      const { paymentMethodType } = event.detail;

      analytics.track('Payment Method Selected', {
        method: paymentMethodType,
      });
    });
    ```
  </Tab>

  <Tab title="Android">
    <Note>Payment method selection tracking is not available through `PrimerCheckoutEvent`. The SDK manages payment method selection internally within its UI components.</Note>
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    Task {
      for await state in checkoutScope.paymentMethodSelection.state {
        if let selected = state.selectedPaymentMethod {
          Analytics.track("payment_method_selected", properties: [
            "type": selected.type,
            "name": selected.name
          ])
        }
      }
    }
    ```
  </Tab>
</Tabs>

## See also

<CardGroup cols={2}>
  <Card title="Log errors for debugging" icon="bug" href="/checkout/primer-checkout/guides-and-recipes/log-errors-debugging">
    Capture and surface errors during development
  </Card>

  <Card title="Events guide" icon="bolt" href="/checkout/primer-checkout/configuration/events">
    Handle payment lifecycle events
  </Card>
</CardGroup>
