Skip to main content

Mobile apps and WebViews

This guide is for anyone whose customers open a Hubpay payment page inside a mobile app — your own iOS or Android app, a React Native app, or an app built with a platform such as Salesforce Mobile Publisher.

Cards and bank transfers work inside apps with no extra setup. Crypto wallet payments need one small change, and this page walks you through it for each platform.

Do I need this page?

Whether any setup is needed depends on where the payment page opens on the payer's phone:

Where the payment page opensWallet payments
The phone's browser app — the payer tapped a payment link and Chrome or Safari opened✅ Work — nothing to do
A browser sheet your app opens — a Chrome Custom Tab (Android) or SFSafariViewController (iOS)✅ Work — nothing to do
A screen inside your app that displays the page — a WebView (including apps built with Salesforce Mobile Publisher)⚠️ Broken until you follow this page

If you are unsure which of these applies, ask your development team whether the mobile app opens the payment page in a WebView. If it does — or if this cannot be confirmed — follow the steps on this page.

The distinction matters because the first two are the phone's full browser, which knows how to open wallet apps. A WebView is a simplified browser component embedded in your app, and by default it does not open other apps.

This is a mobile-only concern. On a desktop or laptop, the payment page offers wallet extensions and a QR code the payer scans with their phone — both work in any window, including web content embedded in a desktop application, with nothing to configure.

If your payers will not pay with crypto from a wallet app (MetaMask, Trust Wallet, Phantom and similar), no setup is needed in any of these cases — cards and bank transfers work everywhere without configuration.

Why crypto needs one extra step

When a payer chooses a wallet app on the payment page, the page opens that wallet using a different kind of link. Instead of starting with https:// like a normal web address, it starts with the wallet's own name — for example metamask:// or phantom://.

The phone's browser knows what to do with these links: it opens the wallet app. A WebView does not. By default it blocks the link and replaces the payment page with an error that reads net::ERR_UNKNOWN_URL_SCHEME, leaving the payer unable to continue.

The fix is always the same idea, whatever your platform: when the payment page opens a link that doesn't start with http, hand that link to the phone instead of blocking it. The phone then opens the wallet app, the payer approves and pays there, and your payment page updates by itself — you don't need to wire anything between the wallet and your app.

No-code alternative

Instead of configuring the WebView, you can open the payment page in a browser sheet — a Chrome Custom Tab on Android or SFSafariViewController on iOS. The sheet appears within your app but is the phone's full browser, so wallet payments work with no configuration.

Salesforce (Mobile Publisher)

If your customer-facing app is built with Salesforce Mobile Publisher for Experience Cloud, no code is required — this is a configuration change in Salesforce.

  1. In Salesforce Setup, type Mobile Publisher in the Quick Find box and open your app's project.

  2. Open the Android Setup and iOS Setup sections.

  3. In each one, find the field called Allowlist Custom URL Schemes.

  4. Add the following list (comma-separated):

    metamask, trust, okx, bitkeep, tpdapp, phantom, tronlinkoutside
  5. Save, and test with Salesforce's Publisher Playground app before releasing.

Salesforce's own reference for these settings: Manage How URLs Open from Your App.

Two details from Salesforce's documentation are worth highlighting:

  • The Allowlist Custom URL Schemes field and the URL Management section are separate settings. URL Management controls how normal web links open, and it does not apply to links inside the Hubpay payment page — the allowlist is the setting that matters here.
  • Without the allowlist, wallet payments in your app fail with ERR_UNKNOWN_URL_SCHEME — the exact problem described above.

For other Salesforce surfaces (for example, links opened inside the main Salesforce mobile app used by your staff), there is no allowlist setting. Open the payment page in the phone's browser instead.

Android (WebView)

If your Android app shows the payment page in a WebView, add the following to your WebViewClient. In plain terms: if the link is a normal web link, load it in the WebView; otherwise, ask the phone to open it.

This callback requires Android 7 (API 24) or newer — the versions the wallet apps themselves support.

override fun shouldOverrideUrlLoading(
view: WebView,
request: WebResourceRequest,
): Boolean {
val url = request.url
if (url.scheme != "http" && url.scheme != "https") {
try {
view.context.startActivity(Intent(Intent.ACTION_VIEW, url))
} catch (e: ActivityNotFoundException) {
// The wallet app is not installed. The payment page shows
// its own guidance, so nothing more is needed here.
}
return true // handled — don't let the WebView try to load it
}
return false // normal web link — let the WebView load it
}

iOS (WKWebView)

If your iOS app shows the payment page in a WKWebView, add the following to your WKNavigationDelegate. The logic is the same: web links stay in the WebView, and anything else is passed to the system.

func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
) {
if let url = navigationAction.request.url,
let scheme = url.scheme,
scheme != "http", scheme != "https" {
UIApplication.shared.open(url)
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}

React Native (react-native-webview)

If you followed our hosted payment page guide and show the paymentUrl in a WebView, add the onShouldStartLoadWithRequest prop:

import { Linking } from "react-native";
import { WebView } from "react-native-webview";

<WebView
source={{ uri: paymentUrl }}
onMessage={handleMessage}
onShouldStartLoadWithRequest={(request) => {
if (!/^https?:\/\//.test(request.url)) {
Linking.openURL(request.url).catch(() => {
// The wallet app is not installed. The payment page shows
// its own guidance, so nothing more is needed here.
});
return false; // handled — don't load it in the WebView
}
return true; // normal web link
}}
/>;

If your platform asks you to list the exact link types (as Salesforce does), these are the ones the payment page currently uses:

WalletLink starts with
MetaMaskmetamask://
Trust Wallettrust://
OKXokx://
Bitgetbitkeep://
TokenPockettpdapp://
Phantomphantom://
TronLinktronlinkoutside://

If your platform lets you forward all non-http links (as the Android, iOS and React Native examples above do), prefer that — it keeps working automatically if we add wallets later.

How to test it

  1. Create a sandbox payment request and open its payment page inside your app.
  2. Choose crypto, then a wallet that is installed on the test phone (for example, MetaMask).
  3. The wallet app should open, showing the payment page inside the wallet's own browser.
  4. Approve and pay in the wallet. Your app's copy of the payment page updates to completed automatically within a few seconds — the payer can also remain in the wallet, where the same completed page is shown.

If an error page mentioning ERR_UNKNOWN_URL_SCHEME appears instead, the setup above is not yet in place.

Common questions

Does this change how I confirm payments? No. Redirect URLs, webhooks and API lookups all behave exactly as described in Confirming payments. Payment status lives on Hubpay's servers, so it doesn't matter whether the payer finishes in your app's WebView or in their wallet's browser.

What if the payer doesn't have the wallet app installed? The payment page detects this and shows guidance, including the option to pay from an exchange account instead. Your app doesn't need to handle it.

Do card and bank transfer payments need any of this? No — they never leave the page. This setup only affects crypto wallet payments.

We embed the checkout in an iframe on the web — does this apply? Desktop and mobile web browsers handle wallet links natively; this page is only about WebViews inside native apps. For the web iframe integration, see Embedded checkout.