Instantiate a PFM widget

In order to instantiate a widget we have set up a simple interface. You will be provided with a link to the application deployment bundle that hosts your widgets and you will need to pass in a valid token and widget_id for the widget to successfully render. There are also additional optional parameters that can be passed in.

There are multiple ways to load the widget and pass in the required parameters detailed below.

Passing in parameters in the URL:

In it’s simplest form you can call the widget like the examples below, with the required token and widget_id in the url passed to the webView or iframe. This is not our recommended method for production but is a good way to get started, and for demo and testing purposes.

val url = "$WIDGET_URI?widget_id=$widgetId&token=$token#$fragment"
webView.loadUrl(url)
import WebKit

let widgetUri = "your_widget_uri" // Replace with your actual widget URI
let widgetId = "your_widget_id"   // Replace with your actual widget ID
let token = "your_token"          // Replace with your actual token
let fragment = "your_fragment"    // Replace with your actual fragment

let urlString = "\(widgetUri)?widget_id=\(widgetId)&token=\(token)#\(fragment)"
if let url = URL(string: urlString) {
    let webView = WKWebView(frame: .zero) // Initialize your WebView
    let request = URLRequest(url: url)
    webView.load(request)
}
<!DOCTYPE html>
<html>
	<body>
    <iframe src="http://mh2.dev.127.0.0.1.nip.io:8777?widget_id=$widgetId&token=$token" title="iFrame Example"></iframe>
	</body>
</html>

Passing in parameters via window.__boot

We recommend this for any production builds. In the examples below we wait for the webView to be ready and load the widget via calling the window.__boot function with the required parameters.

import WebKit
// Assuming you're within your UIViewController
let webView = WKWebView(frame: self.view.frame)
self.view.addSubview(webView)
let widgetUrl = "widget-url"
let token = "your-token"
let numCreditCards = 2 // an example of additional config that can be passed in
let hash = "your-hash" // this is received from the universal link
let widgetId = "your-widget-id"
if let url = URL(string: widgetUrl) {
    webView.load(URLRequest(url: url))
}
webView.navigationDelegate = self
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    let jsCode = """
    if (window.__boot && typeof window.__boot === 'function') {
        window.__boot('\(token)', { numCreditCards: \(numCreditCards), hash: '\(hash)', widget_id: '\(widgetId)' });
    }
    """
    webView.evaluateJavaScript(jsCode, completionHandler: nil)
}

import android.webkit.WebView
import android.webkit.WebViewClient
// Within your Activity or Fragment
val webView: WebView = findViewById(R.id.webView)
webView.settings.javaScriptEnabled = true
val widgetUrl = "widget-url"
val token = "your-token"
val numCreditCards = 2
val hash = "your-hash" // this is received from the universal link
val widgetId = "your-widget-id"
webView.webViewClient = object : WebViewClient() {
    override fun onPageFinished(view: WebView, url: String) {
        val jsCode = """
            if (window.__boot && typeof window.__boot === 'function') {
                window.__boot('$token', { numCreditCards: $numCreditCards, hash: '$hash', widget_id: '$widgetId' });
            }
        """
        webView.evaluateJavascript(jsCode, null)
    }
}
webView.loadUrl(widgetUrl)
// main.dart

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';

void main() {
  runApp(
    MaterialApp(theme: ThemeData(useMaterial3: true), home: const WebViewApp()),
  );
}

class WebViewApp extends StatefulWidget {
  const WebViewApp({super.key});

  @override
  State<WebViewApp> createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  late final WebViewController controller;
  bool _hasBooted = false;

  Future<String?> fetchToken() async {
    try {
      final response = await http.get(
        Uri.parse('your_token_url'),
      );
      if (response.statusCode == 200) {
        final data = jsonDecode(response.body);
        return data['access_token'];
      } else {
        debugPrint('Failed to fetch token: ${response.statusCode}');
      }
    } catch (e) {
      debugPrint('Error fetching token: $e');
    }
    return null;
  }

  @override
  void initState() {
    super.initState();
    controller =
        WebViewController()
          ..setJavaScriptMode(JavaScriptMode.unrestricted)
          ..loadRequest(
            Uri.parse('your_widget_url'),
          )
          ..addJavaScriptChannel(
            'Android',
            onMessageReceived: handleMessageFromWebView,
          )
          ..addJavaScriptChannel(
            'webkit.messageHandlers.iosListener',
            onMessageReceived: handleMessageFromWebView,
          )
          ..setNavigationDelegate(
            NavigationDelegate(
              onPageFinished: (String url) async {
                if (!_hasBooted) {
                  final token = await fetchToken();
                  if (token != null) {
                    await controller.runJavaScript(
                      'window.__boot("$token", {widget_id: "your_widget_id"})',
                    );
                    _hasBooted = true;
                  }
                }
              },
            ),
          );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter WebView')),
      body: WebViewWidget(controller: controller),
    );
  }
}


When the widget is called with this data it will fetch the Moneyhub bundle and instantiate the specified widget id with a session for the user represented by the token.

In some cases, such as open banking connection flows, it will be necessary to forward url params into the widget.


What’s Next