@unifold/connect-react-native
v0.1.43
Published
Unifold Connect React Native SDK - Crypto deposit and onramp for React Native/Expo
Readme
@unifold/connect-react-native
React Native/Expo SDK for crypto deposits and onramp with Unifold.
Installation
Native-linked libraries are peer dependencies so your app (or Expo) owns a single version. That avoids duplicate react-native-svg / react-native-webview installs and the overrides workarounds that come from nested copies.
# Expo (recommended) — versions aligned with your SDK
npx expo install @unifold/connect-react-native \
@react-native-async-storage/async-storage \
@stripe/stripe-react-native \
react-native-gesture-handler \
react-native-svg \
react-native-webview
# npm / yarn — install the same peers your Expo SDK would use
npm install @unifold/connect-react-native \
@react-native-async-storage/async-storage \
@stripe/stripe-react-native \
react-native-gesture-handler \
react-native-svg \
react-native-webviewiOS (bare React Native only)
cd ios && pod installStripe Link Pay (native)
Link Pay uses @stripe/stripe-react-native, which includes native code (Apple Pay, onramp Turbo Module). In Expo, add the Stripe config plugin to app.json (for example merchantIdentifier, enableApplePay, includeOnramp: true). You need a development build or EAS build — Expo Go does not ship Stripe’s onramp native module.
Importing @unifold/connect-react-native loads the Stripe UI registration in the same JS bundle as the provider. Ensure the peer dependencies in Installation above are installed so Metro does not duplicate native modules.
expo-constants is a dependency of @unifold/connect-react-native. The prebuilt bundle uses a static import from expo-constants (in the Stripe helper that reads the Expo plugin) so Metro always links the module. (A runtime require("expo-constants") in that path was still emitted inside the bundle and could trigger “unknown module” in Metro.) You can still set config.stripeMerchantIdentifier on UnifoldProvider to override or skip reading the plugin from constants.
Expo Go vs development build vs prebuild
- Expo Go is a generic client: it does not include this app’s Stripe onramp native code, so Link Pay / onramp will not work there. That is a limitation of Expo Go, not of “Expo” as a whole.
- A development build is your app binary (Stripe plugin + native modules baked in). Create it with
npx expo prebuild(generatesios//android/) and thennpx expo run:ios/run:android, or with EAS Build (eas build --profile development). Day to day you still useexpo startfor JS; only the installed app is custom, not Expo Go. - Simulator: A development build usually runs on the iOS Simulator without the same provisioning hassle as a physical device for many flows. Apple Pay can still be picky (wallet sheet, merchant validation); use a real device when Apple Pay misbehaves on the simulator, and ensure the merchant ID exists in your Apple Developer account and matches
app.json/ Stripe. - Certificates / signing: Debug builds for Simulator often work with Xcode automatic signing and a free Apple ID. Device distribution (TestFlight, App Store) needs your normal certificates and team. Apple Pay production behavior also depends on merchant configuration in Apple and Stripe dashboards—not only the simulator.
Integration checklist
- Peer dependencies — Install everything in Installation (or
expo install …). Missing peers often show up as duplicate native modules or Metro resolution errors. react-native-gesture-handler— In bare React Native, import it at the entry file first (see React Navigation); Expo Router projects usually already satisfy this.UnifoldProviderplacement — Wrap near the root sobeginDepositand theme context are available app-wide. CallsetDevApiUrlbefore the provider if you use staging in development (see example app).- Stripe Link Pay — Requires a development / EAS build on Expo (not Expo Go), the Stripe config plugin in
app.json, andconfig.enableStripeLinkPay: true. Apple Pay needs a matchingmerchantIdentifier(plugin and/orconfig.stripeMerchantIdentifier; Expo apps can rely on plugin +expo-constantsauto-read inStripeOnramp). - Theme —
UnifoldProviderappliesThemeProviderto all children. If you use another theme system, nest it inside or outside deliberately souseThemeresolves as you expect.
Quick Start
1. Wrap your app with UnifoldProvider
import { UnifoldProvider } from '@unifold/connect-react-native';
export default function App() {
return (
<UnifoldProvider
publishableKey="pk_live_your_key"
config={{
appearance: 'dark', // 'light' | 'dark' | 'auto'
}}
>
<YourApp />
</UnifoldProvider>
);
}2. Launch the deposit flow
import { useUnifold } from '@unifold/connect-react-native';
import { Button, View } from 'react-native';
function DepositScreen() {
const { beginDeposit } = useUnifold();
const handleDeposit = async () => {
try {
const result = await beginDeposit({
externalUserId: 'user_123',
destinationChainType: 'ethereum',
destinationChainId: '137', // Polygon
destinationTokenAddress: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
destinationTokenSymbol: 'USDC',
recipientAddress: '0x...user_wallet_address',
onSuccess: (data) => {
console.log('Deposit successful:', data);
},
onError: (error) => {
console.error('Deposit error:', error);
},
});
console.log('Deposit completed:', result);
} catch (error) {
// User cancelled the deposit flow
console.log('Deposit cancelled');
}
};
return (
<View>
<Button title="Deposit Crypto" onPress={handleDeposit} />
</View>
);
}Theming & Customization
The SDK provides comprehensive theming options. For full documentation, see docs/theming.mdx.
Quick Theme Setup
<UnifoldProvider
publishableKey="pk_live_..."
config={{
appearance: "dark", // 'light' | 'dark' | 'auto'
accentColor: "#8B5CF6", // Brand color
// Custom fonts (must be loaded by your app)
fonts: {
regular: "Inter-Regular",
medium: "Inter-Medium",
semibold: "Inter-SemiBold",
},
// Full color customization
theme: {
dark: {
primary: "#8B5CF6",
background: "#0F0F10",
card: "#1A1A1D",
}
},
// Granular component overrides
components: {
header: { titleColor: "#FFFFFF" },
card: { backgroundColor: "#1A1A1D" },
},
// Bottom sheet corner radius
sheetBorderRadius: {
globalBorderTopLeftRadius: 24, // Default for all sheets
globalBorderTopRightRadius: 24,
main: { borderTopLeftRadius: 0, borderTopRightRadius: 0 },
buyWithCard: { borderTopLeftRadius: 16, borderTopRightRadius: 16 },
},
}}
>Pre-selecting Source Token
await beginDeposit({
externalUserId: "user_123",
// ... destination params
// Pre-select USDC on Polygon as the source token
defaultChainType: "ethereum",
defaultChainId: "137",
defaultTokenAddress: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
});API Reference
UnifoldProvider
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| publishableKey | string | Yes | Your Unifold publishable key |
| config.appearance | 'light' \| 'dark' \| 'auto' | No | Theme mode (default: 'dark') |
| config.modalTitle | string | No | Custom modal title |
| config.hideDepositTracker | boolean | No | Hide the deposit tracker button |
| config.transferInputVariant | 'single_input' \| 'double_input' | No | Token selector style (default: 'double_input') |
| config.accentColor | string | No | Primary brand color |
| config.theme | ThemeConfig | No | Full color customization |
| config.fontFamily | string | No | Single font family for all text |
| config.fonts | FontConfig | No | Granular font weight configuration |
| config.components | ComponentConfig | No | Component-specific token overrides |
| config.sheetBorderRadius | SheetBorderRadius | No | Border radius configuration for all bottom sheets (see below) |
| config.enableStripeLinkPay | boolean | No | Show Pay with Link (Stripe) in the deposit menu (default: omit / falsy hides it). Stripe is bundled with Connect. |
| config.stripeMerchantIdentifier | string | No | Apple Pay merchant id for Link Pay. Must match the Stripe Expo plugin in app.json. On Expo, omit if the id is only in the plugin (read from expo-constants). |
SheetBorderRadius
Configure the border radius of all bottom sheets. Set global defaults and optionally override individual sheets. Per-component values accept { borderTopLeftRadius?: number, borderTopRightRadius?: number } and fall back to the global values, then to the default of 24.
| Key | Type | Description |
|-----|------|-------------|
| globalBorderTopLeftRadius | number | Default top-left radius for all sheets (default: 24) |
| globalBorderTopRightRadius | number | Default top-right radius for all sheets (default: 24) |
| main | BorderRadiusConfig | The main deposit modal |
| transferCrypto | BorderRadiusConfig | Transfer crypto wrapper sheet |
| buyWithCard | BorderRadiusConfig | Buy with card wrapper sheet |
| depositsTracker | BorderRadiusConfig | Deposits tracker modal |
| tokenSelector | BorderRadiusConfig | Token selector (inside transfer crypto) |
| chainSelector | BorderRadiusConfig | Chain selector (inside transfer crypto, double_input variant) |
| currencyModal | BorderRadiusConfig | Currency selector (inside buy with card) |
| providerModal | BorderRadiusConfig | Provider selection (inside buy with card) |
| depositStatus | BorderRadiusConfig | Deposit status sheet |
| infoSheet | BorderRadiusConfig | Price impact & slippage info sheet |
| webView | BorderRadiusConfig | WebView sheet (inside buy with card) |
// Example: sharp top corners everywhere, except currency modal gets rounded
<UnifoldProvider
publishableKey="pk_live_..."
config={{
sheetBorderRadius: {
globalBorderTopLeftRadius: 0,
globalBorderTopRightRadius: 0,
currencyModal: { borderTopLeftRadius: 16, borderTopRightRadius: 16 },
},
}}
>useUnifold Hook
const { beginDeposit, closeDeposit, publishableKey } = useUnifold();| Method | Type | Description |
|--------|------|-------------|
| beginDeposit | (config: DepositConfig) => Promise<DepositResult> | Opens the deposit modal and returns a promise |
| closeDeposit | () => void | Programmatically close the deposit modal |
| publishableKey | string | The configured publishable key |
DepositConfig
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| externalUserId | string | Yes | Your user's unique identifier |
| destinationChainType | 'ethereum' \| 'solana' \| 'bitcoin' | No | Target blockchain type |
| destinationChainId | string | No | Target chain ID (e.g., '137' for Polygon) |
| destinationTokenAddress | string | No | Target token contract address |
| destinationTokenSymbol | string | No | Target token symbol (e.g., 'USDC') |
| recipientAddress | string | No | Wallet address to receive funds |
| stripeOnrampEmail | string | No | Pre-fills Stripe Link Pay email when user opens Pay with Stripe Link from the deposit menu |
| stripeOnrampPhone | string | No | Pre-fills Stripe Link Pay phone (use with stripeOnrampEmail per Stripe’s flow) |
| defaultChainType | 'ethereum' \| 'solana' \| 'bitcoin' | No | Pre-select source network type |
| defaultChainId | string | No | Pre-select source chain ID |
| defaultTokenAddress | string | No | Pre-select source token address |
| onSuccess | (data: DepositResult) => void | No | Called when deposit succeeds |
| onError | (error: DepositError) => void | No | Called when an error occurs |
DepositResult
interface DepositResult {
message: string;
transaction?: unknown;
executionId?: string;
}DepositError
interface DepositError {
message: string;
error?: unknown;
code?: string; // e.g., 'DEPOSIT_CANCELLED' when user closes modal
}TypeScript
Full TypeScript support is included. Import types as needed:
import type {
DepositConfig,
DepositResult,
DepositError,
ThemeMode,
ThemeConfig,
FontConfig,
ComponentConfig,
BorderRadiusConfig,
UnifoldProviderProps,
} from '@unifold/connect-react-native';Requirements
| Dependency | Version |
|------------|---------|
| React Native | >= 0.72.0 |
| Expo (optional) | >= 49.0.0 |
| @react-native-async-storage/async-storage | >= 1.19.0 |
| @stripe/stripe-react-native | >= 0.62.0 |
| react-native-gesture-handler | >= 2.14.0 |
| react-native-svg | >= 13.0.0 |
| react-native-webview | >= 13.0.0 |
| expo-constants | Installed with Connect (>= 14) — mirrors merchantIdentifier from the Stripe Expo plugin into JS; optional override via config.stripeMerchantIdentifier |
Support
- Documentation: https://docs.unifold.io
- Issues: GitHub Issues
License
MIT © Unifold
