> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Setup on Bare React Native

> Install and configure the JavaScript SDK in a bare React Native app.

This guide sets up the JavaScript SDK in a bare React Native app created with [`@react-native-community/cli`](https://github.com/react-native-community/cli) (without Expo). These steps configure the native modules, polyfills, and build transforms the SDK needs for cross-platform compatibility.

<Note>
  Before you start: a bare React Native app and a Dynamic environment ID from the [Dynamic dashboard](https://app.dynamic.xyz). For an Expo app, use [Setup on Expo](/docs/javascript/react-native/expo) instead.
</Note>

## Install dependencies

<Steps>
  <Step title="Install the core packages">
    Install the SDK packages and their peer dependencies.

    ```shell theme={"system"}
    npm install \
      @dynamic-labs-sdk/client \
      @dynamic-labs-sdk/react-hooks \
      @tanstack/react-query \
      @react-native-async-storage/async-storage \
      react-native-keychain
    ```
  </Step>

  <Step title="Install the polyfills">
    Install the polyfills required for secure operations.

    ```shell theme={"system"}
    npm install \
      react-native-get-random-values \
      buffer
    ```

    <Note>
      You may already have some of these polyfills installed. Install only the ones your project is missing.
    </Note>
  </Step>
</Steps>

## Feature packages

The packages above cover email, wallet, and session basics. Each feature below needs an extra package — install it only when you use that feature, then follow its guide.

| Feature                    | Install                                                                         | Guide                                                                                |
| -------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Social / OAuth login       | `react-native-inappbrowser-reborn`                                              | [Social login](/docs/javascript/authentication-methods/social)                            |
| WalletConnect              | `@walletconnect/react-native-compat`, `@react-native-community/netinfo`         | [WalletConnect integration](/docs/javascript/reference/wallets/walletconnect-integration) |
| Passkeys                   | `react-native-passkey`                                                          | [React Native Passkeys](/docs/javascript/react-native/passkeys)                           |
| EVM / Solana chains        | `@dynamic-labs-sdk/evm`, `@dynamic-labs-sdk/solana`                             | [Add the EVM extension](/docs/javascript/reference/evm/adding-evm-extensions)             |
| Export embedded wallet key | `@dynamic-labs-sdk/react-native-embedded-wallet-export`, `react-native-webview` | [Export WaaS private key](/docs/javascript/reference/waas/exporting-waas-private-key)     |

<Note>
  `@react-native-community/netinfo` is a peer dependency of `@walletconnect/react-native-compat` — without it, WalletConnect sessions will not reconnect reliably after network changes.
</Note>

## Configure Babel

The SDK ships modern JavaScript syntax that the stock React Native Babel preset does not transform (`export * as ns from …` and static class blocks). Install the two required transform plugins:

```shell theme={"system"}
npm install --save-dev \
  @babel/plugin-transform-export-namespace-from \
  @babel/plugin-transform-class-static-block
```

Then add them to your `babel.config.js`:

```js babel.config.js theme={"system"}
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    '@babel/plugin-transform-export-namespace-from',
    '@babel/plugin-transform-class-static-block',
    // ...other plugins
  ],
};
```

<Note>
  After changing the Babel config, restart Metro with a cleared cache: `npx react-native start --reset-cache`.
</Note>

## Create a polyfills file

Create a `polyfills.ts` file at the root of your project. It handles the critical environment shims: the Crypto API, the Buffer implementation, and a `window.location` shim required for embedded wallets.

```ts polyfills.ts theme={"system"}
/**
 * Random values polyfill (crypto.getRandomValues).
 * Provides the secure native RNG that the SDK relies on.
 * Must load before anything that generates random values.
 */
import 'react-native-get-random-values';

/**
 * Buffer polyfill for Solana and various cryptographic operations.
 */
import { Buffer as BufferPolyfill } from 'buffer';

(globalThis as typeof globalThis & { Buffer: typeof BufferPolyfill }).Buffer =
  BufferPolyfill;

/**
 * crypto.randomUUID polyfill.
 * Hermes doesn't implement crypto.randomUUID, so we generate a v4 UUID
 * from crypto.getRandomValues (polyfilled above).
 */
type CryptoLike = {
  getRandomValues?: (array: Uint8Array) => Uint8Array;
  randomUUID?: () => string;
};

const globalWithCrypto = globalThis as typeof globalThis & {
  crypto?: CryptoLike;
};

if (!globalWithCrypto.crypto) {
  globalWithCrypto.crypto = {};
}

const cryptoRef = globalWithCrypto.crypto;

if (typeof cryptoRef.randomUUID !== 'function') {
  cryptoRef.randomUUID = () => {
    const bytes = new Uint8Array(16);
    // getRandomValues is guaranteed by the react-native-get-random-values import above
    cryptoRef.getRandomValues!(bytes);
    // Set the version (4) and variant bits required by RFC 4122
    bytes[6] = (bytes[6] & 0x0f) | 0x40;
    bytes[8] = (bytes[8] & 0x3f) | 0x80;
    const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');
    return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
  };
}

/**
 * window.location polyfill for Dynamic embedded wallets.
 * React Native has no window.location; the embedded wallet client reads
 * window.location.origin when loading the wallet page inside the SDK's
 * native WebView, and throws without this shim. Use the same value as
 * metadata.universalLink (configured later in createDynamicClient) so the
 * embedded wallet loads with your app's origin.
 */
type MinimalLocation = {
  origin: string;
  href: string;
  protocol: string;
  host: string;
  hostname: string;
  port: string;
  pathname: string;
  search: string;
  hash: string;
};

const globalWithLocation = globalThis as typeof globalThis & {
  location?: MinimalLocation;
};

// React Native's TypeScript config has no DOM lib, so the URL global
// (provided at runtime by React Native) needs an explicit type here
const globalWithUrl = globalThis as typeof globalThis & {
  URL: new (url: string) => MinimalLocation;
};

if (!globalWithLocation.location) {
  const appOriginUrl = new globalWithUrl.URL('https://example.com'); // Your app origin

  globalWithLocation.location = {
    origin: appOriginUrl.origin,
    href: appOriginUrl.href,
    protocol: appOriginUrl.protocol,
    host: appOriginUrl.host,
    hostname: appOriginUrl.hostname,
    port: appOriginUrl.port,
    pathname: appOriginUrl.pathname,
    search: appOriginUrl.search,
    hash: appOriginUrl.hash,
  };
}
```

<Note>
  Using WalletConnect? Install `@walletconnect/react-native-compat` and add `import '@walletconnect/react-native-compat';` as the **first** import in `polyfills.ts`, above the random-values shim — the WalletConnect relay client requires it to load before anything WalletConnect-related. See [WalletConnect integration](/docs/javascript/reference/wallets/walletconnect-integration).
</Note>

## Load the polyfills first

Import the polyfills as the **very first line** of your entry point (`index.js`), so they run before any other application logic:

```js index.js theme={"system"}
// Polyfills must run before any other import
import './polyfills';

import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';

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

## Configure the native projects

<Note>
  These steps configure native deep linking. The custom URL scheme and package visibility are needed whenever your app returns from an external app — **WalletConnect / external wallets** and **social (OAuth) login**. The JitPack repository and the `wc` scheme query are **WalletConnect-specific** — skip them if you don't use WalletConnect.
</Note>

### Register a deep link scheme

The SDK uses a custom URL scheme to return to your app after external wallet interactions and OAuth (social login) flows. Register the same scheme on both platforms (replace `myapp` with your own scheme).

Add to `ios/<YourApp>/Info.plist`:

```xml Info.plist theme={"system"}
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>
```

Add a second intent filter to your `MainActivity` in `android/app/src/main/AndroidManifest.xml`:

```xml AndroidManifest.xml theme={"system"}
<activity android:name=".MainActivity" ...>
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
  <!-- Custom scheme for WalletConnect / OAuth return deeplinks -->
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="myapp" />
  </intent-filter>
</activity>
```

### Declare Android package visibility

On Android 11+, apps must declare which URL schemes they intend to open. Add a `<queries>` block to `AndroidManifest.xml` (as a sibling of `<application>`) so the SDK can open wallet universal links and WalletConnect deeplinks:

```xml AndroidManifest.xml theme={"system"}
<queries>
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="https" />
  </intent>
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="wc" />
  </intent>
</queries>
```

### Add the JitPack Gradle repository (WalletConnect only)

`@walletconnect/react-native-compat` pulls a native artifact hosted on JitPack. Add `jitpack.io` to the repositories in `android/settings.gradle` (or `android/build.gradle`, depending on where your repositories are declared):

```groovy settings.gradle theme={"system"}
dependencyResolutionManagement {
  repositories {
    // ...existing repositories
    maven { url = uri("https://jitpack.io") }
  }
}
```

## Rebuild the native app

After adding native modules, reinstall pods and rebuild so the native code is linked.

```shell theme={"system"}
# iOS: install pods, then build
cd ios && bundle exec pod install && cd ..
npx react-native run-ios

# Android
npx react-native run-android
```

## Initialize the Dynamic client

Create a `dynamicClient.ts` file in your project root or a shared configuration folder. This client is your primary interface to the SDK.

```ts dynamicClient.ts theme={"system"}
import { createDynamicClient } from '@dynamic-labs-sdk/client';

export const dynamicClient = createDynamicClient({
  environmentId: 'YOUR_ENVIRONMENT_ID', // Found in your Dynamic dashboard
  metadata: {
    name: 'My App',
    nativeLink: 'myapp://', // Must match the scheme registered in Info.plist / AndroidManifest.xml
    universalLink: 'https://example.com', // Required for passkeys; same value as the window.location polyfill
  },
  /* Additional configuration options */
});
```

<Note>
  `metadata.universalLink` is required for passkey flows on React Native, and both links are used by WalletConnect to redirect back to your app — set them up front. For a full reference of the options, see [Creating a Dynamic Client](/docs/javascript/reference/client/create-dynamic-client) and [Initializing the Dynamic Client](/docs/javascript/reference/client/initialize-dynamic-client).
</Note>

## Next steps

Your bare React Native app is set up. From here, wrap your app in the React hooks provider, add the chains you support, and the rest of your integration works the same as on the web — the guides below apply unchanged unless they show a **Bare React Native** tab.

<CardGroup cols={2}>
  <Card title="Set up the React hooks" icon="react" href="/docs/javascript/reference/react-hooks">
    Wrap your app in `QueryClientProvider` and `DynamicProvider` to use the hooks.
  </Card>

  <Card title="Add the EVM extension" icon="puzzle-piece" href="/docs/javascript/reference/evm/adding-evm-extensions">
    Register EVM (or another chain) so the client can connect wallets and sign.
  </Card>

  <Card title="WalletConnect integration" icon="link" href="/docs/javascript/reference/wallets/walletconnect-integration">
    Connect external wallets over WalletConnect — see the **Bare React Native** tab for deep linking.
  </Card>

  <Card title="Authenticate with email" icon="envelope" href="/docs/javascript/authentication-methods/email">
    Send an email OTP and verify the user.
  </Card>

  <Card title="Build a wallet picker" icon="wallet" href="/docs/javascript/reference/wallets/build-wallet-picker">
    List wallet providers and connect a wallet.
  </Card>
</CardGroup>

<Tip>
  Running into issues? See [Troubleshooting](/docs/overview/troubleshooting/general) in the Overview docs.
</Tip>
