> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate Any PFM Widget

This guide shows you how to integrate any PFM Widget on a website [using an iframe](#integrate-on-a-website-iframe) (recommended) or [using the Widget Loader](#integrate-on-a-website-widget-loader). You can also integrate on a [mobile app](#integrate-on-a-mobile-app).

<Info>
  **INFO**

  Before you can integrate the widget, you must have worked with MX to enable your access to our PFM product.
</Info>

For this guide, you'll either use the Platform API or SSO API. The API you use depends on what you have purchased and have enabled. If you have the Nexus API enabled, you'll use the SSO API.

## Integrate on a Website (iframe)

**Recommended**

This shows how to integrate the widget on a website using an iframe.

#### Step 1

Create an iframe. If you're integrating the Money Dashboard Widget, see [IFrame Integration](/products/experience/pfm/widget-overviews/money-dashboard-widget#iframe-integration) for a code example to help maintain proper display.

Set the width and height to 100%, or use the widget's [supported dimensions](/products/experience/pfm#supported-dimensions).

```html Example focus=1-5 theme={null}
<html>
  <body>
    <iframe width="100%" height="100%" src=""></iframe>
  </body>
</html>
```

#### Step 2

In the iframe's `src`, you'll need to request a widget URL by specifying the `widget_type`, using the [Platform API](/api-reference/platform-api/reference/request-widget-url) or the [SSO API](/api-reference/sso/v3/reference/widget-urls/get-widget-with-config-options).

For a list of acceptable values, see:

* [Widget Types](/api-reference/platform-api/reference/widgets#widget-types) for Platform API
* [Widget Types](/api-reference/sso/v3/reference/widget-urls/widget-types) for SSO API

The URL you'll receive is single-use and expires after 10 minutes. You must request a new URL every time the page is rendered.

```html Example focus=1-5 theme={null}
<html>
  <body>
    <iframe width="100%" height="100%" src=requestURL()></iframe>
  </body>
</html>
```

#### Step 3

Optionally create listeners for the [application events](#application-events).

See [Postmessage UI Events](#postmessage-ui-events) for more info.

```html Example focus=6-20 theme={null}
<html>
  <head>
  </head>
  <body>
    <iframe id="widgetIframe" width="100%" height="100%" src=requestURL()></iframe>
    <script>
        // an example for handling events.
        window.addEventListener('message', (event) => {
            if (event.data.mx) {
                // example of handling an application event.
                if (event.data.type === "mx/load") {
                  // This event is triggered when the widget is loaded.
                }
                
                // example of handling an application event.
                if (event.data.type === "mx/ping") {
                  // This event is triggered when the user interacts with the UI.
                }
            }
        });
    </script>
  </body>
</html>
```

#### Step 4

Depending on the widget you're integrating, you may have to create additional event listeners:

* If integrating the Connections Widget, you must create listeners for all the [Connections Widget events](#connections-widget-event), which includes all the Connect Widget's postMessage events.
* If integrating the Mini Finstrong Widget, you must create listeners for all the [Mini Finstrong Widget's events](#mini-finstrong-widget-events).

```html Example focus=6-20 theme={null}
<html>
  <head>
  </head>
  <body>
    <iframe id="widgetIframe" width="100%" height="100%" src=requestURL()></iframe>
    <script>
        // an example for handling events.
        window.addEventListener('message', (event) => {
            if (event.data.mx) {
                if (event.data.type === "mx/load") {
                  // This event is triggered when the widget is loaded.
                }
                
                if (event.data.type === "mx/ping") {
                  // This event is triggered when the user interacts with the UI.
                  // For example, when the user swipes through the carousel.
                }
            }
        });
    </script>
  </body>
</html>
```

## Integrate on a Website (Widget Loader)

This shows how to integrate the widget on a website using the widget loader.

#### Step 1

Request a widget URL by specifying the `widget_type`, using the [Platform API](/api-reference/platform-api/reference/request-widget-url) or the [SSO API](/api-reference/sso/v3/reference/widget-urls/get-widget-with-config-options).

For a list of acceptable values, see:

* [Widget Types](/api-reference/platform-api/reference/widgets#widget-types) for Platform API
* [Widget Types](/api-reference/sso/v3/reference/widget-urls/widget-types) for SSO API

The URL you'll receive is single-use and expires after 10 minutes. You must request a new URL every time the page is rendered.

Set the height and width to 100%. If you don't, it will default to 600px height and 100% width.

```html Example focus=1-16 theme={null}
<html>
  <head>
    <title>My Web Page</title>
    <script type="text/javascript" src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"></script>
    <script type="text/javascript">
      var myWidget = new MoneyDesktopWidgetLoader({
        url: 'https://widgets.moneydesktop.com/md/accounts/XXXXX',
        width: "100%",
        height: "100%"
      });
    </script>
  </head>
  <body>
    <div id="md-widget"></div>
  </body>
</html>
```

#### Step 2

Add the widget loader script to the page. Place this file before any other code related to the widgets. This custom script loads the widgets onto the page.

You can load the widget loader from the MX production server or download and store it in your local environment. We update the widget loader when needed, so if you're caching it on your server, refresh your cached version monthly.

```html Example focus=4:4 theme={null}
<html>
  <head>
    <title>My Web Page</title>
    <script type="text/javascript" src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"></script>
    <script type="text/javascript">
      var myWidget = new MoneyDesktopWidgetLoader({
        url: 'https://widgets.moneydesktop.com/md/accounts/XXXXX',
        width: "100%",
        height: "100%"
      });
    </script>
  </head>
  <body>
    <div id="md-widget"></div>
  </body>
</html>
```

#### Step 3

Add a widget placeholder element. Our widget loader will use this placeholder element to embed an iframe containing the widget. The element must have an `id` of `md-widget`.

```html Example focus=13-15 theme={null}
<html>
  <head>
    <title>My Web Page</title>
    <script type="text/javascript" src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"></script>
    <script type="text/javascript">
      var myWidget = new MoneyDesktopWidgetLoader({
        url: 'https://widgets.moneydesktop.com/md/accounts/XXXXX',
        width: "100%",
        height: "100%"
      });
    </script>
  </head>
  <body>
    <div id="md-widget"></div>
  </body>
</html>
```

#### Step 4

Load the widget into the placeholder element.

Create a new instance of the `MoneyDesktopWidgetLoader` class, which is defined in the widget loader script. When you instantiate `MoneyDesktopWidgetLoader`, you must pass in an object with at least the required URL parameter, and possibly one or more [optional parameters](#widget-loader-parameters).

The widget loader will wait until the page has been loaded, and then load the widget into the placeholder element.

Make sure the widget uses its [supported dimensions](/products/experience/pfm#supported-dimensions).

```html Example focus=5-11 theme={null}
<html>
  <head>
    <title>My Web Page</title>
    <script type="text/javascript" src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"></script>
    <script type="text/javascript">
      var myWidget = new MoneyDesktopWidgetLoader({
        url: 'https://widgets.moneydesktop.com/md/accounts/XXXXX',
        width: "100%",
        height: "100%"
      });
    </script>
  </head>
  <body>
    <div id="md-widget"></div>
  </body>
</html>
```

## Integrate on a Mobile App

To integrate the widget on a mobile app:

1. Request a PFM widget URL by specifying the `widget_type`, using the [Platform API](/api-reference/platform-api/reference/request-widget-url) or [SSO API](/api-reference/sso/v3/reference/widget-urls/get-widget-with-config-options). The URL you'll receive is single-use and expires after 10 minutes. You must request a new URL every time the page is rendered. For a list of acceptable values, see:
   * [Widget Types](/api-reference/platform-api/reference/widgets#widget-types) for Platform API
   * [Widget Types](/api-reference/sso/v3/reference/widget-urls/widget-types) for SSO API
2. Load the URL received from the previous request into a WebView.
3. See [Events in Mobile WebViews](#events-in-mobile-webviews).
4. Capture and parse URLs for [application events](#application-events).
5. If you're integrating the Connections Widget or Mini Finstrong Widget, you'll need to capture and parse URLs for additional events. See [PostMessage UI Events](#postmessage-ui-events) for more information.

### Common Problems

This section covers some common problems with loading a widget URL into a WebView.

#### Minimum Size

To embed our mobile widgets into a WebView, we require a device width of at least 320 pixels. Depending on the implementation of the WebView, smaller devices may not be provided the full width, leading to display issues.

<Note>
  **MONEY DASHBOARD INTEGRATION**

  In order to have the benefit of the full responsive nature of our application, please don't restrict the available browser width by adding margins or padding.
</Note>

#### WKWebView vs. UIWebView (iOS)

In apps that run in iOS 8 and later, MX only supports WKWebView. If you previously implemented UIWebView, update your implementation to use WKWebView.

Apple recommends this. For more information, see Apple's developer documentation for [UIWebView](https://developer.apple.com/documentation/uikit/uiwebview) and [WKWebView](https://developer.apple.com/documentation/webkit/wkwebview).

#### Default Padding (iOS)

iOS adds additional padding to its WebViews by default, which sometimes causes problems.

To fix this:

1. Select the WebView providing the widgets in your application and navigate to the size inspector.
2. Change the layout margins from `"Default"` to `"Explicit"`.
3. Update the left and right margins to `"0"`.
4. Ensure the Width is at least 320 pixels.

#### Default Margin (iOS and Android)

Whether using WebViews on Android or iOS, most browsers will have a default margin (set in the user agent stylesheet) on the body element when rendering the HTML page responsible for loading a widget. This margin is deducted from the total available width of the containing element, which will cause a problem.

To fix this:

1. Determine the computed width available on the body element.
   * The width available to the iframe can be confirmed by inspecting the iframe injected by MX and typing window\.innerWidth in the JavaScript console. The width available to the iframe must be at least 320 pixels.
2. Confirm the body and HTML elements have their padding and margin set to "0."

#### Viewport (iOS and Android)

For mobile widgets to render correctly, the viewport must be set in a meta tag on the HTML page used to load the widget URL.

The viewport is the size of the window through which a page is seen. It can be smaller or larger than the actual size of a page or device screen.

On most mobile devices, the virtual viewport is larger than the actual screen size; web pages are rendered according to the viewport size, then shrunk down to the actual screen size. This helps when viewing pages that aren't optimized for mobile, but for pages that are optimized for mobile (like the mobile widgets), the viewport meta tag is used to guarantee that the page is rendered properly.

Set a meta tag within the `<head>` element as follows.

```html Example theme={null}
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
```

## Widget Loader Configurations

This section is for integrating a widget on desktop using the Widget Loader.

It shows the [parameters](#widget-loader-parameters) you'll use to set things like the widget's height and width, [additional configurations](#additional-configurations) that let you set configurations for specific widgets, and also has the following sections to further help your integration:

* [Create a Loading Message](#create-a-loading-message)
* [Keeping a Session Alive and Logging Out](#keeping-a-session-alive-and-logging-out)
* [Loading Multiple Widgets](#loading-multiple-widgets)
* [Loading Widgets at Different Times](#loading-widgets-at-different-times)
* [Master Widget Deep Linking](#master-widget-deep-linking)

### Widget Loader Parameters

When you instantiate `MoneyDesktopWidgetLoader`, you must pass in an object with at least the required URL parameter, and any of the following optional parameters.

| Parameter  | Required? | Default Value | Description                                                                                                                                                                                    |
| ---------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `autoload` | No        | `true`        | Determines if the widget loads automatically. See [Loading Widgets at Different Times](#loading-widgets-at-different-times).                                                                   |
| `config`   | No        |               | This contains an object in which you can pass several configuration options specific to a given widget type. See [Config Parameter](#config-parameter) for all options.                        |
| `deepLink` | No        | `accounts`    | Only use this for the Master Widget. This lets you set which widget loads in the Master Widget by default. See [Master Widget Deep Linking](#master-widget-deep-linking) for more information. |
| `height`   | No        | `600`         | The widget's height, in pixels or a percentage.                                                                                                                                                |
| `id`       | No        | `'md-widget'` | Tells the widget loader what element to place the widget in. See [Loading Multiple Widgets](#loading-multiple-widgets).                                                                        |
| `width`    | No        | `'100%'`      | The widget's width, in pixels or a percentage.                                                                                                                                                 |
| `url`      | Yes       |               | The widget's URL, received through an SSO API or Platform API request.                                                                                                                         |

#### Config Parameter

The `config` object, as shown in the following example, contains configurations options.

```html Example theme={null}
var myWidget = new MoneyDesktopWidgetLoader({
  url: getUrl(url),
  width: "100%",
  height: "100%",
  config: {
    transactions: {
      selected_account_guid: "ACT-bb749d65-7a86-bece-7138-9690b4e8a212"
    }
  },
  postMessageOrigin: "*"
});
```

Specific options are nested under the name of the widget being configured. You can use one of the following widget names for that name:

* `accounts`
* `budgets`
* `connections`
* `debts`
* `goals`
* `help`
* `master`
* `mini_budgets`
* `mini_spending`
* `mini_spending_plan`
* `settings`
* `spending`
* `spending_plan`
* `transactions`
* `trends`

You can set the following configuration options. Boolean fields default to false unless otherwise specified.

| Configuration Option           | Data Type | Widget       | Description                                                                                                                                                                                                                                            |
| ------------------------------ | --------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `is_mobile_webview`            | Boolean   | All          | Renders the widget in a mobile WebView. Executes URL updates in place of the JavaScript event postMessages.                                                                                                                                            |
| `language`                     | String    | All          | **Deprecated**. See [Supported Languages](/products/experience/pfm#supported-languages). Defaults to `en-us`.                                                                                                                                          |
| `ui_message_version`           | Integer   | All          | Determines which version of postMessage events are triggered. All new implementations must include this option when getting any widget URL and must set it to version `4`. Prior versions are deprecated and supported only for existing integrations. |
| `hide_mark_as_duplicate`       | Boolean   | Connections  | Hides the "mark as duplicate" feature option in the widget.                                                                                                                                                                                            |
| `hide_partner_managed_members` | Boolean   | Connections  | Hides any "home" members that are managed by the partner.                                                                                                                                                                                              |
| `selected_institution_guid`    | String    | Connections  | Loads the widget to a specific selected institution.                                                                                                                                                                                                   |
| `selected_member_guid`         | String    | Connections  | Loads the widget to a selected member.                                                                                                                                                                                                                 |
| `update_credentials`           | Boolean   | Connections  | Loads to the update credential feature for a current member. Optionally used with `selected_member_guid`.                                                                                                                                              |
| `hide_account_filter`          | Boolean   | Transactions | Hides the account filter feature within the widget.                                                                                                                                                                                                    |
| `selected_account_guid`        | String    | Transactions | Loads the widget to a selected account.                                                                                                                                                                                                                |

### Create a Loading Message

Any HTML placed inside of the widget placeholder element will be replaced once the widget iframe has loaded. This means you can use the placeholder element's inner HTML to display a loading message. Because this is just HTML, it can be text, images, or anything you want.

The following example adds some loading text that will appear until the widget has loaded.

```html Example theme={null}
<html>
  <head>
    <title>My Web Page</title>
    <script
      type="text/javascript"
      src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"
    ></script>
    <script type="text/javascript">
      var myWidget = new MoneyDesktopWidgetLoader({
        url: "https://widgets.moneydesktop.com/md/accounts/XXXXX",
        width: "100%",
        height: "100%"
      });
    </script>
  </head>
  <body>
    <div id="md-widget">
      Loading...
    </div>
  </body>
</html>
```

### Keeping a Session Alive and Logging Out

MX provides two important functions for the widget loader: ping and logout.

The **ping** function resets the session timer, allowing you to keep the session open as long as needed. The default timeout period is 900 seconds, and ping can be used anywhere in that period to restart the timer. A custom timeout period can be set by contacting MX, but MX recommends using the ping method rather than setting a longer timeout.

```html theme={null}
<script type="text/javascript">
  var myWidget = new MoneyDesktopWidgetLoader({
    url: "https://widgets.moneydesktop.com/md/accounts/XXXXX",
    width: "100%",
    height: "100%"
  });

  myWidget.ping();
</script>
```

The **logout** function ends the session and redirects to the session timeout URL defined in your client profile. If no URL is defined, there is no redirect.

Contact MX if you wish to set a specific session timeout URL.

### Loading Multiple Widgets

To load multiple widgets on a single page:

1. Define multiple placeholder elements, each with a unique CSS `id`.
2. In your JavaScript, create an instance of `MoneyDesktopWidgetLoader` for each widget.
3. Connect each loader instance to a placeholder element by setting the `id` property value as the CSS `id`.

After the page has loaded, all widgets will load in their respective elements.

Here’s an example of loading 3 separate widgets onto a single page.

```html Example theme={null}
<html>
  <head>
    <title>My Web Page</title>
    <script
      type="text/javascript"
      src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"
    ></script>
    <script type="text/javascript">
      var myAccountsWidget = new MoneyDesktopWidgetLoader({
        url: "https://widgets.moneydesktop.com/md/accounts/XXXXX",
        width: "100%",
        height: "100%",
        id: "my-accounts-widget"
      });

      var myTransactionsWidget = new MoneyDesktopWidgetLoader({
        url: "https://widgets.moneydesktop.com/md/transactions/XXXXX",
        width: "100%",
        height: "100%",
        id: "my-transactions-widget"
      });

      var myBudgetsWidget = new MoneyDesktopWidgetLoader({
        url: "https://widgets.moneydesktop.com/md/budgets/XXXXX",
        width: "100%",
        height: "100%",
        id: "my-budgets-widget"
      });
    </script>
  </head>
  <body>
    <div id="my-accounts-widget"></div>
    <div id="my-transactions-widget"></div>
    <div id="my-budgets-widget"></div>
  </body>
</html>
```

### Loading Widgets at Different Times

By default, widgets load automatically once the web page has loaded. If you'd like to load your widgets manually you can use the autoload option by setting autoload to false when instantiating `MoneyDesktopWidgetLoader`.

When you're ready to load a widget, call the load method on the instance of `MoneyDesktopWidgetLoader` with the URL.

Here’s an example of loading the Accounts Widget on page load, then loading the Transactions Widget when a button is selected.

```html Example theme={null}
<html>
  <head>
    <title>My Web Page</title>
    <script
      type="text/javascript"
      src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"
    ></script>
    <script type="text/javascript">
      var myAccountsWidget = new MoneyDesktopWidgetLoader({
        url: "https://widgets.moneydesktop.com/md/accounts/XXXXX",
        width: "100%",
        height: "100%",
        id: "my-accounts-widget"
      });

      var myTransactionsWidget = new MoneyDesktopWidgetLoader({
        url: "https://widgets.moneydesktop.com/md/transactions/XXXXX",
        width: "100%",
        height: "100%",
        id: "my-transactions-widget",
        autoload: false
      });

      var loadTransactionsButton = document.getElementById('load-transactions');

      loadTransactionsButton.addEventListener('click', function(ev) {
        getTransactionWidgetURL().then(widgetURL => {
          myTransactionsWidget.load(widgetURL);
        });
      });
    </script>
  </head>
  <body>
    <div id="my-accounts-widget"></div>
    <button id="load-transactions">Load Transactions</button>
    <div id="my-transactions-widget"></div>
  </body>
</html>
```

### Master Widget Deep Linking

By default, the Master Widget displays the Accounts Widget on initial load. If you want to display a different widget on initial load, set the `deepLink` attribute in `MoneyDesktopWidgetLoader` to one of the following values:

| Widget               | `deepLink` Value |
| :------------------- | :--------------- |
| Accounts Widget      | `accounts`       |
| Budgets Widget       | `budgets`        |
| Debts Widget         | `debts`          |
| Goals Widget         | `goals`          |
| Investments Widget   | `investments`    |
| Net Worth Widget     | `net-worth`      |
| Spending Widget      | `spending`       |
| Spending Plan Widget | `spending_plan`  |
| Transactions Widget  | `transactions`   |
| Trends Widget        | `trends`         |

If you want your Master Widget to load the Spending Plan Widget by default, you can set `deepLink` to `spending_plan` as follows.

```html Example theme={null}
<script>
  var myMasterWidget = new MoneyDesktopWidgetLoader({
    url: "https://int-widgets.moneydesktop.com/md/master/XXXX",
      width: "100%",
      height: "100%",
      deepLink: "spending_plan"
    });
</script>
```

Example scenario: you want to run an email campaign to increase user engagement with the Spending Widget. By default your Master Widget displays the Accounts Widget on initial load, but in this case you want to display the Spending Widget on initial load.

In your email, you might have a link that looks like: `<a href="http://yourinstitutiondomain.com/#spending">Click Here</a>`. When a user clicks that link, they would be taken to the page that contains your implementation of the Master Widget. On that page you'd need logic that parses the URL to determine if a `deepLink` value should be set. This can be done with some simple JavaScript.

Your code might look like the following example.

```html Example theme={null}
<a href="http://yourinstitutiondomain.com/#spending">Click Here</a>

<html>
  <head>
    <title>My Web Page</title>
    <script
      type="text/javascript"
      src="https://widgets.moneydesktop.com/assets/mx-widgetloader.js"
    ></script>
    <script type="text/javascript">
      var widgetOptions = {
        url: "https://widgets.moneydesktop.com/md/master/XXXXX",
        width: "100%",
        height: "100%",
        id: "my-master-widget"
      };

      if (window.location.hash) {
        widgetOptions.deepLink = window.location.hash.replace("#", "");
      }

      var myMasterWidget = new MoneyDesktopWidgetLoader(widgetOptions);
    </script>
  </head>
  <body>
    <div id="my-master-widget"></div>
  </body>
</html>
```

## PostMessage UI Events

When certain events are triggered in our UI, we send you a postMessage UI event. These events have the information you need to take action in your codebase in response to the event.

If integrating on mobile through a WebView, an alternative to standard postMessage UI events is required. See [Events in Mobile WebViews](#events-in-mobile-webviews) for more information.

<Warning>
  **WARNING**

  Don't use postMessage UI events for keeping data in sync between platforms. [Webhooks](/resources/webhooks) are a more reliable way of coordinating events between your servers and MX servers.
</Warning>

PostMessage UI events from MX have the following properties:

* The `mx` field that lets you filter out postMessage UI events coming from MX.
* The `type` field that identifies what the event represents at a high level.
* The `metadata` object field that has information related to the `type`.

The following is an example integration that lets you listen to the events we send.

```js Example Integration theme={null}

function handleEvent(event) {
  if (event.data.mx) {
    // handle the mx post message using event.data.type and event.data.metadata.
  }
}

window.addEventListener('message', handleEvent)
```

### Events in Mobile WebViews

<Note>
  **NOTE**

  This section only applies if you are embedding the widget in a WebView.
</Note>

Because of the technical limitations of WebView-based widget integrations, an alternative to standard postMessage UI events is required if embedding the widget into a WebView.

When requesting widget URLs using the Platform API or SSO API, you must include the `is_mobile_webview` field with a value of true in your request to access WebView event messages.

In WebView integrations, you must capture the URLs delivered via `window.location = "someurl"` calls within the iframe and use the information provided in those calls to build the necessary logic for coordinating events.

All MX URL message events will have the `mx://` prefix as well as the following format: `mx://<entity|widget>/<event>?metadata=<metadata as an encodedURI JSON string>`.

The following is an example URL message:
`mx://account/created?metadata="{'guid':'ACT-1'}"`.

You must capture the URL, parse out the path and query string, then JSON-decode the `metadata` field.

### Application Events

You must create listeners for our postMessage UI application events.

#### Widget Load

This event is triggered when the widget is loaded.

```json theme={null}
{
  "type": "mx/load",
  "mx": true
}
```

#### Widget Ping

This event is used to keep the widget session alive.

```json theme={null}
{
  "type": "mx/ping",
  "mx": true,
  "metadata": {
    "user_guid": "USR-123",
    "session_guid": "ANS-123"
  }
}
```

#### Widget focusTrap

This event is triggered when popover content which traps the focus onto a particular element is opened or closed, but only in the case that no other popover content is already open. This event is triggered by some drawers, menu buttons, and modals.

```json theme={null}
{
  "type": "mx/focusTrap",
  "mx": true,
  "metadata": {
    "trapped": "true"
  }
}
```

### Connections Widget Event

You must create a listener for one event specific to the Connections Widget: the Member Deleted event.

All [postMessage UI events that apply to the Connect Widget](/connect/widget-events) also apply to the Connections Widget.

#### Member Deleted

This event is triggered when a member has been deleted in the widget.

```json Example theme={null}
{
  "type": "mx/connections/memberDeleted",
  "mx": true,
  "metadata": {
    "user_guid": "USR-123",
    "session_guid": "ANS-123",
    "member_guid": "MBR-123"
  }
}
```

### Mini Finstrong Widget Events

The following events are for the Finstrong Mini Widget.

#### Sufficient Data, Primary Action Selected

This event is triggered when the user has enough data to generate a Finstrong health score and the primary action is selected.

```json Example theme={null}
{
  "type": "mx/miniFinstrong/sufficientData/primaryAction",
  "mx": true,
  "metadata": {
    "user_guid": "USR-123",
    "session_guid": "ANS-123",
  }
}
```

#### Insufficient Data, Primary Action Selected

This event is triggered when the user doesn't have enough data to generate a Finstrong health score and the primary action is selected.

```json Example theme={null}
{
  "type": "mx/miniFinstrong/insufficientData/primaryAction",
  "mx": true,
  "metadata": {
    "user_guid": "USR-123",
    "session_guid": "ANS-123",
  }
}
```

### Deprecated PostMessage Events

<Info>
  **INFO**

  These events are deprecated and are only supported for existing integrations.
</Info>

A postMessage is an event-based protocol that allows you to take action in your own codebase in response to events triggered within a widget's user interface. They're intended specifically to allow your code and a widget's user interface to work in concert, not to give a full picture of events happening on MX servers. PostMessage events shouldn't be used for analytics or for keeping data in sync between platforms.

Webhooks are a more reliable way of coordinating events between your servers and MX servers, rather than the UI-oriented postMessages.

#### Maintaining Sessions

Because our widgets are embedded through iframes, the parent frame (usually `window`) isn't aware of any activity going on within the iframe. This can cause the online banking session to time out even though the user is actively using a widget. To prevent this, each of our widgets will periodically send a [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage) to the parent frame. The postMessage will contain a JSON-formatted string as follows.

The most common way to take advantage of these postMessages is to implement an event listener function that will capture any postMessages. When a postMessage is captured, you can then tell your application to maintain its session. An example also follows.

```json theme={null}
{
  "moneyDesktop": true,
  "payload": {},
  "timeStamp": 123435234,
  "type": "ping"
}
```

```javascript theme={null}
var onPostMessage = function(evt) {
  var postMessageData = JSON.parse(evt.data);

  // Check to see if the post message is from MoneyDesktop
  if (postMessageData.moneyDesktop) {
    // Do something to keep my app's session alive
  }
};

window.addEventListener("message", onPostMessage);
```

#### Widget Events

Sometimes, your application may want to know about specific events that have occurred within the widget iframe. To account for this, we send [postMessages](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage) for specific widget events.

All widget event postMessages will contain a JSON-formatted string with the structure shown to the right.

<Info>
  **INFO**

  PostMessage events related to members — such as member updated — will contain the `connection_status` field. This field indicates the current status of the member's aggregation.
</Info>

```json theme={null}
{
  "type": "event_name",
  "moneyDesktop": true,
  "timeStamp": 1426627364010,
  "payload": {
    "type": "indicates the type of payload object"
    ... (additional payload fields)
  }
}
```

<Tabs>
  <Tab title="Account Created">
    This event triggers when any account is created. The `is_manual` field can be used to distinguish manual accounts from other accounts.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "account_subtype": "",
        "account_type": "PROPERTY",
        "balance": 25000,
        "guid": "MBR-12345",
        "id": "A-12345",
        "is_closed": "false",
        "is_hidden": "false",
        "is_manual": "true",
        "member_guid": "MBR-12345",
        "name": "Delorean",
        "property_type": "VEHICLE",
        "type": "account"
      },
      "timeStamp": 1426627364010,
      "type": "created"
    }
    ```
  </Tab>

  <Tab title="Account Updated">
    Triggered when an existing account is updated.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "account_subtype": "",
        "account_type": "CHECKING",
        "balance": 2500,
        "guid": "ACT-12345",
        "id": "A-12345",
        "is_closed": "false",
        "is_hidden": "false",
        "is_manual": "false",
        "member_guid": "MBR-12345",
        "name": "Zen Checking",
        "property_type": "",
        "type": "account"
      },
      "timeStamp": 1426627364010,
      "type": "updated"
    }
    ```
  </Tab>

  <Tab title="Account Deleted">
    Triggered when an existing account is deleted.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "account_subtype": "",
        "account_type": "SAVINGS",
        "balance": 5000,
        "guid": "ACT-12345",
        "id": "A-12345",
        "is_closed": "false",
        "is_hidden": "false",
        "is_manual": "false",
        "member_guid": "MBR-12345",
        "name": "Zen Savings",
        "property_type": "",
        "type": "account"
      },
      "timeStamp": 1426627364010,
      "type": "deleted"
    }
    ```
  </Tab>
</Tabs>

<Tabs>
  <Tab title="Member Created">
    Triggered when a member is created. This event is triggered on the creation of the member before any aggregation is initiated. The aggregation-related fields, such as `most_recent_job_guid`, may be `null`.

    ```json theme={null}
      {
        "moneyDesktop": true,
        "payload": {
          "connection_status": "CREATED",
          "guid": "MBR-45678",
          "institution_guid": "INS-12345",
          "is_manual": false,
          "most_recent_job_guid": null,
          "name": "Zen Bank",
          "type": "member"
        },
        "timeStamp": 1566425077001,
        "type": "created"
      }
    ```
  </Tab>

  <Tab title="Member Updated">
    Triggered when an existing member is updated.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "accounts_count": 3,
        "connection_status": "CONNECTED",
        "guid": "MBR-12345",
        "id": "M-12345",
        "institution_guid": "INS-12345",
        "is_manual": "false",
        "is_user_created": "false",
        "most_recent_job_guid": "JOB-12345",
        "name": "Zen Bank",
        "type": "member"
      },
      "timeStamp": 1426627364010,
      "type": "updated"
    }
    ```
  </Tab>

  <Tab title="Member Deleted">
    Triggered when an existing member is deleted.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "accounts_count": 3,
        "connection_status": "CONNECTED",
        "guid": "MBR-12345",
        "id": "M-12345",
        "institution_guid": "INS-12345",
        "is_manual": "false",
        "is_user_created": "false",
        "most_recent_job_guid": "JOB-12345",
        "name": "Zen Bank",
        "type": "member"
      },
      "timeStamp": 1426627364010,
      "type": "deleted"
    }
    ```
  </Tab>
</Tabs>

<Tabs>
  <Tab title="Transaction Created">
    Triggered when a new transaction is created. This includes the creation of child transactions when the parent transaction is split.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "account_guid": "ACT-12345",
        "amount": 4.25,
        "category_guid": "CAT-12345",
        "date": 1425384000,
        "description": "Transaction Description",
        "guid": "TRN-12345",
        "has_been_split": false,
        "memo": "Transaction Memo",
        "parent_guid": "TRN-45678",
        "transaction_type": 2,
        "type": "transaction"
      },
      "timeStamp": 1426627364010,
      "type": "created"
    }
    ```
  </Tab>

  <Tab title="Transaction Updated">
    Triggered when a transaction `amount`, `account_guid`, `category_guid`, `date`, `memo`, `transaction_type`, or `description` is changed by the User, or when a split has been added or removed.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "account_guid": "ACT-12345",
        "amount": 4.25,
        "category_guid": "CAT-12345",
        "date": 1425384000,
        "description": "Transaction Description",
        "guid": "TRN-12345",
        "has_been_split": true,
        "memo": "Transaction Memo",
        "parent_guid": null,
        "transaction_type": 2,
        "type": "transaction"
      },
      "timeStamp": 1426627364010,
      "type": "updated"
    }
    ```
  </Tab>

  <Tab title="Transaction Deleted">
    Triggered when a transaction is deleted.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "account_guid": "ACT-12345",
        "amount": 100,
        "category_guid": "CAT-12345",
        "date": 1501113600,
        "description": "Transaction Description",
        "guid": "TRN-12345",
        "has_been_split": false,
        "memo": null,
        "parent_guid": null,
        "transaction_type": 1,
        "type": "transaction"
      },
      "timeStamp": 1426627364010,
      "type": "deleted"
    }
    ```
  </Tab>
</Tabs>

<Tabs>
  <Tab title="Focus Trap: trapped: true">
    This event is triggered when popover content is opened which traps the focus onto a particular element, but only in the case that no other popover content is already open. This event is triggered by drawers, menu buttons, and modals.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "trapped": true
      },
      "timeStamp": 1426627364010,
      "type": "focusTrap"
    }
    ```
  </Tab>

  <Tab title="Focus Trap: trapped: false">
    This event is triggered when popover content that has trapped focus onto a particular element is closed, but only in the case that no other popover content is open. This event is triggered by closing drawers, menu buttons, and modals.

    ```json theme={null}
    {
      "moneyDesktop": true,
      "payload": {
        "trapped": false
      },
      "timeStamp": 1426627364010,
      "type": "focusTrap"
    }
    ```
  </Tab>
</Tabs>

##### PostMessage UI Events in Mobile WebViews

Because of the technical limitations of WebView-based widget implementations, an alternative to standard postMessages is required. MX has developed a simple URL-based updating mechanism to replace event messages that are available to other implementations. Capture these URLs and use the information provided in them to build the necessary logic for coordinating application events. URL event messages are available for the widget events outlined in the following sections.

When requesting widget URLs using the SSO API, you must include the `is_mobile_webview` field with a value of `true` in your request to access WebView event messages.

<Info>
  **INFO**

  PostMessage events related to members — such as member updated — will contain the `connection_status` field. This field indicates the current status of the member's aggregation.
</Info>

###### Sample Capture Scripts

The following are example capture scripts in the Java and Swift languages.

```java Java theme={null}
public class MainActivity extends AppCompatActivity {
    private WebView webView = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      webView = (WebView) findViewById(R.id.webview);
      webView.setWebViewClient(new MxWebViewClient());
      webView.getSettings().setDomStorageEnabled(true);
      webView.getSettings().setJavaScriptEnabled(true);
    }
    private class MxWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.startsWith("mx://")) {
                //Take action here.
                return true;
            } else
            return false;
        }
    }
}
```

```swift Swift theme={null}
class ViewController: UIViewController, WKUIDelegate {
  override func viewDidLoad() {
      super.viewDidLoad()
      webView.delegate = self
      ...
  }

  func webView(_ webView: WKWebView, decidePolicyFor
    navigationAction: WKNavigationAction,
               decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {

    // Intercept custom URI
    let surl = webView.url?.absoluteString
    if  (surl?.hasPrefix("mx://"))! {
      // Take action here

      // Cancel request
      decisionHandler(.cancel)
      return
    }

    // Allow request
    decisionHandler(.allow)
  }
}
```

<Tabs>
  <Tab title="Account Created URL">
    This event message triggers when any account is created. The `is_manual` field can be used to distinguish manual accounts from other accounts.

    * Base URL: `mx://accountCreated`
    * Example payload: `mx://accountCreated?account_subtype=""?account_type="PROPERTY"?balance=25000?guid="ACT-12345"?id="A-12345"?is_closed="false"?is_hidden="false"?is_manual="true"?member_guid="MBR-12345"?name="Delorean"?property_type="VEHICLE"?type="account"`
  </Tab>

  <Tab title="Account Updated URL">
    * Base URL: `mx://accountUpdated`
    * Example payload: `mx://accountUpdated?account_subtype=""?account_type="PROPERTY"?balance=25000?guid="ACT-12345"?id="A-12345"?is_closed="false"?is_hidden="false"?is_manual="true"?member_guid="MBR-12345"?name="Delorean"?property_type="VEHICLE"?type="account"`
  </Tab>

  <Tab title="Account Deleted URL">
    * Base URL: `mx://accountDeleted`
    * Example payload: `mx://accountDeleted?account_subtype=""?account_type="PROPERTY"?balance=25000?guid="ACT-12345"?id="A-12345"?is_closed="false"?is_hidden="false"?is_manual="true"?member_guid="MBR-12345"?name="Delorean"?property_type="VEHICLE"?type="account"`
  </Tab>
</Tabs>

<Tabs>
  <Tab title="Member Created URL">
    * Base URL: `mx://memberCreated`
    * Example payload: `mx://memberCreated?accounts_count=0?connection_status="CREATED"?guid="MBR-12345"?id=""?institution_guid?"INS-12345"?is_manual="false"?is_user_created="false"?most_recent_job_guid?""?name="Zen Bank"?type="member"`
  </Tab>

  <Tab title="Member Updated URL">
    * Base URL: `mx://memberUpdated`
    * Example payload: `mx://memberUpdated?accounts_count=3?connection_status="CONNECTED"?guid="MBR-12345"?id="M-12345"?institution_guid?"INS-12345"?is_manual="false"?is_user_created="false"?most_recent_job_guid?"JOB-12345"?name="Zen Bank"?type="member"`
  </Tab>

  <Tab title="Member Deleted URL">
    * Base URL: `mx://memberDeleted`
    * Example payload: `mx://memberDeleted?accounts_count=3?connection_status="CONNECTED"?guid="MBR-12345"?id="M-12345"?institution_guid?"INS-12345"?is_manual="false"?is_user_created="false"?most_recent_job_guid?"JOB-12345"?name="Zen Bank"?type="member"`
  </Tab>
</Tabs>

<Tabs>
  <Tab title="Transaction Created URL">
    * Base URL: `mx://transactionCreated`
    * Example payload: `mx://transactionCreated?account_guid="ACT-12345"?amount=4.25?category_guid="CAT-12345"?date=1425384000?description="Transaction Description"?guid="TRN-12345"?has_been_split=false?memo="Transaction Memo"?parent_guid="TRN-45678"?transaction_type=2?type="transaction"`
  </Tab>

  <Tab title="Transaction Updated URL">
    * Base URL: `mx://transactionUpdated`
    * Example payload: `mx://transactionUpdated?account_guid="ACT-12345"?amount=4.25?category_guid="CAT-12345"?date=1425384000?description="Transaction Description"?guid="TRN-12345"?has_been_split=false?memo="Transaction Memo"?parent_guid="TRN-45678"?transaction_type=2?type="transaction"`
  </Tab>

  <Tab title="Transaction Deleted URL">
    * Base URL: `mx://transactionDeleted`
    * Example payload: `mx://transactionDeleted?account_guid="ACT-12345"?amount=4.25?category_guid="CAT-12345"?date=1425384000?description="Transaction Description"?guid="TRN-12345"?has_been_split=false?memo="Transaction Memo"?parent_guid="TRN-45678"?transaction_type=2?type="transaction"`
  </Tab>
</Tabs>
