Complete guide to integrating Phantom Connect in a React Native app.
1. Install dependencies
npm install @phantom/react-native-sdk @solana/web3.js
# Required polyfill for cryptographic operations
npm install react-native-get-random-values
# Install peer dependencies
npx expo install expo-secure-store expo-web-browser expo-auth-session react-native-svg
If you’re using Expo, use npx expo install to ensure compatibility. For bare React Native projects, you can install the packages directly with npm.
Add your custom scheme to app.json:
{
"expo": {
"name": "My App",
"slug": "my-app",
"scheme": "myapp",
"plugins": [
"expo-router",
"expo-secure-store",
"expo-web-browser",
"expo-auth-session"
]
}
}
3. Create the app entry point
The polyfill must be the first import:
The react-native-get-random-values import must be the very first import in your app’s entry point, before any other imports.
With Expo Router
// app/_layout.tsx
import "react-native-get-random-values"; // Must be first!
import { Stack } from "expo-router";
import { PhantomProvider, AddressType, darkTheme } from "@phantom/react-native-sdk";
export default function Layout() {
return (
<PhantomProvider
config={{
providers: ["google", "apple"],
appId: "your-app-id", // Get from phantom.com/portal
scheme: "myapp",
addressTypes: [AddressType.solana],
authOptions: {
redirectUrl: "myapp://phantom-auth-callback",
},
}}
theme={darkTheme}
appName="My App"
>
<Stack />
</PhantomProvider>
);
}
Without Expo Router
// App.tsx or index.js
import "react-native-get-random-values"; // Must be first!
import React from "react";
import { PhantomProvider, AddressType, darkTheme } from "@phantom/react-native-sdk";
import { WalletScreen } from "./WalletScreen";
export default function App() {
return (
<PhantomProvider
config={{
providers: ["google", "apple"],
appId: "your-app-id", // Get from phantom.com/portal
scheme: "myapp",
addressTypes: [AddressType.solana],
authOptions: {
redirectUrl: "myapp://phantom-auth-callback",
},
}}
theme={darkTheme}
appName="My App"
>
<WalletScreen />
</PhantomProvider>
);
}
4. Create the wallet screen
// WalletScreen.tsx
import React from "react";
import { View, Text, Button, StyleSheet, Alert } from "react-native";
import {
useModal,
usePhantom,
useAccounts,
useDisconnect,
useSolana,
} from "@phantom/react-native-sdk";
export function WalletScreen() {
const { open } = useModal();
const { isConnected } = usePhantom();
const addresses = useAccounts();
const { disconnect } = useDisconnect();
const { solana } = useSolana();
if (isConnected && addresses) {
return (
<View style={styles.container}>
<Text style={styles.title}>Wallet Connected</Text>
<Text style={styles.address}>{addresses[0]?.address}</Text>
<Button
title="Sign Message"
onPress={async () => {
try {
const { signature } = await solana.signMessage("Hello!");
Alert.alert("Success", `Signature: ${signature.slice(0, 10)}...`);
} catch (error) {
Alert.alert("Error", error instanceof Error ? error.message : "Failed to sign");
}
}}
/>
<Button
title="Disconnect"
onPress={() => disconnect()}
/>
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome</Text>
<Button title="Connect Wallet" onPress={open} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
},
title: {
fontSize: 24,
marginBottom: 20,
fontWeight: "bold",
},
address: {
fontSize: 14,
marginBottom: 20,
color: "#666",
},
});
- Go to phantom.com/portal
- Create or select your app
- Add your redirect URL (e.g.,
myapp://phantom-auth-callback) to redirect URLs
- Copy your App ID