Skip to main content

Requirements

  • A React Native project using the latest version
  • iOS and Android platform support (Web is not supported)

Installation

Core Dependencies

Install the Privy React Native SDK and its peer dependencies:
npx expo install expo-apple-authentication expo-application expo-crypto expo-linking expo-secure-store expo-web-browser react-native-passkeys react-native-webview @privy-io/expo-native-extensions @privy-io/expo

Required Polyfills

Install the necessary polyfills:
npm i fast-text-encoding react-native-get-random-values @ethersproject/shims
If your app uses the Expo bare workflow (“React Native without Expo”), also run:
npx pod-install

Configure Polyfills

  • Using expo/router
  • Without expo/router
Create an entrypoint.js file and update your package.json:
entrypoint.js
// Import required polyfills first
import 'fast-text-encoding';
import 'react-native-get-random-values';
import '@ethersproject/shims';
// Then import the expo router
import 'expo-router/entry';
package.json
{
  "name": "<your app name>",
  "main": "entrypoint.js"
}
If you’re using the @solana/web3.js package, install the buffer dependency:
npm i buffer
And add this code after importing react-native-get-random-values:
import 'react-native-get-random-values';
import {Buffer} from 'buffer';
global.Buffer = Buffer;
This guide ensures that your application satisfies the following requirements for integrating:

Enabling Package Exports

React Native 0.79, and Expo 53, have enabled package exports by default.Some popular packages present incompatibilities with this change, and the community is working to get these fixed at source. In the meantime, we present a fix below by disabling package exports for the incompatibilities we have found.
Update your metro.config.js like so:
//...other config logic

// Enable package exports for select libraries
...
const resolveRequestWithPackageExports = (context, moduleName, platform) => {
  // Package exports in `isows` (a `viem`) dependency are incompatible, so they need to be disabled
  if (moduleName === "isows") {
    const ctx = {
      ...context,
      unstable_enablePackageExports: false,
    };
    return ctx.resolveRequest(ctx, moduleName, platform);
  }

  // Package exports in `zustand@4` are incompatible, so they need to be disabled
  if (moduleName.startsWith("zustand")) {
    const ctx = {
      ...context,
      unstable_enablePackageExports: false,
    };
    return ctx.resolveRequest(ctx, moduleName, platform);
  }

  // Package exports in `jose` are incompatible, so the browser version is used
  if (moduleName === "jose") {
    const ctx = {
      ...context,
      unstable_conditionNames: ["browser"],
    };
    return ctx.resolveRequest(ctx, moduleName, platform);
  }

  // The following block is only needed if you are
  // running React Native 0.78 *or older*.
  if (moduleName.startsWith('@privy-io/')) {
    const ctx = {
      ...context,
      unstable_enablePackageExports: true,
    };
    return ctx.resolveRequest(ctx, moduleName, platform);
  }

  return context.resolveRequest(context, moduleName, platform);
};

config.resolver.resolveRequest = resolveRequestWithPackageExports;

...
module.exports = config;

Typescript’s Module Resolution

Also configure your tsconfig.json like so:
{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    // Allows us to use conditional/deep imports on published packages
    "moduleResolution": "Bundler"
  }
}
I