Live API: Server-Side Ad Insertion (SSAI)

Product(s)
Video Cloud
Live
SSAI
Role(s)
API Developer
Topic(s)
Live Streaming
SSAI
API(s)
Live API

This topic shows you how to set up server-side ad insertion (SSAI) for your live stream jobs.

Overview

SSAI allows you display ads during a live streaming event at specified times. The main features include:

  • Insert ads using cue points sent from your encoder or create an instant cue point using the Live API
  • Ingest "slate" assets to fill any unused ad time
  • Avoid ad blockers with ads that are stitched into the live stream on the server side

To create a Live stream with server-side ads, follow these steps:

  1. Review the general information about the Live API
  2. Create a live ad configuration. You can also do this in Video Cloud Studio. See the sections below for details about managing your ad configurations using the Live API.
  3. Create slate assets. If you prefer a UI, you can manage slates in Studio.
  4. Optional: Insert cue points and ad beacons.
  5. Now, you are ready to create a Live stream Using the Live API. If you prefer to use Studio, you can implement server-side ads in the Live module

See the rest of this document for details about custom headers, ad config variables, using DFP and ad macros.

General information

The following information pertains to all Live API with SSAI requests.

Base URL

The base URL for the Live API with SSAI is:

https://api.bcovlive.io/v1/ssai

Authentication

Authentication for requests requires a header with an API key:

X-API-KEY: your API KEY

Contact your account manager to get an API key associated with your account.

Create an ad configuration

To create a new ad configuration, send a POST request as follows:

Method POST
URL https://api.bcovlive.io/v1/ssai/applications
Header X-API-KEY: your API KEY

Sample request body

{
  "application_ad_configuration": {
    "ad_configuration_description": "Human readable description of the configuration",
    "ad_configuration_expected_response_type": "Dfp, Vast or SmartXML",
    "ad_configuration_headers": {
    "X-Custom-Header-Rand": "{{random.int32}}",
    "X-VIDEOPLAZA-FORWARDED-FOR": "{{client.ipaddress}}"
    },
    "ad_configuration_headers_for_impressions": false,
    "ad_configuration_strategy": "SingleAdResponse or MultipleAdResponse",
    "ad_configuration_transforms": [
      {
      "xpath": "/",
      "xslt": "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:Det=\"http://Det.com\"><xsl:output omit-xml-declaration=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>"
      }
    ],
    "ad_configuration_url_format": "https://ad-provider-host.com/path/to/ad-handler?ip={{client.ipaddress}}&num={{random.int32}}&ses={{session.session_id}}"
  },
  "application_description": "Human readable description of the ad application",
  "account_id": "User's Account ID [Optional]"
}

Sample response

{
  "application": {
    "account_id": "User Account ID",
    "application_description": "Human readable description of the ad application",
    "application_ad_configuration": {
      "ad_configuration_description": "Human readable description of the configuration",
      "ad_configuration_expected_response_type": "Dfp | Vast | SmartXML",
      "ad_configuration_headers": {
        "X-Custom-Header-Rand": "{{random.int32}}",
        "X-VIDEOPLAZA-FORWARDED-FOR": "{{client.ipaddress}}"
      },
      "ad_configuration_headers_for_impressions": false,
      "ad_configuration_strategy": "SingleAdResponse | MultipleAdResponse",
      "ad_configuration_transforms": [
        {
          "xpath": "/",
          "xslt": "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:Det=\"http://Det.com\"><xsl:output omit-xml-declaration=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>"
        }
      ],
      "ad_configuration_url_format": "https://ad-provider-host.com/path/to/ad-handler?ip={{client.ipaddress}}&num={{random.int32}}&ses={{session.session_id}}"
    },
    "application_id": "Application ID"
  },
  "inserted": true
}

Update an ad configuration

Updating an ad configuration is very similar to creating one. Make a PUT request as follows:

Method PUT
URL https://api.bcovlive.io/v1/ssai/applications/application/Application_ID
Header X-API-KEY: your API KEY

Sample request body

{
  "application_ad_configuration": {
    "ad_configuration_description": "Some Updated Description Value",
    "ad_configuration_expected_response_type": "Dfp or Vast or SmartXML,
    "ad_configuration_headers": {
      "X-Custom-Header-Rand": "{{random.int32}}",
      "X-VIDEOPLAZA-FORWARDED-FOR": "{{client.ipaddress}}"
    },
    "ad_configuration_headers_for_impressions": false,
    "ad_configuration_strategy": "SingleAdResponse or MultipleAdResponse",
    "ad_configuration_transforms": [
      {
      "xpath": "/",
      "xslt": "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:Det=\"http://Det.com\"><xsl:output omit-xml-declaration=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>"
      }
    ],
    "ad_configuration_url_format": "https://updated-ad-provider-host.com/path/to/ad-handler?ip={{client.ipaddress}}&num={{random.int32}}&ses={{session.session_id}}"
  },
  "application_description": "Human readable description of the ad application",
  "account_id": "User's Account ID [Optional]"
}

Sample response

{
  "account_id": "User Account ID",
  "application_description": "Human readable description of the ad application",
  "application_ad_configuration": {
    "ad_configuration_description": "Some Updated Description Value",
    "ad_configuration_expected_response_type": "Dfp | Vast | SmartXML",
    "ad_configuration_headers": {
    "X-Custom-Header-Rand": "{{random.int32}}",
    "X-VIDEOPLAZA-FORWARDED-FOR": "{{client.ipaddress}}"
    },
    "ad_configuration_headers_for_impressions": false,
    "ad_configuration_strategy": "SingleAdResponse | MultipleAdResponse",
    "ad_configuration_transforms": [
      {
      "xpath": "/",
      "xslt": "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:Det=\"http://Det.com\"><xsl:output omit-xml-declaration=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>"
      }
    ],
    "ad_configuration_url_format": "https://updated-ad-provider-host.com/path/to/ad-handler?ip={{client.ipaddress}}&num={{random.int32}}&ses={{session.session_id}}"
  },
  "application_id": "Application ID"
}

Get all ad configurations

To retrieve all the ad configurations for an account, submit a GET request as follows:

Method GET
URL https://api.bcovlive.io/v1/ssai/applications/account/Account_ID
Header X-API-KEY: your API KEY

Sample response

[
  {
    "application_id": "Application_ID_1",
    "application_description": "DFP Single Midroll",
    "application_ad_configuration": {
    "ad_configuration_description": "DFP Test Config Single Midroll",
    "ad_configuration_strategy": "MultipleAdResponse",
    "ad_configuration_transforms": [],
    "ad_configuration_url_format": "https://ad-provider-host.com/path/to/ad-handler",
    "ad_configuration_expected_response_type": "Dfp"
    },
    "account_id": "Account_ID"
  },
  {
    "application_id": "Application_ID_2",
    "application_description": "Test DFP Single Midroll"
    "application_ad_configuration": {
    "ad_configuration_description": "DFP Test Config Single Midroll",
    "ad_configuration_strategy": "MultipleAdResponse",
    "ad_configuration_transforms": [
    {
      "xslt": "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:Det=\"http://Det.com\"><xsl:output omit-xml-declaration=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>",
      "xpath": "/"
    }
    ],
    "ad_configuration_url_format": "https://ad-provider-host.com/path/to/ad-handler?ip={{client.ipaddress}}&num={{random.int32}}&ses={{session.session_id}}",
    "ad_configuration_expected_response_type": "Dfp"
    },
    "account_id": "Account_ID"
  }
]

Get an ad configuration

You can also retrieve a specific ad configuration by its application_id by sending a GET request as follows:

Method GET
URL https://api.bcovlive.io/v1/ssai/applications/application/Application_ID
Header X-API-KEY: your API KEY

Sample response

{
  "application_id": "Application_ID",
  "application_description": "Test DFP Single Midroll",
  "application_ad_configuration": {
    "ad_configuration_description": "DFP Test Config Single Midroll",
    "ad_configuration_strategy": "MultipleAdResponse",
    "ad_configuration_transforms": [
      {
      "xslt": "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:Det=\"http://Det.com\"><xsl:output omit-xml-declaration=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>",
      "xpath": "/"
      }
    ],
    "ad_configuration_url_format": "https://ad-provider-host.com/path/to/ad-handler?ip={{client.ipaddress}}&num={{random.int32}}&ses={{session.session_id}}",
    "ad_configuration_expected_response_type": "Dfp"
  },
  "account_id": "Account_ID"
}

Delete an ad configuration

To delete an ad configuration, send a DELETE request as follows:

Method DELETE
URL https://api.bcovlive.io/v1/ssai/applications/application/APPLICATION_ID
Header X-API-KEY: your API KEY

Sample response

{
"application_id": "Application_ID",
"deleted": true
}

Custom headers for ad requests

The SSAI platform can pass custom headers with the Ad calls and all beacons used by the backend platform. Some ad servers such as VideoPlaza require custom headers.

Custom headers are specified as a set of key-value pairs in an ad_configuration_headers object, which is part of the application_ad_configuration (see the Create an ad configuration section).

Notes

  • Standard headers are handled by default such as:
    • X-Forwarded-For
    • X-Device-User-Agent
  • Header values can use the ad configuration variables
  • Header values can also be static strings

Ad configuration variables

The following table provides a summary of ad configuration variables, which are used in the requests to manage ad configurations.

Ad Configuration Variables
Variable
Description
session.session_id
unique session id
job.job_id
unique job id
application_ad_configuration.description
value of the application at session creation
random.int32
random 32-bit signed integer
random.int64
random 64-bit signed integer
random.uint32
random 32-bit unsigned integer
random.uint64
random 64-bit unsigned integer
random.uuid
random uuid
server.timestamputc
epoch time in milliseconds when the call from the ads-api has been made
client.useragent
http user-agent header value at session creation
client.ipaddress
http x-forwarded-for header value at session creation, if provided, otherwise the remote address
client.referrer
http referer header value at session creation (note: that is the correct spelling)
client.referer
http referer header value at session creation (http spelling)
client.ipuaid
hash value of client.ipaddress and client.useragent
live.adbreak
(currently unused)
live.adbreakdurationms
Ad break duration in milliseconds
live.adbreakduration
Ad break duration in double-precision floating-point seconds
live.adbreakdurationint
Ad break duration in integer seconds
live.adbreak.timestamputc.wallclock
epoch time in milliseconds when the call to the ads server has been made
live.adbreak.timestamputc.origin
epoch time in milliseconds from the origin chunklist. This value indicates the time when the cue out chunk has been created in the origin chunklist.
live.adbreak.timestamputc.session
epoch time in milliseconds from the ssai chunklist. This value indicates the time of the cue out chunk in the ssai chunklist. Since the adbreak content and the adbreak gap are NOT usually the same, after the 1st adbreak the live.adbreak.timestamputc.origin is different from live.adbreak.timestamputc.session . This value takes into account the time adjustments that have been made in the SSAI chunklist.
scte35_eventID
an unique event id passed with an SCTE35 message.
scte35_programID
A unique program id passed with an SCTE35 message.
scte35_availNum
An id for a specific splice time available for ads, send via a SCTE35 message.
scte35_breakDuration
Break duration for the ad break, in terms of ticks of the program’s 90 kHz clock, passed with a SCTE35 message.
scte35_spliceTime
Splice time for an ad break, in terms of ticks of the program’s 90 kHz clock, passed with a SCTE35 message.

Managing slates

Slates are your own assets used to fill unused ad time. You can use slates to provide a "be right back" message or any content that you like.

Below are details for the API requests to add and manage slate assets.

Add slate asset

To ingest a new slate media source asset, submit a POST request:

Method POST
URL https://api.bcovlive.io/v1/ssai/slates
Header X-API-KEY: your API KEY

Sample request body

{
  "source_url": "https://somesourceasset.com/slate-to-ingest.mp4",
  "account_id": "Account_ID [Optional]",
  "source_description": "User identifiable description for the slate  [Optional]"
}

Sample response

{
  "media_source_asset_id": "New_UUID",
  "account_id": "Account_ID",
  "media_source_asset_default": false,
  "media_source_asset_type": "slate",
  "media_source_asset_url": "https://somesourceasset.com/slate-to-ingest.mp4",
  "media_source_asset_status": "transcoding"
  "media_source_asset_description": "User identifiable description for the slate"
}

Delete slate asset

To delete a slate media source asset, send a DELETE request:

Method DELETE
URL https://api.bcovlive.io/v1/ssai/slates/slate/Slate_MSA_ID
Header X-API-KEY: your API KEY

Sample response

{
  "media_source_asset_id": "MSA_UUID",
  "media_source_asset_type": "slate",
  "media_source_asset_url": "http://someS3urlpath/media.mp4",
  "media_source_asset_default": false,
  "media_source_asset_status": "ready",
  "account_id": "ACCOUNT_ID"
}

Get slate assets

You can retrieve an array of all the slate media source assets for an account by sending a GET request:

Method GET
URL https://api.bcovlive.io/v1/ssai/slates/account/Account_ID
Header X-API-KEY: your API KEY

Sample response

[
  {
  "media_source_asset_id": "MSA_UUID_1",
  "media_source_asset_type": "slate",
  "media_source_asset_default": false,
  "media_source_asset_url": "http://someS3urlpath.com/media.mp4",
  "account_id": "ACCOUNT_ID",
  "media_source_asset_status": "ready"
  },
  {
  "media_source_asset_id": "MSA_UUID_2",
  "media_source_asset_type": "slate",
  "media_source_asset_default": true,
  "media_source_asset_url": "http://someS3urlpath.com/media.mp4",
  "account_id": "ACCOUNT_ID",
  "media_source_asset_status": "ready"
  }
]

Notes about DFP

If you are obtaining ads from DFP, here are some things to keep in mind to help prevent issues.

Ad tag

When you are creating an ad tag for Live, be sure you are following the proper guidelines and including /live . See the DFP document Create a master video tag manually for full details.

Concurrency

If you are expecting a high amount of concurrency we recommended that you talk to your DFP account team.

Single/multiple ad responses

The singleadresponse and multiadresponse parameters are not currently used by SSAI.

Live SSAI only makes a single ad server call and expects the response to contain all the ads for the break with the exception that it will follow any necessary ad wrappers with a limit of 5 redirects per ad. The following ad response formats are accepted and will be parsed as follows:

  • VAST - Single response or a pod of ads in a single response
  • DFP Ad Rules - Aggregates all available ads in the response including pre-, mid-, post-roll defined ads
  • Smart XML - Aggregates all available ads in the response including pre-, mid-, post-roll defined ads

Targeting ads using ad macros

When you create an ad configuration, your ad tag will typically look something like this:

  https://ad-provider-host.com/path/to/ad-handler?ip={{client.ipaddress}}&
  num={{random.int32}}&ses={{session.session_id}}&IDFA={{deviceid}}&
  sitesection={{sitesection}}&breakid={{breakid}}&breaktheme={{breaktheme}}

The items inside the double curly braces are variables, also called ad macros, which Brightcove Live will replace with values, if they exist, when it sends the ad request.

Ad macro values can be supplied in following ways:

Using header information

Header information, detailed in the Ad configuration variables section above, is available for any request. Simply specify the variables you want with the appropriate key names in your ad configuration.

Appending the URL

Additional session values can be appended to the URL for the live stream, like this:

  http://playback.bcovlive.io/e058d9f2737e18/us-west-2/NA/
  playlist.m3u8?deviceid=123456&sitesection=services"

Adding URLs dynamically

You can add URLs dynamically, using Javascript and the Brightcove Player API:

  <!DOCTYPE html>
  <body>
    <video
    id="myPlayerID"
    data-video-id="5975635167001"
    data-account="3737230870001"
    data-player="tIG7lVKBm"
    data-embed="default"
    data-application-id
    class="video-js"
    controls
    width="640"
    height="360"></video>
    <script src="//players.brightcove.net/3737230870001/tIG7lVKBm_default/index.min.js"></script>

    <script type="text/javascript">
    var player = videojs("myPlayerID");

    player.one("loadstart", function(){
      var sourceUrl = player.currentSource();
      console.log(sourceUrl);
      var liveUrlWithParams = sourceUrl.src + "?player_width={width}&player_height={height}&deviceid={deviceid}";

      player.src([{
        "type": "application/vnd.apple.mpegurl",
        "src": liveUrlWithParams
      }]);
    });
  </script>

  </body>

Note that the key names in this example correspond to the variable names in the ad tag shown above.

Using manual cue points

Values for specific ad breaks can be sent with the manual cue point insertion request. For details, see the Live API: Cue Points and Ad Beacons document.

Known issues

  • SSAI requires that the live streaming video have an audio track.
  • If the VAST returned has the same ad ID, then the server will not request the ad content, even though the ad URL uses dynamic variables to make it a unique URL. This does not apply if you are using DFP for ads.
  • With DFP, while you can use the same ad ID, there still needs to be a different creative ID - in other words, you can't do a simple swap of the MediaFile.
  • If an ad break has a duration less than the MAX duration of the ad URL (min_ad_duration=0&max_ad_duration=30000), if ad is returned longer than the ad break, the ad will not be played.

  • VPAID or clickable ads are not supported for Brightcove Live SSAI.

  • When an ad break has remaining time shorter than the segment seconds of the stream and a slate is displayed, the slate is displayed for its segment duration and the actual ad break will be longer than expected.

  • The first time the ad is seen by our system, it will not play until it is transcoded and ready to deliver.