Tracking subscription state

Read and react to a user's subscription status and entitlements.

Beta

The Web SDK is in beta and its API may change between releases.

Subscription status

sw.subscriptionStatus is a reactive value with three shapes:

type SubscriptionStatus =
  | { status: "UNKNOWN" }
  | { status: "INACTIVE" }
  | { status: "ACTIVE"; entitlements: Entitlement[] };
const status = sw.subscriptionStatus.value;

if (status.status === "ACTIVE") {
  console.log("entitled to:", status.entitlements.map((e) => e.id));
}

UNKNOWN means the SDK has not resolved status yet. Do not treat it as INACTIVE.

Reacting to changes

Subscribe to the signal, or listen for the event.

const unsubscribe = sw.subscriptionStatus.subscribe((status) => {
  render(status);
});
const ac = new AbortController();

sw.events.addEventListener(
  "subscriptionStatus_didChange",
  () => render(sw.subscriptionStatus.value),
  { signal: ac.signal },
);

// later
ac.abort();

Subscribing fires the callback synchronously once with the current value before it returns, so you do not need a separate initial read to prime your UI.

Customer info

sw.customerInfo carries the fuller picture of the customer, or null until the first entitlements read lands. There is a snapshot method too, and a way to force a refresh:

sw.customerInfo.value;
await sw.purchases.getCustomerInfo();
await sw.purchases.refreshCustomerInfo();

Restoring

await sw.purchases.restore();

Setting status yourself

If you run your own checkout instead of Superwall's, push the resulting status in:

sw.purchases.setSubscriptionStatus({
  status: "ACTIVE",
  entitlements: [
    { id: "pro", type: "SERVICE_LEVEL", isActive: true, productIds: [] },
  ],
});

An Entitlement needs all four of id, type, isActive, and productIds. Note that @superwall/verify defines a different type also called Entitlement, whose field is identifier rather than id. The two are not interchangeable.

Setting a status equivalent to the current one is a no-op: no event fires and the delegate is not called.

See Purchases for the full picture on custom checkout.

Entitlements tokens

For server-side checks, the SDK exposes a Superwall-signed token describing the user's entitlements.

sw.entitlementsToken.value;              // reactive, null until issued
sw.purchases.getEntitlementsToken();     // snapshot

Forward it to your backend and verify it with @superwall/verify. A valid signature proves Superwall issued those entitlements, with no round trip per request. See Server-side gating.

The token is best-effort and will be null when the backend is not issuing one. It refreshes on roughly a ten-minute poll while the tab is in the foreground, and eagerly after checkout, after a restore, on identify with a different user, and on reset.

How is this guide?

On this page