VAST tracking: Live - HLS
Overview
This guide explains client-side VAST tracking for live HLS streams using Serverside.ai. It covers two methods based on player capabilities, including how to fetch manifests, detect ads, retrieve VAST data, and send tracking beacons.
As with VAST tracking: Live - DASH, the HLS workflow follows five key steps to fully implement client-side VAST tracking.
Methods for integrating live HLS VAST tracking
There are two ways to integrate live HLS VAST tracking, depending on your video player capabilities:
- If you have no access to the segments the player is currently playing back, use Method 1: player has no API to retrieve segments.
- If you have access to the segments, use Method 2: player has an API to retrieve segments.
If you are unsure which method applies or want to get started quickly, use the first method. It works in all cases but might be slightly less accurate under some circumstances.
Differences from DASH
For HLS live, VAST tracking is supported through Serverside.ai, where the client can fetch the VAST document to request the tracking URLs. Unlike DASH, HLS standard manifests don't include ad IDs. Therefore, you need to request the VAST endpoint at the correct moment to obtain the response related to the ad that is about to play.
To signal the appearance of an ad, the HLS manifest includes an EXT-X-PROGRAM-DATE-TIME tag: EXT-X-PROGRAM-DATE-TIME:<date-time-msec>. At this point, you can call the VAST URL to retrieve the VAST data for the ad.
The rest of the process remains the same, with each step described in detail in the following sections.
Method 1: player has no API to retrieve segments
Use this method if you have no access to the segments the player is currently playing back.
The api-key parameter can be viewed in Serverside.ai or retrieved via the API endpoint: https://mydomain.com/api/v2/channels/:channelId.
1. Request the HLS master manifest.
Use the following endpoint to retrieve the URL to the HLS master manifest and start a user session on the server:
https://mydomain.com/hls/view/:channelId?&api-key=:api-keyExample request
https://mydomain.com/hls/view/2aaf2594-68f5-43cc-89f5-f683963e2d23?&api-key=2aaf2594-68f5-43cc-89f5-f683963e2d23The API returns a JSON object containing the mediaURL and vastURL.
Example response
{
"mediaURL":"https://mydomain.com/hls/:channelId/master.m3u8?sid=:sessionId&api-key=2aaf2594-68f5-43cc-89f5-f683963e2d23",
"vastURL":"https://mydomain.com/hls/:channelId/:sessionId/vast.xml"
}2. Start playback.
Use the mediaURL obtained from the previous step to initialize your player and start playback. The player will load the manifests and media segments automatically.
Example GET request
https://mydomain.com/hls/:channelId/master.m3u8?api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxResponse body
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=320x180,CODECS="avc1.4d400c,mp4a.40.2",AVERAGE-BANDWIDTH="545600",BANDWIDTH=545600
1d4b9e30-3232-11ea-a76d-29ae63114b99/320x180.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=480x272,CODECS="avc1.4d4015,mp4a.40.2",AVERAGE-BANDWIDTH="765600",BANDWIDTH=765600
1d4b9e30-3232-11ea-a76d-29ae63114b99/480x270.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=640x360,CODECS="avc1.77.30,mp4a.40.2",AVERAGE-BANDWIDTH="1161600",BANDWIDTH=1161600
1d4b9e30-3232-11ea-a76d-29ae63114b99/640x360.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=960x540,CODECS="avc1.4d401f,mp4a.40.2",AVERAGE-BANDWIDTH="2140600",BANDWIDTH=2140600
1d4b9e30-3232-11ea-a76d-29ae63114b99/960x540.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2",AVERAGE-BANDWIDTH="3339600",BANDWIDTH=3339600
1d4b9e30-3232-11ea-a76d-29ae63114b99/1280x720.m3u83. Load VAST data.
Use the vastURL obtained in Step 1 to retrieve the VAST document for the ad break currently playing. The document contains the original VAST response along with timing information required to synchronize ad playback on the player side.
The vastURL will mostly return a 204 (No Content) response. This occurs because the request to the ad server is made one segment before the ad break begins. The VAST response is stored, and the stitching process runs in the background. Once the ad break starts, the related VAST document becomes available to the front end and will return a 200 (OK) response. After the ad block ends, the API will revert to returning 204 (No Content).
GET request
https://mydomain.com/hls/:channelId/:sessionId/320x180.m3u8/vast.xmlResponse body
{
"time": TIMESTAMP_IN_MS_MATCHING_IMPRESSION_TIME,
"vast": VAST_XML_STRING
}Example
The following example demonstrates a GET request to the vastURL for an HLS live ad break and the corresponding VAST XML response returned by the API.
GET request
https://mydomain.com/hls/5cc9789c-44ce-4e20-927e-2f4fc206144f/de025740-ee93-11ea-8452-1140472856cb/VAR(BANDWIDTH=0;RESOLUTION=1280;).m3u8/vast.xmlResponse body
time: 1599213250873
vast: "<?xml version="1.0" encoding="UTF-8"?>↵ <VAST version="3.0">↵ <Ad id="7253b601c7fd8e8c1708ca6cff1fb994-3c4ca.d1a64.4c52.30">↵ <InLine>↵ <AdSystem version="1.0">SpotXchange</AdSystem>↵ <AdTitle><![CDATA[Nowtilus Test Ad - 30sec]]></AdTitle>↵ <Description><![CDATA[]]></Description>↵ <Impression><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/Start?percentage=0]]></Impression>↵ <Error><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock?error=true]]></Error>↵ <Creatives>↵ <Creative sequence="1">↵ <Linear>↵ <Duration>00:00:30</Duration>↵ <TrackingEvents>↵ <Tracking event="complete"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/Complete?percentage=100]]></Tracking>↵ <Tracking event="firstQuartile"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/25?percentage=25]]></Tracking>↵ <Tracking event="midpoint"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/50?percentage=50]]></Tracking>↵ <Tracking event="thirdQuartile"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/75?percentage=75]]></Tracking>↵ </TrackingEvents>↵ <VideoClicks>↵ <ClickTracking><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock]]></ClickTracking>↵ </VideoClicks>↵ <MediaFiles>↵ <MediaFile delivery="progressive" type="video/mp4" width="480" height="360"><![CDATA[https://cdn.spotxcdn.com/media/videos/orig/1/0/10fa3ca3af9f4600e3eb580eb4da5afc.mp4]]></MediaFile>↵ </MediaFiles>↵ </Linear>↵ </Creative>↵ </Creatives>↵ <Extensions>↵ <Extension type="Pricing">↵ <Price model="CPM" currency="USD" source="spotxchange"><![CDATA[0]]></Price>↵ </Extension>↵ <Extension type="SpotX-Count">↵ <total_available><![CDATA[2]]></total_available>↵ </Extension>↵ <Extension type="Spotx-Regs">↵ <GDPR>1</GDPR>↵ </Extension>↵ <Extension type="Spotx-User">↵ <consent>2</consent>↵ </Extension>↵ </Extensions>↵ </InLine>↵ </Ad>↵ </VAST>"The VAST manifest can now be parsed, and tracking requests can be sent to the ad server, following the same process as Steps 4 and 5 in VAST tracking: Live - DASH.
4. Detect the start of an ad in the stream.
This step works the same way as for VAST tracking: Live - DASH.
5. Keep track of the ad playback and send beacons.
This step works the same way as for VAST tracking: Live - DASH.
Method 2: player has an API to retrieve segments
Use this method if the player provides an API to access the currently playing segment.
1. Manifest API request.
The URL to the channel with ad insertion is called outputUrl and can be viewed in Serverside.ai or retrieved via the API endpoint: https://mydomain.com/api/v2/channels/:channelId.
An outputUrl for HLS has the following schema:
https://mydomain.com/hls/:channelId/master.m3u8?api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx2. Fetch the master manifest.
Fetching the master manifest creates an HLS live session.
GET request
https://mydomain.com/hls/:channelId/master.m3u8?api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxResponse body
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=320x180,CODECS="avc1.4d400c,mp4a.40.2",AVERAGE-BANDWIDTH="545600",BANDWIDTH=545600
1d4b9e30-3232-11ea-a76d-29ae63114b99/320x180.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=480x272,CODECS="avc1.4d4015,mp4a.40.2",AVERAGE-BANDWIDTH="765600",BANDWIDTH=765600
1d4b9e30-3232-11ea-a76d-29ae63114b99/480x270.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=640x360,CODECS="avc1.77.30,mp4a.40.2",AVERAGE-BANDWIDTH="1161600",BANDWIDTH=1161600
1d4b9e30-3232-11ea-a76d-29ae63114b99/640x360.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=960x540,CODECS="avc1.4d401f,mp4a.40.2",AVERAGE-BANDWIDTH="2140600",BANDWIDTH=2140600
1d4b9e30-3232-11ea-a76d-29ae63114b99/960x540.m3u8
#EXT-X-STREAM-INF:FRAME-RATE="25.000",RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2",AVERAGE-BANDWIDTH="3339600",BANDWIDTH=3339600
1d4b9e30-3232-11ea-a76d-29ae63114b99/1280x720.m3u83. Load VAST data.
The URIs pointing to the media manifests will contain the session ID. Appending /vast to any media manifest URI will provide the original VAST response document, along with timing information for synchronization on the player side.
GET request
https://mydomain.com/hls/:channelId/:sessionId/320x180.m3u8/vast.xmlResponse body
{
"time": TIMESTAMP_IN_MS_MATCHING_IMPRESSION_TIME,
"vast": VAST_XML_STRING
}Example
The following example demonstrates how to fetch the VAST document for an HLS live ad break using the vast.xml endpoint.
GET request
https://mydomain.com/hls/5cc9789c-44ce-4e20-927e-2f4fc206144f/de025740-ee93-11ea-8452-1140472856cb/VAR(BANDWIDTH=0;RESOLUTION=1280;).m3u8/vast.xmlResponse body
time: 1599213250873
vast: "<?xml version="1.0" encoding="UTF-8"?>↵ <VAST version="3.0">↵ <Ad id="7253b601c7fd8e8c1708ca6cff1fb994-3c4ca.d1a64.4c52.30">↵ <InLine>↵ <AdSystem version="1.0">SpotXchange</AdSystem>↵ <AdTitle><![CDATA[Nowtilus Test Ad - 30sec]]></AdTitle>↵ <Description><![CDATA[]]></Description>↵ <Impression><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/Start?percentage=0]]></Impression>↵ <Error><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock?error=true]]></Error>↵ <Creatives>↵ <Creative sequence="1">↵ <Linear>↵ <Duration>00:00:30</Duration>↵ <TrackingEvents>↵ <Tracking event="complete"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/Complete?percentage=100]]></Tracking>↵ <Tracking event="firstQuartile"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/25?percentage=25]]></Tracking>↵ <Tracking event="midpoint"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/50?percentage=50]]></Tracking>↵ <Tracking event="thirdQuartile"><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock/75?percentage=75]]></Tracking>↵ </TrackingEvents>↵ <VideoClicks>↵ <ClickTracking><![CDATA[http://ad-server-mock.azurewebsites.net/api/ad-server-mock]]></ClickTracking>↵ </VideoClicks>↵ <MediaFiles>↵ <MediaFile delivery="progressive" type="video/mp4" width="480" height="360"><![CDATA[https://cdn.spotxcdn.com/media/videos/orig/1/0/10fa3ca3af9f4600e3eb580eb4da5afc.mp4]]></MediaFile>↵ </MediaFiles>↵ </Linear>↵ </Creative>↵ </Creatives>↵ <Extensions>↵ <Extension type="Pricing">↵ <Price model="CPM" currency="USD" source="spotxchange"><![CDATA[0]]></Price>↵ </Extension>↵ <Extension type="SpotX-Count">↵ <total_available><![CDATA[2]]></total_available>↵ </Extension>↵ <Extension type="Spotx-Regs">↵ <GDPR>1</GDPR>↵ </Extension>↵ <Extension type="Spotx-User">↵ <consent>2</consent>↵ </Extension>↵ </Extensions>↵ </InLine>↵ </Ad>↵ </VAST>"The VAST manifest can now be parsed, and tracking requests can be sent to the ad server, following the same process as steps 4 and 5 in VAST tracking: Live - DASH.
4. Detect the start of an ad in the stream.
This step works the same way as for VAST tracking: Live - DASH.
5. Keep track of the ad playback and send beacons.
This step works the same way as for VAST tracking: Live - DASH.
Example integration for Method 2
The following HTML page provides a fully working example of client-side tracking for HLS live streams using Serverside.ai, specifically for players with a segment retrieval API.