Skip to main content
Supported on: iOS SDK 1.0.61+ · Android SDK 1.0.33+ · Flutter SDK 1.0.3+
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 stream callback and unlocks premium features.
Web entitlements are separate from in-app purchase entitlements (StoreKit on iOS, Play Billing on Android). 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 via an async getter on AppDNA. The native SDK returns the cached value immediately when available:
final entitlement = await AppDNA.webEntitlement;
if (entitlement != null && entitlement.isActive) {
  // User has an active web subscription
  unlockPremium();
  print("Plan: ${entitlement.planName ?? "unknown"}, Status: ${entitlement.status}");
  if (entitlement.currentPeriodEnd != null) {
    print("Renews: ${entitlement.currentPeriodEnd}");
  }
}

Listen for Changes

AppDNA.onWebEntitlementChanged is a broadcast Stream<WebEntitlement?> backed by a Flutter EventChannel. Subscribe to react in real-time when the entitlement status changes:
final subscription = AppDNA.onWebEntitlementChanged.listen((entitlement) {
  if (entitlement?.isActive == true) {
    unlockPremium();
  } else {
    lockPremium();
  }
});

// Remember to cancel the subscription when no longer needed
// subscription.cancel();
The stream emits 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
isActiveboolWhether the subscription is currently active
planNameString?Name of the subscription plan
priceIdString?Stripe price identifier
statusStringCurrent status (see below)
currentPeriodEndDateTime?End of the current billing period
intervalString?Billing interval (e.g., "month", "year")
trialEndDateTime?Trial expiration date, 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 top-level members on AppDNA:
// Current value (one-shot Future)
final webEntitlement = await AppDNA.webEntitlement;

// Live stream of changes (broadcast Stream)
AppDNA.onWebEntitlementChanged.listen((entitlement) { /* ... */ });

Auto-Tracked Events

EventTrigger
web_entitlement_activatedWeb subscription becomes active
web_entitlement_expiredWeb subscription expires or is canceled

Full Example

import 'dart:async';
import 'package:appdna_sdk/appdna_sdk.dart';

class PremiumManager {
  StreamSubscription<WebEntitlement?>? _webSub;

  void setup() {
    // Listen for web entitlement changes
    _webSub = AppDNA.onWebEntitlementChanged.listen((entitlement) {
      _updateAccessState(entitlement);
    });
  }

  void dispose() {
    _webSub?.cancel();
  }

  Future<void> checkAccessOnLaunch() async {
    // Check in-app purchase entitlements
    final hasIAP = await AppDNA.billing.hasActiveSubscription();
    if (hasIAP) {
      unlockPremium();
      return;
    }

    // Check web entitlement
    final web = await AppDNA.webEntitlement;
    if (web != null && web.isActive) {
      unlockPremium();
      return;
    }

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

  Future<void> _updateAccessState(WebEntitlement? entitlement) async {
    if (entitlement?.isActive == true) {
      unlockPremium();
    } else {
      // Re-check IAP entitlements before locking
      final hasIAP = await AppDNA.billing.hasActiveSubscription();
      if (!hasIAP) {
        lockPremium();
      }
    }
  }

  void unlockPremium() {
    // Enable premium features
  }

  void 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.