Embed Experiences using the SDK

How to embed Experiences into your products using Monterosa / Interaction SDK

Please contact our sales team if you're interested in access to the Monterosa / Interaction SDK v2.

The SDK can be used to embed an Experience into your web or native app. This provides loading and resizing capabilities which save you integration effort and make for a smooth user experience.

You can load any of the ready-made Experiences from the Experience Library or those that have been developed specifically for you and made available in the platform.

Using the SDK to embed Experiences is not mandatory, you can also deploy Experiences using custom code to manage loading and sizing.

Click here to see a working example of an Experience embedded using the SDK.

Why Embed with the SDK?

The SDK supports the following use cases:

  • Launch an Experience with a few lines of code

  • Dynamic resizing and self-managing size based on the needs of the Experience

  • Displaying or removing headers and footers depending on context

  • Preloading the Experience (native apps)

  • Supports sharing storage between your app and the Experience, ensuring a smooth experience for all users even in incognito windows.

You can use our demo page built with the SDK to see these features in action.

Subsequent releases will include additional support for:

  • Cookie consent management

  • Speeding up load times

  • Infinite scrolling

Getting started

You'll need to decide which integration method you want to use:

  • Static page embedding: This approach is the most straightforward manner to embed an Experience on your website, via HTML without any coding required.

  • Dynamically embedding in a web page or mobile app: This approach allows you more fine-tuned control over the integration, by letting you interact with the SDK using Javascript, Kotlin, or Swift, depending on your platform of choice.

Our recommendation is to favour the static embedding if you only will use the following features:

  • Embed an Experience

  • Fix the Experience on a specific Event

  • Autoresize heigh

  • Hide the header and footer of the Experience

If you need any further functionality, such as sharing data or session with the Experience, or passing parameters to it, you'll need to use the dynamic embedding approach.

Get the Experience's metadata

In order to embed an Experience, you'll need its Project ID and Static host. This information can be retrieved from Studio by navigating to the project, then accessing the API tab within the Settings section.

There you'll find a convenient way to copy the data you need:

Static embedding in a web page

If you are aiming for simplicity, you can embed an Experience using a declarative API. There are two primary methods for importing the SDK, each suitable for different use cases.

Step 1. Import the SDK

Choose one of the methods below to import the SDK into your web page. This step is crucial to ensure that the SDK is available for embedding the Experience.

Using a <script> tag in the <head> of your HTML:

This method is ideal for simpler applications. It’s a quick way to get started without setting up a JavaScript module bundler like Webpack or Babel.

<!-- The rest of your head contents -->
<script src="https://sdk.monterosa.cloud/0.16.11/static-embed/index.js" defer="defer"></script>

<!-- If you want to use ES5, you can instead using this script -->
<!-- script src="https://sdk.monterosa.cloud/0.16.11/static-embed/index.es5.js" defer="defer"></script-->

Importing as an npm module in your JavaScript code:

This approach is ideal for complex applications that utilise modern JavaScript bundling tools, allowing developers to integrate the SDK into a single JavaScript file alongside their code. This integration offers a seamless inclusion of the SDK within the application's build process.

import '@monterosa-sdk/widget';

Step 2. Embed Using Custom HTML Tag

Once you have imported our SDK, you can embed an Experience by using a custom HTML tag of type <monterosa-experience> anywhere in the <body> of your web page. Notice you must provide the host and project Id of the Experience you want to embed. It will not function properly without those parameters. Please read through our getting started to find out where to get them. For example:

<monterosa-experience 
    host="<host>" 
    projectId="<project id>"
> 
</monterosa-experience>

For the Experience to be correctly embedded you'll need to serve your webpage via HTTP or HTTPS. Opening it as a file on your browser is currently not supported.

Step 3. Customising the Experience (optional)

In order to configure your Experience, the following attributes of the Experience tag can be customised:

  • host, specifies the host of the Experience (mandatory)

  • project, specifies the project of the Experience (mandatory)

  • eventId, specifies the event that will be displayed when more than one is present in the Experience. If left unspecified, the Experience will display content from all events.

  • autoresizesHeight when present, the Experience will autoresize its own height depending on the size needed by the Experience. This mirrors the behaviour of Manage the Experience's size.

  • hidesHeadersAndFooters, when present, the Experience will remove its own headers and footers to let you use your own instead.

Additionally, the Experience tag can be styled as any other HTML element, allowing you to further customise its look and feel.

Dynamic embedding in a web or application

Download and initialise SDK

First, you'll need to configure your development environment to gain access to the SDK. You'll need the credentials included in your "Welcome pack" to achieve this:

If you're an existing customer and can't find your Welcome Pack, please raise a ticket via support@monterosa.co or speak to your Account Manager.

If you use Swift Package Manager, add the following GIT repository URL as a new package dependency in Xcode:

https://<package-username>:<package-token>@gitlab.com/monterosa-sdk/ios.git

Finally, select MonterosaSDKCore and MonterosaSDKLauncherKit from the list of available Package Products.

If you use CocoaPods, add the following to your app target in your Podfile

target 'MyApp' do
  username = "<YOUR USERNAME>"
  token = "<YOUR TOKEN>"
  version = "0.16.13"

  url = "https://#{username}:#{token}@gitlab.com/monterosa-sdk/ios.git"

  pod 'MonterosaSDKCommon', :git => url, :tag => version
  pod 'MonterosaSDKConnectKit', :git => url, :tag => version
  pod 'MonterosaSDKCore', :git => url, :tag => version
  pod 'MonterosaSDKLauncherKit', :git => url, :tag => version
  pod 'MonterosaSDKIdentifyKit', :git => url, :tag => version
end

Once you have access to the SDK, you'll have to configure it during the startup of your application, so it is able to access your project. For that, you'll need a static host and a project id, which can be retrieved in Studio.

import UIKit
import MonterosaSDKCore

@UIApplicationMain
class AppDelegate: UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        ...
        Core.configure(host: "<static host>", projectId: "<project id>")
        ...
    }
}

Launch an Experience

All Projects are associated with an Experience, also known as an App. You can check Monterosa / Interaction Cloud core concepts if you need more information.

You will need to obtain an Experience Object — a programmatic interface to the Monterosa / Interaction Cloud Experience you're launching — and then place it in your views:

let experience = Launcher.getExperience()
<yourView>.addSubview(experience)

// You need to ensure you layout the experience correctly
// For instance, to display on full screen using autolayout,
// you'll need something like this:
experience.translatesAutoresizingMaskIntoConstraints = false
experience.topAnchor.constraint(equalTo: <yourView>.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
experience.bottomAnchor.constraint(equalTo: <yourView>.bottomAnchor, constant: 0).isActive = true
experience.leadingAnchor.constraint(equalTo: <yourView>.leadingAnchor, constant: 0).isActive = true
experience.trailingAnchor.constraint(equalTo: <yourView>.trailingAnchor, constant: 0).isActive = true

Then, simply place the Experience Object you've just created on the screen and it will initiate automatically.

In the Javascript SDK, the Experience will start loading as soon as embedded. On Android and iOS, it will start loading as soon as created. Additionally, iOS's and Android's ExperienceViews can notify you when the loading of the page has completed, allowing you to add a loading state if you chose to.

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        let experience = Launcher.getExperience()
        experience.delegate = self
        ...
        view.addSubview(experience)
        
        // You need to ensure the experience is laid out however you see fit.
        // For instance, could use autolayout constraints, or setting 
        // its frame
    }
}

extension MyViewController: ExperienceViewDelegate {

    func didStartLoading(experienceView: ExperienceView) {
        displayLoadingUI()
    }

    func didEndLoading(experienceView: ExperienceView) {
        hideLoadingUI()
    }

    func didFailLoading(experienceView: ExperienceView, error: Error) {
        hideLoadingUI()
        displayErrorUI(with: error)
    }

    // [...]
    // Implementation of the rest of ExperienceViewDelegate 
    // [...]
}

Additionally you can launch a specific Event within your Experience using the following snippet:

let eventId = "<event id>"
let config = ExperienceConfiguration(eventId: eventId)
let experience = Launcher.getExperience(config: config)
<yourView>.addSubview(experience)

// You need to ensure the experience is laid out however you see fit.
// For instance, could use autolayout constraints, or setting 
// its frame

Launching multiple Experiences

In some cases you may find it useful to embed multiple Experiences within your application. For example, if you have multiple games or shows you're covering and want each to have a vote associated with them, each set up to look differently in their own Project.

The SDK supports multiple Experiences by allowing you to configure multiple SDK instances as long as you provide a unique name to identify them.

Core.configure(
    host: "<host 1>", 
    projectId: "<project 1>", 
    name: "<name 1>"
)
let sdk1 = Core.core(by: "<name 1>")
let launcher1 = Launcher()
sdk1!.register(kit: launcher1)

let experience1 = launcher1.getExperience()

Core.configure(
    host: "<host 2>", 
    projectId: "<project 2>", 
    name: "<name 2>"
)
let sdk2 = Core.core(by: "<name 2>")
let launcher2 = Launcher()
sdk2!.register(kit: launcher2)

let experience2 = launcher2.getExperience()

let sdk2 = Core.configure(
    host: "<host 2>", 
    projectId: "<project id 2>", 
    name: "<name 2>"
)

<yourView>.addSubview(experience1)
<yourView>.addSubview(experience2)

// You need to ensure the experiences are laid out however you see fit.
// For instance, could use autolayout constraints, or setting 
// their frame

Note that when launching multiple experiences, it is necessary to configure Identify Kit for each individual experience.

See the section here

Configuring Identify Kit for multiple experiences

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        
        // You need to ensure you have followed the Configure Multiple
        // Experiences step
        
        experience1.identify.setCredentials(credentials: UserCredentials(token: "token1")
        experience2.identify.setCredentials(credentials: UserCredentials(token: "token2")

        experience1.identify.add(delegate: self)
        experience2.identify.add(delegate: self)
        
        ...
    }
}

extension MyViewController: IdentifyKitDelegate {

    // [...]
    // Implementation of IdentifyKitDelegate
    // [...]
}

Disposing of an Experience

Once the user is done with an Experience, you'll want to make sure that the resources used by the SDK are freed up. For instance, when they swap from one to another, or if they navigate back in your navigation hierarchy,

To do so, take the following steps:

  • Remove the ExperienceView from the parent view or DOM element

  • Ensure you don't have any reference to it in memory

Once you do that, the garbage collector or reference counter of your language of choice will take care of disposing of the memory used.

Customising an Experience

Preload the Experience

Note: This feature is not yet available in the Javascript SDK.

With the default implementation, the Experience will load when it is shown to the user, but if you are aiming to reduce the loading time, you can trigger proactive loading so that it’s ready to go when the user wants to see it. Use the following snippet:

let experience = Launcher.getExperience()

// At this point the experience will already be loading in the background
// You could now store it in memory until you need to embed it in your UI.

// Please note that this may consume resources, so be careful about how many
// Experiences you preload.

// Eventually...
<yourView>.addSubview(experience)

// You need to ensure the experiences are laid out however you see fit.
// For instance, could use autolayout constraints, or setting 
// their frame

Caching the contents of the Experience on Android and iOS

The Experience builds on top of iOS' WKWebView and Android's WebView, and therefore will cache the content in the same manner as Safari or Google Chrome would.

It is also possible to cache the ExperienceView itself and re-use further down the line of the user flow. This can come in handy in scenarios where the same Experience may be displayed multiple times in the same session.

To do so, you'd need to keep a reference to the ExperienceView after using it, and adding that same instance to your view hierarchy.

Note that if another Experience has been displayed after caching the instance, and before re-using it, the session will have expired.

To avoid displaying the "Session closed" dialog during this scenario, it is possible to leverage the Communication Bridge to notify the Experience not to display it. Please get in touch with our Solutions Architecture team to design the flow of messages required.

In general, this is solved with two messages or requests:

  • One to notify the ExperienceView that it is moved to the background

  • Another to notify that it is moved back to the foreground, also called on first launch

Launching an Experience as an Android Activity or Fragment

Aiming to provide the most flexibility we can, we have also wrapped our ExperienceView in an Activity and Fragment so you can leverage all the functionality Android provides within those two classes.

When using ExperienceActivity and ExperienceFragment, custom loading and error view providers are not supported as we can't parcelise the provider functions.

Instead, use an ExperienceView, or wrap it with your own Fragment or Activity.

You can use them by following the next snippets:

val experienceIntent = Launcher.default.getExperienceIntent(context)

startActivity(experienceIntent)

Listening to touch events in the Experience on Android

If you want to react to how users scroll through the Experience, e.g. in order to collapse a toolbar, we offer the possibility to provide an OnTouchListener that forwards you the user interactions with the Experience. You can register it like so:

val experienceView = Launcher.default.getExperience(context, config)

experienceView.experienceOnTouchListener = View.OnTouchListener{ view, motionEvent ->
    // React to touch events
}

Customising the URLSession used in iOS

Customising the URLSession in an iOS application allows you to adapt network requests to meet your app's specific needs.

By setting a custom URLSession instance to the URLSession.monterosaSDK, the SDK allows you to override the the URLSession that the SDK uses.

This allows to:

  • Control the timeout period

  • Control the caching

  • Meet network security requirements (such as disabling HTTP cache)

  • ...

In order to override the URLSession, you'll need to set the value like so:

import MonterosaSDKConnectKit

...
let config = URLSessionConfiguration.default
// Your customisations, e.g. disable caching:
config.urlCache = nil
URLSession.monterosaSDK = URLSession(configuration: config)
...

Note that the URLSession will be injected into the SDK kits as they are being created, so it's preferable to set this value before accessing any functionality. For instance, you should execute this before:

  • Setting credentials in IdentifyKit

  • Instantiating an ExperienceView

Additionally, this property can be modified before Core.configure is called, so the safest approach would be to set it before the SDK is initialised.

Hosting videos from Experience on fullscreen on Android

To enable an Experience to host videos full screen in Android, you'll need to provide an Activity instance following the next snippet:

val experienceView = Launcher.default.getExperience(context, config)

experienceView.allowFullScreenVideosInActivity(activity = this)

Configuring Permissions Policy for Embedded iFrames

When embedding an <iframe>, SDK allows to manage the permissions policy effectively. This policy dictates which features are available to the <iframe>, considering factors such as access to the device's microphone, camera, battery, web-sharing capabilities, and more, contingent on the origin of the request.

To establish a permissions policy for an <iframe>, you must define the required features within the allow parameter of the getExperience() function. This configuration is essential for ensuring that only authorised features are accessible through the <iframe>, enhancing security and user experience.

For instance, if embedding a YouTube player within an <iframe>, it's necessary to permit features like fullscreen and picture-in-picture. This can be achieved as demonstrated in the following code snippet:

import { getExperience } from '@monterosa-sdk/launcher-kit';

const experience = getExperience({
  // Specify the features to allow in the iframe.
  // In this case, enabling fullscreen and picture-in-picture modes.
  allow: 'fullscreen; picture-in-picture',
  
  // Set allowFullscreen to true to ensure compatibility 
  // with fullscreen mode in older browsers
  allowFullscreen: true,
});

Shared storage in embedded Experiences

We also support a shared storage so that the Experience can access a data storage located on your application with ease. You have the option to choose between two types of storage: persistent or in-memory storage. This gives you more flexibility and control over how your users' data is stored.

The Experience won't request the user permission to store data, instead we expect you to set the storage in persistent mode only if you are certain you comply with all regulations required for the countries and regions you operate in.

By using the SDK, you can also improve the privacy and security of your users' data because you can choose the best way to store it according to your users' preferences, and needs.

If you enable persistent storage, the SDK will store data in the local storage of your webpage for JavaScript, or the application's sandbox for Android and iOS. This ensures that data will be available across multiple sessions. However, if you disable persistent storage, data will be stored in memory. This provides faster access but will not be available across multiple sessions.

// Enable
experienceView.setPersistance(isGranted: true)
// Disable
experienceView.setPersistance(isGranted: false)

Additionally, the SDK will ensure that data is transitioned seamlessly from persistent to in memory and back by copying the data available from memory to disk, and the other way around, so any change in configuration won't result in any data loss during your user's session.

Last updated