React Native Integration
This guide covers how to integrate the Hubble SDK into a React Native application using react-native-webview.
1. Setup the WebView
Install the required dependency:
npm install react-native-webview
# or
yarn add react-native-webview
For iOS, run pod install after adding the dependency.
2. Initialization
Build the SDK URL with your credentials:
| Parameter | Required | Description |
|---|---|---|
clientId | Yes | Client ID provided by the Hubble team |
appSecret | Yes | App secret provided by the Hubble team |
token | Conditional | SSO token for the current user. Required unless lazy login is enabled. |
appVersion | No | App version string. Defaults to "10000". |
deviceId | No | Device identifier for analytics. |
For React Native, set wrap-plt=rn.
const params = {
clientId: "id_given_by_hubble",
appSecret: "secret_given_by_hubble",
token: "your_sso_token",
"wrap-plt": "rn",
};
const baseUrl = "https://sdk.dev.myhubble.money/";
// prod: https://sdk.myhubble.money/
const sourceUrl = `${baseUrl}?clientId=${params.clientId}&appSecret=${params.appSecret}&token=${params.token}&wrap-plt=${params["wrap-plt"]}`;
3. Load the WebView
Render the WebView component with the required props:
<WebView
ref={webViewRef}
source={{ uri: sourceUrl }}
javaScriptEnabled={true}
domStorageEnabled={true}
startInLoadingState={true}
setSupportMultipleWindows={true}
javaScriptCanOpenWindowsAutomatically={true}
cacheEnabled={false}
onShouldStartLoadWithRequest={handleNavigation}
onMessage={handleEvent}
onNavigationStateChange={(navState) => setCanGoBack(navState.canGoBack)}
/>
4. Handling Navigation
This configuration is what enables your app to open the UPI app — without it, it will fail to do so.
Use onShouldStartLoadWithRequest to keep Hubble and payment gateway URLs in the WebView, while handing every other URL — UPI schemes (upi://, phonepe://, tez://), bank pages, external links — to the system:
import { Linking } from "react-native";
// Matches sdk.myhubble.money, sdk.dev.myhubble.money and any Razorpay host
const INTERNAL_URL = /^https:\/\/([a-z0-9-]+\.)*(myhubble\.money|razorpay\.com)(\/|$)/i;
const handleNavigation = (request) => {
if (INTERNAL_URL.test(request.url)) {
return true; // load inside the SDK webview
}
Linking.openURL(request.url).catch(() => {
// No app installed to handle this URL (e.g. a UPI app that is not installed)
});
return false; // everything else goes external
};
Match on the host, not just the base URL. This covers both the dev and production Hubble domains without an env switch, and — critically — allows Razorpay through. The earlier version of this snippet matched only baseUrl, which sent the payment gateway to the external browser and broke the flow: the user completes payment outside the WebView and the SDK never sees the result.
A regex is used here rather than new URL(), whose behaviour is unreliable under Hermes.
Back Navigation
Handle the hardware back button on Android:
useEffect(() => {
const backAction = () => {
if (canGoBack && webViewRef.current) {
webViewRef.current.goBack();
return true;
}
return false;
};
const handler = BackHandler.addEventListener("hardwareBackPress", backAction);
return () => handler.remove();
}, [canGoBack]);
5. Handling Events
The SDK communicates with your application by sending events. There are two types:
Action Events
SDK lifecycle and navigation:
| Action | When It Fires | What You Should Do |
|---|---|---|
app_ready | SDK has finished loading | Show the WebView / iframe. Hide your loading spinner. |
close | User tapped the close or back button in the SDK | Dismiss the WebView / iframe. Navigate the user back. |
error | SDK failed to load (invalid credentials, network error, SSO failure) | Hide the WebView. Show a user-friendly error with a retry option. |
The close action is the only way the SDK tells your application that the user wants to leave. If you do not handle it, the user will be stuck inside the SDK with no way to navigate back. This is one of the most common integration issues.
Analytics Events
User interaction tracking:
{ "type": "analytics", "event": "payment_success", "properties": { "amount": 500 } }
Forward analytics events to your analytics provider (Mixpanel, CleverTap, Amplitude, etc.) to track SDK usage.
For a complete list of events, see the Full Events Reference.
Setting Up the Event Handler
Use the onMessage prop to receive events:
const handleEvent = (event) => {
const data = JSON.parse(event.nativeEvent.data);
if (data.type === "action") {
if (data.action === "close") {
navigation.goBack();
} else if (data.action === "app_ready") {
setLoading(false);
} else if (data.action === "error") {
setError(true);
}
} else if (data.type === "analytics") {
// Forward to your analytics provider
analytics.track(data.event, data.properties);
}
};
6. Payment Configuration
The Hubble SDK supports UPI and credit/debit card payments. Credit/debit card payments are not enabled by default - contact Hubble support to enable them.
UPI on React Native
This configuration is what enables your app to open the UPI app — without it, it will fail to do so.
The navigation handling in Section 4 is only half of it. React Native runs on both iOS and Android, and each platform needs a native declaration before the OS will let your app open a UPI app:
- iOS: add
LSApplicationQueriesSchemestoios/<YourAppName>/Info.plist(see the iOS Integration Guide for the schemes to declare). - Android: add the
<queries>block toandroid/app/src/main/AndroidManifest.xml(see the Android Integration Guide for the configuration required on Android 11+ / API 30+).
The full list of schemes and packages is in the Payment Configuration guide.
Share your equivalent of these three snippets — your onShouldStartLoadWithRequest implementation, your Info.plist schemes, and your AndroidManifest.xml queries — with the Hubble team. These are the first things we check when UPI apps do not open.
Best Practices
- Wrap in SafeAreaView: Always wrap the WebView in a
SafeAreaViewto avoid content being hidden behind the notch or status bar. - Disable caching: Set
cacheEnabled={false}to ensure a fresh session on every load. - Handle loading state: Use
startInLoadingState={true}and theapp_readyevent to show a smooth loading experience. - Test on both platforms: React Native WebView behavior can differ between iOS and Android. Test on both.