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 SDK

Install @voidhash/react-native, set up its native code and create the client.

@voidhash/react-native adds paywalls, purchases, perks, feature flags and analytics to Expo development builds and bare React Native apps on iOS and Android. It runs on the same native core as the Swift and Kotlin SDKs, so purchases, caching and queues behave the same on every platform. Start with the quickstart. Options, hooks and methods are in the React Native SDK reference.

Install

@voidhash/react-native installs from the Voidhash package registry, pkg.voidha.sh. branch:main names the newest build:

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

With pnpm, add blockExoticSubdeps: false to pnpm-workspace.yaml before you install. The SDK's native sources, @voidhash/ios and @voidhash/android, also install from the registry, and recent pnpm versions block dependencies that install from a URL.

To pin a build, install from https://pkg.voidha.sh/@voidhash/react-native/<hash>, using the short commit hash at the end of the installed version, such as 83f7412 in 0.0.1-alpha.1-g83f7412.

Alpha

The SDK is an alpha release and isn't on npm yet: npm install @voidhash/react-native installs an older preview that doesn't match these docs. Builds are kept for three weeks, so pin a recent one and update regularly. See Versions and releases.

Then set up the native code as in Native setup, and rebuild the app.

Compatibility

RequirementVersion
iOS15 or later
AndroidminSdkVersion 23, compileSdkVersion 35 or later
React NativeVerified on 0.83, developed against 0.81
Expo SDKVerified on 55, developed against 54. Optional for bare apps.
effectExactly 4.0.7 (peer dependency)
react-native-nitro-modules0.37.x, ^0.37.1 (peer dependency)
Google Play Billing Library9, added by the SDK
react-native-iap, if used16.6.2 or later

react and react-native are peer dependencies. expo, expo-router and @react-navigation/native are optional peers used only by the config plugin and the screen-tracking integrations.

One Nitro version per app

Every Nitro-based module in the app shares one native runtime. Mixing Nitro minors across modules causes native build or load failures that don't point at Voidhash. Upgrade them together.

On Android, Gradle resolves one Billing Library version for the whole app. A billing library in your app that still calls APIs removed in Billing 8 fails at runtime, so upgrade it before you add the SDK.

The package ships native code. Changing its version needs a new native build: an over-the-air update can't deliver it, and must not roll an app back to an earlier SDK version. A JavaScript bundle running on a binary without the SDK's native modules, such as Expo Go, still loads, but init() fails with FAILED_TO_INITIALIZE_VOIDHASH_CLIENT.

Native setup

SetupExpoBare React Native
iOS pods VoidhashCore, VoidhashConfig plugin @voidhash/react-nativePodfile lines, see the quickstart
Paywall rendererBuilt from source, then plugin option { "renderer": true }Built from source, then the VoidhashUI pod and Voidhash_renderer=true in android/gradle.properties
AndroidNothing elseNothing else

The renderer is off by default, so apps that don't show paywalls don't ship it. Without it, presentFlow() fails with FLOW_RENDERER_MISSING. The published packages don't include it yet; see Add the paywall renderer. After changing plugin options, run npx expo prebuild and rebuild.

On Android, the SDK adds a background job service and the RECEIVE_BOOT_COMPLETED permission to your manifest; see unacknowledged purchases.

Create the client

Create one client at module scope and keep it for the life of the app:

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

export const voidhash = createVoidhashClient(__DEV__ ? "vh_pk_test_..." : "vh_pk_...", {
  dev: true,
});

Release builds, including TestFlight and Play test tracks, use the production key; debug builds use the test key. See API keys and Environments. Never ship a secret key.

A second client for the same key and base URL replaces the first when it initializes; development builds warn about it. Clients for different keys or base URLs run side by side on iOS. Android runs one client per process: a client that initializes there ends the one that was running, so call end() on one before you start another.

Then mount <voidhash.Provider> above your app. It starts the client and gives hooks such as voidhash.useHasPerk their data. See Client options and Provider.

Generated slug types

voidhash types generate writes voidhash.gen.d.ts, which types product, perk and location slugs for the SDK. Without it, slugs are plain strings and everything else works the same. The CLI isn't published to a package registry yet; Install the CLI explains how to build it. Run it after you change slugs in Studio, or regenerate on the fly with the Metro plugin:

metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { withVoidhash } = require("@voidhash/react-native/metro");

module.exports = withVoidhash(getDefaultConfig(__dirname));

While the Metro dev server runs, it runs voidhash-cli types generate --watch, polling every 5,000 ms. Bundling commands such as expo export start nothing. The binary must be on PATH, or set cliBinary to the built CLI; without it Metro logs a warning and keeps running.

OptionDefaultDescription
pollIntervalMs5000How often to check for schema changes.
cliBinaryvoidhash-cliPath to the CLI binary.
extraArgs[]Extra arguments after types generate --watch.

Data collection

Use this table for the App Store privacy details and the Google Play Data safety form.

DataWhenUsed for
Device IDAlways: an anonymous ID per installApp functionality, analytics
User IDWhen you call identify()App functionality, analytics
Email address and nameWhen you pass them to identify() or as attributesApp functionality
Purchase historyAlways: the store transactions the SDK observesApp functionality, analytics
Product interactionWith analytics consent: events, lifecycle events, screensAnalytics
Advertising dataWith analytics consent, unless installAttribution is off: the campaign, ad and click IDs behind the installAnalytics
Crash dataWith analytics consent: that the app crashed, and in which versionAnalytics
Coarse locationWith analytics consent: city-level, derived from the request addressAnalytics

Requests also carry the device model, OS version, app version and locale. Data is linked to the person. The SDK doesn't read advertising identifiers or share data with other companies for tracking.

Next steps

  • Quickstart
  • React Native SDK reference
  • Display a paywall
  • Errors
  • Troubleshooting

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

PreviousAd attribution in your appNextReact Native quickstart

On this page

InstallCompatibilityNative setupCreate the clientGenerated slug typesData collectionNext steps