Skip to main content
Breaking Changes in v4:
  • presentUpsell() renamed to presentPaywall() with new signature
  • hideUpsell() renamed to hidePaywall()
  • hideAllUpsells() renamed to hideAllPaywalls()
  • dontShowIfAlreadyEntitled now defaults to true
  • Initialize parameters moved to Helium.identity and Helium.config namespaces
  • HeliumFallbackConfig removed - use Helium.config properties instead
What’s New:
  • Simplified initialize() - just pass context and API key
  • Automatic PlayStorePaywallDelegate setup if not explicitly configured
  • Cleaner namespaced APIs: Helium.identity, Helium.config
  • New PaywallPresentationConfig consolidates presentation options
  • New PaywallNotShownReason for handling paywall failures

Installation Update

Update your version constraint to 4.x:
// app/build.gradle.kts
dependencies {
    implementation("com.tryhelium.paywall:core:4.0.0")
}
Then sync your Gradle files.

Initialize Migration

The biggest change in v4 is the simplified initialization. Configuration that was previously passed to initialize() is now set on dedicated namespaces beforehand. v0 (many parameters):
val heliumPaywallDelegate = PlayStorePaywallDelegate(this)

Helium.initialize(
    context = this,
    apiKey = "...",
    heliumPaywallDelegate = heliumPaywallDelegate,
    customUserId = "user-123",
    customUserTraits = HeliumUserTraits(
        traits = mapOf("plan" to HeliumUserTraitsArgument.StringParam("free"))
    ),
    fallbackConfig = HeliumFallbackConfig.withFallbackBundle(
        fallbackBundleName = "fallback.json"
    )
)
v4 (simplified):
// Set up user identification
Helium.identity.userId = "user-123"
Helium.identity.setUserTraits(HeliumUserTraits(
    traits = mapOf("plan" to HeliumUserTraitsArgument.StringParam("free"))
))

// Set up configuration (if needed)
Helium.config.customFallbacksFileName = "fallback.json"
// Note: PlayStorePaywallDelegate is auto-created if not set
// Helium.config.heliumPaywallDelegate = PlayStorePaywallDelegate(this)

// Initialize with just context and API key
Helium.initialize(
    context = this,
    apiKey = "..."
)
Set identity and configuration values before calling initialize() for best results.
See the quickstart for more details.

presentUpsell to presentPaywall

The method has been renamed and the signature has changed significantly. Parameters are now consolidated into PaywallPresentationConfig.
Helium.presentUpsell(
    context = this,
    trigger = "premium",
    activityContext = activity,
    dontShowIfAlreadyEntitled = true,
    eventListener = myListener
)

Full Example with All Parameters

v4:
Helium.presentPaywall(
    trigger = "premium",
    config = PaywallPresentationConfig(
        fromActivityContext = activity,  // optional - SDK auto-tracks activities
        customPaywallTraits = HeliumUserTraits(...),
        dontShowIfAlreadyEntitled = true,  // defaults to true
        disableSystemBackNavigation = false,
        presentationStyle = HeliumPresentationStyle.SLIDE_UP,
        fullscreen = false
    ),
    onEntitled = {
        // User is now entitled (purchased or restored)
    },
    eventListener = myListener,
    onPaywallNotShown = { reason ->
        when (reason) {
            is PaywallNotShownReason.TargetingHoldout -> {
                // User is in holdout group
            }
            is PaywallNotShownReason.AlreadyEntitled -> {
                // User already has access
            }
            is PaywallNotShownReason.Error -> {
                // Handle error, check reason.unavailableReason
            }
        }
    }
)
dontShowIfAlreadyEntitled now defaults to true in v4. Set it to false explicitly if you want to show paywalls to entitled users.

Method Renames

v0v4
Helium.presentUpsell()Helium.presentPaywall()
Helium.hideUpsell()Helium.hidePaywall()
Helium.hideAllUpsells()Helium.hideAllPaywalls()

API Namespace Migration

Helium.identity

v0v4
initialize(customUserId: ...)Helium.identity.userId = ...
initialize(customUserTraits: ...)Helium.identity.setUserTraits(...)

Helium.config

v0v4
initialize(heliumPaywallDelegate: ...)Helium.config.heliumPaywallDelegate = ...
initialize(fallbackConfig: ...)See Fallback Changes below

Fallback Changes

v4 removes HeliumFallbackConfig and simplifies fallback configuration.

What’s Changed

  • No more HeliumFallbackConfig class - Use Helium.config properties directly
  • No more fallback views - Use fallback bundles exclusively
  • No more per-trigger config - Use global settings only
  • Automatic detection - SDK auto-detects helium-fallbacks.json in your assets

Migration

v0:
Helium.initialize(
    // ... other parameters
    fallbackConfig = HeliumFallbackConfig(
        fallbackBundleName = "my-fallback.json",
        fallbackView = myFallbackView,
        useLoadingState = true,
        loadingBudgetInMs = 5000,
        perTriggerLoadingConfig = mapOf(...)
    )
)
v4:
// Option 1: Automatic (recommended)
// Just add helium-fallbacks.json to your assets - SDK finds it automatically

// Option 2: Custom file name
Helium.config.customFallbacksFileName = "my-fallback.json"
Helium.config.defaultLoadingBudgetInMs = 5000
Helium.config.defaultLoadingView = myLoadingView  // optional

Helium.initialize(
    context = this,
    apiKey = "..."
)

Configuration Property Mapping

v0 (HeliumFallbackConfig)v4 (Helium.config)
fallbackBundleNamecustomFallbacksFileName
loadingBudgetInMsdefaultLoadingBudgetInMs
loadingViewdefaultLoadingView
useLoadingStateComputed from defaultLoadingBudgetInMs > 0
perTriggerLoadingConfigRemoved
fallbackPerTriggerRemoved
fallbackViewRemoved (use fallback bundles only)
Download your fallbacks from the Helium dashboard. See the Fallback Bundle Guide for details.

New Classes

PaywallPresentationConfig

Consolidates all paywall presentation options into a single data class:
data class PaywallPresentationConfig(
    val fromActivityContext: Activity? = null,
    val customPaywallTraits: HeliumUserTraits? = null,
    val dontShowIfAlreadyEntitled: Boolean = true,
    val disableSystemBackNavigation: Boolean = false,
    val presentationStyle: HeliumPresentationStyle = HeliumPresentationStyle.SLIDE_UP,
    val fullscreen: Boolean = false
) {
    companion object {
        val Default: PaywallPresentationConfig
    }
}

PaywallNotShownReason

Sealed class for handling paywall presentation failures:
sealed class PaywallNotShownReason {
    data object TargetingHoldout : PaywallNotShownReason()
    data object AlreadyEntitled : PaywallNotShownReason()
    data class Error(val unavailableReason: PaywallUnavailableReason?) : PaywallNotShownReason()
}

Quick Migration Checklist

Use this checklist to ensure you’ve covered all migration steps:
  • Update SDK to 4.x
  • Move user ID/traits to Helium.identity.* before initialize()
  • Move delegate to Helium.config.* before initialize() (or let SDK auto-create)
  • Replace presentUpsell() with presentPaywall() and update parameters
  • Replace hideUpsell() with hidePaywall()
  • Replace hideAllUpsells() with hideAllPaywalls()
  • Remove HeliumFallbackConfig usage, migrate to Helium.config.* properties
  • Set up fallback bundle (download from dashboard, add as helium-fallbacks.json)
  • Add onPaywallNotShown handler to presentPaywall() calls
  • Test paywall presentation and purchases

Need Help?