AppKit for React Native enables seamless integration with multiple blockchain ecosystems, including EVM chains (like Ethereum, Polygon, etc.), Solana, and Bitcoin. It provides a unified API to manage wallet connections, interact with different chains, and build rich multi-chain applications. At the core of AppKit is a centralized AppKit instance that handles connection logic, manages various chain adapters, and provides data to your application via a React Context.
Don’t have a project ID?Head over to Reown Cloud and create a new project now!

Get started

Installation

Installation is a two-step process:
  1. Install the core AppKit library.
  2. Install the specific chain adapters you need for your application.

Core Library

npx expo install @reown/appkit-react-native@alpha @react-native-async-storage/async-storage react-native-get-random-values react-native-svg react-native-modal @react-native-community/netinfo @walletconnect/react-native-compat expo-application

Create babel.config.js

For Expo SDK 53 and later, you need to create a babel.config.js file in your project root to properly support the valtio library:
module.exports = function (api) {
  api.cache(true);
  return {
    presets: [["babel-preset-expo", { unstable_transformImportMeta: true }]],
  };
};
This configuration enables the unstable_transformImportMeta option which is required for valtio to work correctly with Expo 53+.

Chain Adapters

For React Native CLI projects, use npm install ... or yarn add ....
Install the adapters for the chains you intend to support:

For EVM-compatible chains, you can choose between the Ethers.js-based adapter or the Wagmi-based adapter. You should install the one that best fits your project’s existing setup or preference.

This adapter uses Ethers.js for interacting with EVM chains.

npx expo install @reown/appkit-ethers-react-native@alpha

To initialize the Ethers adapter:

import { EthersAdapter } from '@reown/appkit-ethers-react-native';

const projectId = 'YOUR_PROJECT_ID'; // Obtain from Cloud
const ethersAdapter = new EthersAdapter({ projectId });

Implementation

1. Initialize AppKit

First, create an instance of AppKit. This is where you’ll configure your project ID (if using WalletConnect features) and define the chains your application will support, along with their respective adapters.
To ensure proper functioning with React Native, make sure import "@walletconnect/react-native-compat"; is the very first line in your configuration file (e.g., AppKitConfig.ts), even before other imports. This import handles necessary polyfills.
// src/AppKitConfig.ts (or wherever you prefer to configure it)
import "@walletconnect/react-native-compat";
import { createAppKit, bitcoin, solana, type AppKitNetwork } from '@reown/appkit-react-native';
import { EthersAdapter } from '@reown/appkit-ethers-react-native';
import { SolanaAdapter } from '@reown/appkit-solana-react-native';
import { BitcoinAdapter } from '@reown/appkit-bitcoin-react-native';

// You can use 'viem/chains' or define your own chains using `AppKitNetwork` type. Check Options/networks for more detailed info
import { mainnet, polygon } from 'viem/chains';

const projectId = 'YOUR_PROJECT_ID'; // Obtain from Cloud

const ethersAdapter = new EthersAdapter({
  projectId
});

const solanaAdapter = new SolanaAdapter({
  projectId
});

const bitcoinAdapter = new BitcoinAdapter({
  projectId
});

export const appKit = createAppKit({
  projectId,
  networks: [mainnet, polygon, solana, bitcoin],
  defaultNetwork: mainnet, // Optional: set a default network
  adapters: [ethersAdapter, solanaAdapter, bitcoinAdapter],

  // Other AppKit options (e.g., metadata for your dApp)
  metadata: {
    name: 'My Awesome dApp',
    description: 'My dApp description',
    url: 'https://myapp.com',
    icons: ['https://myapp.com/icon.png'],
    redirect: {
      native: "YOUR_APP_SCHEME://",
      universal: "YOUR_APP_UNIVERSAL_LINK.com",
    },
  }
});

2. Provide AppKit Instance

Wrap your application with the AppKitProvider to make the AppKit instance available throughout your component tree via context.
// App.tsx
import React from 'react';
import { AppKitProvider } from '@reown/appkit-react-native';
import { appKit } from './AppKitConfig'; // Your configured AppKit instance
import YourAppRootComponent from './YourAppRootComponent';

function App() {
  return (
    <AppKitProvider instance={appKit}>
      <YourAppRootComponent />
    </AppKitProvider>
  );
}

export default App;

3. Render AppKit UI

To display the AppKit modal and other potential UI elements, you need to include the <AppKit /> component in your application. If you want the modal to be accessible from anywhere in your app, it’s best to place this component within your main application root component (e.g., the YourAppRootComponent from the example above, or directly in App.tsx if it serves as your main layout).
// YourAppRootComponent.tsx (or App.tsx if it contains your main layout)
import React from 'react';
import { AppKit } from '@reown/appkit-react-native';
// ... other imports for your app components like ConnectButton, etc.
import ConnectButton from './components/ConnectButton'; // Example import

function YourAppRootComponent() {
  return (
    <>
      {/* Your application's content */}
      <ConnectButton />
      {/* ... other components ... */}

      {/* Add the AppKit component here to render its UI (e.g., the modal) */}
      <AppKit />
    </>
  );
}

export default YourAppRootComponent;

4. Using AppKit in Components

You can now access AppKit functionalities (like connecting, getting account state, etc.) using hooks provided by the library.
// components/ConnectButton.tsx
import { useAppKit, useAccount } from '@reown/appkit-react-native';

function ConnectButton() {
  const { open, disconnect } = useAppKit();
  const { address, isConnected, chainId } = useAccount();

  if (isConnected) {
    return (
      <div>
        <p>Connected to: {chainId}</p>
        <p>Address: {address}</p>
        <button onClick={() => disconnect()}>Disconnect</button>
      </div>
    );
  }

  return <button onClick={() => open()}>Connect Wallet</button>;
}

export default ConnectButton;
For detailed examples on specific actions like signing messages, sending transactions, or switching networks, please refer to the Hooks and Examples sections.

5. Configure Storage

For data to persist across sessions, you need to provide a storage solution. The createAppKit function accepts a storage option that must conform to the Storage interface. The Storage interface, which can be imported from @reown/appkit-react-native, is defined as follows:
export interface Storage {
  /**
   * Returns all keys in storage.
   */
  getKeys(): Promise<string[]>;

  /**
   * Returns all key-value entries in storage.
   */
  getEntries<T = any>(): Promise<[string, T][]>;

  /**
   * Get an item from storage for a given key.
   * @param key The key to retrieve.
   */
  getItem<T = any>(key: string): Promise<T | undefined>;

  /**
   * Set an item in storage for a given key.
   * @param key The key to set.
   * @param value The value to set.
   */
  setItem<T = any>(key: string, value: T): Promise<void>;

  /**
   * Remove an item from storage for a given key.
   * @param key The key to remove.
   */
  removeItem(key: string): Promise<void>;
}
Example with AsyncStorage You can implement this interface using a library like @react-native-async-storage/async-storage. Create a new file, for example src/StorageUtil.ts, with the following content:
// src/StorageUtil.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
import { safeJsonParse, safeJsonStringify } from '@walletconnect/safe-json';
import type { Storage } from '@reown/appkit-react-native';

export const storage: Storage = {
  getKeys: async () => {
    return AsyncStorage.getAllKeys() as Promise<string[]>;
  },
  getEntries: async <T = any>(): Promise<[string, T][]> => {
    function parseEntry(entry: [string, string | null]): [string, any] {
      return [entry[0], safeJsonParse(entry[1] ?? '')];
    }

    const keys = await AsyncStorage.getAllKeys();
    const entries = await AsyncStorage.multiGet(keys);

    return entries.map(parseEntry);
  },
  setItem: async (key: string, value: any) => {
    return await AsyncStorage.setItem(key, safeJsonStringify(value));
  },
  getItem: async <T = any>(key: string): Promise<T | undefined> => {
    const item = await AsyncStorage.getItem(key);
    if (typeof item === 'undefined' || item === null) {
      return undefined;
    }

    return safeJsonParse(item) as T;
  },
  removeItem: async (key: string) => {
    return await AsyncStorage.removeItem(key);
  }
};
Update AppKit Configuration Finally, import your custom storage and pass it to createAppKit in your AppKitConfig.ts. This example builds on the configuration from Initialize AppKit:
// src/AppKitConfig.ts (or wherever you prefer to configure it)
import "@walletconnect/react-native-compat";
import { createAppKit, bitcoin, solana, type AppKitNetwork } from '@reown/appkit-react-native';
import { EthersAdapter } from '@reown/appkit-ethers-react-native';
import { SolanaAdapter } from '@reown/appkit-solana-react-native';
import { BitcoinAdapter } from '@reown/appkit-bitcoin-react-native';
import { storage } from './StorageUtil'; // 1. Import your custom storage

// You can use 'viem/chains' or define your own chains using `AppKitNetwork` type. Check Options/networks for more detailed info
import { mainnet, polygon } from 'viem/chains';

const projectId = 'YOUR_PROJECT_ID'; // Obtain from Cloud

const ethersAdapter = new EthersAdapter({
  projectId
});

const solanaAdapter = new SolanaAdapter({
  projectId
});

const bitcoinAdapter = new BitcoinAdapter({
  projectId
});

export const appKit = createAppKit({
  projectId,
  networks: [mainnet, polygon, solana, bitcoin],
  defaultNetwork: mainnet,
  adapters: [ethersAdapter, solanaAdapter, bitcoinAdapter],
  storage,

  // Other AppKit options (e.g., metadata for your dApp)
  metadata: {
    name: 'My Awesome dApp',
    description: 'My dApp description',
    url: 'https://myapp.com',
    icons: ['https://myapp.com/icon.png'],
    redirect: {
      native: "YOUR_APP_SCHEME://",
      universal: "YOUR_APP_UNIVERSAL_LINK.com",
    },
  }
});

Enable Wallet Detection (Optional)

This is an optional feature that enhances the user experience by:
  • Showing a green checkmark next to installed wallets
  • Prioritizing installed wallets at the top of the list
All 430+ wallets in the AppKit ecosystem work via WalletConnect protocol regardless of this configuration. You only need to add the wallets your users most commonly have installed.
To enable AppKit to detect wallets installed on the device, you can make specific changes to the native code of your project.
To enable AppKit to detect wallets installed on the device in your Expo project for iOS, follow these steps:
  1. Open your app.json (or app.config.js) file.
  2. Locate the ios section within the configuration.
  3. Add the infoPlist object if it doesn’t exist, and within it, include the LSApplicationQueriesSchemes array. This array will contain the desired wallet schemes you want to detect.
  4. Add the wallet schemes to the LSApplicationQueriesSchemes array.
Your configuration should look like this:
{
  "expo": {
    "ios": {
      "infoPlist": {
        "LSApplicationQueriesSchemes": [
          "metamask",
          "trust",
          "safe",
          "rainbow",
          "uniswap"
          // Add other wallet schemes names here
        ]
      }
    }
  }
}

Enable Phantom Wallet (Optional)

Phantom Wallet is a popular wallet on the Solana blockchain. Because it uses a custom connection protocol, it requires a specific connector to be added to your AppKit configuration. To enable Phantom Wallet, you’ll need to import the PhantomConnector from @reown/appkit-solana-react-native and add it to the extraConnectors array in your createAppKit configuration. Here’s how to update your AppKitConfig.ts file, using the example from the Implementation section as a base:
// src/AppKitConfig.ts (or wherever you prefer to configure it)
import "@walletconnect/react-native-compat";
import { createAppKit, bitcoin, solana, type AppKitNetwork } from '@reown/appkit-react-native';
import { EthersAdapter } from '@reown/appkit-ethers-react-native';
import { SolanaAdapter, PhantomConnector } from '@reown/appkit-solana-react-native';
import { BitcoinAdapter } from '@reown/appkit-bitcoin-react-native';

// You can use 'viem/chains' or define your own chains using `AppKitNetwork` type. Check Options/networks for more detailed info
import { mainnet, polygon } from 'viem/chains';

const projectId = 'YOUR_PROJECT_ID'; // Obtain from Cloud

const ethersAdapter = new EthersAdapter({
  projectId
});

const solanaAdapter = new SolanaAdapter({
  projectId
});

const bitcoinAdapter = new BitcoinAdapter({
  projectId
});

export const appKit = createAppKit({
  projectId,
  networks: [mainnet, polygon, solana, bitcoin],
  defaultNetwork: mainnet, // Optional: set a default network
  adapters: [ethersAdapter, solanaAdapter, bitcoinAdapter],
  extraConnectors: [
    new PhantomConnector({ cluster: 'mainnet-beta' }) // Or 'devnet', 'testnet'
  ],
  customWallets: [
    {
      id: 'phantom-wallet',
      name: 'Phantom',
      image_url: 'https://avatars.githubusercontent.com/u/124594793?s=200&v=4',
      mobile_link: 'phantom://',
    }
  ]
  // Other AppKit options (e.g., metadata for your dApp)
});
The cluster option in PhantomConnector can be set to 'mainnet-beta', 'devnet', or 'testnet' depending on which Solana cluster you want to connect to.

Examples

Test Apps

Want to see AppKit in action? Download our sample AppKit apps below and explore what it can do. Enjoy! 😊

Getting Support πŸ™‹

Reown is committed to delivering the best developer experience. If you have any questions, feature requests, or bug reports, feel free to open an issue on GitHub