Skip to content

In App Message

The MovableInk SDK supports showing HTML based MI Content as Interactive In App Messages.

Implementation

MIClient.showInAppMessage(with: "https://mi.example.com/p/rp/abcd12345.html") { buttonID in 
  // User interacted with a link that has a buttonID
}

Note the link ends with .html. When exporting your image links from Studio, make sure to change the suffix (png -> html) when using it as an In App Message in the SDK.

Customization

In Studio, when setting up buttons for your In App Messages, there are a few options that you can use on your clickthrough links to customize the In App Message experience.

Deeplinking

If you want a link from within an In App Message to deeplink into some content on your app, you should have an in app scheme setup and use that scheme for the link. your-scheme://your_path

For example, for our app, we setup a URL Scheme of inkentertainment. This is setup within your Info.plist under the URL Types section.

In our app, we've setup links that match /media/:id to open our Media Details page. To have the button open this page in our app, we'll use the URL inkentertainment://media/1. This will instruct the system to notify our app to handle this URL.

If you need a link within your In App Message to override the current frame where the In App Message is showing, you can use the InFrame query parameter on your clickthrough url.

https://example.com?inFrame

Tapping on a link with the inFrame parameter will instruct the SDK to open that link in place.

If you need link to close the In App Message UI and show an In App Browser, you can use the InAppBrowser query param.

https://example.com?inAppBrowser

Tapping on a link with the inAppBrowser parameter will instruct the SDK to open that link within an In App Browser.

If you wish to use your own In App Browser UI instead of the one the SDK provides, you can TODO.

Do not use both inFrame and inAppBrowser on your links.

By default, any links that are not app scheme links or contain the InFrame or InAppBrowser parameters that the user interacts with in an In App Message will close the In App Message UI and open the link in the users Default Browser.

Will open in default users browser externally
https://example.com
http://google.com

Will not open externally
myapp://terms_of_service
https://example.com?InFrame
https://google.com?InAppBrowser
https://google.com?InAppBrowser&buttonID=0

buttonID

You can use the buttonID parameter to be notified via the handler when a user interacts with a link that contains a buttonID value. This is useful if you need to log an event to any Analytics tools you may use.

inkentertainment://media/7?buttonID=0

You can also append some options to the MovableInk Link that you use for your In App Message.

Close Button

By default, the In App Message will have a close button in the top right corner. If you need to remove that button, you can append the hideCloseButton as a query parameter:

https://mi.example.com/p/rp/abcd12345.html?hideCloseButton

If you want to hide the close button for all in app message, you can do so via the hideCloseButton parameter when showing the In App Message: MIClient.showInAppMessage(with: link, hideCloseButton: true) { buttonID in }

Using MIClient.showInAppMessage(with: link, hideCloseButton: true) will force the close button to always be hidden.

Braze

If you are already using Braze for In App Messages, you can still use MovableInk driven messages and still log your impressions and button clicks to Braze for analytics.

In Braze, when creating an In App Message Campaign, select Custom Code as the message type and insert an empty script.

<script>
</script>

BrazeInAppMessageSetup

Switch to the Settings Tab, right side of Compose, and add a new Key Value Pair.

Set the Key to mi_link Set the Value to your MI HTML Link, such as https://mi.example.com/p/rp/abcd12345.html

BrazeInAppMessageSettings

Setup the rest of your campaign as you normally would.

To show this In App Message, we'll need to be notified of an incoming message and discard it, passing along the link to the SDK to take over.

If you're already managing your Braze instance on your AppDelegate, make your AppDelegate conform to BrazeInAppMessageUIDelegate and implement the inAppMessage(_:.displayChoiceForMessage:) method.

inAppMessage(_:.displayChoiceForMessage:) will be called by the Braze SDK when it decides it wants to show an In App Message. Here, we can check if the message is a MovableInk driven message via the mi_link key and forward it's value to the MovableInk SDK to take over.

import BrazeKit
import BrazeUI
import MovableInk

class AppDelegate: NSObject, UIApplicationDelegate, BrazeInAppMessageUIDelegate {
  private var braze: Braze?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

    let configuration = Braze.Configuration(
      apiKey: "BRAZE_API_KEY",
      endpoint: "BRAZE_ENDPOINT"
    )
    self.braze = Braze(configuration: configuration)

    // Setup the presenter and it's delegate
    let presenter = BrazeInAppMessageUI() 
    presenter.delegate = self
    self.braze?.inAppMessagePresenter = presenter

    return true
  }

  func inAppMessage(
    _ ui: BrazeInAppMessageUI,
    displayChoiceForMessage message: Braze.InAppMessage
  ) -> BrazeInAppMessageUI.DisplayChoice {
    // Check if the incoming message contains an mi_link
    if let miLink = message.extras["mi_link"] {
      // If it does, we'll let the MovableInk SDK handle this.
      // Log the impression to Braze, ask MIClient to show the message, and return .discard to 
      // notify the Braze SDK that we don't want it to show anything.
      logImpression(message: message)

      MIClient.showInAppMessage(with: miLink) { [weak self, message] buttonID in
        // This closure will be called if a user interacts with a link that contains the buttonID parameter.
        // We can use that to log the click back to Braze.

        self?.logClick(message: message, buttonID: buttonID)
      }

      return .discard
    }

    return .now
  }

  private func logImpression(message: Braze.InAppMessage) {
    guard let braze else { return }
    message.logImpression(using: braze)
  }

  private func logClick(message: Braze.InAppMessage, buttonID: String?) {
    guard let braze else { return }
    message.logClick(buttonId: buttonID, using: braze)
  }
}

Logging impressions and button clicks back to Braze may take a minute or two to show up on their side.