Events

Listen to SDK lifecycle events and register a global delegate.

Beta

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

Listening

sw.events is a native EventTarget with typed overloads, including AbortSignal for cleanup.

const ac = new AbortController();

sw.events.addEventListener(
  "subscriptionStatus_didChange",
  (event) => console.log(event.detail),
  { signal: ac.signal },
);

// Removes every listener registered with this signal.
ac.abort();

Handlers receive a typed CustomEvent. The payload is on event.detail.

In React, use useSuperwallEvent, which ties the subscription to the component lifecycle.

What is emitted

The event map covers the same lifecycle the mobile SDKs report:

AreaEvents
Sessionfirst_seen, app_open, app_close, app_launch, app_install, session_start, reset
Configurationconfig_refresh, config_fail, config_attributes
Identity and attributesidentity_alias, user_attributes, device_attributes, integration_attributes
SubscriptionsubscriptionStatus_didChange, customerInfo_didChange
Placementstrigger_fire, paywallPresentationRequest, confirm_all_assignments
Paywall lifecyclepaywall_open, paywall_close, paywall_page_view, paywall_decline
Transactionstransaction_start, transaction_complete, transaction_fail, transaction_abandon, transaction_timeout, transaction_restore, subscription_start, freeTrial_start, nonRecurringProduct_purchase
Restorerestore_start, restore_complete, restore_fail
Discountsdiscount_redeem_complete, discount_redeem_fail
Paywall loadingpaywallPreload_start, paywallPreload_complete, paywallResponseLoad_start, paywallResponseLoad_complete, paywallResponseLoad_notFound, paywallResponseLoad_fail, paywallProductsLoad_start, paywallProductsLoad_complete, paywallProductsLoad_fail
WebviewpaywallWebviewLoad_start, paywallWebviewLoad_complete, paywallWebviewLoad_fail, paywallWebviewLoad_timeout
Surveyssurvey_response, survey_close
Customcustom_placement, customPaywallAction
OtherdeepLink_open, page_view, enrichment_start, enrichment_complete, enrichment_fail

Some events are local-only and never reach Superwall's servers. Those live in LocalSuperwallEventMap. AllSuperwallEvents is the union of both.

Global delegate

The delegate receives global callbacks from the SDK. Register one at creation, or swap it later.

const sw = createSuperwall({
  apiKey: "pk_…",
  delegate: {
    onSubscriptionStatusChange: (from, to) => {
      console.log("subscription", from.status, "->", to.status);
    },
  },
});

sw.setDelegate(otherDelegate);
sw.setDelegate(null);

The delegate covers around a dozen callbacks: subscription and customer changes, the paywall present and dismiss pairs, URL and deep-link interception, link redemption, and onLog.

Per-call handlers passed to register fire alongside the delegate. The two are separate surfaces covering different callbacks. onSkip exists only on a per-call handler, and the delegate's methods cannot be supplied per call. Neither overrides the other, and there is no fallback between them.

Custom actions reach you two ways. onCustomPaywallAction(name) on the delegate receives the legacy custom action from the paywall. Actions defined as custom placements arrive as the custom_placement event, whose detail carries placementName, paywall_info, and params.

Forwarding to your analytics

The delegate has a catch-all for this. It receives every wire-bound event, fully typed.

const sw = createSuperwall({
  apiKey: "pk_…",
  delegate: {
    onEvent: (name, detail) => analytics.track(name, detail),
  },
});

To subscribe to a specific set instead, type the names so detail narrows:

import type { AllSuperwallEvents } from "@superwall/paywalls-js";

const forward = (type: keyof AllSuperwallEvents) =>
  sw.events.addEventListener(type, (e) => analytics.track(type, e.detail));

["paywall_open", "paywall_close", "subscriptionStatus_didChange"].forEach(forward);

How is this guide?

On this page