Skip to main content
Supported on: Android SDK 1.0.33+
Web entitlements enable apps that sell subscriptions via web checkout (e.g., Stripe) to unlock premium features in the native app in real-time. After calling identify(), the SDK listens for entitlement changes automatically — when a user purchases on the web, the app unlocks instantly without a restart.

How It Works

  1. User purchases a subscription on your website (via Stripe or another web payment provider).
  2. Your backend writes the entitlement to AppDNA.
  3. The SDK detects the change in real-time and updates the local cache.
  4. Your app reacts via the callback and unlocks premium features.
Web entitlements are separate from in-app purchase entitlements (Play Billing). They are designed for apps that also sell subscriptions through a web checkout flow.

Check Current Entitlement

After identify(), the current web entitlement is available synchronously from cache:
import java.util.Date

val entitlement = AppDNA.webEntitlement
if (entitlement != null && entitlement.isActive) {
    // User has an active web subscription
    unlockPremium()
    Log.d("WebEnt", "Plan: ${entitlement.planName ?: "unknown"}, Status: ${entitlement.status}")
    val periodEnd = entitlement.currentPeriodEnd // Long? — Unix seconds
    if (periodEnd != null) {
        Log.d("WebEnt", "Renews: ${Date(periodEnd * 1000L)}")
    }
}

Listen for Changes

Register a callback to react in real-time when the entitlement status changes:
AppDNA.onWebEntitlementChanged { entitlement ->
    if (entitlement?.isActive == true) {
        unlockPremium()
    } else {
        lockPremium()
    }
}
This fires immediately when:
  • A new web subscription is purchased
  • A subscription renews
  • A subscription expires or is canceled
  • A subscription enters a grace period

WebEntitlement

PropertyTypeDescription
isActiveBooleanWhether the subscription is currently active
planNameString?Name of the subscription plan
priceIdString?Stripe price identifier
statusStringCurrent status (see below)
currentPeriodEndLong?End of the current billing period (Unix timestamp, seconds)
intervalString?Billing interval (e.g., "month", "year")
trialEndLong?Trial expiration (Unix timestamp, seconds), if in a trial

Entitlement Statuses

StatusDescription
activeSubscription is active and paid
trialingUser is in a free trial period
past_duePayment failed, in grace period
canceledSubscription is canceled (access may continue until period ends)

Access

Web entitlements are accessed as a top-level property on AppDNA:
val webEntitlement = AppDNA.webEntitlement

Auto-Tracked Events

EventTrigger
web_entitlement_activatedWeb subscription becomes active
web_entitlement_expiredWeb subscription expires or is canceled

Full Example

import ai.appdna.sdk.AppDNA
import ai.appdna.sdk.webentitlements.WebEntitlement
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class PremiumManager(
    private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main),
) {

    fun setup() {
        // Listen for web entitlement changes
        AppDNA.onWebEntitlementChanged { entitlement ->
            updateAccessState(entitlement)
        }
    }

    fun checkAccessOnLaunch() {
        scope.launch {
            // Check in-app purchase entitlements
            val hasIAP = AppDNA.billing.hasActiveSubscription()
            if (hasIAP) {
                unlockPremium()
                return@launch
            }

            // Check web entitlement
            val web = AppDNA.webEntitlement
            if (web != null && web.isActive) {
                unlockPremium()
                return@launch
            }

            // No active subscription from either source
            lockPremium()
        }
    }

    private fun updateAccessState(entitlement: WebEntitlement?) {
        if (entitlement?.isActive == true) {
            unlockPremium()
        } else {
            // Re-check IAP entitlements before locking
            scope.launch {
                val hasIAP = AppDNA.billing.hasActiveSubscription()
                if (!hasIAP) {
                    lockPremium()
                }
            }
        }
    }

    private fun unlockPremium() {
        // Enable premium features
    }

    private fun lockPremium() {
        // Disable premium features
    }
}
Web entitlements require Stripe (or compatible payment provider) integration configured in the Console under Settings > Billing > Web Payments. The real-time listener activates automatically after identify() is called.