Import and initialize the SDK in your application.Make sure the container that will host the widget has explicit dimensions in CSS. The Widget will fill the container bounds. Minimum recommended size is 400px × 600px.
JavaScript/TypeScript example
Copy
Ask AI
import { TravelRuleWidget } from '@uphold/enterprise-travel-rule-widget-web-sdk';// Create the widget instanceconst widget = new TravelRuleWidget(session, { debug: true });// Set up event handlerswidget.on('complete', (event) => { console.log('Travel Rule form completed:', event.detail.value); widget.unmount();});widget.on('cancel', () => { console.log('Travel Rule form cancelled by user'); widget.unmount();});widget.on('error', (event) => { console.error('Travel Rule form error:', event.detail.error); widget.unmount();});// Mount the widget's iframe to a DOM elementwidget.mountIframe(document.getElementById('tr-container'));
The session parameter is obtained from the Create Session endpoint.
Native mobile applications integrate the Travel Rule Widget using a WebView component that loads an HTML page containing the Travel Rule Widget SDK.To handle Travel Rule Widget events, your native application needs to implement a communication bridge between the WebView and native code. This bridge enables your native app to receive and respond to events from the Travel Rule Widget.
Create an HTML file that includes the Travel Rule Widget SDK in your JS bundle:
Copy
Ask AI
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Travel Rule widget</title> <style> body { margin: 0; padding: 0; } #travel-rule-container { width: 100%; height: 100vh; } </style> </head> <body> <div id="travel-rule-container"></div> <!-- Include your JS bundle which contains the SDK --> <script src="your-bundle-with-sdk.js"></script> <script> // Initialize widget when page loads window.addEventListener('load', () => { const session = /* Obtain session from Create Session endpoint */; const widget = new TravelRuleWidget(session); widget.on('complete', (event) => { sendToNativeApp('complete', event.detail); widget.unmount(); }); widget.on('cancel', () => { sendToNativeApp('cancel'); widget.unmount(); }); widget.on('error', (event) => { sendToNativeApp('error', event.detail.error); widget.unmount(); }); widget.mountIframe(document.getElementById('travel-rule-container')); }); // Helper function to send events to native app function sendToNativeApp(type, data = null) { const message = { type, data }; if (window.webkit?.messageHandlers?.travelRuleWidgetMessage) { // iOS - send all events through single handler window.webkit.messageHandlers.travelRuleWidgetMessage.postMessage(message); } else if (window.TravelRuleBridge) { // Android - send events through JavaScript interface window.TravelRuleBridge.onMessage(JSON.stringify(message)); } else if (window.ReactNativeWebView) { // React Native - send events through postMessage window.ReactNativeWebView.postMessage(JSON.stringify(message)); } } </script> </body></html>
The Travel Rule Widget SDK must be included in your WebView bundle (for example, via your build pipeline). Loading the SDK directly from a CDN is not supported.
Configure the WebView and event bridge for your platform:
iOS (Swift)
Android (Java/Kotlin)
React Native
Copy
Ask AI
import WebKitclass TravelRuleViewController: UIViewController, WKScriptMessageHandler { @IBOutlet weak var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() // Set up single message handler for all widget events let contentController = webView.configuration.userContentController contentController.add(self, name: "travelRuleWidgetMessage") // Load your HTML file with the widget if let url = Bundle.main.url(forResource: "travel-rule-widget", withExtension: "html") { webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent()) } } // Handle messages from the WebView func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "travelRuleWidgetMessage" { guard let messageDict = message.body as? [String: Any], let type = messageDict["type"] as? String else { return } let data = messageDict["data"] switch type { case "complete": handleTravelRuleComplete(data: data) case "cancel": handleTravelRuleCancel() case "error": handleTravelRuleError(error: data) default: print("Unknown Travel Rule widget message type: \(type)") } } } private func handleTravelRuleComplete(data: Any?) { // Handle successful Travel Rule compliance completion print("Travel Rule form completed: \(data ?? "no data")") // Proceed with the crypto transaction } private func handleTravelRuleCancel() { // Handle Travel Rule process cancellation print("Travel Rule form cancelled by user") // Navigate back or show cancellation message } private func handleTravelRuleError(error: Any?) { // Handle Travel Rule error print("Travel Rule form error: \(error ?? "unknown error")") // Show error message to user }}
Copy
Ask AI
import android.webkit.WebView;import android.webkit.WebSettings;import android.webkit.JavascriptInterface;import android.util.Log;import org.json.JSONObject;// Set up WebViewWebView webView = findViewById(R.id.webview);WebSettings webSettings = webView.getSettings();webSettings.setJavaScriptEnabled(true);// Add JavaScript interface to handle events from WebViewwebView.addJavascriptInterface(new TravelRuleBridge(), "TravelRuleBridge");// Load your HTML file with the widgetwebView.loadUrl("file:///android_asset/travel-rule-widget.html");// JavaScript interface class to handle WebView eventspublic class TravelRuleBridge { @JavascriptInterface public void onMessage(String messageJson) { try { JSONObject message = new JSONObject(messageJson); String type = message.getString("type"); Object data = message.opt("data"); runOnUiThread(() -> { switch (type) { case "complete": handleTravelRuleComplete(data != null ? data.toString() : null); break; case "cancel": handleTravelRuleCancel(); break; case "error": handleTravelRuleError(data != null ? data.toString() : null); break; default: Log.w("TravelRule", "Unknown Travel Rule widget message type: " + type); } }); } catch (Exception e) { Log.e("TravelRule", "Error parsing Travel Rule widget message", e); } } private void handleTravelRuleComplete(String data) { // Handle successful Travel Rule compliance completion Log.d("TravelRule", "Travel Rule form completed: " + data); // Proceed with the crypto transaction } private void handleTravelRuleCancel() { // Handle Travel Rule process cancellation Log.d("TravelRule", "Travel Rule form cancelled by user"); // Navigate back or show cancellation message } private void handleTravelRuleError(String error) { // Handle Travel Rule error Log.e("TravelRule", "Travel Rule form error: " + error); // Show error message to user }}
If you load local assets, ensure the WebView allows file access according to your security requirements (e.g., setAllowFileAccess(true) when needed).
Copy
Ask AI
import { WebView } from 'react-native-webview';import { Alert } from 'react-native';const TravelRuleScreen = () => { const handleMessage = (event) => { try { const message = JSON.parse(event.nativeEvent.data); switch (message.type) { case 'complete': handleTravelRuleComplete(message.data); break; case 'cancel': handleTravelRuleCancel(); break; case 'error': handleTravelRuleError(message.data); break; default: console.log('Unknown message type:', message.type); } } catch (error) { console.error('Error parsing WebView message:', error); } }; const handleTravelRuleComplete = (data) => { // Handle successful Travel Rule compliance completion console.log('Travel Rule form completed:', data); Alert.alert('Success', 'Travel Rule compliance completed!'); // Proceed with the crypto transaction }; const handleTravelRuleCancel = () => { // Handle Travel Rule process cancellation console.log('Travel Rule form cancelled by user'); Alert.alert('Cancelled', 'Travel Rule process was cancelled'); // Navigate back }; const handleTravelRuleError = (error) => { // Handle Travel Rule error console.error('Travel Rule form error:', error); Alert.alert('Error', 'An error occurred during Travel Rule compliance'); // Show error message or retry option }; return ( <WebView source={{ uri: 'file:///path/to/travel-rule-widget.html' }} javaScriptEnabled={true} domStorageEnabled={true} onMessage={handleMessage} /> );};
For iOS, file:// URLs may be restricted. Consider using source={{ html: '<html>...</html>' }} or loading a bundled asset and adjusting the URI per platform.
Widget not displayingThe widget loads in an iframe, which requires proper Content Security Policy (CSP) configuration. Add the following domains to your CSP directives: