Present your first paywall
Register a placement and show a paywall in the browser.
Beta
The Web SDK is in beta and its API may change between releases.
Register a placement
register is the primary entry point. It mirrors Superwall.shared.register(...) on iOS and Android. You give it a placement name; the SDK evaluates your campaign's audience rules and shows a paywall if the user matches one.
const result = await sw.register({ placement: "checkout" });The placement must exist in a campaign in your Superwall dashboard. If nothing matches, nothing is shown. That is not an error.
What you get back
type RegisterPlacementResult =
| { type: "presented"; info: PaywallInfo; result: PaywallResult }
| { type: "skipped"; reason: PaywallSkippedReason }
| { type: "error"; error: Error };Skipped reasons and errors surface in the return value rather than throwing.
const result = await sw.register({ placement: "checkout" });
if (result.type === "presented" && result.result.type === "purchased") {
console.log("Bought:", result.result.productId);
}Run code when the user is entitled
Pass a feature callback and the SDK runs it when the user should get access.
await sw.register({
placement: "checkout",
feature: () => unlockExportButton(),
});See Feature gating for exactly when it runs.
Per-call callbacks
handler gives you lifecycle callbacks scoped to this one call.
await sw.register({
placement: "checkout",
handler: {
onPresent: (info) => console.log("opened", info.identifier),
onDismiss: (info, result) => console.log("dismissed", result),
onSkip: (reason) => console.log("skipped", reason),
onError: (error) => console.error(error),
},
});Passing parameters
params are the values your campaign's audience rules filter on.
await sw.register({
placement: "checkout",
params: { plan: "team", seats: 12 },
});Overriding presentation
Three more optional arguments change how the paywall is shown for a single call:
| Argument | Effect |
|---|---|
overrides | Per-call presentation tweaks applied before the iframe mounts. Currently presentationStyle. |
paywall | Render your own UI instead of the default iframe. The SDK still runs the full pipeline and fires the same events. |
presenter | Replace the presenter entirely for this call. Highest precedence. |
Precedence is presenter > paywall > the default browser presenter. In React, useCustomPaywall wraps the paywall path.
Preloading
Paywalls load in an iframe. During configuration the SDK preloads up to six paywalls that have a URL, two at a time.
sw.placements.preloadAll() and preloadFor() currently do nothing and are being removed from
the API. Do not build on them.
One paywall at a time
Only one paywall can be on screen at once. Calling register while another is presented fails with PaywallAlreadyPresentedError. To close the current one yourself:
sw.dismiss();sw.isPaywallPresented is a reactive read of whether one is currently up. sw.activePaywall carries the presented paywall's info.
Next, identify your users.
How is this guide?