
Product
Reachability for Ruby Now in Beta
Reachability analysis for Ruby is now in beta, helping teams identify which vulnerabilities are truly exploitable in their applications.
@zbdpay/ramp-react-native
Advanced tools
React Native wrapper for ZBD Ramp widget that enables Bitcoin Lightning Network payments in React Native applications.
useZBDRamp hook for programmatic usagenpm install @zbdpay/ramp-react-native react-native-webview
# or
yarn add @zbdpay/ramp-react-native react-native-webview
1. Install CocoaPods dependencies:
cd ios && pod install
2. Add Privacy Permissions to Info.plist:
Add the following entries to your ios/{YourAppName}/Info.plist:
<!-- Essential permissions for ZBD Ramp WebView -->
<key>NSCameraUsageDescription</key>
<string>ZBD Ramp needs camera access for document verification and identity verification processes.</string>
<key>NSMicrophoneUsageDescription</key>
<string>ZBD Ramp needs microphone access for liveness detection during identity verification.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>ZBD Ramp needs photo library access to upload documents for verification purposes.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>ZBD Ramp may save verification photos to your photo library.</string>
Note: These permissions are required for the ZBD Ramp widget to access device features like camera (document verification) and microphone (liveness detection) within the WebView context. You can customize the permission descriptions to match your app's language and privacy policy.
Add the following permissions to your android/app/src/main/AndroidManifest.xml:
<!-- Essential permissions for ZBD Ramp WebView -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
These permissions are required to prevent permissions_unavailable errors that can occur when the ZBD Ramp widget tries to access device features (camera for document verification, microphone for liveness detection, etc.) within the WebView context.
# Clone the repository
git clone <repository-url>
cd ramp-iframe/ramp-react-native
# Install package dependencies (for the wrapper package)
npm install
# Navigate to example React Native app
cd example
# Install example app dependencies
npm install
# For iOS - install pods
cd ios && pod install && cd ..
The repository includes a complete React Native example app in the example/ folder:
# Navigate to example app
cd example
# Install example dependencies
npm install
# For iOS - install pods
cd ios && pod install && cd ..
# Start Metro bundler (in separate terminal)
npm start
# iOS (in another terminal)
npm run ios
# Android (in another terminal)
npm run android
The example app provides:
To integrate ZBD Ramp into your existing React Native app:
# Install the package
npm install @zbdpay/ramp-react-native react-native-webview
# For iOS - install pods
cd ios && pod install && cd ..
Then import and use in your app:
import { ZBDRamp } from '@zbdpay/ramp-react-native';
<ZBDRamp
sessionToken="your-session-token"
onSuccess={(data) => console.log('Success:', data)}
onError={(error) => console.error('Error:', error)}
style={{ flex: 1 }}
/>
First, create a session token using the built-in initRampSession function:
import { initRampSession, QuoteCurrencyEnum, BaseCurrencyEnum } from '@zbdpay/ramp-react-native';
// Using email authentication
const response = await initRampSession({
apikey: 'your-zbd-api-key',
email: 'user@example.com',
destination: 'lightning-address-or-username',
quote_currency: QuoteCurrencyEnum.USD,
base_currency: BaseCurrencyEnum.BTC,
webhook_url: 'https://your-webhook-url.com',
});
// Or using access token authentication
const response = await initRampSession({
apikey: 'your-zbd-api-key',
access_token: 'user-access-token',
destination: 'lightning-address-or-username',
quote_currency: QuoteCurrencyEnum.USD,
base_currency: BaseCurrencyEnum.BTC,
webhook_url: 'https://your-webhook-url.com',
});
const sessionToken = response.data.session_token;
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { ZBDRamp } from '@zbdpay/ramp-react-native';
function App() {
return (
<View style={styles.container}>
<ZBDRamp
sessionToken="your-session-token"
onSuccess={(data) => console.log('Success:', data)}
onError={(error) => console.error('Error:', error)}
onStepChange={(step) => console.log('Step:', step)}
style={styles.webview}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
webview: {
flex: 1,
},
});
Enable debugging by adding logging callbacks and WebView event handlers:
<ZBDRamp
sessionToken="your-session-token"
onLog={(log) => {
console.log(`[${log.level.toUpperCase()}] ${log.message}`, log.data);
}}
webViewProps={{
// Enable debugging
onLoadStart={() => console.log('WebView load started')}
onLoadEnd={() => console.log('WebView load ended')}
onError={(error) => console.error('WebView error:', error)}
}}
/>
If you're using access token authentication, you can refresh expired tokens using the refreshAccessToken function:
import { refreshAccessToken } from '@zbdpay/ramp-react-native';
const handleRefreshToken = async () => {
try {
const response = await refreshAccessToken({
apikey: 'your-zbd-api-key',
access_token_id: 'user-access-token-id',
refresh_token: 'user-refresh-token',
});
if (response.success) {
const newAccessToken = response.data.access_token;
const newRefreshToken = response.data.refresh_token;
// Store the new tokens securely
console.log('Token refreshed successfully');
} else {
console.error('Token refresh failed:', response.error);
}
} catch (error) {
console.error('Error refreshing token:', error);
}
};
React Native component that renders the ZBD Ramp widget using WebView.
interface ZBDRampProps {
sessionToken: string; // Required: Session token from ZBD API
style?: WebViewProps['style']; // WebView style
webViewProps?: Omit<WebViewProps, 'source' | 'onMessage' | 'style'>; // Additional WebView props
// Callbacks
onSuccess?: (data: any) => void; // Payment successful
onError?: (error: RampError) => void; // Error occurred
onStepChange?: (step: string) => void; // User navigated to different step
onLog?: (log: RampLog) => void; // Debug/info logging
onReady?: () => void; // Widget fully loaded
onClose?: () => void; // User closed widget
}
interface ZBDRampRef {
mount: (container?: HTMLElement | string) => void;
unmount: () => void;
destroy: () => void;
}
Hook for managing ZBD Ramp instances programmatically.
const { rampRef, sendMessage, updateConfig, reload } = useZBDRamp(options);
import React from 'react';
import { View, StyleSheet, Alert } from 'react-native';
import { ZBDRamp } from '@zbdpay/ramp-react-native';
function PaymentScreen() {
const handleSuccess = (data: any) => {
Alert.alert('Success', 'Payment completed successfully!');
console.log('Payment data:', data);
};
const handleError = (error: any) => {
Alert.alert('Error', error.message);
console.error('Payment error:', error);
};
return (
<View style={styles.container}>
<ZBDRamp
sessionToken="your-session-token"
onSuccess={handleSuccess}
onError={handleError}
style={styles.webview}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
webview: {
flex: 1,
backgroundColor: 'transparent',
},
});
import React, { useRef } from 'react';
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';
import { ZBDRamp } from '@zbdpay/ramp-react-native';
import type { ZBDRampRef } from '@zbdpay/ramp-react-native';
function ControlledPayment() {
const rampRef = useRef<ZBDRampRef>(null);
const unmountWidget = () => {
rampRef.current?.unmount();
};
const destroyWidget = () => {
rampRef.current?.destroy();
};
return (
<View style={styles.container}>
<View style={styles.controls}>
<TouchableOpacity style={styles.button} onPress={unmountWidget}>
<Text style={styles.buttonText}>Unmount</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={destroyWidget}>
<Text style={styles.buttonText}>Destroy</Text>
</TouchableOpacity>
</View>
<ZBDRamp
ref={rampRef}
sessionToken="your-session-token"
onSuccess={(data) => console.log('Success:', data)}
onError={(error) => console.error('Error:', error)}
style={styles.webview}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
controls: {
flexDirection: 'row',
justifyContent: 'space-around',
padding: 10,
backgroundColor: '#fff',
},
button: {
backgroundColor: '#ff6b35',
paddingHorizontal: 15,
paddingVertical: 8,
borderRadius: 4,
},
buttonText: {
color: 'white',
fontSize: 12,
fontWeight: 'bold',
},
webview: {
flex: 1,
},
});
import React, { useState } from 'react';
import { View, TouchableOpacity, Text, StyleSheet, Modal } from 'react-native';
import { ZBDRamp, useZBDRamp } from '@zbdpay/ramp-react-native';
function HookExample() {
const [isVisible, setIsVisible] = useState(false);
const { rampRef, sendMessage, updateConfig, reload } = useZBDRamp({
sessionToken: 'your-session-token',
onSuccess: (data) => {
console.log('Payment successful:', data);
setIsVisible(false);
},
onClose: () => {
setIsVisible(false);
},
});
const openPayment = () => {
setIsVisible(true);
};
const closePayment = () => {
setIsVisible(false);
};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.openButton} onPress={openPayment}>
<Text style={styles.buttonText}>Open Payment</Text>
</TouchableOpacity>
<Modal visible={isVisible} animationType="slide">
<View style={styles.modalContainer}>
<View style={styles.modalHeader}>
<TouchableOpacity onPress={closePayment}>
<Text style={styles.closeButton}>Close</Text>
</TouchableOpacity>
</View>
<ZBDRamp
ref={rampRef}
sessionToken="your-session-token"
onSuccess={(data) => {
console.log('Success:', data);
setIsVisible(false);
}}
style={styles.webview}
/>
</View>
</Modal>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
openButton: {
backgroundColor: '#ff6b35',
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
modalContainer: {
flex: 1,
},
modalHeader: {
flexDirection: 'row',
justifyContent: 'flex-end',
padding: 15,
backgroundColor: '#f8f8f8',
},
closeButton: {
fontSize: 16,
color: '#007AFF',
},
webview: {
flex: 1,
},
});
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { ZBDRamp } from '@zbdpay/ramp-react-native';
function CustomWebViewRamp() {
return (
<View style={styles.container}>
<ZBDRamp
sessionToken="your-session-token"
style={styles.webview}
webViewProps={{
bounces: false,
scrollEnabled: false,
showsHorizontalScrollIndicator: false,
showsVerticalScrollIndicator: false,
allowsBackForwardNavigationGestures: false,
userAgent: 'MyApp/1.0',
}}
onSuccess={(data) => console.log('Success:', data)}
onError={(error) => console.error('Error:', error)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
webview: {
flex: 1,
backgroundColor: '#ffffff',
},
});
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Alert } from 'react-native';
import { ZBDRamp } from '@zbdpay/ramp-react-native';
import type { RampError } from '@zbdpay/ramp-react-native';
function PaymentWithErrorHandling() {
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
const handleError = (error: RampError) => {
setIsLoading(false);
let errorMessage = 'An unexpected error occurred.';
switch (error.code) {
case 'INVALID_CONFIG':
errorMessage = 'Configuration error. Please check your settings.';
break;
case 'NETWORK_ERROR':
errorMessage = 'Network error. Please check your connection.';
break;
case 'PAYMENT_FAILED':
errorMessage = 'Payment failed. Please try again.';
break;
}
setError(errorMessage);
Alert.alert('Payment Error', errorMessage);
};
const handleReady = () => {
setIsLoading(false);
setError(null);
};
const retry = () => {
setError(null);
setIsLoading(true);
};
return (
<View style={styles.container}>
{isLoading && (
<View style={styles.loadingContainer}>
<Text>Loading payment widget...</Text>
</View>
)}
{error && (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error}</Text>
<TouchableOpacity style={styles.retryButton} onPress={retry}>
<Text style={styles.retryButtonText}>Retry</Text>
</TouchableOpacity>
</View>
)}
{!error && (
<ZBDRamp
sessionToken="your-session-token"
onReady={handleReady}
onError={handleError}
onSuccess={() => {
setError(null);
Alert.alert('Success', 'Payment completed!');
}}
style={styles.webview}
/>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
errorText: {
color: 'red',
textAlign: 'center',
marginBottom: 20,
fontSize: 16,
},
retryButton: {
backgroundColor: '#ff6b35',
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 8,
},
retryButtonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
webview: {
flex: 1,
},
});
The package includes comprehensive TypeScript definitions:
import type {
ZBDRampProps,
ZBDRampRef,
RampConfig,
RampCallbacks,
RampOptions,
RampError,
RampLog,
PostMessageData,
InitRampSessionConfig,
InitRampSessionData,
InitRampSessionResponse,
RefreshAccessTokenConfig,
RefreshAccessTokenData,
RefreshAccessTokenResponse,
QuoteCurrencyEnum,
BaseCurrencyEnum,
} from '@zbdpay/ramp-react-native';
@zbdpay/ramp-ts - Core TypeScript/JavaScript package@zbdpay/ramp-reactzbd_ramp_flutterMIT License - see the LICENSE file for details.
For support, email dev@zbdpay.com or create an issue on GitHub.
FAQs
React Native wrapper for ZBD Ramp widget
We found that @zbdpay/ramp-react-native demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Reachability analysis for Ruby is now in beta, helping teams identify which vulnerabilities are truly exploitable in their applications.

Research
/Security News
Malicious npm packages use Adspect cloaking and fake CAPTCHAs to fingerprint visitors and redirect victims to crypto-themed scam sites.

Security News
Recent coverage mislabels the latest TEA protocol spam as a worm. Here’s what’s actually happening.