Live - HLS

As in the Live - DASH example the HLS example follows five steps to completely implement VAST tracking client side.

There are two ways to integrate Live - HLS VAST tracking depending on the capabilities of the video player.

  1. If you have no access to the segments that the player is currently playing back use:

  2. If you have access to the segments use:

If you are in doubt that you have access or just want to get quickly started use the first option. It will always work but can be slightly inaccurate under some circumstances.

Differences to DASH

For HLS-Live, VAST tracking is supported through Serverside.ai, where the VAST document can be fetched by the client to request the tracking URLs. Different from DASH there are no ad-ids in the HLS-standard manifests. Therefore you need to request the vast endpoint at the right point in time to get the vast response related to the ad that is going to run.

To signal the appearance of an ad there will be a EXT-X-PROGRAMM tag in the HLS manifest: EXT-X-PROGRAM-DATE-TIME:<date-time-msec>. It is now possible to call the vastURL at the moment when an ad is playing and receive the VAST data for this ad.

The rest of the process stays the same. We will nevertheless run through every single step below.

Option 1: Player has no API to retrieve segments

The parameter needed below can be viewed at Serverside.ai or via the https://admin.serverside.ai/api/v2/channels/:channelId API endpoint.

1. Manifest API Request

To retrieve a URL to the HLS master manifest and open a user session on the server use the following endpoint:

https://live.serverside.ai/hls/view/:channelId?&api-key=:api-key

For Example:

https://live.serverside.ai/hls/view/2aaf2594-68f5-43cc-89f5-f683963e2d23?&api-key=2aaf2594-68f5-43cc-89f5-f683963e2d23

In the response you'll get a json with mediaURL and vastURL like:

{
    "mediaURL":"https://live.serverside.ai/hls/:channelId/master.m3u8?sid=:sessionId&api-key=2aaf2594-68f5-43cc-89f5-f683963e2d23",
    "vastURL":"https://live.serverside.ai/hls/:channelId/:sessionId/vast.xml"
}

2. Starting Playback

Handover the mediaURL to the player which will load the manifests and video data.

GET Request:

https://live.serverside.ai/hls/:channelId/master.m3u8?api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Response 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.m3u8

3. Load-VAST data

To get the VAST document relating to the ad break that is currently playing use the vastURL from above. It will provide the original VAST response document together with the timing information for the synchronization on the player side.

The vastURL will mostly respond with a 204 (No Content). This happens because a request to the ad server is made one segment before the ad break. The VAST response from the ad server is stored and the stitching process takes place in the background. At this time the related VAST document is available to the front end as well (response with 200 OK), but as soon as the ad block is over the API will switch back to 204.

GET Request:

https://live.serverside.ai/hls/:channelId/:sessionId/320x180.m3u8/vast.xml

Response Body:

{
  "time": TIMESTAMP_IN_MS_MATCHING_IMPRESSION_TIME,
  "vast": VAST_XML_STRING
}

Example

GET Request:

https://live.serverside.ai/hls/5cc9789c-44ce-4e20-927e-2f4fc206144f/de025740-ee93-11ea-8452-1140472856cb/VAR(BANDWIDTH=0;RESOLUTION=1280;).m3u8/vast.xml

Response-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 sent to the ad-server exactly as described in steps 4 and 5 from the above DASH example.

4. Detect the start of an ad in the stream

Same as for DASH-Live

5. Keep track of the ad playback and send beacons

Same as for DASH-Live

Option 2: Player has an API to retrieve segments

In the case the player has an API to retrieve the currently playing segment use the following option.

1. Manifest API Request

The URL to the ad-insertion enabled channel is called outputUrl and can be viewed at Serverside.ai or via the https://admin.serverside.ai/api/v2/channels/:channelId API endpoint.

An outputUrl for HLS will have the following schema:

https://live.serverside.ai/hls/:channelId/master.m3u8?api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

2. Fetching the Master Manifest

An HLS-Live session is created by fetching the master manifest.

GET Request:

https://live.serverside.ai/hls/:channelId/master.m3u8?api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Response 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.m3u8

3. Load-VAST data

The URIs pointing to the media manifests will contain the session id. Appending /vast to any of the media manifest URI will provide the original VAST response document together with the timing information for the synchronization on the player side.

GET Request:

https://live.serverside.ai/hls/:channelId/:sessionId/320x180.m3u8/vast.xml

Response Body:

{
  "time": TIMESTAMP_IN_MS_MATCHING_IMPRESSION_TIME,
  "vast": VAST_XML_STRING
}

Example

GET Request:

https://live.serverside.ai/hls/5cc9789c-44ce-4e20-927e-2f4fc206144f/de025740-ee93-11ea-8452-1140472856cb/VAR(BANDWIDTH=0;RESOLUTION=1280;).m3u8/vast.xml

Response-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 sent to the ad server exactly as described in steps 4 and 5 from the above DASH example.

Find a complete implementation of HLS tracking for JavaScript and hls.js below.

4. Detect the start of an ad in the stream

Same as for DASH-Live

5. Keep track of the ad playback and send beacons

Same as for DASH-Live

Example integration of Option 2

The following HTML page shows a fully working example of the Serverside.ai HLS-live client-side tracking.

Last updated