A modern, maintained Razorpay SDK for Expo and React Native.
Built as a community replacement for the outdated official Razorpay React Native SDK.
Quick demo of the Razorpay Expo SDK in action
- 🎯 Hook-based API - Use
useRazorpay()directly in any component - 🌐 Works with Expo (WebView-based)
- 📦 No outdated native dependencies
- ⚡ Lightweight and fast
- 🎨 Simple to integrate - returns JSX that you render
- 🔄 Designed for real production usage
npm install @codearcade/expo-razorpayThe useRazorpay hook returns a JSX component (RazorpayUI) that you must render in your component. This gives you complete control over when and where the checkout appears.
import React from 'react';
import { View, Button } from 'react-native';
import { useRazorpay } from '@codearcade/expo-razorpay';
export default function PaymentScreen() {
const { openCheckout, RazorpayUI } = useRazorpay();
const handleBuy = () => {
openCheckout(
{
key: 'YOUR_RAZORPAY_KEY',
amount: 100, // Amount in paise (100 paise = 1 INR)
currency: 'INR',
order_id: 'order_RPNBJhnTs2Lq0B',
name: 'Test Company',
description: 'Test Transaction',
prefill: {
name: 'John Doe',
email: 'test@example.com',
contact: '1234567890',
},
theme: {
color: '#ffd35c',
},
},
{
onSuccess: (data) => {
console.log('Payment Success:', data);
// Handle successful payment
},
onFailure: (error) => {
console.log('Payment Failed:', error);
// Handle payment failure
},
onClose: () => {
console.log('Checkout closed');
},
}
);
};
return (
<View>
<Button title="Buy Now" onPress={handleBuy} />
{/* Render the checkout UI */}
{RazorpayUI}
</View>
);
}import React from 'react';
import { View, Button } from 'react-native';
import { useRazorpay } from '@codearcade/expo-razorpay';
import { useRouter } from 'expo-router';
export default function PaymentScreen() {
const { openCheckout, closeCheckout, RazorpayUI } = useRazorpay();
const router = useRouter();
const handleBuy = async () => {
// 1. Create order on your backend
// const orderResponse = await fetch("/api/create-order", { method: "POST" });
// const { orderId, amount } = await orderResponse.json();
// For demo:
const orderId = 'order_RPNBJhnTs2Lq0B';
const amount = 100;
openCheckout(
{
key: 'YOUR_RAZORPAY_KEY',
amount: amount,
currency: 'INR',
order_id: orderId,
name: 'Your Store',
description: 'Purchase Description',
image: 'https://your-logo-url.com/logo.png',
prefill: {
name: 'John Doe',
email: 'john@example.com',
contact: '9876543210',
},
notes: {
order_id: orderId,
},
theme: {
color: '#3399cc',
},
},
{
onSuccess: (data) => {
console.log('Payment Success:', data);
closeCheckout();
// Navigate to success screen
router.replace({
pathname: '/success',
params: {
paymentId: data.razorpay_payment_id,
amount: amount.toString(),
date: new Date().toISOString(),
},
});
},
onFailure: (error) => {
console.log('Payment Failed:', error);
// Optionally close and navigate to failure screen
},
onClose: () => {
console.log('Customer closed the checkout');
},
}
);
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button title="Proceed to Checkout" onPress={handleBuy} />
{/* The checkout UI is rendered here when active */}
{RazorpayUI}
</View>
);
}The main hook to manage Razorpay checkout. Returns an object with the following properties:
{
openCheckout: (options: RazorpayOptions, callbacks: RazorpayCallbacks) => void;
closeCheckout: () => void;
RazorpayUI: JSX.Element | null;
isVisible: boolean;
}| Property | Type | Description |
|---|---|---|
openCheckout |
(options: RazorpayOptions, callbacks: RazorpayCallbacks) => void |
Opens the checkout modal with the given options and callbacks |
closeCheckout |
() => void |
Closes the checkout modal programmatically |
RazorpayUI |
JSX.Element | null |
Required: The JSX component that renders the checkout. Must be rendered in your component tree |
isVisible |
boolean |
Whether the checkout is currently visible |
Configuration object passed to openCheckout().
| Field | Type | Required | Description |
|---|---|---|---|
key |
string |
Yes | Your Razorpay Key ID (from dashboard settings) |
amount |
number |
Yes | Amount in lowest currency unit (paise for INR, e.g., 100 = 1 INR) |
currency |
string |
Yes | Currency code (e.g., "INR") |
order_id |
string |
Yes* | Order ID from your backend. (*Either order_id or subscription_id is mandatory) |
subscription_id |
string |
Yes* | Subscription ID for recurring payments. (*Either order_id or subscription_id is mandatory) |
name |
string |
No | Your company/app name, displayed in checkout |
description |
string |
No | Transaction description |
image |
string |
No | Your logo URL (recommended: 120x120px) |
prefill |
object |
No | Pre-fill customer details: { name, email, contact } |
notes |
object |
No | Custom notes object (key-value pairs) |
theme |
object |
No | Theme customization: { color: "#hexcolor" } |
Callbacks passed as the second argument to openCheckout().
interface RazorpayCallbacks {
onSuccess: (data: RazorpaySuccessResponse) => void;
onFailure: (error: RazorpayErrorResponse['error']) => void;
onClose?: () => void;
}| Field | Type | Description |
|---|---|---|
onSuccess |
(data: RazorpaySuccessResponse) => void |
Called when payment succeeds |
onFailure |
(error: RazorpayError) => void |
Called when payment fails |
onClose |
() => void |
Called when user closes checkout (optional) |
{
razorpay_payment_id: string;
razorpay_order_id: string;
razorpay_signature: string;
// Additional payment details...
}-
Always Render RazorpayUI: Make sure to include
{RazorpayUI}in your component's JSX. Without this, the checkout modal won't appear.return ( <View> <Button title="Pay Now" onPress={handleBuy} /> {RazorpayUI} {/* ✅ Required */} </View> );
-
Create Orders on Backend: Always generate
order_idon your backend for security.const createOrder = async () => { const response = await fetch('https://your-api.com/orders', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: 100, currency: 'INR' }), }); return await response.json(); };
-
Handle Errors Gracefully: Always implement
onFailurefor user feedback.onFailure: (error) => { Alert.alert('Payment Failed', error.description); };
-
Verify Payments: Always verify the signature on your backend:
onSuccess: async (data) => { const verified = await fetch('https://your-api.com/verify-payment', { method: 'POST', body: JSON.stringify(data), }); };
- ✅ Make sure you're rendering
RazorpayUIin your JSX - ✅ Verify that
openCheckout()is being called with valid options - ✅ Check browser console for errors
- ✅ Ensure
key,amount, andorder_idare correctly set - ✅ Verify order was created on your backend
- ✅ Check Razorpay dashboard for API key validity
This is an independent, community-maintained project and is not affiliated with or endorsed by Razorpay or Expo.
MIT
