Client-side implementation

How to configure a SIMID-compatible player application to support non-linear ad insertion

This page only covers the implementation for SIMID-compatible client platforms (web, CTV, iOS, Android/AndroidTV). Check Fallback mechanisms for other devices

Client-side Components

The following functional client-side components are involved in the flow sequence:

  • App: The application / page that controls user interactions and the interactions between the main other client-side components
  • Video Player: the component in the app that streams and renders the video
  • Smartlib: the client-side Broadpeak SDK that manages interaction with the BkYou/broadpeak.io platform to receive metadata on inserted linear ads and non-linear ads to to be inserted
  • Smartlib Session: the object that manages individual playback sessions (specific to the stream and user)
  • SIMID Creative: the SIMID non-linear ad. It's an HTML document that contains the visual part of the ad and implements part of the SIMID protocol.
  • SIMID Controller: the component or object in the app that manages the display of SIMID creatives, typically through the management of a WebController object. The SIMID controller implements part of the SIMID protocol.
    For clarity about client-side responsibilities in this document, we introduce this component separate from the App itself. Naturally, application developers have the choice of how they model this distinction within the app.
  • Web Controller: the element in charge of loading and displaying the SIMID creative (HTML). This object depends on the device type: WebView (Android), WKWebView (iOS) or iframe (Web)

SIMID Controller

👍

Open-source reference

Broadpeak provides an open-source reference implementation of a SIMID controller that can be integrated in a web, Android or iOS app. It does implement most of the SIMID specification, and is maintained regularly.

https://github.com/Broadpeak-tv/simid-controller

The repository also offers sample web, Android and iOS apps to illustrate the workflow documented in this page.

The rest of this page explains the client-side implementation based on the use of the open-source implementation of the SIMID controller. If you build your own implementation of the SIMID controller, you will need to adapt accordingly.

Note also that data flows and APIs documented here are mostly the same for all devices (web, Android, iOS). However, exact function and method names and data types may vary between platforms. This page will provide examples for Android, unless specified otherwise. Where relevant, differences for iOS (Swift) are called out explicitly; unless stated otherwise, iOS follows the same conventions as Web.

Role

The role of the SIMID controller is best understood from its relationship to the other component:

  • The app receives programmatic events from the SmartLib. The events carry information that indicates whether non-linear ads were returned by the ad server.
  • The app instantiates a SIMID controller to display the non-linear ad.
💡

These instructions are represented in the diagram below with the terms "init", "load url", "show" and "destroy". These names are purely informative, and the choice of implementation of these interactions between the App and the SIMID controller are in the hands of the application developer

  • The SIMID controller listens to the events that the Creative (loaded in a web view) sends - see “SIMID Implementation” below
  • The SIMID controller propagates the information captured from those to the SmartLib, enabling it to react accordingly. - see “Event listener” below
💡

This functionality is necessary to ensure that the Smartlib can have access to certain information that passes between the SIMID Controller and the SIMID Creative, on all devices, particularly those on which events cannot be listened to by all components (e.g. Android and iOS). This is critical in particular for the purpose of ensuring that insertions are tracked correctly. see “Event listener” below

SIMID Implementation

The controller implements the SIMID specification, and must at minimum support the following methods and messages:

  1. Section 8 - Protocol
    1. 8.4.1 - createSession
    2. 8.2.1 - resolve
    3. 8.2.2 - reject
  2. Section 4.3 - "Messages from the player" - sent by the SIMID controller to the Creative
    1. 4.3.7 - SIMID:Player:init
    2. 4.3.10 - SIMID:Player:startCreative
    3. 4.3.6 - SIMID:Player:fatalError
    4. 4.3.9 - SIMID:Player:resize
  3. Section 4.4 - "Messages from the Creative to the Player" - sent by the SIMID Creative to the SIMID controller. The need for supporting these messages will depend on the type of creative templates used in your configuration. The following may likely be relevant:
    1. 4.4.1 - SIMID:Creative:clickThru - for interactive creatives, to notify the application (and SmartLib) that the user has clicked the ad.
    2. 4.4.4 - SIMID:Creative:fatalError - error reported by the SIMID creative​
    3. 4.4.14 - SIMID:Creative:requestPlay - typically for creatives used for Pause Ads, providing buttons for resuming playback
    4. 4.4.16 - SIMID:Creative:requestSkip - for creatives that provide a way to discard them
    5. 4.4.15 - SIMID:Creative:requestResize - necessary to enable ads that don’t overlay over the video, such as in L-Shape scenarios - see “Player Resizing” below for more information

Other SIMID messages

The SIMID spec contains other messages. Those are not currently deemed to be necessary for SIMID ads generated by broadpeak.io (whether static of interactive). They may however be required for 3rd party SIMID creatives

The payload of SIMID messages is defined in the SIMID specification, and in most cases is wrapped into a common enveloppe.

propertytypeexample
sessionIdstring“173378a4-b2e1-11e9-a2a3-2a2ae2dbcce4”
messageIdint0
timestamplong1564501643047
typestring“createSession”
argsmap<string, any>depends on each message type, see the SIMID spec

Event listener

The SIMID controller must propagate SIMID messages in such a way that the SmartLib can listen to them. This is critical in particular for the purpose of:

  • automated ad tracking
  • automated error catching and tracking

To do so, in our open-source implementation, the application needs to create an instance of a GenericSimidControllerApi class (bundled with the SmartLib) and pass it to SmartLib with session.attachSimidController().

Whenever a SIMID controller receives a SIMID message from the creative, it fires the method onMessageReceived() of that instance with the message envelope encoded as a JSON string.

Conversely, when a SIMID controller sends a SIMID message to the creative, it fires the method onMessageSent() from that instance of GenericSimidControllerApi, with the message sent encoded as a JSON string.

💡

The instance of GenericSimidControllerApi is created once and attached once per streaming session, with session.attachSimidController(). This is the object that SmartLib actually listens to.

The SIMID controller itself (the object that manages the WebController and speaks the SIMID protocol with the Creative) is instantiated separately, once for every ad that has a non-linear component. Each new SIMID controller instance is given a reference to the single, session-scoped GenericSimidControllerApi instance, and forwards every message it receives from or sends to the Creative to that instance (by calling its onMessageReceived() / onMessageSent() methods as described above). This is how SmartLib can keep listening to SIMID messages across an arbitrary number of ads within the session, without needing to re-attach a new listener for each one.

Overall flow

📘

The solution has been architected to ensure minimal changes in the Smartlib compared to standard SSAI linear ads flows (documented at https://delivery-platform.broadpeak.tv/smartlib/public/ad-insertion/integration). Familiarity with those flows is assumed in the remainder of this document.
A “new” icon 🌟 is used below to highlight areas specific to flows with non-linear ads which require specific and additional handling by the app or player developer.

⚠️

In-band implementation

The flow described below is primarily for in-band ads.

Implementation for out-of-band ads require additional steps on top of this in-band implementation. See Pause Ads for details.

  1. When the app launches, SmartLib is initialised

  2. For each video load (i.e., each channel change), a SmartLib session is created

    1. The app calls SmartLib.getInstance().createStreamingSession() and stores the session object.

    2. The app attaches the video player instance to Smartlib with session.attachPlayer(playerInstance).

    3. 🌟 The app creates a single instance of bpkSimidController, valid for the whole session. Some of the SIMID messages received from that point on must be forwarded using bpkSimidController.onMessageReceived(messageStr) for received messages and bpkSimidController.onMessageSent(messageStr) for sent messages. Every SIMID controller instance created later on (see 3.2.3 below) will need to keep a reference to this bpkSimidController instance in order to perform that forwarding.

      • On Android and iOS), GenericSimidControllerApi is an abstract class: the app must extend it (e.g. class BpkSimidController : GenericSimidControllerApi()) and override at least getSimidControllerName().
      • On Web, GenericSimidControllerApi can be instantiated directly (new GenericSimidControllerApi()), with no subclassing needed, since the class already provides default, harmless implementations of its methods.
    4. 🌟 The app attaches the bpkSimidController instance to the session with session.attachSimidController(bpkSimidController). This allows SmartLib to listen to the messages forwarded to that instance.

    5. The app calls session.setAdEventsListener(…) so that the app can receive ad events.

    6. The app calls session.getURL(contentURL) to start the streaming session.

  3. When SmartLib detects an ad break

    1. 🌟 onPrepareAdBreak(adBreakData) is triggered a few seconds before the start of the ad break, in all cases (whether the ad break contains linear non-linear ads). In most situations, this event can be ignored, but could be useful in specific scenarios.

    2. 🌟 onPrepareAd(adBreakData, adData) is triggered a few seconds before the start of an ad

      1. 🌟 The app determines if the ad has non-linear ads attached

        1. on Web and iOS, this is done by looking up the field adData.adType, which will contain one of the following values:

          linearThe ad only contains a linear creative
          nonlinearThe ad only contains a non-linear creative
          linear_and_nonlinearThe ad contains both linear and non-linear creatives
        2. on Android, this is done by calling adData.getType(), which returns an enum value

          AD_LINEARThe ad only contains a linear creative
          AD_NON_LINEARThe ad only contains a non-linear creative
          AD_LINEAR_AND_NON_LINEARThe ad contains both linear and non-linear creatives
      2. 🌟 If a non-linear creative is present, the app retrieves the metadata for the SIMID resource:

        1. On Web and iOS, by looking up adData.nonLinearIframeResources
        2. On Android, by calling adData.getNonLinearIframeResources()

        Both return an array of objects with the following properties:

        propertytypedescription
        creativeIdstringID of the creative to display
        urlstringURL of the SIMID resource
        parametersstringContains information that needs to be passed to the SIMID Creative through the Player:init. It contains a stringified JSON string, which the SIMID creative will parse and interpret it.
        clickURLstringClick-through URL (typically for the landing page)
      3. 🌟 The app instantiates a new SIMID controller for this specific ad, which loads the SIMID creative from that URL.

        1. This new instance is given a reference to bpkSimidController so that it can forward messages to it - see “Event listener” and step 2.c above.
      4. The SIMID Creative exchanges a few messages with the SIMID controller to ensure everything is working properly: createSession, Player:init, resolve - see section 6.2 “Workflow Initialization” of the SIMID specification.

      5. The SIMID Controller (the per-ad instance) propagates those messages to bpkSimidController (the session-scoped instance) with bpkSimidController.onMessageReceived(messageStr) and bpkSimidController.onMessageSent(messageStr), which in turn allows SmartLib to observe them.

    3. onAdBreakBegin(adBreakData) is triggered when the ad break starts.

    4. onAdBegin(adBreakData, adData) is triggered when an ad starts.

      1. 🌟 The app instructs the SIMID controller to display the SIMID Creative (if one was successfully prepared in onPrepareAd())
      2. The SIMID Creative exchanges a few messages with the controller: Player:startCreative, resolve- see section 6.3 “Typical Start Creative Workflow” of the SIMID specification:
      3. 🌟 The SIMID Controller instructs the app to show the WebController to the end-user.
      4. Smartlib detects that the ad has been shown and automatically fires the appropriate ad trackers. Optionally, this can be done explicitly by the application instead (see "Ad Tracking" below).
      5. 🌟 Optionally, the SIMID Creative optionally sends a Creative:requestResize message to instruct the app to resize the player. The app resizes the video player component accordingly - see “Player Resizing” below for more information.
      6. 🌟 Depending on the specific SIMID creatives used, other messages can be sent by the creative, which are relayed to the app by the SIMID controller. For example: requests to skip, requests to play, clickthrough notifications, etc.
      7. The SIMID Controller continues to propagate all messages to SmartLib with bpkSimidController.onMessageReceived(messageStr) and bpkSimidController.onMessageSent(messageStr).
    5. onAdEnd(adBreakData, adData) is triggered when the ad ends

      1. 🌟 The app instructs the SIMID Controller to hide the SIMID Creative
      2. 🌟 The app resets the size of the video player if necessary
      3. 🌟 The app can dispose of the per-ad SIMID controller instance created in step 3.2.3, since a new one will be created for the next ad, if any.
    6. onAdBreakEnd(adBreakData) is triggered when the ad break ends

      1. 🌟 The app can use this event to free the memory of the SIMID controller (if appropriate)

Sample Code

Please refer to SIMID controller repository for reference implementation:

Ad Tracking

Non-linear ads are typically tracked with 2 types of beacons:

  • impression - they are valid for the whole ad, whether or not they contain linear and/or non-linear components.
  • creativeView - these apply at the level of the creative itself, and are normally triggered at the same time as the impression.

In most scenarios, SmartLib will automatically send both trackers when it detects that the creative has been displayed (ie. then the SIMID creative resolves the SIMID:Player:startCreative message.

Explicit firing

However, to enable more complex use cases (or integrations in which the SIMID Controller does implement the GenericSimidControllerApi), the application has the ability to trigger those events explicitly, after ensuring that the creative has been displayed correctly.

  1. You first need to set the boolean SmartLib session option AD_TRACKERS_NON_LINEAR_AUTO_SEND to false
  2. You then need to use the session's sendTracker(trackerType, adId) method for each tracker type:
    1. impression
    2. creativeView

adId should be set to the identifier of the current ad (which was obtained from the AdData object in the onAdBegin event. If not set, SmartLib will attempt to determine it automatically.

Error handling

When errors occur (whether determined by the SIMID controller or the creative itself, for example when a creative is missing, or when the creative refuses to be displayed), SmartLib will automatically fire an error beacon for that ad. This too relies on the SIMID Controller implements the GenericSimidControllerApi, just as for automated ad tracking.

Here again, the application can elect to take control, and can trigger the error with session.sendTracker("error", adId).

Reacting to creative messages

Depending on the type of creative being used (and therefore the type of Creative templates​), specific messages may be received by the SIMID Controller, which will need the application to handle.

Player resizing

To enable the display of non-linear ads around the video content and avoid obscuring part of the content, the SIMID creative will send a SIMID:Creative:requestResize command to the SIMID controller, with the calculated coordinates and dimensions (in pixels) of the area of the creative within which the video needs to be displayed.

The dimensions returned take into account the dimensions of the player component and of the creative.

The SIMID controller passes those dimensions to the app, which must resize the video component accordingly. If transitions are warranted for a better user experience (such as a gradual squeeze back), it is the responsibility of the application to apply them.

⚠️

Deviation from SIMID spec

The SIMID spec (latest v1.2) indicates that:

SIMID does not support L-shaped ads that resize the video player without an overlay covering the video

and that, instead

The video asset will need to be cropped or resized to allow the interactive creative to be put into the correct place

This constraint is not workable, in particular in a SSAI solution supporting non-linear ads (such as L-Banners), especially when they don’t accompany a corresponding linear creative and are therefore to be displayed alongside the main content.

Our solution therefore requires a small “deviation” from the standard specification, to allow a creative to inform a player/app of the need to resize the video component and make it smaller than the (full-frame) creative. This is possible without any change to the SIMID message syntax.

Example

💡

For simplicity, we use a 4-tuple to represent a Dimensions object: (x, y, width, height)

This example assumes that

  • the display has a natural 4K (3840x2160) resolution
    • This is sent by the SIMID controller to the creative in the SIMID:Player:init message
  • the source image (returned by the ad server) has a resolution of 1920x1080, with a media area declared as (200, 0, 1720, 968)
    • This information is passed by the Smartlib to the Creative through the SIMID:Player:init message, in particular the CreativeData.adParameters
non-linear ad creative, with dimensions

non-linear ad creative, with dimensions

On that basis, the creative will calculate and send a SIMID:Creative:requestResize message with the following payload

  • creativeDimensions: (0, 0, 3840, 2160)
  • mediaDimensions: (400, 0, 3440, 1935)

The application performs the resize of the video player accordingly:

Application, with resized video player (hashed area)

Application, with resized video player (hashed area)

❗️

It is critical that the player not send a SIMID:Player:resize after receiving and resolving a SIMID:Creative:requestResize

Ad dismissal

Creatives can offer a way for users to interact and request to discard the non-linear ad.

In this case, the SIMID creative will send a SIMID:Creative:requestSkip message to the SIMID Controller. The application may then decide to terminate the ad before its scheduled end, by essentially following the same steps as on an onAdEnd event (step 3.e. in the flow above)

Click-through

Ads may be decorated with a click-through URL in their metadata, typically with the URL to a landing page.

On devices that support the ability to open a browser app or page, a SIMID Creative might provide a button or other mechanism to enable the users to "click" the ad and be directed to the landing page.

In this case, the creative will send a SIMID:Creative:clickThru message to the SIMID Controller. This message's payload will carry 2 parameters:

  • A boolean indicating whether it is the application's responsibility to redirect the user playerHandles=true) or whether it's the creative itself playerHandles=false).
  • The click-through URL (optional)

If playerHandles is true and the click-through URL is set, the application will need to open the web page in whichever way is relevant for that specific client platform.

Usually, the application will also pause playback, although that is scenario-dependent and left at the discretion of the app developer.

💡

For the creative to be able to set playerHandles to true (which will usually be the case), the SIMID controller needs to be configured in such a way that it sends a navigationSupport=playerHandles in the SIMID:Player:init message to the creative.

📘

Transactional click-through

The Broadpeak Click2 solution for interactive advertising may make use of click-through URLs that are not landing pages (navigational), but instead are programmatic notifications to remote endpoints. In this case, when the user "clicks" the ad, the creative will send playerHandles=false and/or an empty click-through URL. The application can simply ignore those messages.

Click tracking

As long as the SIMID Controller implements the GenericSimidControllerApi, SmartLib will automatically fire the click tracking beacons associated with that ad, whether it uses navigational or transactional click-through URLs.

In more complex cases, and as for the other ad and error tracking use cases, SmartLib can also be explicitly instructed to fire them, with session.sendTracker("click", adId) .

Miscellaneous considerations

A complete implementation on the client side will also need to take some additional constraints into account

Full-screen playback

On mobile devices and mobile browsers, application developers must intercept any full-screen request before it reaches the native player. Native full-screen mode usually does not permit overlays (such as SIMID overlays) to remain visible and interactive.

Instead, the application should implement simulated full-screen: expanding a container element to fill the viewport, so that the SIMID creative stays within the same rendering context as the player.

Visual transitions

Visual transitions — such as a fade-in as the ad appears and a fade-out as it disappears — are in most cases the responsibility of the application, as the SIMID protocol does not support them.

They are easily implemented with CSS transitions on the iframe, and equivalent techniques on web views in native apps, as part of the logic attached to the handling of the web view being shown (step 3.d.iii.).

Content metadata overlay

For creatives that are architected to allow presentation of additional (client-side) metadata within the ad creative, the application needs to obtain and provide this data to the creative.

The recommended mechanism is to enrich the ad parameters exposed by the SmartLib in the onPrepareAd event with that metadata. The exact ways to do so are template-dependent and will be documented as part of an integration project.



Did this page help you?