Examples
Complete, standalone example projects — each teaching exactly one idea, from a minimal paywall to trials, funnels, and Rive animations.
Every example is a complete, standalone framework project teaching exactly one idea. Styling is deliberately plain so the mechanism is the thing you read. When what you're building matches one, read it before writing code — each README.md explains the idea, and every example runs as-is.
Use an example
superwall create --example multi-page # scaffold it as a new project
superwall dev # open it in the studioAll examples are public at github.com/superwall/superwall/tree/main/examples — browse them there, or copy a directory anywhere for a working superwall dev.
Fundamentals
| Example | The one idea | Reach for it when |
|---|---|---|
minimal | One page, one product, purchase — a paywall is a React component, not a template | Starting anything |
product-selection | Selection state is ordinary React — the framework has no "selected plan" concept | Multiple plans, price rows |
minimal shows the canonical price guard (render the price only when it exists, with bare copy as the fallback). product-selection adds a typed plan union, haptics.selection() on choice vs haptics.light() on the CTA, a real radiogroup with aria-checked, store-formatted price and monthlyPrice side by side, and a designed unpriced state.
Navigation
| Example | The one idea |
|---|---|
multi-page | router.push/back, the page stack, and chrome in layout.tsx that reads router state |
transitions | All four built-ins plus a custom zoom — proof a transition is just CSS on two attributes |
onboarding-quiz | Answers decide where you land; the router carries no state (a plain module outside React does) |
onboarding-quiz's terminal page defends every read — a replayed page never crashes on a missing answer — and hardcodes step labels per page, because a branching flow's depth is not its step number.
Purchases
| Example | The one idea |
|---|---|
purchase-states | The two channels: what your purchase() call resolves vs what the SDK reports on its own |
trial-eligibility | Two paywalls in one, chosen by the store — every string forks and both states read as intentional |
abandonment-offer | purchase() resolving abandoned is a signal only this paywall can act on — a last-chance offer on a custom sheet transition |
trial-reminders | A local notification declared in config, scheduled by the SDK when the trial starts |
web-funnel | Selling on the web: steps as pages, then checkout: "sheet" — one config key, purchase() unchanged |
purchase-states is the only example showing the full haptic vocabulary (success() / error() keyed to outcomes). abandonment-offer holds the deepest CSS lesson of the set: the scrim behind its sheet reuses the framework's timing variables, so one number drives both the page dim and the backdrop — see Transitions.
The host
| Example | The one idea |
|---|---|
personalization | useVariables() — device, user, placement params, and guarding every read |
permissions | requestPermission (asks the OS) vs requestCallback (asks your app); a denial is an outcome, not an error |
Look and feel
| Example | The one idea |
|---|---|
custom-fonts | A typeface from a file in your project — relative-path @font-face, subset to latin |
with-tailwind | Tailwind v4 with zero framework config — and the dark: variant redefined onto the SDK's class |
with-motion | In-page animation gated on presentation, plus a price count-up gated on the value existing |
with-rive | Interactive vector animation — .riv as a hosted asset, the WASM engine bundled |
orientation | useDevice().orientation — landscape is a two-column reflow, not a shrunken portrait |
Localization
| Example | The one idea |
|---|---|
localization | Four locales by filename, shared + paywall-local catalogs, guarded {price} interpolation, no language picker on device |
Habits every example carries
These are the "treat it like a real paywall" conventions — carry them into anything you build:
- Haptics on every meaningful tap —
light()for navigation and CTAs,selection()for changing a choice,success()when a purchase lands (Styling & mobile design). - Never a loading state on the buy button — the store sheet is the feedback, and the SDK owns it (Purchases).
- Prices from
useProducts(), never hardcoded; example product identifiers are placeholders to repoint at your own (Products). - Every control reachable — icon-only buttons carry
aria-label, tap targets are at least 44px, primary actions sit full-width at the bottom. - Links through
openUrl, never an<a href>(Actions). - Light and dark via the
:root.darkclass, both always checked; safe areas with sensible minimums; responsive from 320px to tablet.
How is this guide?