Ionic React
Integrate Commerce in Ionic React with Capgo InAppBrowser
Our Commerce SDK works in Ionic React apps that use Capacitor by opening Commerce in a managed native WebView and bridging JavaScript callbacks to your app.
Do not embed Commerce in a same-page <iframe>. Your Ionic app and commerce.bidali.com are different origins, so you cannot inject window.bidaliProvider into an iframe due to the browser same-origin policy. Use a native WebView that can inject JavaScript instead.
Step 1: Obtain your API Key
To get set up with API Keys please email us at support@bidali.com with your request. We will provide you with API keys for our staging and production environments.
The Commerce URLs to use in the webview will be:
| Environment | URL |
|---|---|
| Staging / Testnet | https://commerce.staging.bidali.com/dapp?key=YOUR_API_KEY |
| Production / Mainnet | https://commerce.bidali.com/dapp?key=YOUR_API_KEY |
When specifying the accepted payment options and providing balances, Bidali uses a unique internal identifier named protocol. You can view the list of supported protocols below.
| Environment | URL |
|---|---|
| Staging / Testnet | https://docs.bidali.com/commerce/currencies?environment=testnet |
| Production / Mainnet | https://docs.bidali.com/commerce/currencies |
Step 2: Install Capgo InAppBrowser and open Commerce
The official Capacitor @capacitor/inappbrowser plugin does not currently expose the JavaScript injection APIs Bidali needs (executeScript / document-start injection).
Use @capgo/capacitor-inappbrowser instead. Install the plugin major version that matches your app's Capacitor major version (for example Capgo 8.x with Capacitor 8.x).
npm install @capgo/capacitor-inappbrowser
# match Capacitor major, e.g. @capgo/capacitor-inappbrowser@8
npx cap syncOpen Commerce with InAppBrowser.openWebView() and inject window.bidaliProvider before page JavaScript runs:
const { id } = await InAppBrowser.openWebView({
url: `https://commerce.staging.bidali.com/dapp?key=${API_KEY}`,
isPresentAfterPageLoad: true,
preShowScript: providerScript,
preShowScriptInjectionTime: 'documentStart',
showToolbar: false,
});preShowScriptInjectionTime: 'documentStart' is the closest equivalent to React Native's injectedJavaScriptBeforeContentLoaded.
See full sample code below.
Bridge mapping vs other platforms:
| Web → wallet | Wallet → Web | |
|---|---|---|
| React Native | ReactNativeWebView.postMessage() | injectJavaScript() |
| Flutter | BidaliChannel.postMessage() | runJavaScript() |
| Ionic React | mobileApp.postMessage() | executeScript() |
Step 3: Add a bidaliProvider onto the window
window.bidaliProvider = {
key: 'YOUR API KEY', // This is provided by Bidali
name: 'YOUR WALLET NAME', // This will be provided by Bidali with your apiKey
paymentCurrencies: ['stellar', 'stellarusdc'],
brandColor: '#35D07F',
email: 'test@test.com',
phoneNumber: '15554321234',
balances: {
stellar: '5',
usdcstellar: '20'
},
onPaymentRequest: function (paymentRequest) {
window.mobileApp.postMessage({
detail: {
method: 'onPaymentRequest',
data: paymentRequest
}
});
},
openUrl: function (url) {
window.mobileApp.postMessage({
detail: {
method: 'openUrl',
data: { url: url }
}
});
}
};Capgo injects window.mobileApp into managed WebViews. Listen for 'messageFromWebview' in your Ionic app to receive those messages.
window.bidaliProvider must have the following properties:
| Property | Type | Description |
|---|---|---|
name | String | The name of the wallet integrating (Provided by Bidali) |
key | String | This is your Bidali Commerce Publishable Key. The unique and public key that identifies your organization. It looks like pk_viqah4squsnuw6p0e1ue.(Provided by Bidali) |
paymentCurrencies | String[] | Allows you to only show certain cryptocurrencies as payment options. It takes an Array of Strings that are the coin protocols (Bidali's unique identifier) |
brandColor | String | Hex color used to theme CTA button backgrounds, ex: #35D07F |
limitToCountries | String[] | Country codes of the countries to limit the products to, ex: [ "US", "CA" ] |
email | String | Allows us to pre-populate their email, user has to confirm during checkout flow |
phoneNumber | String | Allows us to pre-populate the phone number for mobile topups, the user has the chance to change this |
balances | object | The balances for the allowed currencies, ex. { stellar: '25.2', usdcstellar: '2000' } |
onPaymentRequest | Function | Provide a handler for this function that displays a payment confirmation modal for the user |
openUrl | Function | Opens a URL to our support docs, etc. Ideally should open in an external browser or a new in-app modal browser |
Step 4: Handle onPaymentRequest
Add a handler for onPaymentRequest that shows the user a payment confirmation modal using the information in the paymentRequest. If an extraId field is present on the paymentRequest it must be sent with the transaction (ex. as a memo).
This is what a paymentRequest looks like
{
amount: '0.0187',
symbol: 'ETH', // This is the payment currency your user chose
protocol: 'ethereum', // This is Bidali's unique identifier for a currency
address: '0x220b48eda85a0a067c769f0442dd2f4e03ba625a',
chargeId: 'vIQ807gvR',
extraId: 'vIQ807gvR',
extraIdName: 'Memo text',
description: '$50 Amazon US',
lineItems: [
{
name: 'Amazon US',
quantity: 1,
amount: '$50 USD',
image: 'https://assets.bidali.com/commerce/brands/amazon-com-us.png'
}
]
}A paymentRequest has the following properties:
| Property | Type | Description |
|---|---|---|
address | String | The address to send to |
amount | String | The amount to send, as a user readable string (ex. "25") |
symbol | String | The symbol of the currency the user has chosen to pay with, ex: BTC, not unique to a currency (for instance USDC ERC20 and USDC on Stellar both have the symbol USDC) |
protocol | String | The protocol of the currency the user has chosen to pay with, this is unique for each currency. ex: usdcstellar |
description | String | A comma-delimited list of products being purchased. Can be used on your payment approval screen so the user sees what they are approving payment for. Ex: $50 USD Amazon US, 2x $25 USD Apple US |
lineItems | Array | A list of products being purchased. Just like with description, you can use this on your payment approval screen. A line item looks like { name: 'Apple US', quantity: 1, amount: '$5 USD', image: 'https://assets.bidali.com/commerce/brands/apple.png' } |
chargeId | String | The users order reference, helpful to reference the order in the future or if there are any issues. Ex: vIQ807gvR |
extraId | String | The extraId that must be passed for the payment to be credited appropriately to the order. See memo / note requirements by network. |
extraIdName | String | The name of the extraId that must be sent with the transaction. See memo / note requirements by network. |
Note for currencies on Stellar, Algorand, Solana, Cosmos, and Osmosis networks
Below are the additional fields that will be populated on the BidaliPaymentRequest and MUST be passed with the transaction for it to be successful.
| Network | extraIdName |
|---|---|
| Stellar | Memo text |
| Solana | Memo |
| Algorand | Note/Memo |
| Cosmos | Memo |
| Osmosis | Memo |
Step 5: Notify Bidali of payment status
When the user sends the transaction call window.bidaliProvider.paymentSent() inside the WebView. If they cancel payment / dismiss the modal then call window.bidaliProvider.paymentCancelled().
await InAppBrowser.executeScript({
id,
code: `window.bidaliProvider.paymentSent();`,
});
await InAppBrowser.executeScript({
id,
code: `window.bidaliProvider.paymentCancelled();`,
});Step 6: Update balances
After a user sends a transaction or their balances change, update the balances object on window.bidaliProvider via executeScript:
async function updateBidaliBalances(
id: string,
balances: Record<string, string>
) {
await InAppBrowser.executeScript({
id,
code: `
window.bidaliProvider.balances = ${JSON.stringify(balances)};
`,
});
}Example code
Here’s sample Ionic React + Capacitor code that opens Commerce with Capgo InAppBrowser, injects window.bidaliProvider, and handles onPaymentRequest via messageFromWebview.
import { InAppBrowser } from '@capgo/capacitor-inappbrowser';
import { Browser } from '@capacitor/browser';
const API_KEY = 'YOUR_API_KEY';
const WALLET_NAME = 'YOUR WALLET NAME';
const balances = {
stellar: '5.2',
usdcstellar: '2000',
};
const user = {
email: 'test@test.com',
phoneNumber: '15554321234',
};
export async function openBidali() {
const providerScript = `
window.bidaliProvider = {
key: ${JSON.stringify(API_KEY)},
name: ${JSON.stringify(WALLET_NAME)},
paymentCurrencies: ['stellar', 'usdcstellar'],
brandColor: '#35D07F',
email: ${JSON.stringify(user.email)},
phoneNumber: ${JSON.stringify(user.phoneNumber)},
balances: ${JSON.stringify(balances)},
onPaymentRequest: function(paymentRequest) {
window.mobileApp.postMessage({
detail: {
method: 'onPaymentRequest',
data: paymentRequest
}
});
},
openUrl: function(url) {
window.mobileApp.postMessage({
detail: {
method: 'openUrl',
data: { url: url }
}
});
}
};
`;
const messageListener = await InAppBrowser.addListener(
'messageFromWebview',
async (event) => {
const payload = event.detail;
if (!payload) return;
switch (payload.method) {
case 'onPaymentRequest': {
const paymentRequest = payload.data as {
amount: string;
address: string;
symbol: string;
protocol: string;
description: string;
chargeId: string;
extraId?: string;
};
// Show your wallet's native transaction confirmation UI here.
// const result = await wallet.sendTransaction(...)
// Notify Bidali of the payment status:
// await InAppBrowser.executeScript({
// id,
// code: 'window.bidaliProvider.paymentSent();',
// });
// or
// await InAppBrowser.executeScript({
// id,
// code: 'window.bidaliProvider.paymentCancelled();',
// });
console.log('Bidali payment request', paymentRequest);
break;
}
case 'openUrl': {
const { url } = payload.data as { url: string };
await Browser.open({ url });
break;
}
}
}
);
const { id } = await InAppBrowser.openWebView({
url: `https://commerce.staging.bidali.com/dapp?key=${API_KEY}`,
// Inject window.bidaliProvider before Bidali app JS executes
isPresentAfterPageLoad: true,
preShowScript: providerScript,
preShowScriptInjectionTime: 'documentStart',
showToolbar: false,
});
return { id, messageListener };
}
export async function updateBidaliBalances(
id: string,
nextBalances: Record<string, string>
) {
await InAppBrowser.executeScript({
id,
code: `window.bidaliProvider.balances = ${JSON.stringify(nextBalances)};`,
});
}Please send any feedback to support@bidali.com