Phantom Embedded React Native Starter

Phantom Embedded React Native Starter
A minimal Expo starter template for integrating Phantom's embedded user wallets on Solana for mobile apps.
โจ Features
- ๐ Phantom Connect Authentication - Secure OAuth-based wallet connection
- ๐ Embedded User Wallet - No browser extension required
- ๐ฐ Solana Balance Display - Real-time SOL balance fetching
- ๐ Address Management - Copy wallet address to clipboard
- ๐ Balance Refresh - Manual balance updates
- ๐ช Disconnect Functionality - Clean session management
- ๐ฑ Mobile-First Design - Optimized for iOS and Android
- ๐จ Dark Theme UI - Beautiful Phantom-branded interface
๐จ Important: Development Builds Required
This template requires a custom development build and will NOT work with Expo Go.
The Phantom React Native SDK requires native modules that are not available in Expo Go. You must create a development build to test this app.
๐ Prerequisites
Before you begin, ensure you have:
- Node.js 18+ installed
- pnpm package manager (
npm install -g pnpm) - Expo CLI (
npm install -g expo-cli) - iOS Simulator (macOS) or Android Emulator set up
- Phantom App ID from Phantom Portal
๐ Quick Start
1. Install Dependencies
pnpm install2. Configure Environment Variables
Copy the example environment file and add your Phantom App ID:
cp .env.example .envEdit .env and add your Phantom App ID:
EXPO_PUBLIC_PHANTOM_APP_ID=your-app-id-here
EXPO_PUBLIC_APP_SCHEME=your-app-scheme
EXPO_PUBLIC_SOLANA_RPC_URL=your-prefered-rpc3. Get Your Phantom App ID
- Visit Phantom Portal
- Sign in with your Phantom wallet
- Create a new app or use an existing one
- Copy your App ID (not Organization ID)
- Add the redirect URI:
phantomwallet://phantom-auth-callback
4. Create Development Build
For iOS:
pnpm run iosThis will:
- Run
expo prebuildto generate native code - Install iOS dependencies via CocoaPods
- Build and launch the app in iOS Simulator
For Android:
pnpm run androidThis will:
- Run
expo prebuildto generate native code - Build and launch the app in Android Emulator
๐ง Configuration
URL Scheme
The URL scheme is critical for OAuth deep linking. It must match in two places:
1. app.json:
{
"expo": {
"scheme": "phantomwallet"
}
}2. .env file:
EXPO_PUBLIC_APP_SCHEME=phantomwalletThe complete redirect URI will be: phantomwallet://phantom-auth-callback
Solana RPC Endpoint
By default, the app uses Solana mainnet-beta. You can customize the RPC endpoint:
EXPO_PUBLIC_SOLANA_RPC_URL=https://api.devnet.solana.comFor production apps, consider using a dedicated RPC provider like:
๐ Project Structure
phantom-embedded-react-native-starter/
โโโ app/
โ โโโ _layout.tsx # Root layout with PhantomProvider
โ โโโ index.tsx # Home screen (connect button)
โ โโโ wallet.tsx # Wallet screen (account info)
โโโ components/
โ โโโ ConnectButton.tsx # Phantom Connect button
โ โโโ WalletInfo.tsx # Wallet details display
โ โโโ LoadingSpinner.tsx # Reusable loading component
โโโ lib/
โ โโโ solana.ts # Solana balance fetching
โ โโโ utils.ts # Utility functions
โโโ assets/ # App icons and images
โโโ app.json # Expo configuration
โโโ package.json # Dependencies
โโโ tsconfig.json # TypeScript config
โโโ .env.example # Environment variables templateKey Files Explained
app/_layout.tsx
CRITICAL: The polyfill import MUST be first!
// THIS MUST BE THE FIRST IMPORT!
import 'react-native-get-random-values'
import { PhantomProvider, AddressType } from '@phantom/react-native-sdk'This file:
- Sets up the PhantomProvider with your App ID
- Configures the URL scheme for OAuth callbacks
- Defines the navigation structure
components/ConnectButton.tsx
Handles Phantom Connect authentication using the useConnect() hook. On successful connection, navigates to the wallet screen.
components/WalletInfo.tsx
Displays connected wallet information:
- Solana address (truncated)
- SOL balance with refresh
- Copy address functionality
- Disconnect button
lib/solana.ts
Solana blockchain interaction:
- Connects to Solana RPC
- Fetches wallet balance
- Converts lamports to SOL
๐ Deep Linking
The app uses deep linking for OAuth callbacks. Here's how it works:
- User taps "Connect with Phantom"
- App opens Phantom Connect in browser
- User authenticates with Phantom
- Phantom redirects back to app via:
phantomwallet://phantom-auth-callback - SDK handles the callback and creates session
Troubleshooting Deep Links
If deep linking isn't working:
- Check URL scheme matches in
app.jsonand.env - Verify App ID is correct in
.env - Ensure redirect URI is added in Phantom Portal
- Rebuild the app after changing
app.json
๐งช Testing on Physical Devices
iOS Device
Create a development build:
pnpm run ios --deviceOr build with EAS:
eas build --profile development --platform iosInstall the build on your device
Android Device
Enable USB debugging on your device
Connect device via USB
Run:
pnpm run android --device
๐ ๏ธ Development
Start Development Server
pnpm startThis opens the Expo development server. Press:
ito open iOS Simulatorato open Android Emulatorrto reload the app
Clear Cache
If you encounter issues:
pnpm start --clear๐ API Reference
Phantom Hooks
useConnect()
Initiates Phantom Connect flow:
const { connect, isLoading } = useConnect()
await connect()useAccounts()
Returns array of connected accounts:
const accounts = useAccounts()
const solanaAccount = accounts?.[0]useDisconnect()
Disconnects the current session:
const { disconnect, isLoading } = useDisconnect()
await disconnect()Custom Functions
getBalance(address: string)
Fetches SOL balance for an address:
import { getBalance } from '@/lib/solana'
const balance = await getBalance('5eykt...3j9ss')
console.log(`Balance: ${balance} SOL`)truncateAddress(address: string, chars?: number)
Truncates long addresses for display:
import { truncateAddress } from '@/lib/utils'
const short = truncateAddress('5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp...', 4)
// Returns: "5eyk...j9ss"๐ Troubleshooting
"Module not found: react-native-get-random-values"
Solution: Ensure the polyfill is imported first in app/_layout.tsx.
"Invalid appId"
Solution:
- Check your App ID in
.env - Ensure you're using
appId, NOTorganizationId - Verify the App ID in Phantom Portal
"Deep linking not working"
Solution:
- Rebuild the app after changing URL scheme
- Verify redirect URI in Phantom Portal
- Check
app.jsonand.envmatch
"Failed to fetch balance"
Solution:
- Check RPC endpoint is reachable
- Verify wallet address is valid
- Try using a different RPC provider
"Expo Go not working"
Expected behavior. Expo Go doesn't support the native modules required by Phantom SDK. You must create a development build.
๐ Security Best Practices
- Never commit
.env- Keep your App ID private - Use environment variables - Don't hardcode sensitive values
- Validate user input - Always check wallet addresses
- Handle errors gracefully - Provide user-friendly error messages
- Use HTTPS RPC endpoints - Ensure secure connections
๐ Resources
๐ฌ Support
- Phantom Discord: discord.gg/phantom
- Phantom Twitter: @phantom
- Report Issues: GitHub Issues
โก Next Steps
After getting the starter working:
- Add Transaction Signing - Use
useSignTransaction()hook - Implement Message Signing - Use
useSignMessage()hook - Multi-Chain Support - Add Ethereum, Polygon, etc.
- Token Balances - Fetch SPL token balances
- NFT Display - Show user's NFT collection
- Custom Styling - Match your brand colors
- Error Handling - Add comprehensive error handling
- Analytics - Track user interactions
- Production RPC - Use a dedicated RPC provider
- Testing - Add unit and integration tests
๐ Success!
You now have a working Phantom embedded wallet integration! Your users can:
โ
Connect with Phantom using OAuth
โ
View their Solana wallet address
โ
Check their SOL balance
โ
Copy their address
โ
Disconnect their wallet
Build something amazing! ๐
