> For the complete documentation index, see [llms.txt](/llms.txt).

# Embedded Wallet SDK for React Native

## Overview

The Web3Auth by MetaMask, Embedded Wallet SDK for React Native (`@web3auth/react-native-sdk`) adds social sign-in and wallet functionality to your iOS and Android apps. Wrap your app in `Web3AuthProvider` and use React hooks to sign users in, read the wallet connection, and open Wallet Services.

This page covers v10 of the SDK. After sign-in, `useWeb3Auth().connection` exposes an EIP-1193 `ethereumProvider` for EVM chains and a Wallet Standard `solanaWallet` for Solana. Optional entry points add [Wagmi hooks](/embedded-wallets/sdk/react-native/ethereum-hooks/) (`@web3auth/react-native-sdk/wagmi`) and [Solana hooks](/embedded-wallets/sdk/react-native/solana-hooks/) (`@web3auth/react-native-sdk/solana`).

Migrate from an earlier version

See the [React Native migration guide](/embedded-wallets/migration-guides/react-native/) to upgrade from any earlier `@web3auth/react-native-sdk` version.

## Requirements

- Node.js 22 or later.
- React Native. The [official examples](https://github.com/Web3Auth/web3auth-react-native-examples)use React Native 0.74 (bare) and Expo SDK 51.
- For Expo, a [development build](https://docs.expo.dev/develop/development-builds/introduction/), because the SDK uses the native module `react-native-quick-crypto`.
- iOS: deployment target supported by your React Native version. Sign-in uses `ASWebAuthenticationSession`.
- Android: a browser that supports Custom Tabs.

## Prerequisites

Set up your project on the [Embedded Wallets dashboard](https://developer.metamask.io/):

1. Create a project and copy the **Client ID**.
2. Choose a custom URL scheme for your app (for example, `web3authrnexample`) and add the full redirect URL you pass to the SDK (for example, `web3authrnexample://auth`) to the allowlist.
3. Configure the chains your app uses, or pass them in code with `chains`.

See the [dashboard setup guide](/embedded-wallets/dashboard/) for details.

## Install

### 1. Install the SDK and its peer packages

The SDK needs an in-app browser, secure storage, and a native crypto implementation. The packages differ between bare React Native and Expo:

**Bare React Native**

**Expo**

```bash
npm install @web3auth/react-native-sdk @toruslabs/react-native-web-browser react-native-encrypted-storage
npm install --save-dev @babel/plugin-transform-export-namespace-from

```

**npm**

```bash
yarn add @web3auth/react-native-sdk @toruslabs/react-native-web-browser react-native-encrypted-storage
yarn add --dev @babel/plugin-transform-export-namespace-from

```

**Yarn**

```bash
pnpm add @web3auth/react-native-sdk @toruslabs/react-native-web-browser react-native-encrypted-storage
pnpm add --save-dev @babel/plugin-transform-export-namespace-from

```

**pnpm**

```bash
bun add @web3auth/react-native-sdk @toruslabs/react-native-web-browser react-native-encrypted-storage
bun add --dev @babel/plugin-transform-export-namespace-from

```

**Bun**

```bash
npx expo install @web3auth/react-native-sdk expo-web-browser expo-secure-store expo-linking expo-constants
npm install --save-dev @babel/plugin-transform-export-namespace-from

```

Then install `react-native-quick-crypto`. Pick the version that matches your app:

| Your app                                                | Install                                                                                                     |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| React Native 0.75 or later with the New Architecture    | `react-native-quick-crypto` 1.x, `react-native-nitro-modules`, and `react-native-quick-base64` 3.x or later |
| React Native earlier than 0.75, or the old architecture | `react-native-quick-crypto` 0.7.x (the official examples use `^0.7.6`)                                      |

**React Native 0.75+ (New Architecture)**

**Earlier React Native**

```bash
npm install react-native-quick-crypto react-native-nitro-modules react-native-quick-base64

```

**npm**

```bash
yarn add react-native-quick-crypto react-native-nitro-modules react-native-quick-base64

```

**Yarn**

```bash
pnpm add react-native-quick-crypto react-native-nitro-modules react-native-quick-base64

```

**pnpm**

```bash
bun add react-native-quick-crypto react-native-nitro-modules react-native-quick-base64

```

**Bun**

**npm**

```bash
npm install react-native-quick-crypto@^0.7.6

```

**Yarn**

```bash
yarn add react-native-quick-crypto@^0.7.6

```

**pnpm**

```bash
pnpm add react-native-quick-crypto@^0.7.6

```

**Bun**

```bash
bun add react-native-quick-crypto@^0.7.6

```

Install a working `react-native-quick-crypto`

`@web3auth/react-native-sdk/setup` installs `react-native-quick-crypto` as the global `crypto`object, and sign-in uses `crypto.getRandomValues`. The SDK declares `react-native-quick-crypto` as an optional peer dependency, but if it's missing or its native library fails to load, `setup`skips it without an error. In our testing on an Android emulator, the SDK then initialized but `connectTo` failed with `TypeError: undefined is not a function` in `randomBytes`.

On an Android emulator with 16 KB memory pages, `react-native-quick-crypto` 0.7.x failed to load (`dlopen failed: empty/missing DT_HASH/DT_GNU_HASH`), while 1.x loaded. If your app must run on 16 KB-page devices, use 1.x.

### 2. Configure Android

Register your URL scheme on the main activity in `android/app/src/main/AndroidManifest.xml` so the in-app browser can return to your app. Set `android:launchMode="singleTask"` and `android:exported="true"`:

android/app/src/main/AndroidManifest.xml

```xml
<activity
  android:name=".MainActivity"
  android:launchMode="singleTask"
  android:exported="true">
  <!-- existing MAIN / LAUNCHER intent filter -->
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <!-- replace with your own scheme -->
    <data android:scheme="web3authrnexample" />
  </intent-filter>
</activity>

```

Gradle 9 and `@toruslabs/react-native-web-browser`

`@toruslabs/react-native-web-browser` 1.1.0 calls `jcenter()` in its `android/build.gradle`. Gradle 9 removed `jcenter()`, so on React Native versions that use Gradle 9 (for example, 0.84) the Android build fails with `Could not find method jcenter()`. Until a fixed version is released, replace `jcenter()` with `mavenCentral()` in `node_modules/@toruslabs/react-native-web-browser/android/build.gradle` and persist the change with [patch-package](https://www.npmjs.com/package/patch-package).

### 3. Configure iOS

Install pods:

```bash
cd ios && pod install

```

### 4. Configure Expo

Add your scheme to `app.json`, then create a development build with `npx expo prebuild` or EAS Build:

app.json

```json
{
  "expo": {
    "scheme": "web3authexpoexample"
  }
}

```

Build the redirect URL with `expo-linking`. Expo Go and development or standalone builds resolve different URLs, so allowlist each URL your app uses:

```ts
import Constants, { AppOwnership } from 'expo-constants'
import * as Linking from 'expo-linking'

const redirectUrl =
  Constants.appOwnership === AppOwnership.Expo ||
  // @ts-expect-error AppOwnership.Guest is missing from the expo-constants typings
  Constants.appOwnership === AppOwnership.Guest
    ? Linking.createURL('web3auth', {})
    : Linking.createURL('web3auth', { scheme: 'web3authexpoexample' })

```

## Configure Metro, Babel, and the entry file

### Entry file

Import `@web3auth/react-native-sdk/setup` as the first line of your app's entry file. It installs the `Buffer`, `TextEncoder`, and `crypto` globals that the SDK needs.

**Bare React Native**

index.js

```js
import '@web3auth/react-native-sdk/setup' // must be first
import { AppRegistry } from 'react-native'
import App from './App'
import { name as appName } from './app.json'

AppRegistry.registerComponent(appName, () => App)

```

**Expo**

Create `index.ts` and set `"main": "index.ts"` in `package.json`:

index.ts

```ts
import '@web3auth/react-native-sdk/setup' // must be first
import { registerRootComponent } from 'expo'
import App from './App'

registerRootComponent(App)

```

For Solana apps, also import the Solana polyfills described in [Solana hooks](/embedded-wallets/sdk/react-native/solana-hooks/#set-up).

### Metro

`withWeb3Auth` adds the Node.js module aliases and global shims that the SDK and its dependencies need:

**Bare React Native**

metro.config.js

```js
const { getDefaultConfig } = require('@react-native/metro-config')
const { withWeb3Auth } = require('@web3auth/react-native-sdk/metro-config')

const config = getDefaultConfig(__dirname)
module.exports = withWeb3Auth(config)

```

**Expo**

metro.config.js

```js
const { getDefaultConfig } = require('expo/metro-config')
const { withWeb3Auth } = require('@web3auth/react-native-sdk/metro-config')

const config = getDefaultConfig(__dirname)
module.exports = withWeb3Auth(config)

```

### Babel

Add `@babel/plugin-transform-export-namespace-from`. Some SDK dependencies use `export * as`syntax that the React Native Babel preset doesn't transform.

**Bare React Native**

babel.config.js

```js
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: ['@babel/plugin-transform-export-namespace-from'],
}

```

**Expo**

The Expo example also uses the legacy Hermes transform profile and enables `import.meta`transforms, which some EVM dependencies need on Hermes:

babel.config.js

```js
module.exports = function (api) {
  api.cache(true)
  return {
    presets: [
      [
        'babel-preset-expo',
        {
          unstable_transformProfile: 'hermes-v0',
          unstable_transformImportMeta: true,
        },
      ],
    ],
    plugins: ['@babel/plugin-transform-export-namespace-from'],
  }
}

```

## Configure the SDK

Create a `web3authConfig.ts` file that exports a `Web3AuthContextConfig`. `chains` is optional when you configure chains on the dashboard; chains you pass in code are merged with the dashboard chains and take precedence.

**Dashboard chains**

web3authConfig.ts

```typescript
import { WEB3AUTH_NETWORK, type Web3AuthContextConfig } from '@web3auth/react-native-sdk'

const web3AuthConfig: Web3AuthContextConfig = {
  web3AuthOptions: {
    clientId: '<YOUR_CLIENT_ID>', // from developer.metamask.io
    redirectUrl: 'web3authrnexample://auth', // must be allowlisted on the dashboard
    network: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
  },
}

export default web3AuthConfig

```

**EVM chain in code**

web3authConfig.ts

```typescript
import {
  CHAIN_NAMESPACES,
  WEB3AUTH_NETWORK,
  type Web3AuthContextConfig,
} from '@web3auth/react-native-sdk'

const web3AuthConfig: Web3AuthContextConfig = {
  web3AuthOptions: {
    clientId: '<YOUR_CLIENT_ID>',
    redirectUrl: 'web3authrnexample://auth',
    network: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
    chains: [
      {
        chainNamespace: CHAIN_NAMESPACES.EIP155,
        chainId: '0xaa36a7',
        rpcTarget: 'https://ethereum-sepolia-rpc.publicnode.com',
        displayName: 'Ethereum Sepolia Testnet',
        blockExplorerUrl: 'https://sepolia.etherscan.io',
        ticker: 'ETH',
        tickerName: 'Ethereum',
      },
    ],
    defaultChainId: '0xaa36a7',
  },
}

export default web3AuthConfig

```

**Solana chain in code**

web3authConfig.ts

```typescript
import {
  CHAIN_NAMESPACES,
  WEB3AUTH_NETWORK,
  type Web3AuthContextConfig,
} from '@web3auth/react-native-sdk'

const web3AuthConfig: Web3AuthContextConfig = {
  web3AuthOptions: {
    clientId: '<YOUR_CLIENT_ID>',
    redirectUrl: 'web3authrnexample://auth',
    network: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
    chains: [
      {
        chainNamespace: CHAIN_NAMESPACES.SOLANA,
        chainId: '0x67', // Solana Devnet (0x65 Mainnet, 0x66 Testnet)
        rpcTarget: 'https://api.devnet.solana.com',
        displayName: 'Solana Devnet',
        blockExplorerUrl: 'https://explorer.solana.com?cluster=devnet',
        ticker: 'SOL',
        tickerName: 'Solana',
      },
    ],
    defaultChainId: '0x67',
  },
}

export default web3AuthConfig

```

See [Advanced configuration](/embedded-wallets/sdk/react-native/advanced/) for all `web3AuthOptions`.

## Set up `Web3AuthProvider`

`Web3AuthProvider` is the React context provider that initialises the SDK and makes all hooks available to the component tree.

**Bare React Native**

```tsx
import * as WebBrowser from '@toruslabs/react-native-web-browser'
import EncryptedStorage from 'react-native-encrypted-storage'
import { Web3AuthProvider } from '@web3auth/react-native-sdk'
import web3AuthConfig from './web3authConfig'

export default function App() {
  return (
    <Web3AuthProvider webBrowser={WebBrowser} storage={EncryptedStorage} config={web3AuthConfig}>
      <Screen />
    </Web3AuthProvider>
  )
}

```

**Expo**

```tsx
import * as WebBrowser from 'expo-web-browser'
import * as SecureStore from 'expo-secure-store'
import { Web3AuthProvider } from '@web3auth/react-native-sdk'
import web3AuthConfig from './web3authConfig'

export default function App() {
  return (
    <Web3AuthProvider webBrowser={WebBrowser} storage={SecureStore} config={web3AuthConfig}>
      <Screen />
    </Web3AuthProvider>
  )
}

```

### Props

| Prop         | Type                              | Required | Description                                                                                                                     |
| ------------ | --------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `webBrowser` | `IWebBrowser`                     | Yes      | In-app browser implementation. Use `@toruslabs/react-native-web-browser` for bare React Native and `expo-web-browser` for Expo. |
| `storage`    | `EncryptedStorage \| SecureStore` | Yes      | Secure storage for session data. Use `react-native-encrypted-storage` for bare React Native and `expo-secure-store` for Expo.   |
| `config`     | `Web3AuthContextConfig`           | Yes      | `{ web3AuthOptions }` object, typically exported from `web3authConfig.ts`.                                                      |
| `children`   | `React.ReactNode`                 | Yes      | Components that use the Embedded Wallets hooks.                                                                                 |

The provider creates a new SDK instance whenever the `config.web3AuthOptions` object, `webBrowser`, or `storage` changes identity. Define the config outside your component or memoize it. To switch configurations at runtime (for example, to toggle account abstraction), pass a new React `key` to remount the provider.

## Sign users in

Call `connectTo` from the `useWeb3AuthConnect` hook. The SDK opens the sign-in flow in an in-app browser and returns to your app through `redirectUrl`.

```tsx
import { AUTH_CONNECTION, useWeb3Auth, useWeb3AuthConnect } from '@web3auth/react-native-sdk'
import { ActivityIndicator, Button, View } from 'react-native'

function Screen() {
  const { isConnected, isInitializing } = useWeb3Auth()
  const { connectTo, loading } = useWeb3AuthConnect()

  if (isInitializing) return <ActivityIndicator />
  if (isConnected) return <HomeView />

  return (
    <View>
      <Button
        title={loading ? 'Signing in…' : 'Sign in with Google'}
        disabled={loading}
        onPress={() => connectTo({ authConnection: AUTH_CONNECTION.GOOGLE })}
      />
      <Button
        title="Sign in with email"
        disabled={loading}
        onPress={() =>
          connectTo({
            authConnection: AUTH_CONNECTION.EMAIL_PASSWORDLESS,
            extraLoginOptions: { login_hint: 'user@example.com' },
          })
        }
      />
    </View>
  )
}

```

See [Sign in](/embedded-wallets/sdk/react-native/usage/login/) and [useWeb3AuthConnect](/embedded-wallets/sdk/react-native/hooks/useWeb3AuthConnect/) for all `connectTo` parameters.

## Make EVM calls

After sign-in, pass `connection.ethereumProvider` to viem or ethers:

```tsx
import { useWeb3Auth } from '@web3auth/react-native-sdk'
import { createWalletClient, custom } from 'viem'

function HomeView() {
  const { connection } = useWeb3Auth()

  const signMessage = async () => {
    const walletClient = createWalletClient({
      transport: custom(connection!.ethereumProvider!),
    })
    const [account] = await walletClient.getAddresses()
    return walletClient.signMessage({ account, message: 'Hello' })
  }

  // ...
}

```

To use Wagmi hooks instead, see [Ethereum hooks (Wagmi)](/embedded-wallets/sdk/react-native/ethereum-hooks/).

## Make Solana calls

For Solana chains, wrap your app in `SolanaProvider` and use the hooks from `@web3auth/react-native-sdk/solana`. See [Solana hooks](/embedded-wallets/sdk/react-native/solana-hooks/).

## Next steps

- [Hooks reference](/embedded-wallets/sdk/react-native/hooks/)
- [Custom authentication](/embedded-wallets/sdk/react-native/advanced/custom-authentication/)
- [Smart accounts](/embedded-wallets/sdk/react-native/advanced/smart-accounts/)
- [Whitelabel](/embedded-wallets/sdk/react-native/advanced/whitelabel/)
- [Multi-factor authentication](/embedded-wallets/sdk/react-native/advanced/mfa/)
- [Examples](/embedded-wallets/sdk/react-native/examples/)

## Troubleshooting

For Metro bundler and polyfill errors, see [React Native Metro polyfill issues](/embedded-wallets/troubleshooting/metro-issues/).
