React Native wrapper for the Onramper iOS SDK.
iOS only. Constructing an
OnramperClienton a non-iOS platform throws immediately with a clear "iOS-only in this release" error. A native Android SDK is not part of this release, and no Android native code is shipped.
npm install @onramper/onramper-react-native react-native-nitro-modules
cd ios && pod installRequires React Native 0.79+, react-native-nitro-modules 0.35+, the New Architecture, and an iOS 16.0+ deployment target. Works in bare React Native (no Expo required) and Expo apps — not Expo Go, since the package vendors a native binary.
Expo apps — add the bundled config plugin to app.json, then prebuild:
{ "expo": { "plugins": ["@onramper/onramper-react-native"] } }The plugin applies the required iOS build flag (it does not change your deployment target). Set your app's deployment target to 16.4+ — Expo SDK 56's own minimum (bare RN only needs 16.0). For bare-RN Podfile setup (Xcode 16+/26) and full details, see the integration guide.
import { OnramperClient } from '@onramper/onramper-react-native';
const client = new OnramperClient({
apiKey: 'pk_live_...',
clientId: '01K...',
environment: 'production',
// Fully async — fetch fresh credentials when the SDK asks.
onSessionExpired: async () => {
const r = await fetch('/api/onramper-session', { method: 'POST' });
return r.json();
},
});
await client.initialize({ sessionId, sessionToken });
const { button, quote } = await client.getCheckoutRequirements({
source: 'usd',
destination: 'eth',
amount: 100,
type: 'buy',
paymentMethod: 'creditcard',
wallet: { network: 'ethereum', address: '0x...' },
});
return (
<View>
<Text>Rate: {quote.rate ?? 'unavailable'}</Text>
{button}
</View>
);The button renders natively and presents login + payment sheets internally. ToS is rendered inside the button view.
The SwiftUI OnramperCheckoutButton does not expose external callback hooks; checkout outcomes flow via the module-level event stream:
const unsub = client.addEventListener('completed', (e) => {
console.log('done:', e.checkoutId);
});
const onFailed = client.addEventListener('failed', (e) => {
console.log('failed:', e.error.code, e.error.message);
});All native errors arrive as OnramperError with a typed code:
import { OnramperError } from '@onramper/onramper-react-native';
try {
await client.initialize({ sessionId, sessionToken });
} catch (e) {
if (e instanceof OnramperError) {
switch (e.code) {
case 'deviceBlocked':
case 'amountOutOfRange':
// ...
}
}
}Full code list in src/errors.ts.
@onramper/onramper-react-native@X.Y.Z always bundles OnramperSDK@X.Y.Z (iOS). Wrapper-only patches are published as X.Y.Z-N pre-releases (npm install @onramper/onramper-react-native@next to opt in).
The vendored OnramperSDK.xcframework already ships its own PrivacyInfo.xcprivacy. Don't add a duplicate.
- Native checkout outcomes are observed via the module-level event stream (
client.addEventListener(...)); the native checkout button exposes no per-instance callbacks.
pod installfails finding the xcframework — confirmnode_modules/@onramper/onramper-react-native/ios/Frameworks/OnramperSDK.xcframework/exists.- Bare RN build fails with
module map file ... not found(Xcode 16+/26) — disable explicit Swift modules in yourPodfilepost_install(SWIFT_ENABLE_EXPLICIT_MODULES = NO). Expo apps get this automatically via the config plugin. See the integration guide. - App Attest errors in simulator — expected. App Attest only works on real devices. The SDK surfaces this as
attestationFailed. - Buttons appear but sheets don't open — the host RN screen must be inside a normal
UIViewController(the default). Modal-presented screens may need extra care; report an issue with a repro.