Feature Gating
Control access to premium features with Superwall placements.
Beta
The KMP SDK is in beta and its API may change between releases.
The idea
Superwall.register lets you register a placement to access a feature that may or may not be paywalled later in time. Whether the user can access that feature without paying is a dashboard decision, not a code decision.
fun pressedWorkoutButton() {
// Remotely decide if a paywall is shown, and whether
// startWorkout() is a paid-only feature.
Superwall.register(placement = "StartWorkout") {
navigation.startWorkout()
}
}Given how cheap register is, we strongly recommend registering all core functionality. That is what lets you change what is gated without shipping an app update.
What happens when you register
When you register a placement:
- The SDK checks your campaigns for a matching audience filter.
- If one matches and the user is not in a holdout, the assigned paywall is presented.
- Once a user is assigned a paywall for an audience, they keep seeing that paywall until you remove it from the audience or reset assignments.
- After the paywall closes, the SDK looks at the paywall's Feature Gating value, set in the paywall editor under General → Feature Gating:
- Non Gated: the
featureclosure runs when the paywall is dismissed, whether they paid or not. - Gated: the
featureclosure runs only if the user is already paying, or begins paying.
- Non Gated: the
- If no paywall is configured for the placement, the feature runs immediately with no extra network calls.
Gating with entitlements directly
Sometimes you need to branch on subscription state rather than gate a call. Read it synchronously:
import com.superwall.sdk.kmp.models.entitlements.SubscriptionStatus
if (Superwall.subscriptionStatus.isActive) {
showProContent()
} else {
showFreeContent()
}Or collect the flow to keep UI in sync. See Tracking subscription state.
Prefer register with a feature closure over hand-rolled if checks where you can. The closure
keeps the decision on the dashboard; an if statement hard-codes it into the build.
Inspecting entitlements
Superwall.entitlements is an immutable snapshot:
val entitlements = Superwall.entitlements
entitlements.active // Set<Entitlement>
entitlements.inactive // Set<Entitlement>
entitlements.all // Set<Entitlement>
entitlements.web // Set<Entitlement>, granted via web checkoutEach Entitlement carries its id, productIds, store, expiry and renewal dates, and whether it is a lifetime purchase.
To resolve entitlements for specific products, use getEntitlementsByProductIds, which asks the native SDK on both platforms:
val granted = Superwall.getEntitlementsByProductIds(setOf("pro_monthly", "pro_annual"))Previewing the outcome
To adjust UI before a placement fires (hiding an upgrade button for users who would never see a paywall, for example), ask what registering would do:
val result = Superwall.getPresentationResult(placement = "StartWorkout")This presents nothing. It just tells you what would happen.
Next, track subscription state.
How is this guide?