> ## Documentation Index
> Fetch the complete documentation index at: https://helium-mintlify-android-docs-bump-version-0-0-6-19565.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Helium Events

> Reference for the full list of helium events

## Overview

Helium emits paywall and lifecycle events related to paywalls, purchasing, configuration, and experimentation.

This page acts as a reference to what events are available in Helium, and when each one is fired. Visit each SDK's quickstart page to see how to listen for and handle events.

## Event Types

<Tabs>
  <Tab title="iOS">
    ```swift
    // Base protocol for all events
    protocol HeliumEvent {
        var eventName: String { get }
        var timestamp: Date { get }
        func toDictionary() -> [String: Any]
    }

    // Events with paywall context
    protocol PaywallContextEvent: HeliumEvent {
        var triggerName: String { get }
        var paywallName: String { get }
        var isSecondTry: Bool { get }
    }

    // Product-related events
    protocol ProductEvent: PaywallContextEvent {
        var productId: String { get }
    }

    // All Event Types:
    // Lifecycle: PaywallOpenEvent, PaywallCloseEvent, PaywallDismissedEvent,
    //            PaywallSkippedEvent, PaywallButtonPressedEvent
    // Purchase:  ProductSelectedEvent, PurchasePressedEvent, PurchaseSucceededEvent,
    //            PurchaseCancelledEvent, PurchaseFailedEvent, PurchaseRestoredEvent,
    //            PurchaseRestoreFailedEvent, PurchasePendingEvent
    // System:    InitializeStartEvent, PaywallsDownloadSuccessEvent,
    //            PaywallsDownloadErrorEvent, PaywallWebViewRenderedEvent
    // Experiment: UserAllocatedEvent
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin
    // Base sealed class for all events
    sealed class HeliumEvent(
        open val timestamp: Long
    )

    // Events with paywall context
    sealed class PaywallContextEvent(
        override val timestamp: Long,
        open val triggerName: String,
        open val paywallName: String,
        open val isSecondTry: Boolean,
    ) : HeliumEvent(timestamp)

    // Product-related events
    sealed class ProductEvent(
        override val timestamp: Long,
        override val triggerName: String,
        override val paywallName: String,
        override val isSecondTry: Boolean,
        open val productId: String,
    ) : PaywallContextEvent(timestamp, triggerName, paywallName, isSecondTry)

    // All Event Classes:
    // Lifecycle: PaywallOpen, PaywallClose, PaywallDismissed, PaywallOpenFailed,
    //            PaywallSkipped, PaywallButtonPressed
    // Purchase:  ProductSelected, PurchasedPressed, PurchaseSucceeded, PurchaseCancelled,
    //            PurchaseFailed, PurchaseRestored, PurchaseRestoreFailed, PurchasePending
    // System:    InitializeStart, InitializeCalled, PaywallsDownloadSuccess,
    //            PaywallsDownloadError, PaywallWebViewRendered
    ```
  </Tab>

  <Tab title="React Native">
    ```typescript
    export type HeliumPaywallEvent = {
      type: 'paywallOpen' | 'paywallClose' | 'paywallDismissed' |
        'paywallOpenFailed' | 'paywallSkipped' | 'paywallButtonPressed' |
        'productSelected' | 'purchasePressed' | 'purchaseSucceeded' |
        'purchaseCancelled' | 'purchaseFailed' | 'purchaseRestored' |
        'purchaseRestoreFailed' | 'purchasePending' | 'initializeStart' |
        'paywallsDownloadSuccess' | 'paywallsDownloadError' | 
        'paywallWebViewRendered' | 'userAllocated';
      triggerName?: string;
      paywallName?: string;
      productId?: string;
      buttonName?: string;
      configId?: string;
      numAttempts?: number;
      downloadTimeTakenMS?: number;
      webviewRenderTimeTakenMS?: number;
      imagesDownloadTimeTakenMS?: number;
      fontsDownloadTimeTakenMS?: number;
      bundleDownloadTimeMS?: number;
      dismissAll?: boolean;
      isSecondTry?: boolean;
      error?: string;
      experimentInfo?: ExperimentInfo;
      timestamp?: number;
    }
    ```
  </Tab>

  <Tab title="Flutter">
    ```dart
    // Base event structure
    abstract class HeliumEvent {
      String get eventName;
      DateTime get timestamp;
      Map<String, dynamic> toMap();
    }

    // Events with paywall context
    abstract class PaywallContextEvent extends HeliumEvent {
      String get triggerName;
      String get paywallName;
      bool get isSecondTry;
    }

    // Product-related events
    abstract class ProductEvent extends PaywallContextEvent {
      String get productId;
    }

    // All Event Types:
    // Lifecycle: PaywallOpenEvent, PaywallCloseEvent, PaywallDismissedEvent,
    //            PaywallOpenFailedEvent, PaywallSkippedEvent, PaywallButtonPressedEvent
    // Purchase:  ProductSelectedEvent, PurchasePressedEvent, PurchaseSucceededEvent,
    //            PurchaseCancelledEvent, PurchaseFailedEvent, PurchaseRestoredEvent,
    //            PurchaseRestoreFailedEvent, PurchasePendingEvent
    // System:    InitializeStartEvent, PaywallsDownloadSuccessEvent,
    //            PaywallsDownloadErrorEvent, PaywallWebViewRenderedEvent
    ```
  </Tab>
</Tabs>

## Available Events

### Paywall and Purchase Events

| Event Name                 | Description                                                                                                             | Parameters                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **paywallOpen**            | Fires when a paywall is displayed                                                                                       | `triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`viewType` (String) - presented, triggered, or embedded<br />`loadTimeTakenMS` (Number, optional) - Loading time in milliseconds<br />`loadingBudgetMS` (Number, optional) - Loading budget in milliseconds<br />`timestamp` (Number) - When event occurred                                                                     |
| **paywallClose**           | Fires when a paywall is closed (removed from view hierarchy). **Fires on both explicit dismissal AND purchase success** | `triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                                                                      |
| **paywallDismissed**       | Fires when paywall is explicitly dismissed by user                                                                      | `triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`dismissAll` (Boolean) - Whether entire paywall stack dismissed<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                 |
| **paywallSkipped**         | Fires if paywall display is skipped due to targeting or workflow configuration                                          | `triggerName` (String) - Associated trigger<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                                                                                                                                                                                     |
| **paywallButtonPressed**   | Fires when a non-purchase button is pressed                                                                             | `buttonName` (String) - Button identifier<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                       |
| **paywallWebViewRendered** | Fires when the paywall content has finished rendering                                                                   | `triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`webviewRenderTimeTakenMS` (Number, optional) - Time to render in milliseconds<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                  |
| **productSelected**        | Fires when a user selects a product on the paywall                                                                      | `productId` (String) - Product identifier<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                       |
| **purchasePressed**        | Fires when a purchase button is pressed in the paywall                                                                  | `productId` (String) - Product being purchased<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                  |
| **purchaseSucceeded**      | Fires when a purchase is successfully completed.                                                                        | `productId` (String) - Product identifier<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`storeKitTransactionId` (String, optional) - Transaction ID<br />`storeKitOriginalTransactionId` (String, optional) - Original transaction ID<br />`skPostPurchaseTxnTimeMS` (Number, optional) - Post-purchase transaction time<br />`timestamp` (Number) - When event occurred |
| **purchaseCancelled**      | Fires when the purchase process is cancelled by the user                                                                | `productId` (String) - Product that was cancelled<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                               |
| **purchaseFailed**         | Fires when the purchase fails for any reason                                                                            | `productId` (String) - Product that failed<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`error` (String, optional) - Error message<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                      |
| **purchaseRestored**       | Fires when a previous purchase is successfully restored                                                                 | `productId` (String) - Restored product ID<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                      |
| **purchaseRestoreFailed**  | Fires when an attempt to restore purchases fails                                                                        | `triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                                                                      |
| **purchasePending**        | Fires when purchase is in a pending state (e.g. waiting for parental approval)                                          | `productId` (String) - Pending product<br />`triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                          |

### System Events

| Event Name                  | Description                                                        | Parameters                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| --------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **initializeStart**         | Fires when SDK initialization is started                           | `timestamp` (Number) - When event occurred                                                                                                                                                                                                                                                                                                                                                                                                                                |
| **paywallsDownloadSuccess** | Fires when Helium paywalls downloaded and initialized successfully | `downloadTimeTakenMS` (Number, optional) - Config download time in milliseconds<br />`imagesDownloadTimeTakenMS` (Number, optional) - Images download time in milliseconds<br />`fontsDownloadTimeTakenMS` (Number, optional) - Fonts download time in milliseconds<br />`bundleDownloadTimeMS` (Number, optional) - Bundle download time in milliseconds<br />`numAttempts` (Number, optional) - Number of attempts made<br />`timestamp` (Number) - When event occurred |
| **paywallsDownloadError**   | Fires when paywalls download failed                                | `error` (String) - Error description<br />`numAttempts` (Number, optional) - Number of attempts made<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                                                                                                                                      |
| **paywallOpenFailed**       | Fires if a paywall fails to open and fallback fails to show        | `triggerName` (String) - Associated trigger<br />`paywallName` (String) - Paywall name<br />`isSecondTry` (Boolean) - True if paywall is "second try" flow<br />`error` (String) - Error message describing failure<br />`timestamp` (Number) - When event occurred                                                                                                                                                                                                       |

### Experiment Events

| Event Name        | Description                                                              | Parameters                                                                                                                       |
| ----------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| **userAllocated** | Fires once per trigger when a user is allocated to an experiment variant | `experimentInfo` (Object) - Complete experiment allocation data (see below)<br />`timestamp` (Number) - When allocation occurred |

### ExperimentInfo Structure

The `experimentInfo` object in the `userAllocated` event contains experiment allocation data. This event fires once per session when a user is assigned to an experiment variant, which happens on the **first** trigger the user sees.

#### Core Fields

| Field     | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `trigger` | String | Name of the first trigger the user sees |

#### Experiment Details

| Field            | Type     | Description                                                                                      |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `experimentName` | String   | Human-readable name of the experiment                                                            |
| `experimentId`   | String   | Unique identifier for the experiment. You can look this experiment id up in the helium dashboard |
| `experimentType` | String   | Type of experiment (e.g., "A/B/n test", "MAB", "CMAB")                                           |
| `startDate`      | DateTime | When the experiment started                                                                      |
| `endDate`        | DateTime | When the experiment ends                                                                         |

#### Targeting Details

| Field                    | Type   | Description                                                                                                                                                                                      |
| ------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `audienceId`             | String | Audience ID that user matched (for lookup in Helium)                                                                                                                                             |
| `audienceDataDictionary` | Object | Parsed audience rules/criteria<br />- `operator`: How rules are combined ("AND", "OR")<br />- `isAllUsers`: Whether this targets all users<br />- `rules`: Array of targeting rules that matched |

#### Variant Details

| Field                                 | Type     | Description                                 |
| ------------------------------------- | -------- | ------------------------------------------- |
| `chosenVariantIndex`                  | Integer  | Variant number (1-indexed)                  |
| `chosenVariantDetails`                | Object   | Details about the assigned variant          |
| `chosenVariantDetails.allocationName` | String   | Variant/paywall name                        |
| `chosenVariantDetails.allocationId`   | String   | Variant UUID                                |
| `chosenVariantDetails.allocationTime` | DateTime | When the user was allocated to this variant |

#### Hash Details

These fields provide information about how the user was deterministically assigned to a variant.

| Field                      | Type    | Description                                                                                                                                                            |
| -------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hashedUserIdBucket1To100` | Integer | User's hash bucket (1-100) - deterministic value for consistent variant assignment                                                                                     |
| `hashedUserId`             | String  | The user ID that was hashed                                                                                                                                            |
| `hashMethod`               | String  | Hash method used:<br />- `"HASH_USER_ID"`: Standard user ID hashing<br />- `"HASH_HELIUM_PERSISTENT_ID"`: Persistent device ID hashing (more stable across reinstalls) |

## Logged Events

All Helium events (see the full list [above](#available-events)) get logged to your analytics backend automatically with automatic event forwarding, along with the parameters listed there. Each event's parameters will usually show up as event properties.

<Note>
  Event names and properties might show up as underscored/camelcase/JSON, depending on the platform.
</Note>

In addition, all lifecycle, paywall, downloadSuccess, and experimental events will include **contextual** and **custom** traits as event parameters:

### Contextual Traits

Helium automatically and securely collects device and software attributes:

* **Locale**: country, currency, currency symbol, language, preferred languages, time zone, decimal separator, uses metric system
* **Screen**: brightness, bounds, native bounds, scale, native scale, dark mode enabled
* **Device**: device identifier, orientation, system name, system version, device model, interface idiom, storage capacity
* **Application**: version, build number, app name, Helium SDK version, environment

### Custom Traits

Custom user traits included in the `Helium.initialize()` call also get sent as part of all events. If you pass custom user traits as part of a paywall presentation method call, these will **override** any custom traits of the same name passed in during `initialize()`.
