DCR Thailand Video Browser SDK: Difference between revisions

From Engineering Client Portal

(Created page with "{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}} {{CurrentBreadcrumb}} Category:Digital == Overview == The Nielsen SDK is one of multiple framework SD...")
 
No edit summary
 
(3 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}}  {{CurrentBreadcrumb}}
{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}}  {{CurrentBreadcrumb}}
[[Category:Digital]]
[[Category:Digital]]


__NOTOC__
== Overview ==
== Overview ==
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring live streaming  and video on-demand content viewing using computer, mobile devices, etc.
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.
The Browser SDK is the framework for browsers developers to integrate Nielsen Measurement into their media player pages.
The Browser SDK (BSDK) is the framework for website developers to integrate Nielsen Measurement into their media players. Nielsen SDKs are also equipped to measure static content and can track key life cycle events.


== Prerequisites ==
== Prerequisites ==
To get started, an AppID is needed. The AppID is a unique ID assigned to the player/site/app. This will be provided upon starting the integration from Nielsen.
Before you start the integration, you will need:
 
{| class="wikitable"
<syntaxhighlight lang="javascript">
|-
  apid: "XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" // eg. PDA7D5EE6-B1B8-XXXX-XXXX-2A788BCXXXCA
! style="width: 30px;" |
</syntaxhighlight>
! style="width: 15%;" | Item
! Description
! Source
|-
|| ☑ || '''App ID (apid)''' || Unique ID assigned to the player/site and configured by product. During initial implementation, a 'test' apid will be given. Once the implementation has been certified, a 'production' apid will then be generated and needs to be used before 'going live'. || Contact Nielsen
|}


== Configure SDK ==
== Configure SDK ==
Line 19: Line 25:


=== Static Queue Snippet ===
=== Static Queue Snippet ===
The static queue snippet allows the SDK APIs to be called while the actual SDK and configuration file are still being downloaded. As the queue can capture all API calls before the download completes, there is no wait time. Once the SDK is available, the API calls will transition from directing to the queue to the SDK seamlessly.
<br>
Add the following script tag to the website:
Add the following script tag to the website:
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
<script>
!function(e,n){
!function(t,n)
  function t(e){
{
    return"object"==typeof e?JSON.parse(JSON.stringify(e)):e
   t[n]=t[n]||
   }
  e[n]=e[n]||
   {
   {
     nlsQ:function(e,o,c,r,s,i)
     nlsQ:function(o,r,c){
    {
      var s=e.document,
    return s=t.document,
      a=s.createElement("script");
    r=s.createElement("script"),
      a.async=1,
    r.async=1,
      a.src=("http:"===e.location.protocol?"http:":"https:")+"//cdn-gl.imrworldwide.com/conf/"+o+".js#name="+r+"&ns="+n;
    r.src=("http:"===t.location.protocol?"http:":"https:")+"//cdn-gl.imrworldwide.com/conf/"+e+".js#name="+o+"&ns="+n,
      var i=s.getElementsByTagName("script")[0];
    i=s.getElementsByTagName("script")[0],
      return i.parentNode.insertBefore(a,i),
    i.parentNode.insertBefore(r,i),
      e[n][r]=e[n][r]||{g:c||{},
    t[n][o]=t[n][o]||{g:c||{},
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}
    ggPM:function(e,c,r,s,i){(t[n][o].q=t[n][o].q||[]).push([e,c,r,s,i])}},t[n][o]
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}},
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}}},
      e[n][r]
     }
     }
   }
   }
}
}(window,"NOLBUNDLE");
 
(window,"NOLBUNDLE");
 
var nSdkInstance = NOLBUNDLE.nlsQ("PXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "nlsnInstance");
 
</script>
</syntaxhighlight>
</syntaxhighlight>
 
<br>
The static queue snippet allows the SDK APIs to be called while the actual SDK and configuration file are still being downloaded. As the queue can capture all API calls before the download completes, there is no wait time. Once the SDK is available, the API calls will transition from directing to the queue to the SDK seamlessly.


===Create SDK Instance===
===Create SDK Instance===
Line 54: Line 60:
==== Initialization API Call ====
==== Initialization API Call ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
NOLBUNDLE.nlsQ("<apid>", "<instanceName>",{nol_sdkDebug: "debug"})
NOLBUNDLE.nlsQ("<apid>", "<instanceName>",{nol_sdkDebug: "debug"});
</syntaxhighlight>
</syntaxhighlight>
 
<br>
When creating an instance, pass the following three values:
When creating an instance, pass the following values: (<code>nol_sdkDebug</code> and <code>optout</code> are optional)
{| class="wikitable"
{| class="wikitable"
|-
|-
! Parameter !! Description !! Values
! Parameter !! Description !! Values
|-
|-
| apid || Unique ID assigned to player/site || 'PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
| apid || Unique ID assigned to player/site ||
'TXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Test Apid that starts with 'T'<br/>
'PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Production Apid that starts with 'P'
|-
|-
|instanceName || Name of SDK instance || "any string value"
|instanceName || Name of SDK instance || "any string value"
|-
|-
| nol_sdkDebug || Enables Nielsen console logging. Only required for testing (not in production) || "{nol_sdkDebug: "debug"})"
| nol_sdkDebug || Enables Nielsen console logging if desired. || <syntaxhighlight lang="javascript">
{nol_sdkDebug: "debug"}  
{nol_sdkDebug: "info"}
{nol_sdkDebug: "warn"}
{nol_sdkDebug: "true"}
</syntaxhighlight>
|-
|optout || Optional: OptOut global parameter. || <code>1/0</code> or <code>true/false</code>
|}
|}


==== Example SDK Initialization ====
==== Example SDK Initialization ====
When the initialization call is made, a unique static configuration file, <apid>.js, will be downloaded based on the apid and will be cached on the user’s browser.
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
var nSdkInstance = NOLBUNDLE.nlsQ("PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", {nol_sdkDebug: "debug"});
</syntaxhighlight>


When the initialization call is made, a unique static configuration file, <apid>.js, will be downloaded based on the apid and will be cached on the user’s browser.
var nSdkInstance = NOLBUNDLE.nlsQ("XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", {
    nol_sdkDebug: "debug",
    optout: "false"
});


</syntaxhighlight>
<br>


Once the configuration is downloaded, the SDK itself will be downloaded and initialized. All SDK modules are included in one file: “nlsSDK600.eu.bundle.min.js”.
Once the configuration is downloaded, the SDK itself will be downloaded and initialized. All SDK modules are included in one file: “nlsSDK600.bundle.min.js”. More information on OptOut Parameter under [[DCR Thailand Video Browser SDK#Privacy_and_Opt-Out|Privacy and Opt-Out.]]


=== Example SDK Configuration ===
=== Example SDK Configuration ===
The configuration should include the Static Queue Snippet and an SDK Instance for an unique AppID as shown in the example:
 
<syntaxhighlight lang="javascript">
The configuration should include the Static Queue Snippet and an SDK Instance for an unique App ID as shown in the example:
<script type="text/javascript">
<syntaxhighlight lang="html"><script type="text/javascript">
  // Add Static Queue Snippet
// Add Static Queue Snippet
!function(t,n)
!function(e,n){
{
  function t(e){
   t[n]=t[n]||
    return"object"==typeof e?JSON.parse(JSON.stringify(e)):e
  }
   e[n]=e[n]||
   {
   {
     nlsQ:function(e,o,c,r,s,i)
     nlsQ:function(o,r,c){
    {
      var s=e.document,
    return s=t.document,
      a=s.createElement("script");
    r=s.createElement("script"),
      a.async=1,
    r.async=1,
      a.src=("http:"===e.location.protocol?"http:":"https:")+"//cdn-gl.imrworldwide.com/conf/"+o+".js#name="+r+"&ns="+n;
    r.src=("http:"===t.location.protocol?"http:":"https:")+"//cdn-gl.imrworldwide.com/conf/"+e+".js#name="+o+"&ns="+n,
      var i=s.getElementsByTagName("script")[0];
    i=s.getElementsByTagName("script")[0],
      return i.parentNode.insertBefore(a,i),
    i.parentNode.insertBefore(r,i),
      e[n][r]=e[n][r]||{g:c||{},
    t[n][o]=t[n][o]||{g:c||{},
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}
    ggPM:function(e,c,r,s,i){(t[n][o].q=t[n][o].q||[]).push([e,c,r,s,i])}},t[n][o]
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}},
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}}},
      e[n][r]
     }
     }
   }
   }
}
}(window,"NOLBUNDLE");
(window,"NOLBUNDLE");
   
   
  // Created SDK Instance
// Created SDK Instance
var nSdkInstance = NOLBUNDLE.nlsQ("PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX","myPlayerName", {nol_sdkDebug: "DEBUG"});
var nSdkInstance = NOLBUNDLE.nlsQ("XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", {nol_sdkDebug: "debug"});
</script>
</script></syntaxhighlight>
</syntaxhighlight>


=== Create Metadata Objects ===
=== Create Metadata Objects ===
Line 117: Line 139:
Metadata can be passed through key-values using the Nielsen reserved keys. User will need to set up content and ad objects with the required Nielsen keys as shown in the sample code below.
Metadata can be passed through key-values using the Nielsen reserved keys. User will need to set up content and ad objects with the required Nielsen keys as shown in the sample code below.


==== Content Metadata (VOD)====
==== Content Metadata ====
Content metadata should remain constant throughout the completion of an episode / clip including the ads play.
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.
<table>
{| class="wikitable"
<tr>
|-
<th> Keys </th>
! Key !! Description !! Values !! Required
<th> Description </th>
|-
<th> Example </th>
| clientid ||
<th> Required
parent ID – value is automatically populated through provided App ID.<br/>
</th></tr>
In order to override the brand configured to the App ID, pass parent <br/>
<tr>
value here and the sub-brand ID associated to that brand in the subbrand <br/>
<td>'''type'''</td>
key (e.g. multiple brands in App)
<td><code>'content', 'ad'</code></td>
||
<td> <code> 'content'</code> </td>
Nielsen provided
<td> Yes
||
</td></tr>
|-
<tr>
| subbrand || sub-brand ID – value is automatically populated through provided<br/>
<td> '''assetid''' </td>
App ID. In order to override the sub-brand configured to the App ID, value can <br/>
<td> unique ID assigned to asset </td>
be passed here (e.g. multiple sub-brands in App)
<td> custom </td>
||
<td> Yes
Nielsen provided
</td></tr>
||
<tr>
|-
<td> '''program''' </td>
| type || type of asset || "content" || ✓
<td>name of program (25 character limit) </td>
|-
<td> custom </td>
| assetid || unique ID assigned to asset || custom<br>(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓
<td> Yes
|-
</td></tr>
| program || name of program || custom || ✓
<tr>
|-
<td> '''title''' </td>
| title || episode name || custom || ✓
<td>name of program (40 character limit) </td>
|-
<td> custom </td>
| length || length of content in seconds || seconds (86400 for live stream)|| ✓
<td> Yes
|-
</td></tr>
| segB || custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform. || custom ||
<tr>
|-
<td> '''length''' </td>
| segC || For VOD: Populate TVContent ID, For livestream: leave blank || custom || Required for VOD only
<td> length of content in seconds </td>
|-
<td> <code>seconds</code></td>
| isfullepisode || full episode flag ||
<td> Yes
*'y', 'yes', or 'lf' full episode
</td></tr>
*'n', 'no', or 'sf' – non full episode
<tr>
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'.
<td> '''isfullepisode''' </td>
||
<td> full episode flag</td>
<td> 'y'- full episode, 'n'- non full episode</td>
|-
<td> Yes
|adloadtype || type of Ad load:
</td></tr>
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.
<tr>
* 2) Dynamic – Dynamic Ad Insertion (DAI)
<td> <b>adloadtype</b>
||
</td>
*"1" – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement.
<td> ad model (only pass value as 2)
*"2" – content with dynamic Ads
</td>
||
<td> '2'
</td>
|}
<td>Yes
</td></tr>
<tr>
<td> '''segB''' </td>
<td> custom segment B</td>
<td> custom </td>
<td>
</td></tr>
<tr>
<td> '''segC''' </td>
<td> custom segment C</td>
<td> custom </td>
<td>
</td></tr>
<tr>
<td> '''crossId1''' </td>
<td> standard episode ID </td>
<td> custom </td>
<td>
</td></tr>
<tr>
<td> '''crossId2 '''</td>
<td> content originator (only required for distributors) </td>
<td> Nielsen provided </td>
<td>
</td></tr>


</table>
==== Example Content Object ====
 
==== Example Content Object (VOD)====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
var content_metadata_object = {   
var contentMetadataObject =
  // SDK
{   
   type:     'content',
   type:           'content',
   assetid:   'VID123-123456',
   assetid:       'VID-123456',
   program:   'program name',
   program:       'program name',
   title:     'episode title',
   title:         'episode title',
   length:   '543',
   length:         'length in seconds',
   isfullepisode: 'n',
   isfullepisode: 'y',
   adloadtype:'2'
   adloadtype:     '2',
}
  segB:          'custom segment B', // optional
  segC:          'custom segment C', // optional
};
</syntaxhighlight>
</syntaxhighlight>


<br/>
=== Ad Metadata ===
==== Content Metadata (Live Streaming)====
The Ad Metadata (if applicable) should be passed for each individual ad.
Content metadata should remain constant throughout the completion of an episode / clip including the ads play.
<table>
<tr>
<th> Keys </th>
<th> Description </th>
<th> Example </th>
<th> Required
</th></tr>
<tr>
<td>'''type'''</td>
<td><code>'content', 'ad'</code></td>
<td> <code> 'content'</code> </td>
<td> Yes
</td></tr>
<tr>
<td> '''assetid''' </td>
<td> unique ID for each quarter </td>
<td> live021 </td>
<td> Yes
</td></tr>
<tr>
<td> '''program''' </td>
<td>name of program (25 character limit) </td>
<td> "CH Live" </td>
<td> Yes
</td></tr>
<tr>
<td> '''title''' </td>
<td>Use period as title name per each quarter </td>
<td>”02.00-02.14”</td>
<td> Yes</td></tr>
<tr>
<td> '''length''' </td>
<td> length of content in seconds </td>
<td>  900 </td>
<td> Yes
</td></tr>
<tr>
<td> '''isfullepisode''' </td>
<td> full episode flag</td>
<td> 'y'- full episode</td>
<td> Yes
</td></tr>
<tr>
<td> <b>adloadtype</b>
</td>
<td> ad model (only pass value as 2)
</td>
<td> '2'</td>
<td>Yes
</td></tr>
<tr>
<td> '''segB''' </td>
<td> custom segment B</td>
<td> custom </td>
<td>
</td></tr>
<tr>
<td> '''segC''' </td>
<td> custom segment C</td>
<td> custom </td>
<td>
</td></tr>
<tr>
<td> '''crossId1''' </td>
<td> standard episode ID </td>
<td> custom </td>
<td>
</td></tr>
<tr>
<td> '''crossId2 '''</td>
<td> content originator (only required for distributors) </td>
<td> Nielsen provided </td>
<td>
</td></tr>
</table>
 
==== Example Content Object (Live Streaming)====
<syntaxhighlight lang="javascript">
var content_metadata_object = { 
  // SDK
  type:      'content',
  assetid:  'live021',
  program:  'CHLive',
  title:    '02.00-02.14',
  length:    '900',
  isfullepisode: 'y',
  adloadtype:'2'
}
</syntaxhighlight>
 
<br/>
=== Ad Metadata Object ===
The ad metadata should be passed for each individual ad.
 
{| class="wikitable"
{| class="wikitable"
|-
|-
! Keys !! Description !! Values !! Required
! Keys !! Description !! Values !! Required
|-
|-
| type || type of ad || 'preroll', 'midroll', 'postroll' or  'AD' || ✓
| type || type of Ad || <code>'preroll'</code>, <code>'midroll'</code>, <code>'postroll'</code> <br> <code>'ad'</code>  - If specific type can not be identified.|| ✓
|-
|-
| assetid || unique ID assigned to ad || custom || ✓
| assetid || unique ID assigned to Ad || custom || ✓
|}
|}


Line 322: Line 223:
var adMetadataObject =  
var adMetadataObject =  
{   
{   
   assetid: 'AD-1',
   type:   'preroll',
   type:   'preroll'
   assetid: 'AD-1'
};
};
</syntaxhighlight>
</syntaxhighlight>
<br/>
<br/>
<blockquote> URL Character Limit: There is a URL character limit of 2K characters due to browser limitations. Exceeding this value could impair data delivery on particular browsers. </blockquote>
<blockquote> URL Character Limit: There is a URL character limit of 2K characters due to browser limitations. Exceeding this value could impair data delivery on particular browsers. </blockquote>
Avoid Carriage Return (CR) and/or Linefeeds (LF) in all fields (because of current data reporting as CSV)!
Implementations has to filter out CR/LF with appropriate programming.
It's also a good idea to check and validate entries from other systems (eg. CMS, player) before simply copy them to the variables in metadata.


==== Call Nielsen APIs ====
==== Call Nielsen APIs ====
Line 344: Line 240:


=== Pause Event ===
=== Pause Event ===
To indicate pause
The setPlayheadPostion event is used for handling pause. To indicate pause, stop passing the playhead position to the SDK. Once the content resumes, begin sending the playhead again with the correct playhead value.
 
* Call [[stop]] immediately and withhold sending playhead position.
* Start sending pings – [[loadMetadata]] and [[playheadPosition]] - once the playback resumes.


=== Other Interrupt Scenarios ===
=== Other Interrupt Scenarios ===
Line 355: Line 248:
* Leaving the page to another destination
* Leaving the page to another destination
* Pressing the stop button
* Pressing the stop button
* Network Loss


There are many cases where the player itself has the ability to detect such situations. If not, these interruption scenarios can be handled through JavaScript. The events that are called will depend on the asset being played (e.g. midroll vs. content).
There are many cases where the player itself has the ability to detect such situations. If not, these interruption scenarios can be handled through JavaScript. The events that are called will depend on the asset being played (e.g. midroll vs. content).


<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
var stopped = false;
window.addEventListener('beforeunload', function(event)  
function closePlayer() {
{
if (stopped) {return;}
  // Only inside a midroll indicate <stop> for the ad
stopped = true;
  nSdkInstance.ggPM('stop', playheadPosition);
if (inMidroll) {    // Only inside a midroll indicate <stop> for the ad
 
nSdkInstance.ggPM('stop', playheadPositionMidroll);
  // Indicate <end> and <stop> for the content
}
  nSdkInstance.ggPM('end', playheadPosition);
nSdkInstance.ggPM('end', playheadPositionContent);    // Indicate <end> for the content
   nSdkInstance.ggPM('stop', playheadPosition);
};
window.addEventListener("beforeunload", function (e) {
closePlayer();   // call nielsensdk with end/stop
});
window.addEventListener("pagehide", function (e) { // for iOS mobile "pagehide" recommended by apple
closePlayer();   // call nielsensdk with end/stop
});
});
</syntaxhighlight>
</syntaxhighlight>


<blockquote>'''Note:''' User may need to add code to support specific browser versions (e.g. older versions of Internet Explorer or covering Safari on mobile browsers ... you may use "onpagehide" event as well).</blockquote>
<blockquote>'''Note:''' User may need to add code to support specific browser versions (e.g. older versions of Internet Explorer).</blockquote>
 
== Call Nielsen APIs ==
The method for calling events is ggPM().


<syntaxhighlight lang="javascript">
=== SDK Events ===
nSdkInstance.ggPM('event', parameter);
</syntaxhighlight>
 
=== Events ===
The events are included in the table below:
{| class="wikitable"
{| class="wikitable"
|-
|-
! Event name !! Values to pass !! Description
! Event !! Parameter !! Description
|-
|-
| 'loadMetadata' || content/ad metadata object || Needs to be called at the beginning of each content/ad metadata object
| 'loadMetadata' || content/ad metadata object || Needs to be called at the beginning of each asset
|-
|-
| 'setPlayheadPosition'
| 'setPlayheadPosition' || playhead position as integer<br/>
||
VOD: || current position in seconds <br/>
*""VOD (or ad ): || current position in seconds (integer)<br/><br/> nSdkInstance.ggPM('setPlayheadPosition', Math.round(player.getcurrentPosition)) <br/><br/>
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) <br/>
*""Live streaming: current UTC timestamp<br/>
Note: 'setPlayheadPosition' has to be called every second
var currenttime = Math.round(newDate()/1000);<br/> <br/>
nSdkInstance.ggPM("setPlayheadPosition",
currenttime);<br/>
||
||
Pass playhead position every second during playback
Pass playhead position every second during playback
|-
|-
| 'stop' || playhead position in seconds || Call when ads complete playing and at the very end of the stream. The playhead position must be passed when calling stop
| 'stop' || playhead position in seconds || Call when content or ads complete playing and pass playhead position
|-
|-
| 'end' || playhead position in seconds || This event has to be called once for the current video asset at the end of the playback.At the end of the content stream, if the user switches to another piece of content or when the browser is refreshed or closed.
| 'end' || playhead position in seconds || Call when the current video asset completes playback and pass the playhead position. <br/>
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.
|}
|}


'''Note:''' Playhead position as integer
== SDK Playhead Event Sequence ==
 
The sample event lifecycles can be used as a reference for identifying the order for calling events.
'''Note:''' 'setPlayheadPosition' has to be called every second (for livestream send the UTC timestamp, for vod send the time in seconds as integer)
 
==== Example Events ====
<br/>
 
'''VOD'''
 
*'''Event:''' loadMetadata  |  '''Value Pass ( Object ):''' Content Metadata Object
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
</syntaxhighlight>
 
 
*'''Event:''' loadMetadata  |  '''Value Pass  ( Object ):''' Pre-roll AD Metadata Object
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);
</syntaxhighlight>
 
 
*'''Event:''' setPlayheadPosition  |  '''Value Pass ( Integer ):''' playheadPosition
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
</syntaxhighlight>
 
 
*'''Event:''' stop  |  '''Value Pass ( Integer ):''' stopPlayheadPosition
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('stop', stopPlayheadPosition);
</syntaxhighlight>
 
 
*'''Event:''' end  |  '''Value Pass ( Integer ):''' endPlayheadPosition
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('end', endPlayheadPosition);
</syntaxhighlight>
 
<br/>
 
'''Live Streaming'''
 
*'''Event:''' loadMetadata  |  '''Value Pass ( Object ):''' Content Metadata Object
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
</syntaxhighlight>
 
 
*'''Event:''' setPlayheadPosition  |  '''Value Pass ( Integer ):''' playheadPosition
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
</syntaxhighlight>
 
<br/>
 
  '''When the quarters hour change'''
<br/>
*'''Event:''' end  |  '''Value Pass ( Integer ):''' endPlayheadPosition
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('end', endPlayheadPosition);
</syntaxhighlight>
 
 
*'''Event:''' loadMetadata  |  '''Value Pass ( Object ):''' Content Metadata Object


<syntaxhighlight lang="javascript">
=== Content Playback ===
  nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
</syntaxhighlight>
 
 
*'''Event:''' setPlayheadPosition  |  '''Value Pass ( Integer ):''' playheadPosition
 
<syntaxhighlight lang="javascript">
  nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
</syntaxhighlight>
 
==  SDK Event Lifecycle ==
 
The sample event lifecycle can be used as a reference for identifying the order for calling events.
 
 
{{Examples|
without Ads|
 
==== Event Lifecycle without ads: ====
<br>
[[File:even browser no ads.png]]
 
==== Example without ads: ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
// START OF STREAM
// START OF STREAM
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);  // must be called as start of stream
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);  
 
   
// CONTENT
// CONTENT PLAYS
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);  // must be fired every second with playhead starting from 0 (or with seconds since 1970-01-01 00:00:00 in case of livestream)
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
 
//  
... /*** pass playheads every second ***/
//   pass playhead every second
// 
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);


nSdkInstance.ggPM('setPlayheadPosition', lastPlayheadPosition);
// END OF STREAM
// END OF STREAM
nSdkInstance.ggPM('end', endPlayheadPosition); // has to be called here at the end of the content
nSdkInstance.ggPM('end', playheadPosition);
// endPlayheadPosition = lastPlayheadPosition
</syntaxhighlight>
</syntaxhighlight>




|with Ads=
=== Content Playback with Ads ===
 
==== Event Lifecycle with ads: ====
<br>
[[File:event browser.png|event browser.png]]
<br>
 
==== Example with ads: ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
// START OF STREAM
// START OF STREAM
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); // must be called as start of stream (even if 1st asset is preroll)
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);  
   
   
// PREROLL
// PREROLL
nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);
nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition); // must be fired every second with playhead starting from 0
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
 
//
... /*** pass playhead every second ***/
/pass playhead every second
 
/
nSdkInstance.ggPM('setPlayheadPosition', lastPlayheadPosition); // end pre-roll stream
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('stop', stopPlayheadPosition); // stopPlayheadPosition = lastPlayheadPosition
nSdkInstance.ggPM('stop', playheadPosition);
   
   
// CONTENT
// CONTENT
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);  // must be fired every second with playhead starting from 0 for the first segment (or with seconds since 1970-01-01 00:00:00 in case of livestream)
... /*** pass playhead every second ***/
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
// 
//  pass playhead every second
// 
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('stop', playheadPosition);


// MIDROLL
// MIDROLL
nSdkInstance.ggPM('loadMetadata', midrollMetadataObject);
nSdkInstance.ggPM('loadMetadata', midrollMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition); // must be fired every second with playhead starting from 0
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
 
//
... /*** pass playhead every second ***/
/pass playhead every second
    
//   
nSdkInstance.ggPM('setPlayheadPosition', lastPlayheadPosition); // end mid-roll stream
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('stop', stopPlayheadPosition); // stopPlayheadPosition = lastPlayheadPosition
nSdkInstance.ggPM('stop', playheadPosition);
   
   
// CONTENT
// CONTENT RESUMES
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition); // must be fired every second with playhead starting from where it left off before mid-roll (or with seconds since 1970-01-01 00:00:00 in case of livestream)
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
//
//  pass playhead every second
// 
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);


... /*** pass playhead every second ***/
// END OF STREAM
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('setPlayheadPosition', lastPlayheadPosition);  
nSdkInstance.ggPM('end', playheadPosition);
nSdkInstance.ggPM('end', endPlayheadPosition); // has to be called here at the end of the content
// endPlayheadPosition = lastPlayheadPosition
   
   
// POSTROLL
// POSTROLL
nSdkInstance.ggPM('loadmetadata', postrollMetadataObject);
nSdkInstance.ggPM('loadmetadata', postrollMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition); // must be fired every second with playhead starting from 0
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
 
//
... /*** pass playhead every second ***/
/pass playhead every second
/
nSdkInstance.ggPM('setPlayheadPosition', lastPlayheadPosition); // end post-roll stream
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
// END OF STREAM
nSdkInstance.ggPM('stop', playheadPosition);
nSdkInstance.ggPM('stop', stopPlayheadPosition); // stopPlayheadPosition = lastPlayheadPosition
</syntaxhighlight>
</syntaxhighlight>
 
<blockquote>
<br>
}}
 
* 'setPlayheadPosition' is used for calculating duration and must be passed every second. The final playhead position must be sent for the current asset being played before calling 'stop', 'end', or 'loadmetadata'.
* 'setPlayheadPosition' is used for calculating duration and must be passed every second. The final playhead position must be sent for the current asset being played before calling 'stop', 'end', or 'loadmetadata'.


* after an 'end' in case there is a new content played, there is a need to have another 'loadmetadata' again.
* For Ad Pods, events must be called for each individual Ad. Each Ad playhead position should begin at ‘0’ when ad starts.


* For Ad, events must be called for each individual Ad. Each Ad playhead position should begin at ‘0’ when ad starts.
* When content has resumed following an ad break, the playhead position update must continue where previous content segment left off. The playhead position should be passed as a rounded number with no decimals.
</blockquote>


* When content has resumed following an ad break, the playhead position update must continue where previous content segment left off. The playhead position should be passed as a rounded number with no decimals.
== Privacy and Opt-Out ==
There are two primary methods for implementing user Opt-out preferences:
# [[#User Opt Out|User Opt Out]] - Provide a link to the Nielsen Privacy Policy page when a User can make their selection
# [[#Initialization Opt Out|Initialization Opt Out]] - Global OptOut Parameter


* For pre-roll ads you have to call the loadMetadata event for content at the start of stream and after the preroll
=== User Opt Out ===
The site must provide a means for the user to opt-out of, or opt back into, Nielsen Measurement. A user can opt-out if they would prefer not to participate in any Nielsen online measurement research. To implement the User Opt-Out option, include the following two items in your privacy policy.
*A notice that the player (or page in relation to static measurement) includes proprietary measurement software that allows users to contribute to market research (such as Nielsen Content Ratings).
*A link to the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/


== Nielsen Opt-Out ==
On the Nielsen Digital Measurement Privacy Policy page, users can click Choices to read more detailed information about the measurement software, learn about their options with regard to Nielsen measurement, and, if they do not want to participate in Nielsen online measurement, click a link to receive an opt-out cookie.
<br />
* Once users have opted out via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=total&tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/  link], their browser cookies will contain the value '''TOTAL_OPTOUT'''. This will prevent a redirect to our data provider from occurring
* Users can opt back in via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=cancel&tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/ link].  When a user selects that link, their opt-out cookie will be deleted and they will be able to be measured moving forward.
<br>
The following paragraph is a template for a Privacy Statement.
<blockquote>
The properties may feature Nielsen proprietary measurement software, which will allow users to contribute to market research, such as Nielsen Digital Content Ratings. To learn more about the information that Nielsen software may collect and your choices with regard to it, please see the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/
</blockquote>


The site must provide a means for the user to opt-out of, or opt back into, Nielsen Measurement. A user can opt-out if they would prefer not to participate in any Nielsen online measurement research. To implement the opt-out option, include the following two items in your privacy policy.
==== User Opt Back In ====
* A notice that the player includes proprietary measurement software that allows users to contribute to market research.
Once users have opted-out, they can choose to opt back into Nielsen Measurement at anytime by selecting the opt back in link on the Nielsen Digital Privacy Policy page. When a user selects the link, their opt-out cookie will be deleted and they will be able to be measured.
* A link to the Nielsen Digital Measurement Privacy Policy at https://priv-policy.imrworldwide.com/priv/browser/th/en/optout.html.
On the Nielsen Digital Measurement Privacy Policy page, users can click "Choices" to read more detailed information about the measurement software, learn about their options with regard to Nielsen measurement, and, if they do not want to participate in Nielsen Online Measurement, click a link to receive an opt-out cookie.


The following paragraph is a template for an opt-out statement.
=== Initialization Opt Out ===
The BSDK600 now supports the ability to optout on initialization of the SDK by allowing an optout global parameter to be passed.  This optout will be maintained through the session of the SDK instance. Specifications and limitations are specified below.


''The properties may feature Nielsen proprietary measurement software, which will allow users to contribute to market research. To learn more about the information that Nielsen software may collect and your choices with regard to it, please see the Nielsen Digital Measurement Privacy Policy at https://priv-policy.imrworldwide.com/priv/browser/th/en/optout.html."
{| class="wikitable"
|-
! Type
! Supported Values
! Notes
! Optout
|-
||optout||True, Yes, or 1|| Case is insensitive and can be string or bool
Example: nlsQ("XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7", "myInstance", { optout: true});
|| Ping parameter will set uoo=true.
|-
||optout|| False, No, or 0 || Case is insensitive and can be string or bool
Example: nlsQ("XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7", "myInstance", { optout: false});
|| Ping parameter will set uoo to blank.
|-
|}
==== Example of using OptOut ====


====Opt Back In====
<syntaxhighlight lang="javascript">
var nSdkInstance = NOLBUNDLE.nlsQ("XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", {
  nol_sdkDebug: "debug",
  optout: "true"
});
</syntaxhighlight>


Once users have opted-out, they can choose to opt back into Nielsen Measurement at anytime by selecting the opt back in link on the Nielsen Digital Privacy Policy page. When a user selects the link, their opt-out cookie will be deleted and they will be able to be measured.
=== Opt Out Overview ===
{| class="wikitable"
|-
! Browser Cookie
! uoo value in session ping
! Final Optout Status
|-
||Default Value || no uoo value or uoo=0|| Not Opted Out
|-
||Default Value ||  uoo=1 || Opted Out
|-
|}


== Going Live ==
== Going Live ==
Following Nielsen testing, users need to make a couple of updates to the initialization call to ensure that the site is being measured properly.
After the integration has been certified, users will need to make a couple of updates to the initialization call to ensure that player will be measured properly. Ensure that a production apid (starting with 'P') is used after going live.
# '''Debug Logging''': Disable logging by deleting <code>{nol_sdkDebug: 'debug'}</code> from initialization call.
Disable debug logging by deleting {nol_sdkDebug: 'DEBUG'} from initialization call.


====Example Production Initialization Call ====
'''Example Production Initialization Call'''
Refer to the production initialization call below:


<syntaxhighlight lang="javascript">var nSdkInstance = NOLBUNDLE.nlsQ("PDA7D5EE6-B1B8-XXXX-XXXX-2A788BCXXXCA", "myPlayerName");
<syntaxhighlight lang="javascript">
var nSdkInstance = NOLBUNDLE.nlsQ("PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", { optout: "false"});
</syntaxhighlight>
</syntaxhighlight>
'''Note''': before going live you have to inform Nielsen - this is necessary, because Nielsen team has to adjust internal configuration parameter to enable data collection. Without that notification no data will be collected and no data will be reported.

Latest revision as of 05:09, 25 November 2021

Engineering Portal / Digital / International_DCR / DCR Thailand Video Browser SDK


Overview

The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc. The Browser SDK (BSDK) is the framework for website developers to integrate Nielsen Measurement into their media players. Nielsen SDKs are also equipped to measure static content and can track key life cycle events.

Prerequisites

Before you start the integration, you will need:

Item Description Source
App ID (apid) Unique ID assigned to the player/site and configured by product. During initial implementation, a 'test' apid will be given. Once the implementation has been certified, a 'production' apid will then be generated and needs to be used before 'going live'. Contact Nielsen

Configure SDK

There are two steps required for configuring the SDK:

  • Add Static Queue Snippet
  • Create SDK Instance

Static Queue Snippet

The static queue snippet allows the SDK APIs to be called while the actual SDK and configuration file are still being downloaded. As the queue can capture all API calls before the download completes, there is no wait time. Once the SDK is available, the API calls will transition from directing to the queue to the SDK seamlessly.

Add the following script tag to the website:

!function(e,n){
  function t(e){
    return"object"==typeof e?JSON.parse(JSON.stringify(e)):e
  }
  e[n]=e[n]||
  {
    nlsQ:function(o,r,c){
      var s=e.document,
      a=s.createElement("script");
      a.async=1,
      a.src=("http:"===e.location.protocol?"http:":"https:")+"//cdn-gl.imrworldwide.com/conf/"+o+".js#name="+r+"&ns="+n;
      var i=s.getElementsByTagName("script")[0];
      return i.parentNode.insertBefore(a,i),
      e[n][r]=e[n][r]||{g:c||{},
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}},
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}}},
      e[n][r]
    }
  }
}(window,"NOLBUNDLE");


Create SDK Instance

To initialize the SDK, create an SDK instance by making the initialization call:

Initialization API Call

NOLBUNDLE.nlsQ("<apid>", "<instanceName>",{nol_sdkDebug: "debug"});


When creating an instance, pass the following values: (nol_sdkDebug and optout are optional)

Parameter Description Values
apid Unique ID assigned to player/site

'TXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Test Apid that starts with 'T'
'PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Production Apid that starts with 'P'

instanceName Name of SDK instance "any string value"
nol_sdkDebug Enables Nielsen console logging if desired.
{nol_sdkDebug: "debug"} 
{nol_sdkDebug: "info"}
{nol_sdkDebug: "warn"}
{nol_sdkDebug: "true"}
optout Optional: OptOut global parameter. 1/0 or true/false

Example SDK Initialization

When the initialization call is made, a unique static configuration file, <apid>.js, will be downloaded based on the apid and will be cached on the user’s browser.

var nSdkInstance = NOLBUNDLE.nlsQ("XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", {
    nol_sdkDebug: "debug",
    optout: "false"
});


Once the configuration is downloaded, the SDK itself will be downloaded and initialized. All SDK modules are included in one file: “nlsSDK600.bundle.min.js”. More information on OptOut Parameter under Privacy and Opt-Out.

Example SDK Configuration

The configuration should include the Static Queue Snippet and an SDK Instance for an unique App ID as shown in the example:

<script type="text/javascript">
// Add Static Queue Snippet
!function(e,n){
  function t(e){
    return"object"==typeof e?JSON.parse(JSON.stringify(e)):e
  }
  e[n]=e[n]||
  {
    nlsQ:function(o,r,c){
      var s=e.document,
      a=s.createElement("script");
      a.async=1,
      a.src=("http:"===e.location.protocol?"http:":"https:")+"//cdn-gl.imrworldwide.com/conf/"+o+".js#name="+r+"&ns="+n;
      var i=s.getElementsByTagName("script")[0];
      return i.parentNode.insertBefore(a,i),
      e[n][r]=e[n][r]||{g:c||{},
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}},
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}
catch(e){console&&console.log&&console.log("Error: Cannot register event in Nielsen SDK queue.")}}},
      e[n][r]
    }
  }
}(window,"NOLBUNDLE");
 
// Created SDK Instance
var nSdkInstance = NOLBUNDLE.nlsQ("XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", {nol_sdkDebug: "debug"});
</script>

Create Metadata Objects

There are two types of asset metadata:

  • content: identify video
  • ad: identify each ad

The metadata received for each asset is used for classification and reporting.

Metadata can be passed through key-values using the Nielsen reserved keys. User will need to set up content and ad objects with the required Nielsen keys as shown in the sample code below.

Content Metadata

Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.

Key Description Values Required
clientid

parent ID – value is automatically populated through provided App ID.
In order to override the brand configured to the App ID, pass parent
value here and the sub-brand ID associated to that brand in the subbrand
key (e.g. multiple brands in App)

Nielsen provided

subbrand sub-brand ID – value is automatically populated through provided

App ID. In order to override the sub-brand configured to the App ID, value can
be passed here (e.g. multiple sub-brands in App)

Nielsen provided

type type of asset "content"
assetid unique ID assigned to asset custom
(no Special Characters). The Content ID should be populated here which should correspond to the same value in the post transmission logs.
program name of program custom
title episode name custom
length length of content in seconds seconds (86400 for live stream)
segB custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform. custom
segC For VOD: Populate TVContent ID, For livestream: leave blank custom Required for VOD only
isfullepisode full episode flag
  • 'y', 'yes', or 'lf' – full episode
  • 'n', 'no', or 'sf' – non full episode

Note: For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'.

adloadtype type of Ad load:
  • 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.
  • 2) Dynamic – Dynamic Ad Insertion (DAI)
  • "1" – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement.
  • "2" – content with dynamic Ads

Example Content Object

var contentMetadataObject =
{  
  type:           'content',
  assetid:        'VID-123456',
  program:        'program name',
  title:          'episode title',
  length:         'length in seconds',
  isfullepisode:  'y',
  adloadtype:     '2',
  segB:           'custom segment B', // optional
  segC:           'custom segment C', // optional
};

Ad Metadata

The Ad Metadata (if applicable) should be passed for each individual ad.

Keys Description Values Required
type type of Ad 'preroll', 'midroll', 'postroll'
'ad' - If specific type can not be identified.
assetid unique ID assigned to Ad custom

Example Ad Object

var adMetadataObject = 
{  
  type:    'preroll',
  assetid: 'AD-1'
};


URL Character Limit: There is a URL character limit of 2K characters due to browser limitations. Exceeding this value could impair data delivery on particular browsers.

Call Nielsen APIs

The method for calling events is ggPM().

nSdkInstance.ggPM('event', parameter, ...);

Interrupt Scenarios

Pause Event

The setPlayheadPostion event is used for handling pause. To indicate pause, stop passing the playhead position to the SDK. Once the content resumes, begin sending the playhead again with the correct playhead value.

Other Interrupt Scenarios

The following possible browser interruption scenarios must be handled:

  • Browser/Tab close
  • Leaving the page to another destination
  • Pressing the stop button
  • Network Loss

There are many cases where the player itself has the ability to detect such situations. If not, these interruption scenarios can be handled through JavaScript. The events that are called will depend on the asset being played (e.g. midroll vs. content).

window.addEventListener('beforeunload', function(event) 
{
  // Only inside a midroll indicate <stop> for the ad
  nSdkInstance.ggPM('stop', playheadPosition);
  
  // Indicate <end> and <stop> for the content
  nSdkInstance.ggPM('end', playheadPosition);
  nSdkInstance.ggPM('stop', playheadPosition);
});

Note: User may need to add code to support specific browser versions (e.g. older versions of Internet Explorer).

SDK Events

Event Parameter Description
'loadMetadata' content/ad metadata object Needs to be called at the beginning of each asset
'setPlayheadPosition' playhead position as integer

VOD: || current position in seconds
Live: current Unix timestamp (seconds since Jan-1-1970 UTC)
Note: 'setPlayheadPosition' has to be called every second

Pass playhead position every second during playback

'stop' playhead position in seconds Call when content or ads complete playing and pass playhead position
'end' playhead position in seconds Call when the current video asset completes playback and pass the playhead position.

Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.

SDK Playhead Event Sequence

The sample event lifecycles can be used as a reference for identifying the order for calling events.

Content Playback

// START OF STREAM
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); 
 
// CONTENT PLAYS
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
//  
//   pass playhead every second
//   
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);

// END OF STREAM
nSdkInstance.ggPM('end', playheadPosition);


Content Playback with Ads

// START OF STREAM
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); 
 
// PREROLL
nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
//  
//   pass playhead every second
//   
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('stop', playheadPosition);
 
// CONTENT
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
//  
//   pass playhead every second
//   
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('stop', playheadPosition);

// MIDROLL
nSdkInstance.ggPM('loadMetadata', midrollMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
//  
//   pass playhead every second
//   
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('stop', playheadPosition);
 
// CONTENT RESUMES
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
//  
//   pass playhead every second
//   
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);

// END OF STREAM
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('end', playheadPosition);
 
// POSTROLL
nSdkInstance.ggPM('loadmetadata', postrollMetadataObject);
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
//  
//   pass playhead every second
//   
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);
nSdkInstance.ggPM('stop', playheadPosition);
  • 'setPlayheadPosition' is used for calculating duration and must be passed every second. The final playhead position must be sent for the current asset being played before calling 'stop', 'end', or 'loadmetadata'.
  • For Ad Pods, events must be called for each individual Ad. Each Ad playhead position should begin at ‘0’ when ad starts.
  • When content has resumed following an ad break, the playhead position update must continue where previous content segment left off. The playhead position should be passed as a rounded number with no decimals.

Privacy and Opt-Out

There are two primary methods for implementing user Opt-out preferences:

  1. User Opt Out - Provide a link to the Nielsen Privacy Policy page when a User can make their selection
  2. Initialization Opt Out - Global OptOut Parameter

User Opt Out

The site must provide a means for the user to opt-out of, or opt back into, Nielsen Measurement. A user can opt-out if they would prefer not to participate in any Nielsen online measurement research. To implement the User Opt-Out option, include the following two items in your privacy policy.

On the Nielsen Digital Measurement Privacy Policy page, users can click Choices to read more detailed information about the measurement software, learn about their options with regard to Nielsen measurement, and, if they do not want to participate in Nielsen online measurement, click a link to receive an opt-out cookie.

  • Once users have opted out via this link, their browser cookies will contain the value TOTAL_OPTOUT. This will prevent a redirect to our data provider from occurring
  • Users can opt back in via this link. When a user selects that link, their opt-out cookie will be deleted and they will be able to be measured moving forward.


The following paragraph is a template for a Privacy Statement.

The properties may feature Nielsen proprietary measurement software, which will allow users to contribute to market research, such as Nielsen Digital Content Ratings. To learn more about the information that Nielsen software may collect and your choices with regard to it, please see the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/

User Opt Back In

Once users have opted-out, they can choose to opt back into Nielsen Measurement at anytime by selecting the opt back in link on the Nielsen Digital Privacy Policy page. When a user selects the link, their opt-out cookie will be deleted and they will be able to be measured.

Initialization Opt Out

The BSDK600 now supports the ability to optout on initialization of the SDK by allowing an optout global parameter to be passed. This optout will be maintained through the session of the SDK instance. Specifications and limitations are specified below.

Type Supported Values Notes Optout
optout True, Yes, or 1 Case is insensitive and can be string or bool

Example: nlsQ("XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7", "myInstance", { optout: true});

Ping parameter will set uoo=true.
optout False, No, or 0 Case is insensitive and can be string or bool

Example: nlsQ("XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7", "myInstance", { optout: false});

Ping parameter will set uoo to blank.

Example of using OptOut

var nSdkInstance = NOLBUNDLE.nlsQ("XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", {
  nol_sdkDebug: "debug",
  optout: "true"
});

Opt Out Overview

Browser Cookie uoo value in session ping Final Optout Status
Default Value no uoo value or uoo=0 Not Opted Out
Default Value uoo=1 Opted Out

Going Live

After the integration has been certified, users will need to make a couple of updates to the initialization call to ensure that player will be measured properly. Ensure that a production apid (starting with 'P') is used after going live. Disable debug logging by deleting {nol_sdkDebug: 'DEBUG'} from initialization call.

Example Production Initialization Call

var nSdkInstance = NOLBUNDLE.nlsQ("PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", "nlsnInstance", { optout: "false"});