Configure

Create a Superwall instance and understand what happens before it is ready.

Beta

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

Create an instance

createSuperwall returns an instance synchronously and starts configuring in the background.

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

const sw = createSuperwall({ apiKey: "pk_…" });

Do this once, as early as your app boots. Keep the returned instance around, or use the named exports and let the SDK hold it for you.

Wait for ready before presenting

register waits for identity to hydrate, but it does not wait for configuration. Called before config lands, it returns { type: "error" } carrying a PaywallNotAvailableError.

const sw = createSuperwall({ apiKey: "pk_…" });

await sw.ready;

const result = await sw.register({ placement: "checkout" });

Reads never block. sw.user.id.value and sw.subscriptionStatus.value return synchronously at any time. Before hydration lands they return defaults ("" and { status: "UNKNOWN" }). Persisted state replaces the defaults shortly after.

Treat UNKNOWN as unresolved, not as unsubscribed. A returning subscriber reads UNKNOWN until hydration completes, so branching on "not ACTIVE" at startup shows paying users an upsell.

Check configurationStatus, not ready, to detect failure. A failed config fetch is swallowed internally: sw.ready still resolves, and sw.configurationStatus becomes "failed".

await sw.ready;

if (sw.configurationStatus.value === "failed") {
  // Superwall could not configure. Paywalls will not present.
}

Options

const sw = createSuperwall({
  apiKey: "pk_…",
  options: {
    /* SuperwallOptions: logging, networking, paywall behavior */
  },
  delegate: myDelegate,
  storage: myStorageAdapter,
  purchaseController: myPurchaseController,
  identity: {
    appUserId: "user_123",
    aliasId: "$SuperwallAlias:…",
    vendorId: "…",
    vendorIdProvider: async () => "…",
  },
});
OptionPurpose
apiKeyYour pk_… publishable key. Required.
optionsTuning for logging, networking, and paywall behavior.
delegateGlobal callbacks for SDK-wide events. See Events.
storageCustom storage adapter. Defaults to localStorage plus cookies in the browser.
purchaseControllerTake over checkout. Omit to use the built-in Stripe flow. See Purchases.
identityPre-seed identity. Useful on the server or during SSR hydration.
surveyPresenterRenderer for post-paywall surveys. Omit and the SDK skips survey presentation.

identity.vendorIdProvider is where a fingerprinting library plugs in. The SDK does not bundle fingerprinting.

Named exports

Instead of threading the instance through your app, import the namespaces directly. The first createSuperwall call registers the default instance, and these bind to it.

import { createSuperwall, user, register, events } from "@superwall/paywalls-js";

createSuperwall({ apiKey: "pk_…" });

await user.identify("user_42");
const result = await register({ placement: "checkout" });

Importing only user lets bundlers drop the rest as dead code.

Multiple instances

Creating more than one instance is supported. Useful for tests, Storybook, and multi-tenant edge workers. The default instance is the first one created in the process, and it is the one the named exports target.

Next, present your first paywall.

How is this guide?

On this page