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
iOS
Android
React Native
Flutter
// 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
Available Events
Paywall and Purchase Events
Event Name | Description | Parameters |
---|
paywallOpen | Fires when a paywall is displayed | triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
viewType (String) - presented, triggered, or embedded
loadTimeTakenMS (Number, optional) - Loading time in milliseconds
loadingBudgetMS (Number, optional) - Loading budget in milliseconds
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
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
timestamp (Number) - When event occurred |
paywallDismissed | Fires when paywall is explicitly dismissed by user | triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
dismissAll (Boolean) - Whether entire paywall stack dismissed
timestamp (Number) - When event occurred |
paywallSkipped | Fires if paywall display is skipped due to targeting or workflow configuration | triggerName (String) - Associated trigger
timestamp (Number) - When event occurred |
paywallButtonPressed | Fires when a non-purchase button is pressed | buttonName (String) - Button identifier
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
timestamp (Number) - When event occurred |
paywallWebViewRendered | Fires when the paywall content has finished rendering | triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
webviewRenderTimeTakenMS (Number, optional) - Time to render in milliseconds
timestamp (Number) - When event occurred |
productSelected | Fires when a user selects a product on the paywall | productId (String) - Product identifier
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
timestamp (Number) - When event occurred |
purchasePressed | Fires when a purchase button is pressed in the paywall | productId (String) - Product being purchased
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
timestamp (Number) - When event occurred |
purchaseSucceeded | Fires when a purchase is successfully completed. | productId (String) - Product identifier
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
storeKitTransactionId (String, optional) - Transaction ID
storeKitOriginalTransactionId (String, optional) - Original transaction ID
skPostPurchaseTxnTimeMS (Number, optional) - Post-purchase transaction time
timestamp (Number) - When event occurred |
purchaseCancelled | Fires when the purchase process is cancelled by the user | productId (String) - Product that was cancelled
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
timestamp (Number) - When event occurred |
purchaseFailed | Fires when the purchase fails for any reason | productId (String) - Product that failed
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
error (String, optional) - Error message
timestamp (Number) - When event occurred |
purchaseRestored | Fires when a previous purchase is successfully restored | productId (String) - Restored product ID
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
timestamp (Number) - When event occurred |
purchaseRestoreFailed | Fires when an attempt to restore purchases fails | triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
timestamp (Number) - When event occurred |
purchasePending | Fires when purchase is in a pending state (e.g. waiting for parental approval) | productId (String) - Pending product
triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
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
imagesDownloadTimeTakenMS (Number, optional) - Images download time in milliseconds
fontsDownloadTimeTakenMS (Number, optional) - Fonts download time in milliseconds
bundleDownloadTimeMS (Number, optional) - Bundle download time in milliseconds
numAttempts (Number, optional) - Number of attempts made
timestamp (Number) - When event occurred |
paywallsDownloadError | Fires when paywalls download failed | error (String) - Error description
numAttempts (Number, optional) - Number of attempts made
timestamp (Number) - When event occurred |
paywallOpenFailed | Fires if a paywall fails to open and fallback fails to show | triggerName (String) - Associated trigger
paywallName (String) - Paywall name
isSecondTry (Boolean) - True if paywall is “second try” flow
error (String) - Error message describing failure
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 | type (String) - “userAllocated”
experimentInfo (Object) - Complete experiment allocation data (see below)
timestamp (Number) - When allocation occurred |
Accessing ExperimentInfo from Events
All paywall events (any event that implements PaywallContextEvent
) provide a getExperimentInfo()
method to access experiment allocation data on-demand:func onPaywallEvent(_ event: HeliumEvent) {
// Access experiment info from any paywall event
if let openEvent = event as? PaywallOpenEvent,
let experimentInfo = openEvent.getExperimentInfo() {
print("Variant: \(experimentInfo.chosenVariantDetails?.allocationIndex ?? 0)")
print("Experiment: \(experimentInfo.experimentName ?? "none")")
}
// Track which variant led to purchase
if let purchaseEvent = event as? PurchaseSucceededEvent,
let experimentInfo = purchaseEvent.getExperimentInfo() {
analytics.track("conversion", variant: experimentInfo.chosenVariantDetails?.allocationIndex)
}
}
You can also access experiment info directly by trigger:if let experimentInfo = Helium.shared.getExperimentInfoForTrigger("onboarding") {
print("Variant: \(experimentInfo.chosenVariantDetails?.allocationIndex ?? 0)")
}
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 | The trigger the user first sees that’s in this epxeriment. |
Experiment Details
Field | Type | Description |
---|
experimentName | String | 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 (“A/B/n test”) |
startDate | String | When the experiment started (ISO8601 string) |
endDate | String | When the experiment is scheduled to end (ISO8601 string) |
Targeting Details
Field | Type | Description |
---|
audienceId | String | Audience ID that user matched (for lookup in Helium) |
audienceData | String | Stringified JSON of the logged targeting logic. Useful for reference, though we recommend using the audience defined in the Helium dashboard. |
Variant Details
Field | Type | Description |
---|
chosenVariantDetails | Object | Details about the assigned variant |
chosenVariantDetails.allocationName | String | Variant name. This will be the paywall name for paywall A/B/n tests. More names to come soon! |
chosenVariantDetails.allocationId | String | Variant UUID |
chosenVariantDetails.allocationIndex | Integer | Variant number (1-indexed) |
Hash Details
These fields provide information about how the user was deterministically assigned to a variant.
Field | Type | Description |
---|
hashDetails | Object | Hash bucketing information |
hashDetails.hashedUserIdBucket1To100 | Integer | User’s hash bucket (1-100) - deterministic value for consistent variant assignment |
hashDetails.hashedUserId | String | The actual user ID that was hashed (either the userId or heliumPersistentId depending on hashMethod) |
hashDetails.hashMethod | String | Hash method used: - "HASH_USER_ID" : we’re hashing the user id passed into Helium.initialize() - "HASH_HELIUM_PERSISTENT_ID" : We’re hashing a persistent device ID (does NOT persist across re-installs) |
Logged Events
All Helium events (see the full list above) 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.
Event names and properties might show up as underscored/camelcase/JSON, depending on the platform.
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()
.