Skip to main content
This guide covers installing the Travel Rule widget SDK and setting it up in web and native applications.

Prerequisites

  • Access to Widgets API to create widget sessions
  • A quote or transaction with the travel-rule requirement

Installation

Install the SDK via npm:
npm install @uphold/enterprise-travel-rule-widget-web-sdk

Web app integration

Import and initialize the SDK in your application:
import { TravelRuleWidget } from '@uphold/enterprise-travel-rule-widget-web-sdk';

// Create the widget instance
const widget = new TravelRuleWidget(session, { debug: true });

// Set up event handlers
widget.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 element
widget.mountIframe(document.getElementById('tr-container'));
The session parameter is obtained from the Create Session endpoint.

Native app integration

For native applications, the widget runs in a WebView that loads an HTML page containing the SDK.

WebView HTML template

<!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>

Platform-specific setup

Configure the WebView and event bridge for your platform:
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}
    />
  );
};

Troubleshooting

Widget not displaying The widget loads in an iframe, which requires proper Content Security Policy (CSP) configuration. Add the following domains to your CSP directives:
  • Sandbox: https://travel-rule-widget.enterprise.sandbox.uphold.com
  • Production: https://travel-rule-widget.enterprise.uphold.com
Example CSP configuration:
<meta 
  http-equiv="Content-Security-Policy" 
  content="frame-src 'self' https://travel-rule-widget.enterprise.sandbox.uphold.com https://travel-rule-widget.enterprise.uphold.com;"
>
Events not firing in native apps Verify that:
  • JavaScript is enabled in the WebView
  • The message bridge is properly registered before the HTML page loads
  • Event handlers match the platform-specific bridge implementation

Next steps