Live Ad Replacement with SpringServe VAST

A tutorial on how to use a SpringServe VAST endpoint as ad server in a Live Ad Replacement service with broadpeak.io

This playbook explains how to configure SpringServe as a VAST ad decision server (ADS) in a broadpeak.io Dynamic Ad Insertion (DAI) workflow for Live content.

You’ll learn how to:

  • Configure SpringServe as an ad server source.
  • Determine how to map the SpringServe macros.
  • Validate ad insertion and tracking in a live stream.
❗️

This page provides guidance for using SpringServe as an ad server. It is not a recommendation nor a complete guide, and is only offered to show principles and common practice.

Prerequisites

Before you begin, ensure you have:

  • A broadpeak.io account, and access to the Web App
  • A SpringServe VAST tag
    • This may have been provided to you by a colleague or a content partner

    • However if you have your own SpringServe account, you can easily get one from the SpringServe console, which provides a handy interface to be able to choose macros and export the URL

  • Familiarity with the basic configuration of a DAI service. Check our tutorial on ❆ Creating a Live Ad Replacement service in particular.

Overview: Live DAI Flow

  • SCTE-35 markers in the live source signal the start of an ad break.
  • broadpeak.io detects the cue and calls the SpringServe VAST tag URL, substituting macros.
  • SpringServe returns a VAST response with the appropriate creatives.
  • if necessary, broadpeak.io transcodes and packages the ad creatives
  • stitches ad segments into the live stream manifest.
  • playback resumes seamlessly after the ad break.

Configuration

Step 1 - Create an Ad Server source

In the broadpeak.io WebApp:

  • Go to SourcesCreate new.

  • Choose Type: Ad Server.

  • Fill in:

    • Template: Custom
    • Name: SpringServe VAST for Live Ad Replacement
  • URL: paste the SpringServe VAST URL

    • For this playbook, we'll use the default value returned provided by SpringServe for a demo router: https://tv.springserve.com/rt/123456?w=1920&h=1080&cb={{CACHEBUSTER}}&ip={{IP}}&ua={{USER_AGENT}}&pod_max_dur={{POD_MAX_DUR}}&pod_ad_slots={{POD_AD_SLOTS}}&app_bundle={{APP_BUNDLE}}&app_name={{APP_NAME}}&app_store_url={{APP_STORE_URL}}&did={{DEVICE_ID}}&us_privacy={{US_PRIVACY}}

At this point, a table will be pre-filled with all query parameters from that URL. When working with ad servers and VAST tags, those are usually known as macros. SpringServe indicates them with double curly brackets.

Mapping macros

The main task now is to correctly map the macros by modifying that table, which entails determining

  1. what macros to include, and
  2. where their values will originate from.

There is no single answer to both of these questions - much will depend on your individual circumstances, how your SpringServe account is connected to the supply side, the type of devices your users will play content on, and many other factors that broadpeak.io does not control.

In the remainder of this page, we will document a standard set of macros that are usually found. For each of these macros, we provide the typical configuration of the mapping that you can apply in the aforementioned table.

Common macros

The most common ones are:

  • w and h - width and height of the player, primarily used in modern streaming to provide an indication of the aspect ratio of the content (rather than exact dimensions for the creatives). They are the only mandatory parameters expected by SpringServe
    • In most circumstances, they can be set as a static value
      type:Custom & value: 1920 and 1080 respectively for typical 16x9 content.
  • cb - cache buster, a random value to prevent caching of the VAST response
    • broadpeak.io will ensure that a random value is sent on each request
      type:From Variable & value (from dropdown): Random value (to prevent caching of request).
  • ip - IP address of the end-user
    • This information comes in the headers of the streaming request. broadpeak.io will forward that header automatically, which means this macro is not strictly necessary. However it can also be surfaced in the query parameters.
      type:From Variable, value (from dropdown): IP address of the client (end-user) device

Ad pod control

There are a number of macros that control the number and duration of the ads returned by SpringServe

  • pod_max_dur - Used to set the maximum duration of the ad pod returned by the ad server (in seconds)
    • In a Live Ad Replacement scenario, this should be the duration of the ad break, which broadpeak.io can dynamically fill
      type:From Variable, value (from dropdown): Duration of the ad break (in seconds)
    • For Live Pre-roll and AVOD scenario, it is up to you whether to use it to apply a constraint, in which case you will probably want a static value
      type:Custom, value: 90 (for a maximum of 1 min 30s of ads)
  • pod_ad_slots - Generally used to set the maximum number of ads returned in the pod.
    • It's rarely necessary to set this macro, but tends to appear by default in the VAST tags exported from SpringServe. You can therefore remove it, or set it to a custom value.

Player and device info

Player and device information is usually passed as well to the ad server to help with targeting and analytics. There are a number of macros available, the values of which are almost always passed from the player as query parameters in the streaming request and need to be passed through to SpringServe. The most usual ones are:

  • did - A device id (usually the IFA or "Identifier for Advertising") → type:From Query Parameter & value: did
  • ifa_type - the type of device identifier (under the "Identifier for Advertising" nomenclature) → type:From Query Parameter & value: ifa_type
  • ua - User agent of the end-user's device
    • This information comes in the headers of the streaming request. broadpeak.io will forward that header automatically, which means this macro is not strictly necessary. However it can also be surfaced in the query parameters. → type:From Header, value: User-Agent

Privacy

You then need to communicate user privacy and content signals to SpringServe, as required for compliance with privacy regulations. The exact ones to use will depend on the region you operate in. Those values will always come in the streaming request, and just need to be passed through to the ad server.

  • In the EU (and associated countries) this is generally done with macros gdpr and gdpr_consent
    type:From Query Parameter & value: gdpr and gdrp_content (respectively)
  • In the US, privacy strings are usually provided with the us_privacy macro. An additional coppa macro is required for children's content → type:From Query Parameter & value: us_privacy and coppa (respectively)

Site / App

You usually also need to provide information about the site or app that the request comes from. There are a number of typical macros used for this

  • url - For web players, this is typically the domain name of the website, though sometimes you need to pass the full URL to the page containing the player.
    • In typical circumstances this can be set as a static value
      type:Custom, value: mywebsite.com (adapt as necessary with your own)
  • app_name, app_bundleand app_store_url (and sometimes appVersion) are used for mobile and CTV applications
    • Again, you likely will want to set static values for those
      type:Custom, values: myvideoapp, com.mine.myapp, https://play.google.com/store/apps/details?id=com.mine.myapp&hl=en_US respectively (adapt as necessary with your own)
    • In more complex scenarios, such as if you have multiple apps using the same ad server endpoint, you may want to pass them from equivalently named query parameters present on the streaming request from the player. The easiest way to do this is to establish a forward rule:
      name: app* & type:Forward

Content Identification

Next, you need to pass macros that identify the main content. Here again, there are a number of options possible, depending on the circumstances.

  • For Live channels, you typically would pass
    • channel_name with the name of the live channel, which would typically be configured as a static value
      type:Custom & value: mylivechannel
    • content_livestream with a static value of 1 to indicate that it is a live stream
      type:Custom & value: 1
  • There are also a series of macros that usually need to be passed to identify the content, such as content_id, content_episode, content_title, content_series, etc. Those are more typically used in VOD scenarios, but can also apply to live content (in particular in catch-up and start-over scenarios). Those values are normally provided by the player as query parameters in the streaming request, and the simplest thing to do is to forward them:
    name: content_* & type:Forward

Others

👍

SpringServe also has mechanisms to define custom macros that can be passed, to provide additional information (usually for ad targeting). You will typically pass those through unchanged from query parameters added to the streaming call.


As you map the macros in this way in your Ad Server configuration, the URL input field gets updated to reflect the choices made in the table:

When you are done with the mapping, save your new source. Don't worry, you can always go update it at a later stage.

👍

If you want to have this configuration pre-filled in a new ad server, you can simply copy the following URL and paste it in the URL field:
https://tv.springserve.com/rt/[your-router-id]?w=1920&h=1080&cb=$CACHE_BUSTER&ip=$CLIENT_IP&ua=$http_User-Agent&pod_max_dur=$ADBREAK_DURATION_S&app*=$FORWARD&did=$arg_did&gdpr=$arg_gdpr&gdpr_consent=$arg_gdpr_consent&channel_name=my-live-channel&content_livestream=1&content_*=$FORWARD

Don't forget to replace [your-router-id] with your own, as well as the channel_name macro.

Step 2 - Assign it to a DAI Service

Next we'll create a DAI service that uses that ad server. We'll use one of the standard live stream samples, which contains ad breaks every few minutes.

  • Go to ServicesCreate new.

  • Fill in:

    • Application: Ad Insertion (Live, AVOD, Linear Parity).
    • Name: Live Ad Replacement with SpringServe
    • Content source: Live ad replacement sample (DASH)
  • Press Next

  • Toggle Ad replacement and fill:

    • Ad server: SpringServe VAST for Live Ad Replacement (the one just created)
  • Toggle Ad transcoding under the Common section, and choose Default profile sample

  • All other fields can remain at their default values

  • Click Run

Step 3 - Test the Service

In the next screen, click Service preview. Or from the Services page, click the preview icon (an eye) in the Actions column. This brings you into the preview player (with the source on the left, and the service output on the right)

To be able to test the service properly, and ensure that SpringServe can target ads appropriately, you need to add query parameters with values for the relevant macros.

In our example, let's add the following:

  • app_name: myapp
  • app_bundle: com.super.myapp
  • did: test-device
  • gdpr: 0
  • gdpr_consent: (empty string - it is not really possible to pass a random string into gdpr_consent - the values must be valid TFC 2.0 strings; whether SpringServe will return ads if you don't pass GDPR consent string will depend on its configuration for that VAST endpoint)

Troubleshooting

It can be difficult to troubleshoot this type of solution. Some general tips are provided in Ad insertion issues.

When ads do not appear where you expect them, it may sometimes be caused by the ad server not receiving valid values for the macros.

One way to check what is going on - if you have access to the SpringServe console - is to use the Real Time Debugger in their Troubleshooting tools. It offers a way to inspect the requests being made for a particular VAST tag, with all associated macros. If you leave your player running, you should see this view populate with requests.

Clicking on any of the request URLs will display the VAST response that was sent by SpringServe.

References

For more information on the typical macros supported by SpringServe:

For more information on the broadpeak.io concepts involved: