VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Groups
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL
React Native SDK
React Native quickstart
Display a paywall
Make and restore purchases
Check access
Identify users
Evaluate feature flags
Capture analytics
Groups
Track screens
Development mode
React Native SDK reference
Errors
Troubleshooting

React Native quickstart

Add Voidhash to an Expo or React Native app, sell a product and unlock a perk.

Install @voidhash/react-native, sell pro_monthly from your own screen, and unlock the premium perk with a test purchase. Development mode lets you finish before you connect the App Store or Google Play.

Before you start

You need:

  • An Expo app with development builds or a bare React Native app. Expo Go can't load the SDK's native code.
  • A Voidhash project with a perk premium and a subscription product pro_monthly that unlocks it. Give the product a billing duration; store mapping can wait. See Products and perks.
  • Both publishable keys from Settings → API keys: production (vh_pk_...) and test (vh_pk_test_...). See API keys.

Set up

Install the SDK

Install the SDK from the Voidhash package registry, with the exact peer versions it supports:

npm install @voidhash/react-native@https://pkg.voidha.sh/@voidhash/react-native/branch:main react-native-nitro-modules@0.37 effect@4.0.7

The SDK requires effect 4.0.7 exactly and react-native-nitro-modules 0.37.x. With pnpm, add blockExoticSubdeps: false to pnpm-workspace.yaml first: the SDK's native sources also install from the registry, and recent pnpm versions block that. To pin a build, see Install.

In an Expo app, register the config plugin. It adds the iOS pods when you prebuild.

app.json
{
  "expo": {
    "plugins": ["@voidhash/react-native"]
  }
}

In a bare React Native app, add the pods inside your app target in ios/Podfile, above use_native_modules!, then run npx pod-install:

ios/Podfile
voidhash_ios = File.dirname(`node --print "require.resolve('@voidhash/ios/package.json', { paths: [require.resolve('@voidhash/react-native/package.json')] })"`.strip)
pod "VoidhashCore", :path => voidhash_ios
pod "Voidhash", :path => voidhash_ios

Android needs no extra setup.

Configure the client

Create one client at module scope. Debug builds use the test key with development mode, so purchases go through a simulated store; release builds use the production key and the real store.

src/lib/voidhash.ts
import { createVoidhashClient } from "@voidhash/react-native";

export const voidhash = createVoidhashClient(__DEV__ ? "vh_pk_test_..." : "vh_pk_...", {
  // Simulated purchases in debug builds; release builds ignore it.
  dev: true,
});

Mount the provider once at the app root:

app/_layout.tsx
import { Stack } from "expo-router";

import { voidhash } from "../src/lib/voidhash";

export default function RootLayout() {
  return (
    <voidhash.Provider>
      <Stack />
    </voidhash.Provider>
  );
}

Show products and buy

Load the product and buy it with usePurchase:

app/upgrade.tsx
import { useState } from "react";
import { Button, Text, View } from "react-native";

import { voidhash } from "../src/lib/voidhash";

export default function UpgradeScreen() {
  const { data: products, isLoading } = voidhash.useProducts();
  const { purchase, isLoading: isPurchasing } = voidhash.usePurchase();
  const [message, setMessage] = useState<string>();
  const monthly = products.get("pro_monthly");

  if (isLoading) return null;
  if (!monthly) return <Text>Product unavailable</Text>;

  return (
    <View>
      <Button
        disabled={isPurchasing}
        title={`Subscribe for ${monthly.displayPrice}`}
        onPress={async () => {
          const result = await purchase(monthly);
          if (result.isErr()) setMessage(`Purchase failed: ${result.error.message}`);
          else if (result.value.status === "pending") setMessage("Waiting for approval.");
          else if (result.value.status === "deferred")
            setMessage("Purchase received. Unlocking soon.");
          else setMessage(undefined);
        }}
      />
      {message ? <Text>{message}</Text> : null}
    </View>
  );
}

purchase() never rejects; it resolves to a Result. A closed store sheet is cancelled, not an error. pending waits for approval, such as Ask to Buy, and deferred means the store charged but Voidhash hasn't confirmed yet. In both cases the SDK unlocks the perk once the purchase completes. See Make and restore purchases.

Check access

Gate premium content on the perk:

app/premium.tsx
import { Text } from "react-native";

import { voidhash } from "../src/lib/voidhash";

export default function PremiumScreen() {
  const { hasAccess, isLoading } = voidhash.useHasPerk("premium");

  if (isLoading) return null;
  return <Text>{hasAccess ? "Premium unlocked" : "Upgrade to unlock"}</Text>;
}

The hook re-renders when a purchase or restore grants the perk.

Test a purchase

Rebuild the app, because the SDK contains native code:

npx expo run:ios

Use npx expo run:android for Android, or a new EAS development build. Open the upgrade screen and tap Subscribe. In a debug build with the test key, a confirmation sheet replaces the store sheet and prices are fixed test prices. After you confirm, the premium screen shows Premium unlocked.

The purchase is a test purchase: it appears in Studio under Test in the environment switcher and never unlocks production. See Development mode.

Buy through the store (optional)

Once the simulated purchase works, test the real store sheet. Test accounts aren't charged.

  • App Store: connect the App Store (Help center) and map pro_monthly to your App Store product. Run a release build (npx expo run:ios --configuration Release) on a device signed in to a Sandbox Apple Account, or install it from TestFlight.
  • Google Play: connect Google Play (Help center) and map the product. Upload a release build to an internal test track and install it from Google Play as a license tester.

Release builds use the production key and the real store. The purchase appears in Studio under Sandbox. See Test purchases (Help center).

Next steps

  • See a complete sample app: products, restore, a paywall with a fallback screen, sign-in and a feature flag.
  • Identify signed-in users
  • Look up options, hooks and methods
  • Show a paywall designed in Studio

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousReact Native SDKNextDisplay a paywall

On this page

Before you startSet upInstall the SDKConfigure the clientShow products and buyCheck accessTest a purchaseBuy through the store (optional)Next steps