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 (@web3auth/react-native-sdk/wagmi) and
Solana hooks (@web3auth/react-native-sdk/solana).
See the React Native migration guide to upgrade
from any earlier @web3auth/react-native-sdk version.
Requirements
- Node.js 22 or later.
- React Native. The official examples use React Native 0.74 (bare) and Expo SDK 51.
- For Expo, a development build,
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:
- Create a project and copy the Client ID.
- 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. - Configure the chains your app uses, or pass them in code with
chains.
See the dashboard setup guide 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
- npm
- Yarn
- pnpm
- Bun
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
yarn add @web3auth/react-native-sdk @toruslabs/react-native-web-browser react-native-encrypted-storage
yarn add --dev @babel/plugin-transform-export-namespace-from
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
bun add @web3auth/react-native-sdk @toruslabs/react-native-web-browser react-native-encrypted-storage
bun add --dev @babel/plugin-transform-export-namespace-from
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
- npm
- Yarn
- pnpm
- Bun
npm install react-native-quick-crypto react-native-nitro-modules react-native-quick-base64
yarn add react-native-quick-crypto react-native-nitro-modules react-native-quick-base64
pnpm add react-native-quick-crypto react-native-nitro-modules react-native-quick-base64
bun add react-native-quick-crypto react-native-nitro-modules react-native-quick-base64
- npm
- Yarn
- pnpm
- Bun
npm install react-native-quick-crypto@^0.7.6
yarn add react-native-quick-crypto@^0.7.6
pnpm add react-native-quick-crypto@^0.7.6
bun add react-native-quick-crypto@^0.7.6
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":
<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>
@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.
3. Configure iOS
Install pods:
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:
{
"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:
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
- Expo
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)
Create index.ts and set "main": "index.ts" in package.json:
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.
Metro
withWeb3Auth adds the Node.js module aliases and global shims that the SDK and its dependencies
need:
- Bare React Native
- Expo
const { getDefaultConfig } = require('@react-native/metro-config')
const { withWeb3Auth } = require('@web3auth/react-native-sdk/metro-config')
const config = getDefaultConfig(__dirname)
module.exports = withWeb3Auth(config)
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
- Expo
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: ['@babel/plugin-transform-export-namespace-from'],
}
The Expo example also uses the legacy Hermes transform profile and enables import.meta
transforms, which some EVM dependencies need on Hermes:
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
- EVM chain in code
- Solana chain in code
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
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
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 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
- Expo
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>
)
}
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.
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 and useWeb3AuthConnect for
all connectTo parameters.
Make EVM calls
After sign-in, pass connection.ethereumProvider to viem or ethers:
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).
Make Solana calls
For Solana chains, wrap your app in SolanaProvider and use the hooks from
@web3auth/react-native-sdk/solana. See Solana hooks.
Next steps
- Hooks reference
- Custom authentication
- Smart accounts
- Whitelabel
- Multi-factor authentication
- Examples
Troubleshooting
For Metro bundler and polyfill errors, see React Native Metro polyfill issues.