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
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
Track screens
Development mode
React Native SDK reference
Errors
Troubleshooting

React Native SDK reference

Client options, provider state, hooks, client methods, caching and diagnostics of @voidhash/react-native.

Everything createVoidhashClient accepts and the client exposes. To install the SDK, see React Native SDK.

Client options

OptionDefaultDescription
devfalseSimulated purchases in debug builds; ignored in release builds. See Development mode.
debugfalseLogs HTTP requests and responses, with sensitive values redacted.
enabledtruefalse makes the client inert. Fixed at construction. See Disabled clients.
readOnlyfalseObserver mode. See Observer mode.
distinctIdStored or new anonymous IDSeeds the identity on the first init() only. Usually omit it and call identify().
analyticsConsent"granted""denied" or "pending" stops analytics. See Analytics consent.
automaticLifecycleEventstrueCaptures $app_* events and $sign_out.
installAttributiontrueCredits installs to the ad behind them. See Install attribution.
metaAppIdnoneAndroid only: also asks Meta's apps about the install.
screenTracking{ enabled: true }Automatic $screen events. See Track screens.
flowCapabilities["links"]What paywalls may do beyond purchasing. See Flow capabilities.
preloadPlacements[]Location slugs whose paywalls download at launch.
onDiagnosticnoneReceives failures the SDK recovered from. See Diagnostics.
baseUrlhttps://api.voidhash.comAPI origin for self-hosted deployments.
ingestUrlOrigin of baseUrlAnalytics origin only.

baseUrl and ingestUrl must be absolute http:// or https:// URLs; blank counts as unset. For an invalid URL, development builds throw INVALID_ARGUMENT; release builds use the default origin and report INVALID_CONFIGURATION through onDiagnostic.

scheme, connectivity and unstable_nativeEngine are deprecated and have no effect. unstable_swallowErrors is deprecated; use onDiagnostic.

Disabled clients

With enabled: false the client never touches the store or the network. Methods resolve as no-ops and reads return their empty shape. Mount the provider either way, so hook order matches in flagged-off and flagged-on builds. To enable the SDK later, create a new client.

Observer mode

With readOnly: true the SDK records purchases that another billing SDK makes, but never starts, finishes or acknowledges them. purchase() and setPersonAttributesSync() return READ_ONLY_PURCHASE_NOT_ALLOWED; everything else works. Switch at runtime without a new client:

voidhash.client.setReadOnly(false); // Voidhash now owns purchases
voidhash.client.isReadOnly; // false

A purchase already in flight keeps the mode it started in. Report the other SDK's purchases with reportTransaction. See Observer mode for the migration plan.

Provider

Mount <voidhash.Provider> above your app. It initializes identity, the project schema, the person, the store connection and the transaction observer. With several React roots, mount a provider in each; they share one client, which stops when the last provider unmounts.

useVoidhash() returns the provider state:

FieldTypeDescription
status"initializing" | "ready" | "failed" | "disabled"Lifecycle state.
initErrorVoidhashError | nullSet only while status is failed.
retryInit() => voidRuns init() again. Does nothing unless status is failed.
isInitializedbooleanstatus === "ready".
clientVoidhashClientThe imperative client.

Initialization doesn't wait for the network: an offline cold start initializes from device state. It fails when the binary lacks the SDK's native modules, so handle failed:

const { status, initError, retryInit } = voidhash.useVoidhash();

if (status === "failed") return <RetryScreen error={initError} onRetry={retryInit} />;

On iOS, an app launched in the background before the first unlock after a reboot stays initializing until the device is unlocked. Events captured meanwhile are kept.

Hooks

Hooks are client properties, such as voidhash.useHasPerk. Data hooks report isLoading: true until the provider initializes and their first read answers, and false for a disabled or failed provider. error is null when there is none. After identify() or reset(), mounted hooks read again for the new person.

HookReturnsGuide
useHasPerk(perkSlug){ hasAccess, grant, isLoading, isStale, error, refetch }Check access
useCurrentPerson(){ data, error, isLoading, refetch }Check access
usePresentFlow(placement){ present, isPresenting }Display a paywall
useProducts(){ data: { get, toList, bySlug }, error, isLoading, refetch }Purchases
usePurchase(options?){ purchase, isLoading, error }Purchases
useFeatureFlags(keys?){ isEnabled, getVariant, data, error, isLoading, refetch }Feature flags
useVoidhash()Provider stateProvider

Client methods

voidhash.client exposes the same workflows outside React. Methods that can fail resolve to a Result and never reject; see Errors.

MethodDescription
hasPerk(slug, { forceFetch? })Checks one perk, with freshness.
getCurrentPerson({ forceFetch? })Returns { person, isStale, isExpired, reason }.
getProducts()Products by slug.
purchase(product, { offerId? })Buys a product, optionally an offer.
restorePurchases()Restores purchases for the current person.
syncPurchases()Scans the store and sends missing receipts without prompting.
reportTransaction(transaction, { isRestore? })Reports another SDK's purchase in observer mode.
presentFlow(placement) / dismissFlow()Presents or closes the paywall at a location.
getPaywallForLocation(slug)What is shown at a location, or null, without presenting it.
getFeatureFlags(keys?)Evaluates flags.
identify(userId, { email?, name? }) / identifySync(...)Identifies the person.
signOut() / reset()Starts a new anonymous identity.
getDistinctId()The current distinct ID.
setPersonAttributes(attrs) / setPersonAttributesSync(attrs)Sets person attributes.
setAdDataSharing(granted)Records consent to share purchases with ad platforms.
capture(name, props?) / screen(name, props?)Records an event or a screen.
trackPushOpened(data)Records an opened Voidhash notification.
setAnalyticsConsent(consent) / getAnalyticsConsent()Sets or reads analytics consent.
getSessionId()The current analytics session ID.
flush()Sends queued writes, receipts and events now.
resetCache()Clears the cached person; the next read fetches it.
setReadOnly(readOnly)Switches observer mode.
iosPresentCodeRedemptionSheet() / iosShowManageSubscriptions()Apple's offer-code and subscription sheets. iOS only.
init() / end()Starts or stops the client. The provider calls both for you.

end() flushes for at most about 2 seconds, saves what's still queued and stops every timer and listener; the queue is sent after the next init(). Events captured after end() are dropped.

Package entry points

ImportUse
@voidhash/react-nativeClient, provider, hooks, types, isAnonymousDistinctId
@voidhash/react-native/expo-routerScreenTracking, useExpoRouterScreenTracking
@voidhash/react-native/react-navigationuseScreenTracking
@voidhash/react-native/metrowithVoidhash for Metro
@voidhash/react-native/app.plugin.jsThe Expo config plugin

Caching and offline behavior

Reads answer from the device cache first and refresh in the background, so they don't fail offline.

DataFresh forKept for
Person and perks5 minutes2 days, then isExpired
Feature flags5 minutesUntil replaced
Paywall per location1 hour7 days

A stale read waits at most 500 ms for a refresh, then answers from cache. An uncached read waits for the request, about 10 seconds. The SDK refreshes at launch, on foreground and on reconnect (each at most once a minute), after purchases and restores, and on identity changes.

Events, person writes and store receipts are stored on the device and retried until Voidhash accepts them. Only the event queue is capped: 1,000 events, oldest dropped first. Receipts are never dropped.

Diagnostics

onDiagnostic reports problems the SDK recovered from, for logging and alerts:

import { createVoidhashClient } from "@voidhash/react-native";

createVoidhashClient("vh_pk_...", {
  onDiagnostic: (diagnostic) => {
    if (diagnostic.kind === "auth") reportToMonitoring(diagnostic);
  },
});
FieldMeaning
kindtransport, eviction, breaker, auth, cache, configuration or consent
codeStable code, such as AUTHENTICATION_FAILED or TRANSACTION_REJECTED
operationThe SDK operation, such as capture
retryableWhether the SDK retries on its own
httpStatusPresent when there was a response
messageHuman-readable detail; don't parse it

A rejected publishable key is reported once as AUTHENTICATION_FAILED. The refused traffic pauses and stays queued; one request is let through every 60 seconds.

Next steps

  • React Native SDK
  • Display a paywall
  • Errors

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

PreviousDevelopment modeNextErrors

On this page

Client optionsDisabled clientsObserver modeProviderHooksClient methodsPackage entry pointsCaching and offline behaviorDiagnosticsNext steps