- iOS SDK
- Android SDK
- Flutter SDK
- React Native SDK
- Capacitor
- Expo
- Web SDK
iOS SDK
Compatibility
Compatibility
Installation
Installation
- Swift Package Manager installation
- CocoaPods installation
https://github.com/Appboxo/boxo-ios-spm.git
cd your-project-directory
pod init
pod 'BoxoSDK'
pod install
open your-project.xcworkspace
Launch miniapp
Launch miniapp
import BoxoSDK
client_id field with your client_id.let config = Config(clientId: "client_id")
Boxo.shared.setConfig(config: config)
UIKit
To open miniapp write this code in your UIViewController:let miniapp = Boxo.shared.getMiniapp(appId: "app_id")
miniapp.open(viewController: self)
SwiftUI
If you are using SwiftUI, you need to access the current UIViewController. There are many ways to obtain a UIViewController. Here is one of them:struct ViewControllerFinder: UIViewControllerRepresentable {
var onViewControllerFound: (UIViewController) -> Void
func makeUIViewController(context: Context) -> UIViewController {
let viewController = UIViewController()
DispatchQueue.main.async {
self.onViewControllerFound(viewController)
}
return viewController
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
...
struct ContentView: View {
@State private var currentViewController: UIViewController?
var body: some View {
ViewControllerFinder { viewController in
currentViewController = viewController
}
Button(action: {
guard let currentViewController = currentViewController else { return }
let miniapp = Boxo.shared.getMiniapp(appId: "app_id")
miniapp.open(viewController: currentViewController)
}) {
Text("Open miniapp")
}
}
}
Miniapp lifecycle events
Miniapp lifecycle events
onLaunch, onResume, onPause, onClose, and onError. These events help track the miniapp’s behavior throughout its usage lifecycle.miniapp.delegate = self
...
extension ViewController: MiniappDelegate {
func onLaunch(miniapp: Miniapp) {
print("onLaunchMiniapp: \(miniapp.appId)")
}
func onResume(miniapp: Miniapp) {
print("onResumeMiniapp: \(miniapp.appId)")
}
func onPause(miniapp: Miniapp) {
print("onPauseMiniapp: \(miniapp.appId)")
}
func onClose(miniapp: Miniapp) {
print("onCloseMiniapp: \(miniapp.appId)")
}
func onError(miniapp: Miniapp, message: String) {
print("onErrorMiniapp: \(miniapp.appId) message: \(message)")
}
}
Dark mode
Dark mode
Boxo.shared.setConfig(config: Config(clientId: "client_id", theme: .Dark)) //[Dark, Light, System] System - by default
miniapp.setConfig(config: MiniappConfig(theme: .Dark))
Auth flow
Auth flow
miniapp.delegate = self
...
extension ViewController : MiniappDelegate {
func onAuth(miniapp: Miniapp) {
miniapp.setAuthCode(authCode: "[AUTH_CODE]")
}
}
Logout to clear mininapp data
Logout to clear mininapp data
.logout():Boxo.shared.logout()
Miniapp URL listener
Miniapp URL listener
miniapp.delegate = self
...
extension ViewController: MiniappDelegate {
func didChangeUrlEvent(miniapp: Miniapp, url: URL) {
// Listen for search URL
if url.path.components(separatedBy: "/").contains("search") {
print("Search url: \(url)")
}
}
}
Append custom params to miniapp URL
Append custom params to miniapp URL
let miniapp = Boxo.shared.getMiniapp(appId: "app_id")
let miniappConfig = MiniappConfig(theme: .System)
// Set params that will be appended to miniapp's url
// Ex. https://google.com/?name=Orave
miniappConfig.setExtraParams(extraParams: ["name" : "Orave"])
miniapp.setConfig(config: miniappConfig)
Custom action menu item
Custom action menu item
.setCustomActionMenuItemImagelet miniapp = Boxo.shared.getMiniapp(appId: "app_id")
let miniappConfig = MiniappConfig(theme: .System)
// Set third custom action menu item
// It is hidden by default
miniappConfig.setCustomActionMenuItemImage(image: UIImage(named: "ic_custom_action_button"))
miniapp.setConfig(config: miniappConfig)
...
extension ViewController : MiniappDelegate {
func didSelectCustomActionMenuItemEvent(miniapp: Miniapp) {
//show any custom dialog when custom action menu item is clicked
}
}
miniapp.showCustomActionMenuItem() and miniapp.hideCustomActionMenuItem()Retrieve Miniapp List
Retrieve Miniapp List
- Basic miniapp information (id, name, description)
- Logo
- Category
Boxo.shared.getMiniapps { miniapps, error in
miniapps.forEach { data in
print(data.appId)
print(data.name)
print(data.longDescription)
print(data.logo)
print(data.category)
}
}
Consent Management
Consent Management
let config = Config(clientId: "CLIENT_ID")
config.setUserId(id: "HOST_APP_USER_ID") //will be used for the consent screen
Boxo.shared.setConfig(config: config)
To skip miniapp splash screen
To skip miniapp splash screen
let miniapp = Boxo.shared.getMiniapp(appId: "app_id")
let miniappConfig = MiniappConfig()
miniappConfig.enableSplash(isSplashEnabled: false) // to skip splash screen. if enabled, the splash screen will be hidden when 50% of web content is loaded. Otherwise, when the web page starts loading. By default is enabled.
miniapp.setConfig(config: miniappConfig)
miniapp.open(viewController: self)
Sandbox mode
Sandbox mode
- when true, miniapps in “Approved” and “InTesting” statuses
- when false, miniapps only in “Approved” status
let config = Config(clientId: "CLIENT_ID")
config.sandboxMode = true //by default false
Boxo.shared.setConfig(config: config)
Page Animation Configuration
Page Animation Configuration
LEFT_TO_RIGHT- The miniapp slides in from the left side of the screen to the right.RIGHT_TO_LEFT- The miniapp slides in from the right side of the screen to the left.BOTTOM_TO_TOP- The miniapp slides in from the bottom of the screen to the top.TOP_TO_BOTTOM- The miniapp slides in from the top of the screen to the bottom.FADE_IN- The miniapp fades in gradually from completely transparent to opaque.
BOTTOM_TO_TOP animation is the default page transition effect. You can easily change the animation to any of the other available options based on the user experience you want to provide.let config = MiniappConfig()
config.pageAnimation = PageAnimation.RIGHT_TO_LEFT
let miniapp = Boxo.shared.getMiniapp(appId: "app_id")
miniapp.setConfig(config: config)
miniapp.open(viewController: self)
Android SDK
Please see our sample Android app to learn more.Compatibility
Compatibility
Installation
Installation
io.boxo.sdk:boxo-android to the dependencies block of your app/build.gradle file:...
dependencies {
implementation("io.boxo.sdk:boxo-android:1.x.x")
}
android.enableJetifier=true
Launch miniapp
Launch miniapp
-
Add to your existing
Applicationclass or create a new one if you don’t have anApplicationclass yet.MyApplication.ktCopyAsk AIimport android.app.Application import io.boxo.sdk.Boxo import io.boxo.sdk.Config class MyApplication : Application() { override fun onCreate() { super.onCreate() Boxo.init(this) .setConfig( Config.Builder() .setClientId("client_id") .build() ) } } -
Then register it in AndroidManifest.xml:
CopyAsk AI
<application android:name=".MyApplication" ...> -
Open miniapp
CopyAsk AI
val miniapp = Boxo.getMiniapp(appId) miniapp.open(context)
package io.boxo.launchminiapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.boxo.launchminiapp.ui.theme.LaunchminiappTheme
import io.boxo.sdk.Boxo
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
LaunchminiappTheme {
WelcomeScreen(
onOpenMiniappClick = {
Boxo.getMiniapp("appId")
.open(this)
}
)
}
}
}
}
@Composable
fun WelcomeScreen(
onOpenMiniappClick: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Welcome",
style = typography.headlineMedium,
modifier = Modifier.padding(bottom = 16.dp)
)
Spacer(modifier = modifier.height(64.dp))
Button(
onClick = onOpenMiniappClick,
modifier = Modifier
.fillMaxWidth()
.height(52.dp)
) {
Text("Open Miniapp")
}
}
}
@Preview(showBackground = true)
@Composable
fun WelcomeScreenPreview() {
LaunchminiappTheme {
WelcomeScreen(
onOpenMiniappClick = {}
)
}
}
SDK Configurations
SDK Configurations
Language Configuration
Use it to provide language to miniapp. Default: ‘en’Boxo.init(this)
.setConfig(
Config.Builder()
.setLanguage("en")
.build()
)
System Behavior
Boxo.setConfig(
Config.Builder()
.multitaskMode(false)
.debug(BuildConfig.DEBUG)
.build()
)
| Parameter | Type | Description | Default |
|---|---|---|---|
multitaskMode | Boolean | Shows Miniapps in Android Recents screen when true | false |
debug | Boolean | Enables WebView debugging (Chrome DevTools) | false |
Miniapp Menu Customization
Boxo.setConfig(
Config.Builder()
.permissionsPage(false) // Hide "Settings"
.showClearCache(false) // Hide "Clear Cache"
.showAboutPage(true) // Show "About"
.build()
)
| Parameter | Description | Default |
|---|---|---|
permissionsPage | Setting menu item | true |
showClearCache | Clear Cache menu item | true |
showAboutPage | About Miniapp menu item | true |
Sandbox Mode Configuration
Control which miniapps are available in your development environment using the sandbox mode flag:Boxo.setConfig(
Config.Builder()
.sandboxMode(true) // Enable sandbox mode
.build()
)
| Sandbox Mode | Available Miniapp Statuses | Use Case |
|---|---|---|
true | Approved + InTesting | Development environment - access to miniapps still in testing |
false | Approved only | Production environment - only fully approved miniapps |
Theme Configuration
Configure native component theming to match your app’s design system or respect user preferences. The SDK provides comprehensive theme support for:- Splash screens
- Native UI components
- System dialogs and alerts
| Option | Description |
|---|---|
SYSTEM | Automatically matches device theme |
LIGHT | Forces light theme |
DARK | Forces dark theme |
Boxo.setConfig(Config.Builder()
...
.setTheme(Config.Theme.SYSTEM) // DEFAULT: Follows system setting
.build())
// Override theme for specific miniapp
Boxo.getMiniapp(appId)
.setConfig(MiniappConfig.Builder()
.setTheme(Config.Theme.LIGHT) // Overrides global theme
.build())
.open()
Miniapp Auth Flow
Miniapp Auth Flow
miniapp.setAuthListener { boxoActivity, miniapp ->
// 1. Fetch auth code from your backend
//use boxoActivity to open dialogs or activity
val authCode = fetchAuthCodeFromBackend()
// 2. Provide code to Miniapp
miniapp.setAuthCode(authCode)
}
User Logout & Data Clearing
User Logout & Data Clearing
Boxo.logout()
Miniapp URL Change Listener
Miniapp URL Change Listener
Boxo.getMiniapp(appId)
.setUrlChangeListener { boxoActivity, miniapp, uri ->
Log.e("URL Path", uri.path)
uri.queryParameterNames.forEach {
Log.e("URL params", "$it = ${uri.getQueryParameter(it)}")
}
}
.open(this)
Custom URL Parameters
Custom URL Parameters
- User-specific data injection
- Campaign tracking
- Contextual deep linking
- A/B testing configuration
Boxo.getMiniapp(appId)
.setConfig(
MiniappConfig.Builder()
.setExtraUrlParams(
mapOf(
"user_id" to "u_12345",
"campaign" to "summer_sale"
)
)
.build()
)
.open(this)
https://miniapp.example.com?user_id=u_12345&campaign=summer_sale
Custom Event Handling
Custom Event Handling
- Real-time data exchange
- User interaction tracking
- Miniapp to host app callbacks
- Dynamic content updates
miniapp.setCustomEventListener { boxoActivity, miniapp, event ->
//use boxoActivity to open dialogs or activity
when (event.name) {
"userAction" -> handleUserAction(event.payload)
"requestData" -> sendResponseData(miniapp, event)
else -> Log.w("CustomEvent", "Unhandled event: ${event.name}")
}
}
// Send response back to miniapp
private fun sendResponseData(miniapp: Miniapp, event: CustomEvent) {
event.payload = mapOf(
"status" to "success",
"code" to 200
)
miniapp.sendEvent(event)
}
Adding Custom Action Menu
Adding Custom Action Menu
- Define the Menu Item
Use.setCustomActionMenuItem()to specify your custom button’s appearance - Handle User Interactions
Implement.setCustomActionMenuItemClickListener()to respond when users tap your button
Boxo.getMiniapp(appId)
.setConfig(
MiniappConfig.Builder()
.setCustomActionMenuItem(R.drawable.ic_custom_menu)
.build()
)
.setCustomActionMenuItemClickListener { boxoActivity, miniapp ->
// do something
}
.open(this)
// Hide the item
miniapp.hideCustomActionMenuItem()
// Show when needed
miniapp.showCustomActionMenuItem()
Retrieve Miniapp List
Retrieve Miniapp List
- Basic miniapp information (id, name, description)
- Logo
- Category
Boxo.getMiniapps(object: MiniappListCallback{
override fun onFailure(e: Exception) {
Log.e("MiniappList", "Failed to load miniapps")
}
override fun onSuccess(miniapps: List<MiniappData>) {
miniapps.forEach { data->
print(data.appId)
print(data.name)
print(data.description)
print(data.logo)
print(data.category)
}
}
})
Splash Screen Configuration
Splash Screen Configuration
Boxo.getMiniapp(appId)
.setConfig(
MiniappConfig.Builder()
.enableSplash(false) // Skip splash screen entirely
.build()
)
.open(this)
Page Animation Configuration
Page Animation Configuration
multitaskMode is set tofalse. Make sure to configure it accordingly to enable page transition animations.Customize the animation effects to enhance the user experience by setting the appropriate page transition animation when opening a miniapp.You can choose from the following page animations:LEFT_TO_RIGHT- The miniapp slides in from the left side of the screen to the right.RIGHT_TO_LEFT- The miniapp slides in from the right side of the screen to the left.BOTTOM_TO_TOP- The miniapp slides in from the bottom of the screen to the top.TOP_TO_BOTTOM- The miniapp slides in from the top of the screen to the bottom.FADE_IN- The miniapp fades in gradually from completely transparent to opaque.
BOTTOM_TO_TOP animation is the default page transition effect. You can easily change the animation to any of the other available options based on the user experience you want to provide.Boxo.getMiniapp(appId)
.setConfig(
MiniappConfig.Builder()
...
// Set the page animation to slide from right to left
.pageAnimation(PageAnimation.RIGHT_TO_LEFT)
.build()
)
.open(requireActivity())
Miniapp Lifecycle Events
Miniapp Lifecycle Events
LifecycleListener. These events help you monitor user interactions and manage app state transitions.miniapp.setLifecycleListener(object : Miniapp.LifecycleListener {
override fun onLaunch(miniapp: Miniapp) {
// Triggers when miniapp begins launching via miniapp.open()
// Ideal for analytics tracking and initial setup
}
override fun onResume(miniapp: Miniapp) {
// Called when miniapp returns to foreground
// Use to resume paused operations
}
override fun onPause(miniapp: Miniapp) {
// Called when miniapp loses foreground focus
// Pause ongoing operations
}
override fun onClose(miniapp: Miniapp) {
// Triggers when:
// - User taps close button
// - Miniapp activity is destroyed
// Clean up resources and finalize analytics
}
override fun onError(miniapp: Miniapp, message: String) {
// Called when miniapp fails to launch due to internet connection issues
}
override fun onUserInteraction(miniapp: Miniapp) {
// Called on every user touch event
// Useful for implementing custom idle timeouts
}
})
Customizing Miniapp Loading Experience
Customizing Miniapp Loading Experience
setProgressBarColors method in Config.Builder.Boxo.init(this)
.setConfig(
Config.Builder()
.setProgressBarColors(
lightIndicator = "#000000".toColorInt(),
lightTrack = "#DAD5D5".toColorInt(),
darkIndicator = "#006DD1".toColorInt(),
darkTrack = "#FFFFFF".toColorInt()
)
.build()
)
Obfuscation Rules
Obfuscation Rules
-keepclassmembers class io.boxo.js.jsInterfaces.BoxoJsInterface{
public *;
}
Flutter SDK
A Flutter plugin to integrate Boxo for iOS and Android. Please see our sample Flutter app to learn more.Installation
Installation
flutter pub add appboxo_sdk
flutter pub get):dependencies:
appboxo_sdk: ^0.8.0Add this line to android/gradle.properties android.enableJetifier=true
Launch Miniapp
Launch Miniapp
import 'package:appboxo_sdk/boxo.dart';
Boxo.setConfig( clientId: '[client_id]');
Boxo.openMiniapp( appId );
Set Config
Set Config
import 'package:appboxo_sdk/boxo.dart';
Boxo.setConfig(
clientId: '[client_id]', // your Boxo client_id
userId: '[hostapp_user_id]',// will be used for the consent screen
language: 'en', // use it to provide language to miniapp. by default 'en'
multitaskMode: true, // (optional) 'multitaskMode' works only on Android. By default 'true', each miniapp appears as a task in the Recents screen.
sandboxMode: false, // sandbox mode. By default 'false'
theme: 'dark', // (optional) miniapp theme "dark" | "light" (by default is system theme),
isDebug: true, // by default 'false', enables webview debugging
showClearCache: true, // use it to hide "Clear cache" from Miniapp menu, by default 'true'
showPermissionsPage: true, // use it to hide "Settings" from Miniapp menu, by default 'true'
showAboutPage: true // show/hide "About page" on Miniapp menu, by default 'true'
);
Boxo.openMiniapp(
"[miniapp_id]", // your miniapp id
data: {'key': 'value'}, // (optional) data as Map that is sent to miniapp
theme: 'dark', // (optional) miniapp theme "dark" | "light" (by default is system theme)
enableSplash: false // (optional) to skip splash screen. if enabled, the splash screen will be hidden when 50% of web content is loaded. Otherwise, when the web page starts loading. By default is enabled.
);
Boxo.hideMiniapps(); //use it to close all miniapp screens
Boxo.logout(); //On logout from your app, call it to clear all miniapps data.
Sandbox mode
Sandbox mode
- when true, miniapps in “Approved” and “InTesting” statuses
- when false, miniapps only in “Approved” status
Get list of miniapps
Get list of miniapps
Boxo.miniapps().listen((result) {
result.miniapps?.forEach((data) {
print(data.appId);
print(data.name);
print(data.description);
print(data.logo);
print(data.category);
});
print('error - ${result.error}');
});
Boxo.getMiniapps();
To listen miniapp lifecycle events
To listen miniapp lifecycle events
import 'package:flutter/material.dart';
import 'package:appboxo_sdk/boxo.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future<void> Function() subscription;
@override
void dispose() {
subscription();
super.dispose();
}
@override
void initState() {
super.initState();
subscription = Boxo.lifecycleHooksListener(
onAuth: (appId) { // called when authorization flow starts
//sample
http.get(Uri.parse('get_auth_code_url'))
.then((response) {
if (response.statusCode >= 400) {
print('Error fetching auth code: ${response.body}');
Boxo.setAuthCode(appId, "");
} else {
Boxo.setAuthCode(appId, json.decode(response.body)["auth_code"]);
}
});
},
onLaunch: (appId) {
print(appId);
print('onLaunch');
},
onResume: (appId) {
print(appId);
print('onResume');
},
onPause: (appId) {
print(appId);
print('onPause');
},
onClose: (appId) {
print(appId);
print('onClose');
},
onError: (appId, error) {
print(appId);
print(error);
print('onError');
},
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Boxo SDK Test'),
),
body: Center(
child: MaterialButton(
onPressed: () {
Boxo.openMiniapp("[miniapp_id]"); //launch miniapp by id
},
padding: const EdgeInsets.all(16),
color: Colors.blue,
child: const Text(
'Run miniapp',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
),
),
),
),
);
}
}
React Native SDK
A react native wrapper over Boxo SDK for iOS and Android.Installation
Installation
yarn add @appboxo/react-native-sdk
npm install @appboxo/react-native-sdk
react-native link @appboxo/react-native-sdk
android.enableJetifier=true
cd ios && pod install
Launch Miniapp
Launch Miniapp
import Boxo from '@appboxo/react-native-sdk';
Boxo.setConfig( clientId );
Boxo.openMiniapp( appId );
Usage
Usage
import React from 'react';
import Boxo from '@appboxo/react-native-sdk';
import { StyleSheet, View, Button } from 'react-native';
export default function App() {
React.useEffect(() => {
Boxo.setConfig(
'[client_id]', { // your Boxo client_id
userId: [hostapp_user_id], // will be used for the consent screen
language: 'en', // to provide language to miniapp. by default 'en'
enableMultitaskMode: true, // (optional) 'multitaskMode' works only on Android. By default 'true', each miniapp appears as a task in the Recents screen.
sandboxMode: false, // sandbox mode. By default 'false'
theme: 'light', // (optional) miniapp theme "dark" | "light" (by default is "system")
isDebug: true, // by default 'false', enables webview debugging
showClearCache: true, // use it to hide "Clear cache" from Miniapp menu, by default 'true'
showPermissionsPage: true, // use it to hide "Settings" from Miniapp menu, by default 'true'
showAboutPage: true // show/hide "About page" on Miniapp menu, by default 'true'
}
);
}, [])
const handleOpenMiniapp = () => {
const options = {
data: {'key': 'value'}, // (optional) data as {[key: string]: any} that is passed to miniapp in `.getInitData` call
theme: 'dark', // (optional) miniapp theme "dark" | "light" | "system" (by default is value of "theme" argument in setConfig function)
extraUrlParams: {param: 'test'}, // (optional) extra query params to append to miniapp URL (like: http://miniapp-url.com/?param=test)
}
Boxo.openMiniapp(
'[miniapp_id]', // miniapp ID to be launched
options // (optional) options
);
}
return (
<View style={styles.container}>
<Button
color="#841584"
title="Launch miniapp"
onPress={handleOpenMiniapp}
accessibilityLabel="Launch miniapp"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
backgroundColor: '#fff',
justifyContent: 'center',
},
});
Miniapp lifecycle events
Miniapp lifecycle events
import React from 'react';
import Boxo from '@appboxo/react-native-sdk';
import { StyleSheet, View, Button } from 'react-native';
export default function App() {
React.useEffect(() => {
Boxo.setConfig('[client_id]', false); //set your Boxo client id
const subscription = Boxo.lifecycleHooksListener({
onLaunch: (appId: string) => console.log('onLaunch', appId), // called when the miniapp will launch with openMiniapp(...)
onResume: (appId: string) => console.log('onResume', appId), // called when the miniapp will start interacting with the user
onPause: (appId: string) => console.log('onPause', appId), // called when clicked close button in miniapp or when destroyed miniapp activity
onClose: (appId: string) => console.log('onClose', appId), // called when the miniapp loses foreground state
onAuth: (appId: string) => console.log('onAuth', appId), // called when authorization flow starts
onError: (appId: string, error: string) => console.log('onError', appId, error), // handle error
});
return () => subscription();
}, [])
const handleOpenMiniapp = () => {
Boxo.openMiniapp('[miniapp_id]'); // miniapp ID to be launched
}
return (
<View style={styles.container}>
<Button
color="#841584"
title="Launch miniapp"
onPress={handleOpenMiniapp}
accessibilityLabel="Launch miniapp"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
backgroundColor: '#fff',
justifyContent: 'center',
},
});
Append custom params to miniapp URL
Append custom params to miniapp URL
const options = {
extraUrlParams: {param: 'test'} // (optional) extra query params to append to miniapp URL (like: http://miniapp-url.com/?param=test)
}
Boxo.openMiniapp(
'[miniapp_id]', // miniapp ID to be launched
options // (optional) options
);
Sandbox mode
Sandbox mode
- when true, miniapps in “Approved” and “InTesting” statuses
- when false, miniapps only in “Approved” status
Get list of miniapps
Get list of miniapps
React.useEffect(() => {
const miniappListSubscription = Boxo.miniapps.subscribe((miniapps: MiniappData[]) => {
setMiniapps(miniapps);
}, (error) => {
console.log(error)
},
);
Boxo.getMiniapps();
return () => miniappListSubscription();
}, [])
Capacitor
Installation
Installation
npm install @appboxo/capacitor-boxo-sdk
npx cap sync
Launch Miniapp
Launch Miniapp
import { Boxo } from 'capacitor-boxo-sdk';
Boxo.setConfig({ clientId: clientId });
Boxo.openMiniapp({ appId: appId });
<!DOCTYPE html>
<html lang="en" dir="ltr" class="hydrated">
<head>
<meta charset="UTF-8" />
<title>Example Capacitor App</title>
<meta
name="viewport"
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="format-detection" content="telephone=no" />
</head>
<body>
<main>
<h1>Capacitor Test App</h1>
<p>Click to button to open Demo Miniapp</p>
<button onclick="openMiniapp()">Open miniapp</button>
</main>
<script src="./js/example.js" type="module"></script>
</body>
</html>
import { Boxo } from 'capacitor-boxo-sdk';
const clientId = '';
const appId = '';
Boxo.setConfig({
clientId: clientId
});
window.openMiniapp = () => {
Boxo.openMiniapp({ appId: appId});
};
Set Config
setConfig(options: ConfigOptions) => Promise<void>
Set Config
Set Config
| Prop | Type | Description |
|---|---|---|
| clientId | string | your client id from dashboard |
| userId | string | (optional) hostapp userId, will be used for the Consent Management |
| language | string | language value will be passed to the miniapp |
| sandboxMode | boolean | switch to sandbox mode |
| enableMultitaskMode | boolean | (Android only) Each miniapp appears as a task in the Recents screen. |
| theme | ’light’ | ‘dark’ | ‘system’ | theme for splash screen and other native components used inside miniapp. |
| isDebug | boolean | enables webview debugging |
| showPermissionsPage | boolean | use it to hide “Settings” from Miniapp menu |
| showClearCache | boolean | use it to hide “Clear cache” from Miniapp menu |
| showAboutPage | boolean | use it to hide “About Page” from Miniapp menu |
| miniappSettingsExpirationTime | number | use it to change miniapp settings cache time in sec. Default: 60 sec |
Miniapp Control
Miniapp Control
Open
openMiniapp(options: OpenMiniappOptions) => Promise<void>
| Prop | Type | Description |
|---|---|---|
| appId | string | miniapp id |
| data | object | (optional) data as Map that is sent to miniapp |
| theme | ’light’ | ‘dark’ | ‘system’ | (optional) miniapp theme “dark” | “light” (by default is system theme) |
| extraUrlParams | object | (optional) extra query params to append to miniapp URL (like: http://miniapp-url.com/?param=test) |
| urlSuffix | string | (optional) suffix to append to miniapp URL (like: http://miniapp-url.com/?param=test) |
| colors | ColorOptions | (optional) provide colors to miniapp if miniapp supports |
| enableSplash | boolean | (optional) use to skip miniapp splash screen |
| saveState | boolean | (optional) use to save state on close miniapp |
| pageAnimation | ’BOTTOM_TO_TOP’ | ‘TOP_TO_BOTTOM’ | ‘LEFT_TO_RIGHT’ | ‘RIGHT_TO_LEFT’ | ‘FADE_IN’ | (optional) use to change launch animation for miniapp |
| Prop | Type |
|---|---|
| primaryColor | string |
| secondaryColor | string |
| tertiaryColor | string |
Close
closeMiniapp(options: { appId: string; }) => Promise<void>
Hide
hideMiniapps() => Promise<void>
Miniapp Auth Flow
Miniapp Auth Flow
setAuthCode(options: { appId: string; authCode: string; }) => Promise<void>
User Logout & Data Clearing
User Logout & Data Clearing
logout() => Promise<void>
Retrieve Miniapp List
Retrieve Miniapp List
getMiniapps() => Promise<MiniappListResult>
| Prop | Type |
|---|---|
| miniapps | [MiniappData] |
| error | string |
| Prop | Type |
|---|---|
| appId | string |
| name | string |
| category | string |
| description | string |
| logo | string |
Miniapp Custom Events
Miniapp Custom Events
addListener(eventName: 'custom_event', listenerFunc: (customEvent: CustomEvent) => void) => Promise<PluginListenerHandle>
| Param | Type |
|---|---|
| eventName | ’custom_event’ |
| listenerFunc | (customEvent: CustomEvent) => void |
sendCustomEvent(customEvent: CustomEvent) => Promise<void>
| Prop | Type |
|---|---|
| appId | string |
| requestId | number |
| type | string |
| errorType | string |
| payload | object |
Miniapp Payment Events
Miniapp Payment Events
addListener(eventName: 'payment_event', listenerFunc: (paymentEvent: PaymentEvent) => void) => Promise<PluginListenerHandle>
| Param | Type |
|---|---|
| eventName | ’payment_event’ |
| listenerFunc | (paymentEvent: PaymentEvent) => void |
sendPaymentEvent(paymentEvent: PaymentEvent) => Promise<void>
| Prop | Type |
|---|---|
| appId | string |
| transactionToken | string |
| miniappOrderId | string |
| amount | number |
| currency | string |
| status | string |
| hostappOrderId | string |
| extraParams | object |
Miniapp Lifecycle Events
Miniapp Lifecycle Events
addListener(eventName: 'miniapp_lifecycle', listenerFunc: (lifecycle: LifecycleEvent) => void) => Promise<PluginListenerHandle>
| Param | Type |
|---|---|
| eventName | ’miniapp_lifecycle’ |
| listenerFunc | (lifecycle: LifecycleEvent) => void |
| Prop | Type |
|---|---|
| appId | string |
| lifecycle | string |
| error | string |
Expo
Expo plugin to integrate Boxo for iOS and Android. Please see our sample Expo app to learn more.Installation
Installation
npm install @appboxo/expo-boxo-sdk
{
"expo": {
"plugins": [
["@appboxo/expo-boxo-sdk"]
]
}
}
Launch Miniapp
Launch Miniapp
import * as Boxo from 'expo-boxo-sdk';
Boxo.setConfig({ clientId: clientId });
Boxo.openMiniapp({ appId: appId });
Set Config
Set Config
setConfig(options: ConfigOptions)
| Prop | Type | Description |
|---|---|---|
| clientId | string | your client id from dashboard |
| userId | string | (optional) hostapp userId, will be used for the Consent Management |
| language | string | language value will be passed to the miniapp |
| sandboxMode | boolean | switch to sandbox mode |
| enableMultitaskMode | boolean | (Android only) Each miniapp appears as a task in the Recents screen. |
| theme | ’light’ | ‘dark’ | ‘system’ | theme for splash screen and other native components used inside miniapp. |
| isDebug | boolean | enables webview debugging |
| showPermissionsPage | boolean | use it to hide “Settings” from Miniapp menu |
| showClearCache | boolean | use it to hide “Clear cache” from Miniapp menu |
| showAboutPage | boolean | use it to hide “About Page” from Miniapp menu |
| miniappSettingsExpirationTime | number | use it to change miniapp settings cache time in sec. Default: 60 sec |
Miniapp Control
Miniapp Control
Open
openMiniapp(options: MiniappOptions)
| Prop | Type | Description |
|---|---|---|
| appId | string | miniapp id |
| data | object | (optional) data as Map that is sent to miniapp |
| theme | ’light’ | ‘dark’ | ‘system’ | (optional) miniapp theme “dark” | “light” (by default is system theme) |
| extraUrlParams | object | (optional) extra query params to append to miniapp URL (like: http://miniapp-url.com/?param=test) |
| urlSuffix | string | (optional) suffix to append to miniapp URL (like: http://miniapp-url.com/?param=test) |
| colors | ColorOptions | (optional) provide colors to miniapp if miniapp supports |
| enableSplash | boolean | (optional) use to skip miniapp splash screen |
| saveState | boolean | (optional) use to save state on close miniapp |
| pageAnimation | ’BOTTOM_TO_TOP’ | ‘TOP_TO_BOTTOM’ | ‘LEFT_TO_RIGHT’ | ‘RIGHT_TO_LEFT’ | ‘FADE_IN’ | (optional) use to change launch animation for miniapp |
| Prop | Type |
|---|---|
| primaryColor | string |
| secondaryColor | string |
| tertiaryColor | string |
Close
closeMiniapp(appId: string)
Hide
hideMiniapps()
Miniapp Auth Flow
Miniapp Auth Flow
Boxo.addAuthListener((authEvent) => {
Boxo.setAuthCode(authEvent.appId, authCode)
});
User Logout & Data Clearing
User Logout & Data Clearing
logout()
Retrieve Miniapp List
Retrieve Miniapp List
Boxo.addMiniappListListener((result) => {
console.log(result.miniapps);
});
| Prop | Type |
|---|---|
| miniapps | [MiniappData] |
| error | string |
| Prop | Type |
|---|---|
| appId | string |
| name | string |
| category | string |
| description | string |
| logo | string |
Miniapp Custom Events
Miniapp Custom Events
Boxo.addCustomEventListener((customEvent) => {
..handle custom event
Boxo.sendCustomEvent(customEvent);
});
| Prop | Type |
|---|---|
| appId | string |
| requestId | number |
| type | string |
| errorType | string |
| payload | object |
Miniapp Payment Events
Miniapp Payment Events
Boxo.addPaymentEventListener((paymentData) => {
Boxo.hideMiniapps();
.. show payment page
paymentData.status = "success";
..confirm payment
Boxo.sendPaymentEvent(paymentData);
Boxo.openMiniapp({ appId: paymentData.appId })
});
| Prop | Type |
|---|---|
| appId | string |
| transactionToken | string |
| miniappOrderId | string |
| amount | number |
| currency | string |
| status | string |
| hostappOrderId | string |
| extraParams | object |
Miniapp Lifecycle Events
Miniapp Lifecycle Events
Boxo.addMiniappLifecycleListener((lifecycleData) => {
console.log(lifecycleData);
});
| Prop | Type |
|---|---|
| appId | string |
| lifecycle | string |
| error | string |
Web SDK
A JavaScript SDK for embedding miniapps into desktop web applications using iframe communication. Please see our sample web app to learn more.Installation
Installation
npm install @appboxo/web-sdk
pnpm install @appboxo/web-sdk
Launch Miniapp
Launch Miniapp
import { AppboxoWebSDK } from "@appboxo/web-sdk";
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id"
});
// Mount miniapp
await sdk.mount({
container: document.getElementById("miniapp")
});
Configuration
Configuration
const sdk = new AppboxoWebSDK({
clientId: string; // Required
appId: string; // Required
userId?: string; // Optional, user reference identifier
baseUrl?: string; // Optional, default: "https://dashboard.boxo.io/api/v1"
sandboxMode?: boolean; // Optional, default: false
debug?: boolean; // Optional, default: false. When true, enables all console logs for debugging
locale?: string; // Optional, locale/language code (e.g., 'en', 'en-US', 'ru', 'zh-CN')
theme?: 'dark' | 'light' | 'system'; // Optional, theme/color scheme preference (default: 'system')
allowedOrigins?: string[]; // Optional, restrict message events to specific origins. Empty array allows all origins
onGetAuthCode?: () => Promise<string>; // Optional, for automatic auth code retrieval
onGetAuthTokens?: () => Promise<LoginResponse>; // Optional, for direct auth tokens
onPaymentRequest?: (params: PaymentRequest) => Promise<PaymentResponse>; // Optional, for handling payment requests
});
Locale/Language
Set the locale/language code to pass to the miniapp. The locale will be included in the InitData response.// Set locale during initialization
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
locale: "en-US" // or 'ru', 'zh-CN', etc.
});
// Or set locale dynamically
sdk.setLocale("ru");
InitData.data.locale on the next AppBoxoWebAppGetInitData request.Important Notes:- If you call
setLocale()after the miniapp has already loaded, the locale will be included in the next InitData request. The miniapp may need to reload or request InitData again to receive the updated locale. - To ensure the locale is available immediately, set it during SDK initialization or before calling
mount().
Debug Mode
Control console logging for debugging:const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
debug: true // Enable debug mode
});
debug mode:debug: false(default): No console logs are output. Suitable for production.debug: true: All SDK operations are logged to console. Useful for development and troubleshooting.- The
debugoption does not affect SDK functionality - it only controls console logging.
Allowed Origins
Control which origins can send messages to the SDK for security:const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
allowedOrigins: ["https://miniapp.example.com"] // Restrict to specific origins
});
- Empty array
[](default): Allows all origins (flexible for different deployment URLs) - Set specific origins: Only messages from listed origins will be accepted
allowedOriginsshould be the miniapp’s origin (where iframe loads from), NOTwindow.location.origin
Miniapp Auth Flow
Miniapp Auth Flow
// Set auth code explicitly
const authCode = await fetch('/api/auth-code').then(r => r.json());
sdk.setAuthCode(authCode);
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
onGetAuthCode: async () => {
const res = await fetch('/api/generate-auth-code');
return (await res.json()).auth_code;
}
});
// Set tokens directly
const tokens = await getTokensFromBackend();
sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
onGetAuthTokens: async () => {
const res = await fetch('/api/get-miniapp-tokens');
const result = await res.json();
return {
token: result.access_token,
refresh_token: result.refresh_token
};
}
});
sdk.onAuth(async () => {
const response = await fetch('/api/get-miniapp-tokens');
const tokens = await response.json();
sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);
});
- Pre-set tokens (
setAuthTokens) - Direct auth callback (
onGetAuthTokens) - OAuth auth code (
setAuthCodeoronGetAuthCodecallback)
Payment Processing
Payment Processing
appboxo.pay(), the SDK will call your onPaymentRequest callback. Process the payment and return the result.Payment status values: 'success', 'failed', or 'cancelled'.const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
onPaymentRequest: async (paymentData) => {
// Process payment with your backend
const response = await fetch('/api/payments/process', {
method: 'POST',
body: JSON.stringify(paymentData)
});
const result = await response.json();
return {
...paymentData,
status: result.status, // 'success', 'failed', or 'cancelled'
hostappOrderId: result.orderId,
transactionId: result.transactionId, // optional
};
},
});
// Optional: listen for payment completion
sdk.onPaymentComplete((success, data) => {
if (success) {
console.log('Payment succeeded:', data);
}
});
- When
onPaymentRequestis set, the SDK automatically tells the miniapp it supportsAppBoxoWebAppPay, so it can callappboxo.pay(). - If
onPaymentRequestis not configured, payment requests will fail. Enabledebug: trueto see error messages.
Dark mode
Dark mode
// Set theme during initialization
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
theme: "dark" // or 'light', 'system'
});
// Or set theme dynamically
sdk.setTheme("light");
'dark': Force dark mode'light': Force light mode'system': Use system preference (default)
InitData.data.theme on the next AppBoxoWebAppGetInitData request. If you call setTheme() after the miniapp has already loaded, the SDK will automatically notify the miniapp about the theme change via postMessage, allowing the miniapp to respond immediately without waiting for the next InitData request.Important Notes:- To ensure the theme is available immediately, set it during SDK initialization or before calling
mount(). - The miniapp must implement theme handling logic to receive and apply the theme from
InitData.data.theme.
User Logout & Data Clearing
User Logout & Data Clearing
sdk.logout();
localStorage, sessionStorage, and SDK’s internal authCode and authTokens.Mount Miniapp
Mount Miniapp
await sdk.mount({
container: '#miniapp-container',
className: 'miniapp-iframe'
});
const iframe = document.createElement('iframe');
iframe.src = await sdk.getMiniappUrl();
document.getElementById('miniapp').appendChild(iframe);
sdk.setIframe(iframe);
sdk.initialize();
mount helper, styling is handled via CSS:.miniapp-container {
width: 100%;
height: 500px;
}
.miniapp-iframe {
width: 100%;
height: 100%;
border: none;
}
Retrieve Miniapp List
Retrieve Miniapp List
// Note: This feature may require additional API integration
// Check SDK documentation for latest implementation
Custom Events
Custom Events
sdk.onEvent('custom_event', (event) => {
// Handle custom event from miniapp
console.log('Custom event received:', event);
// Send response back to miniapp if needed
// (implementation depends on SDK version)
});
Methods
Methods
| Method | Description |
|---|---|
setAuthCode(code) | Set authentication code |
setAuthTokens(token, refreshToken?) | Set authentication tokens directly |
setLocale(locale) | Set locale/language code (e.g., ‘en’, ‘en-US’, ‘ru’, ‘zh-CN’) |
setTheme(theme) | Set theme/color scheme preference (‘dark’ | ‘light’ | ‘system’) |
onAuth(callback) | Register callback for authentication events |
mount(config) | Create iframe and initialize SDK |
getMiniappUrl() | Fetch miniapp URL from API settings endpoint |
setIframe(iframe) | Set iframe element manually |
initialize() | Start listening for events |
onEvent(type, handler) | Register custom event handler |
onLoginComplete(callback) | Login completion callback |
onPaymentComplete(callback) | Payment completion callback |
logout() | Clear host app’s localStorage, sessionStorage, and SDK’s internal auth data |
destroy() | Clean up resources |
Events
Events
AppBoxoWebAppLogin- User authenticationAppBoxoWebAppPay- Payment processingAppBoxoWebAppGetInitData- Initial data requestAppBoxoWebAppCustomEvent- Custom events
Lifecycle Events
Lifecycle Events
// Login completion
sdk.onLoginComplete((success, data) => {
if (success) {
console.log('Login succeeded:', data);
} else {
console.log('Login failed:', data);
}
});
// Payment completion
sdk.onPaymentComplete((success, data) => {
if (success) {
console.log('Payment succeeded:', data);
} else {
console.log('Payment failed:', data);
}
});
React Examples
React Examples
OAuth Flow Example
import { useEffect, useRef, useState } from "react";
import { AppboxoWebSDK } from "@appboxo/web-sdk";
import type { PaymentRequest, PaymentResponse } from "@appboxo/web-sdk";
function OAuthExample() {
const containerRef = useRef<HTMLDivElement>(null);
const sdkRef = useRef<AppboxoWebSDK | null>(null);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
debug: false,
allowedOrigins: [], // Empty array allows all origins
onPaymentRequest: async (paymentData: PaymentRequest): Promise<PaymentResponse> => {
const response = await fetch('/api/payments/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(paymentData)
});
const result = await response.json();
return {
...paymentData,
status: result.status,
hostappOrderId: result.hostappOrderId,
};
},
});
// Set auth code (OAuth flow)
sdk.setAuthCode("your-auth-code");
sdk.onLoginComplete((success, data) => {
console.log('Login:', success ? 'success' : 'failed', data);
});
sdk.onPaymentComplete((success, data) => {
console.log('Payment:', success ? 'success' : 'failed', data);
});
sdkRef.current = sdk;
const mountMiniapp = async () => {
if (containerRef.current) {
try {
await sdk.mount({
container: containerRef.current,
className: "miniapp-iframe"
});
setIsMounted(true);
} catch (err) {
console.error('Failed to mount miniapp:', err);
}
}
};
mountMiniapp();
return () => {
sdk.destroy();
};
}, []);
return (
<div>
<div ref={containerRef} style={{ width: '100%', height: '500px' }} />
<p>Status: {isMounted ? "Mounted" : "Mounting..."}</p>
</div>
);
}
Direct Auth Flow Example
import { useEffect, useRef, useState } from "react";
import { AppboxoWebSDK } from "@appboxo/web-sdk";
import type { PaymentRequest, PaymentResponse } from "@appboxo/web-sdk";
function DirectAuthExample() {
const containerRef = useRef<HTMLDivElement>(null);
const sdkRef = useRef<AppboxoWebSDK | null>(null);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
debug: false,
// Alternative: Use onGetAuthTokens callback
// onGetAuthTokens: async () => {
// const response = await fetch('/api/get-miniapp-tokens');
// const result = await response.json();
// return { token: result.access_token, refresh_token: result.refresh_token };
// }
});
// Direct auth flow - onAuth lifecycle hook
sdk.onAuth(async () => {
// Your backend calls Boxo Dashboard connect endpoint to get miniapp tokens
const response = await fetch('/api/get-miniapp-tokens', {
headers: { 'Authorization': `Bearer ${yourToken}` }
});
const tokens = await response.json();
sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);
});
// Alternative: Pre-set tokens if you already have them
// const tokens = await getTokensFromBackend();
// sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);
sdk.onLoginComplete((success, data) => {
console.log('Login:', success ? 'success' : 'failed', data);
});
sdkRef.current = sdk;
const mountMiniapp = async () => {
if (containerRef.current) {
try {
await sdk.mount({
container: containerRef.current,
className: "miniapp-iframe"
});
setIsMounted(true);
} catch (err) {
console.error('Failed to mount miniapp:', err);
}
}
};
mountMiniapp();
return () => {
sdk.destroy();
};
}, []);
return (
<div>
<div ref={containerRef} style={{ width: '100%', height: '500px' }} />
<p>Status: {isMounted ? "Mounted" : "Mounting..."}</p>
</div>
);
}