Skip to content

React Native Configuration

Stampers, storage, and connector options

On the web, the zeroDevWallet connector falls back to platform defaults for key storage and session persistence. React Native has no equivalent defaults, so the storages and stampers must be configured explicitly.

Full example

import { createReactNativePasskeyStamper } from "@zerodev/wallet-core/react-native/stampers/passkey";
import { createSecureStoreStamper } from "@zerodev/wallet-core/react-native/stampers/secure-store";
import { asyncStorageAdapter } from "@zerodev/wallet-core/react-native/storage/async-storage";
import { zeroDevWallet } from "@zerodev/wallet-react";
import { createConfig, createStorage, http } from "wagmi";
import { arbitrumSepolia, sepolia } from "wagmi/chains";
 
const ZERODEV_PROJECT_ID = process.env.EXPO_PUBLIC_ZERODEV_PROJECT_ID ?? "";
export const RP_ID = "example.com";
 
const chains = [sepolia, arbitrumSepolia] as const;
 
export const wagmiConfig = createConfig({
  chains,
  connectors: [
    zeroDevWallet({
      projectId: ZERODEV_PROJECT_ID,
      chains,
      rpId: RP_ID,
      apiKeyStamper: createSecureStoreStamper(),
      passkeyStamper: createReactNativePasskeyStamper({ rpId: RP_ID }),
      sessionStorage: asyncStorageAdapter,
      persistStorage: asyncStorageAdapter,
    }),
  ],
  transports: {
    [sepolia.id]: http(),
    [arbitrumSepolia.id]: http(),
  },
  storage: createStorage({ storage: asyncStorageAdapter }),
  multiInjectedProviderDiscovery: false,
});

Connector options

On React Native, zeroDevWallet takes these options in addition to the shared ones (projectId, chains, …):

OptionRequiredDescription
rpIdYesThe relying party ID — your app's domain (no scheme), e.g. example.com. Used for passkeys and as the Origin of the SDK's requests. See Domain Association.
apiKeyStamperYesSigns SDK requests with a device-bound API key. Use createSecureStoreStamper.
sessionStorageYesStorage adapter for session data. Use asyncStorageAdapter.
persistStorageNoStorage adapter for persisting wallet state across app restarts. Usually also asyncStorageAdapter.
passkeyStamperNoOnly needed for passkey auth. Use createReactNativePasskeyStamper.

The rpId is a domain, as defined by the WebAuthn standard. As long as you don't use passkeys or App Links for OAuth / magic-link redirects, it doesn't have to be a valid domain you own; otherwise the domain association must be served from it.

The connector automatically sends Origin: https://<rpId> on its requests — so if you specify an Access Control List of whitelisted Origins on the ZeroDev Dashboard, the same domain needs to be on the allowlist as https://<rpId>/.

Stampers

createSecureStoreStamper

Creates the API-key stamper that signs the SDK's requests. The keypair is generated on first use and stored in expo-secure-store (Keychain on iOS, Keystore-backed storage on Android).

import { createSecureStoreStamper } from "@zerodev/wallet-core/react-native/stampers/secure-store";
 
const apiKeyStamper = createSecureStoreStamper();

Requires the expo-secure-store peer dependency:

npm
npx expo install expo-secure-store

createReactNativePasskeyStamper

Creates the passkey stamper used by useRegisterPasskey and useLoginPasskey. It wraps the native platform passkey APIs and requires the rpId to match a domain your app is associated with — see Domain Association and Passkeys on React Native for the full setup.

import { createReactNativePasskeyStamper } from "@zerodev/wallet-core/react-native/stampers/passkey";
 
const passkeyStamper = createReactNativePasskeyStamper({ rpId: "example.com" });

Requires these peer dependencies (native module — rebuild your dev client after installing):

npm
npx expo install @turnkey/react-native-passkey-stamper uuid

If your app doesn't use passkeys, omit passkeyStamper — the OTP, magic-link, and OAuth flows work without it.

Storage

asyncStorageAdapter

A storage adapter backed by @react-native-async-storage/async-storage. Use it for the connector's sessionStorage and persistStorage, and for Wagmi's own createStorage:

import { asyncStorageAdapter } from "@zerodev/wallet-core/react-native/storage/async-storage";
import { createStorage } from "wagmi";
 
const storage = createStorage({ storage: asyncStorageAdapter });

Requires the @react-native-async-storage/async-storage peer dependency:

npm
npx expo install @react-native-async-storage/async-storage

How React Native differs from web

  • No platform defaultsrpId, apiKeyStamper, and sessionStorage are required on React Native; on the web they have built-in defaults.
  • Crypto polyfill — import react-native-get-random-values at the very top of your app's entry file (see the quickstart).
  • Wallet export is a component, not a hookuseExportWallet and useExportPrivateKey are not available on React Native. Use ZeroDevExportWebView instead.
  • OAuth uses deep links — instead of the web popup flow, use useAuthenticateOAuthWithExpoWebBrowser.

Running the same Expo app on the web too? See React Native Web — the web build auto-defaults the stampers and storage, so the connector is just zeroDevWallet({ projectId, chains }).