React Native quickstart
Add Voidhash to an Expo or React Native app and show your first paywall.
This guide adds Voidhash to an existing Expo or React Native app. By the end you will have the SDK installed, a paywall on screen, and an access check that gates a premium feature.
Install the SDK
Install the SDK package and its native peers.
npm install @voidhash/react-native react-native-nitro-modules effectThe SDK requires react-native-nitro-modules 0.35.x (peer range ^0.35.5). In an Expo project,
npx expo install react-native-nitro-modules picks the version that matches your Expo SDK. Every
Nitro-based module in the app must resolve to the same Nitro version.
On iOS, install pods after adding the packages.
npx pod-installConnect your project
Link the app directory to a Voidhash project with the interactive initializer. The CLI is not a dependency of the SDK, so run it directly from your app's root.
npx voidhash-cli initpnpm dlx voidhash-cli init works the same way. Install the CLI with --save-dev only if you want
the Metro integration. That integration runs types generate --watch alongside the dev server and
needs the binary on PATH. See the CLI reference.
The command signs you in, connects the directory to a Voidhash project, and creates three files:
voidhash.config.tswith your team and project slugs.src/lib/voidhash.tswith the project's publishable key.voidhash.gen.d.tswith typed product, perk, and paywall-location slugs.
It does not change your dependencies or create a local product schema. Products and paywall locations are managed in Studio.
Add a deep-link scheme
Give the SDK a URL scheme so purchase callbacks can return to your app. Expo projects set it in
app.json.
{
"expo": {
"scheme": "myapp"
}
}In a bare React Native app, pass the same value when you create the client.
import { createVoidhashClient } from "@voidhash/react-native";
export const voidhash = createVoidhashClient("vh_pk_...", {
scheme: "myapp",
});Expo Router treats incoming links as routes. If you use Expo Router, add a native intent handler so callback links do not become routes.
import { expoRouterWithVoidhashCallback } from "@voidhash/react-native";
export function redirectSystemPath(options: { path: string; initial: boolean }) {
return expoRouterWithVoidhashCallback(options);
}Configure one test offer in Studio
Set up the smallest catalog that can show a paywall and grant access.
- Create a perk such as
premium. - Create a product, choose its billing duration, and attach the perk.
- Create a paywall that includes the product, then publish it.
- Create a paywall location such as
onboardingand assign the published paywall.
You do not need a store connection for this first run. The generated client enables development purchases in debug builds. Connect App Store or Google Play before you test a release build. See Development purchase mode for fixed prices, isolation, and lifecycle tools.
Regenerate the types whenever you change a product, perk, or location slug.
npx voidhash-cli types generateFor the model behind the catalog, see Products and perks and Paywalls.
Wrap your app
Mount the generated provider once at the app root.
import { Stack } from "expo-router";
import { voidhash } from "../src/lib/voidhash";
export default function RootLayout() {
return (
<voidhash.Provider>
<Stack />
</voidhash.Provider>
);
}The provider initializes the native store connection, loads the project schema, restores the current identity, and starts observing transactions.
Show the paywall
Resolve the paywall assigned to a location and call show().
import { Button } from "react-native";
import { voidhash } from "../src/lib/voidhash";
export default function UpgradeScreen() {
const paywall = voidhash.usePaywallByLocation("onboarding");
return (
<Button
title="View plans"
onPress={async () => {
const result = await paywall.show();
if (result.status !== "shown") {
// `not_assigned` is the expected case when the location has no
// published paywall. Fall back to your own screen instead of
// leaving the customer with nothing.
console.warn("Paywall not shown", result.status);
}
}}
/>
);
}show() resolves to a ShowPaywallResult that names why a paywall was not presented. See
Display a paywall for every status.
For a hosted paywall, the SDK handles product loading, purchase and restore actions, and dismissal for you.
Check access
Gate a feature on an active perk grant with useHasPerk.
const { hasAccess, isLoading } = voidhash.useHasPerk("premium");
if (isLoading) return null;
return hasAccess ? <PremiumContent /> : <UpgradePrompt />;The person snapshot refreshes after a successful purchase or restore, so React re-renders with the
new grant. See Check access for offline behavior and the
imperative client.hasPerk().
Run the app
The SDK contains native modules, so rebuild the app after installing it.
npx expo run:iosUse npx expo run:android for Android. If you use EAS, create a new development build instead.