Hooks Reference
Every hook the framework provides — signatures, what each returns, and the semantics that matter.
Everything a paywall reads or triggers comes through hooks. One concern each — there is deliberately no kitchen-sink hook.
import {
useProducts, usePurchase, useActions, useHaptics, useTranslation,
useTrialEligibility, useDevice, useUser, useVariables, useColorScheme,
useSuperwallEvent, useSuperwallSnapshot, useSuperwallSession,
type ProductReference,
} from "superwall/hooks";
import { useRouter, useIsFocused } from "superwall/navigation";useProducts()
const { products, getProduct } = useProducts();
const annual = getProduct("annual"); // typed reference — typos are compile errorsProducts, keyed by the reference declared in config.ts, each carrying store-owned variables (price, period, trialPeriodDays, …). A declared reference always exists, but its variables may not have arrived — guard every read and design the empty state. The full variable list and reading rules are in Products.
usePurchase()
const { purchase, prefetch, isPurchasing, transaction, failure } = usePurchase();
const result = await purchase("annual");
// { status: "completed" | "abandoned" | "failed" } — never throws for flow outcomesThe whole purchase flow — outcomes, the no-loading-state rule, web checkout, and prefetch — is in Purchases.
useActions()
const { close, restore, openUrl, requestPermission, requestCallback } = useActions();Also on the object: openExternalUrl, openDeepLink, customPlacement, requestStoreReview. Everything a paywall asks its host to do — Actions has the full table, the permission types, and the callback pattern.
useHaptics()
const haptics = useHaptics();
haptics.light(); // navigation, CTAs
haptics.selection(); // changing a choice
haptics.success(); // purchase landedAlso available: medium, heavy, warning, error. Fire one on every meaningful tap — iOS produces no feedback of its own inside a paywall. No-ops where haptics are unavailable, so call them unconditionally.
useTranslation()
const { t, locale, setLocale, locales } = useTranslation();
t("paywall.cta", { price });Localized copy from messages/<locale>.ts catalogs — the catalog system, fallback rules, and interpolation are in Localization.
useTrialEligibility()
const { eligible } = useTrialEligibility(); // boolean | undefined — the store decidesundefined until the SDK reports, so gate trial-only UI on eligible === true. Splits the paywall into eligible and ineligible versions — both must read as intentional. See Free trials.
useVariables()
const { device, user, params } = useVariables();Everything the app and SDK told this paywall about the presentation: the SDK-filled device record, user attributes your app set, and the placement's params. All three are host-filled — guard every read. The records, fields, and guarding doctrine are in Variables & personalization.
useUser()
const user = useUser();Shorthand for useVariables().user when the device and params records aren't needed.
useDevice()
const { orientation, platform, deviceModel } = useDevice();The same device record as useVariables().device, plus orientation ("portrait" | "landscape") — measured in the page, so it updates the moment the device turns. See Variables & personalization.
useColorScheme()
const scheme = useColorScheme(); // "light" | "dark"Rarely needed: the framework already keeps a dark/light class on <html> from what the device reports, so style with plain CSS (:root.dark { … }). Reach for the hook only when you need the scheme in JavaScript. Never use @media (prefers-color-scheme: dark) as the mechanism — see Styling & mobile design.
useSuperwallEvent(name, handler)
useSuperwallEvent("transaction_complete", () => haptics.success());Typed SDK events, subscribed for the component's lifetime; an inline arrow handler is fine. The event list and when each fires: Lifecycle & events. For anything a dedicated hook covers (products, trial, variables), use the hook — it cannot miss data that arrived before your component subscribed.
useSuperwallSnapshot()
const snapshot = useSuperwallSnapshot();
const opened = snapshot.paywall !== undefined;The whole runtime state as one subscribed object. Its most common use is gating entry animations on presentation — paywalls are preloaded hidden, and snapshot.paywall flips when the paywall is actually shown (Lifecycle & events). It also carries experiment (the A/B assignment), locale, and the current purchase and transaction state.
useSuperwallSession()
const session = useSuperwallSession();
session.setUserAttributes({ onboardingCompleted: "true" });The full session for advanced work — the few methods no hook surfaces (setUserAttributes, raw protocol messaging) and use outside React components. If you're reaching for it for products, purchases, actions, or events, use the dedicated hook instead.
useRouter()
import { useRouter } from "superwall/navigation";
const router = useRouter();
router.push("plans");
router.replace("terms");
router.back();
router.canGoBack();
router.dismiss(2);
router.dismissAll();
router.dismissTo("goals");
router.name; // current page
router.depth; // pages underneath (index = 0)The stack router for multi-page flows — expo-router's API, method for method. Page names autocomplete and reject typos via the generated superwall.d.ts. Pages & navigation covers the stack model, state between pages, and shared chrome.
useIsFocused()
import { useIsFocused } from "superwall/navigation";
const focused = useIsFocused();Whether this page is on top of the stack. Pages you navigate away from stay alive — a covered page can't be clicked or focused, and useIsFocused() tells it so, so it can pause video or timers. See Pages & navigation.
ProductReference
import { type ProductReference } from "superwall/hooks";
const [selected, setSelected] = React.useState<ProductReference>("annual");The union of product references declared in your config.ts — the type behind getProduct, purchase, and prefetch. Use it for selection state so an invalid reference is a compile error.
How is this guide?