developer
Flutter & React Native: Integrating Seamless UPI Intent on Mobile Apps (Zero SDK Bloat)
How to integrate native UPI intent in Flutter and React Native without bulky 30MB gateway SDKs. Deep linking, zero 2% commissions, and direct-to-bank settlement.
When developing mobile applications for the Indian market in Flutter or React Native, integrating an e-commerce checkout or in-app payment feature often brings a frustrating dilemma.
Installing a traditional payment gateway’s mobile SDK frequently inflates your APK/AAB download size by 25MB to 40MB, introduces brittle native Android/iOS binary dependencies, and subjects your business to continuous 2% transaction fees.
Here is the clean, lightweight blueprint to implementing native UPI intent checkout with zero SDK bloat.
The SDK Bloat Crisis in Indian Mobile Apps
Direct Answer: You do not need a bulky 35MB third-party payment gateway SDK to accept UPI on mobile. Because Android and iOS have native URI protocol handlers, a single standard URL launcher package (less than 50KB) can invoke Google Pay, PhonePe, and Paytm directly via the
upi://paystandard, delivering a faster, crash-free 1-tap checkout experience while bypassing 2% gateway cuts.
Proprietary SDK Method:
Your App ──► Heavy 35MB Gateway Binary ──► Webview Overlay ──► UPI App ──► 2% Fee Lost
Zero-Bloat Native Intent:
Your App ──► Native OS URL Dispatch (0MB Bloat) ──► UPI App ──► Direct to Bank (0% Fee)
How Native UPI Deep Linking Works
- Your mobile app calls your backend to create a unique order session via VyaparGateway’s API.
- The server returns the standard NPCI intent string:
upi://pay?pa=merchant@bank&pn=Store&tr=ORD1049&am=1299.00&cu=INR&mc=5411 - Your mobile app opens this URI using the mobile operating system’s native linking API.
- The smartphone’s OS prompts the customer to choose their preferred UPI app, authenticate with their PIN, and returns to your app seamlessly.
Flutter Implementation (url_launcher)
In your Flutter project, add the standard, official url_launcher package:
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
url_launcher: ^6.3.0
http: ^1.2.0
The Checkout Controller:
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class UpiCheckoutService {
static Future<void> initiatePayment(BuildContext context, double amount, String orderId) async {
// 1. Call your backend to create dynamic order
final response = await http.post(
Uri.parse('https://api.yourstore.com/create-order'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'amount': amount, 'orderId': orderId}),
);
final data = jsonDecode(response.body);
final String upiUrl = data['upiString']; // e.g. upi://pay?pa=...
final Uri uri = Uri.parse(upiUrl);
// 2. Launch native UPI Intent sheet
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('No compatible UPI app found on device.')),
);
}
}
}
React Native Implementation (Linking API)
In React Native, you don’t even need an external package—the core framework’s built-in Linking module handles it directly:
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, Linking, Alert, StyleSheet } from 'react-native';
export default function CheckoutScreen() {
const [loading, setLoading] = useState(false);
const handleUpiPay = async () => {
setLoading(true);
try {
// 1. Fetch dynamic order intent from your backend
const res = await fetch('https://api.yourstore.com/create-order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 999.00, orderId: `ORD_${Date.now()}` }),
});
const { upiString } = await res.json();
// 2. Check if device can resolve generic UPI intent
const supported = await Linking.canOpenURL(upiString);
if (supported) {
await Linking.openURL(upiString);
} else {
Alert.alert('Notice', 'Please install PhonePe, Google Pay, or Paytm to pay.');
}
} catch (err: any) {
Alert.alert('Payment Error', err.message);
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Mobile App Checkout</Text>
<TouchableOpacity style={styles.btn} onPress={handleUpiPay} disabled={loading}>
<Text style={styles.btnText}>{loading ? 'Launching UPI...' : 'Pay ₹999 with Any UPI App'}</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', padding: 20 },
title: { fontSize: 20, fontWeight: 'bold', marginBottom: 20, textAlign: 'center' },
btn: { backgroundColor: '#2563EB', padding: 16, borderRadius: 12 },
btnText: { color: '#FFF', textAlign: 'center', fontWeight: '600', fontSize: 16 },
});
Android Manifest and iOS Info.plist Configuration
Modern mobile OS versions require apps to declare external intent queries in their security manifests:
Android (android/app/src/main/AndroidManifest.xml)
Inside the <manifest> block:
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="upi" />
</intent>
</queries>
iOS (ios/Runner/Info.plist)
Inside the root <dict> element:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>upi</string>
<string>tez</string>
<string>phonepe</string>
<string>paytmmp</string>
<string>bhim</string>
<string>cred</string>
</array>
By ditching 35MB third-party SDKs, your app installs faster, runs lighter, and preserves 100% of transaction profits directly into your bank.
Explore VyaparGateway’s Developer API to power zero-commission in-app checkouts.
Direct answers
Frequently asked questions
- Why should mobile developers avoid proprietary payment gateway SDKs for UPI?
- Proprietary payment gateway SDKs add 25MB to 40MB of binary bloat, introduce third-party native crash dependencies, create Android 14 targetSDK compliance headaches, and lock merchants into paying 2% transaction fees on every in-app payment.
- How does native UPI deep linking work in Flutter and React Native?
- Mobile frameworks use standard OS URL launcher libraries (url_launcher in Flutter or Linking in React Native) to invoke the native upi://pay URI scheme directly, triggering the device's native app sheet without any intermediary gateway binary.
- Can iOS apps launch UPI intent deep links?
- Yes, provided the iOS app's Info.plist declares the LSApplicationQueriesSchemes array containing specific target app schemes (tez, phonepe, paytmmp, bhim) and opens the specific scheme URL.
Build your payment flow
Explore the API and browser-only merchant tools.
Create UPI checkout orders, verify signed events, or test the free calculators and generators without exposing credentials.