Accept Payments with Paystack in React Native
React Native apps cannot call the Paystack API with a secret key. Your backend initializes the transaction and returns the authorization_url. Open this URL with react-native-paystack-webview or a custom react-native-webview. Detect the callback URL redirect, extract the reference, and verify the transaction on your backend.
Install react-native-paystack-webview
npm install react-native-paystack-webview react-native-webview
# or
yarn add react-native-paystack-webview react-native-webview
# iOS
cd ios && pod install
For Expo managed workflow, use Expo WebBrowser instead:
npx expo install expo-web-browser
Backend: Initialize Transaction
// Node.js backend
app.post('/api/pay/initialize', async (req, res) => {
var { email, amount } = req.body;
var reference = 'rn_' + Date.now() + '_' + Math.random().toString(36).slice(2, 6);
var response = await fetch('https://api.paystack.co/transaction/initialize', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
amount: Math.round(amount * 100), // kobo
reference,
callback_url: 'https://yourapp.com/payment/callback',
}),
});
var data = await response.json();
if (!data.status) return res.status(400).json({ error: data.message });
res.json({
authorization_url: data.data.authorization_url,
access_code: data.data.access_code,
reference: data.data.reference,
});
});
React Native: Paystack WebView Checkout
// PaymentScreen.tsx
import React, { useState } from 'react';
import { View, ActivityIndicator, Alert } from 'react-native';
import PaystackWebView from 'react-native-paystack-webview';
interface PaymentScreenProps {
route: {
params: {
email: string;
amount: number; // in display units (e.g. NGN 5000)
};
};
navigation: any;
}
export function PaymentScreen({ route, navigation }: PaymentScreenProps) {
var { email, amount } = route.params;
var [loading, setLoading] = useState(true);
return (
<View style={{ flex: 1 }}>
<PaystackWebView
paystackKey="pk_test_xxxxxxxxxxxx" // Your PUBLIC key
amount={amount}
billingEmail={email}
activityIndicatorColor="green"
onCancel={() => {
navigation.goBack();
}}
onSuccess={async (response) => {
// response contains transactionRef
var reference = response.transactionRef?.reference || response.transactionRef;
// Verify on your backend
try {
var verifyRes = await fetch(
'https://your-backend.com/api/pay/verify?reference=' + reference
);
var result = await verifyRes.json();
if (result.verified) {
navigation.navigate('PaymentSuccess', { reference });
} else {
Alert.alert('Payment issue', 'Please contact support');
navigation.goBack();
}
} catch (e) {
Alert.alert('Error', 'Could not verify payment');
navigation.goBack();
}
}}
autoStart={true}
/>
</View>
);
}
Note: paystackKey takes your public key, not the secret key. react-native-paystack-webview loads Paystack's hosted checkout and handles the WebView internally.
Expo: WebBrowser Alternative
For Expo managed workflow, use expo-web-browser to open the authorization URL:
import * as WebBrowser from 'expo-web-browser';
async function startPayment(email: string, amount: number) {
// Get authorization URL from your backend
var response = await fetch('https://your-backend.com/api/pay/initialize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, amount }),
});
var data = await response.json();
if (!data.authorization_url) {
Alert.alert('Error', 'Could not initialize payment');
return;
}
// Open in WebBrowser
var result = await WebBrowser.openAuthSessionAsync(
data.authorization_url,
'yourapp://payment/callback' // Deep link callback
);
if (result.type === 'success') {
var url = new URL(result.url);
var reference = url.searchParams.get('reference') || url.searchParams.get('trxref');
if (reference) {
await verifyPayment(reference);
}
}
}
Deep link handling requires configuring the scheme in your app.json and setting up deep link routing.
Learn More
This guide is part of the Paystack integration guides by language and framework series.
Key Takeaways
- ✓Never put your Paystack secret key in React Native code. Initialize transactions from your backend.
- ✓react-native-paystack-webview is the most popular library for Paystack checkout in React Native.
- ✓Both Expo and bare React Native workflows support the WebView approach.
- ✓After checkout, the library provides the transaction reference in the onSuccess callback.
- ✓Always verify the transaction on your backend before granting access or fulfilling orders.
- ✓Add INTERNET permission on Android and ATS configuration on iOS for WebView to load Paystack pages.
Frequently Asked Questions
- Can I use Paystack in Expo without ejecting?
- Yes. Use expo-web-browser to open the Paystack authorization URL. This opens the checkout in a system browser or in-app browser. After payment, handle the deep link callback. You do not need react-native-paystack-webview, which requires native modules.
- Where do I put the Paystack public key in React Native?
- The public key (pk_test_ or pk_live_) can go in your React Native code — it is safe to expose. Store it in your .env file as EXPO_PUBLIC_PAYSTACK_KEY for Expo, or in a config file. Never put the secret key (sk_test_ or sk_live_) in your React Native code.
- Does react-native-paystack-webview work on both iOS and Android?
- Yes. The library wraps react-native-webview, which supports both platforms. Ensure you install pods for iOS (cd ios && pod install) and have INTERNET permission in AndroidManifest.xml.
- What is the difference between access_code and authorization_url for React Native?
- Both can be used to launch checkout. The authorization_url is a full URL you can open in a WebView or browser. The access_code is a shorter token used with react-native-paystack-webview's accessCode prop for inline checkout on the hosted Paystack page.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon