DCR Video & Static Mobile Cloud API

From Engineering Client Portal

Engineering Portal / Digital / DCR & DTVR / DCR Video & Static Mobile Cloud API

This guide shows you how to integrate the Nielsen Cloud API to enable Digital Content Ratings (DCR) measurement on your Mobile Apps.

Prerequisites

To get started, you will need a Nielsen App ID. The App ID is a unique ID assigned to your app. This will be provided to you upon starting the integration.

XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Integration

We will cover the steps for constructing the Cloud API Calls.

Request Overview

URL Structure

The Cloud API Calls are HTTP GET Requests with the URL structure:

[endpoint]/[appid]/[sessionID]/a?b=[payload]

The URL includes the following components:

  • [endpoint]: location of data collection environment
  • [appid]: provided App ID
  • [sessionID]: unique value for each user session
  • [payload]: metadata and events

Endpoint

There are endpoints for testing and production:

During testing, all calls should be pointed to the testing endpoint. We will review the update to the production endpoint during the Go Live section of this guide.

URL Example

As you move through the integration steps, you can reference the below URL structure with the expanded payload:

http://sandbox.cloudapi.nielsen.com/nmapi/v2/[appid]/[sessionID]/a?b=
{
  "devInfo": [deviceInfo],
  "metadata": {
    "static": [static_metadata],
    "content": [content_metadata],
    "ad": [ad metadata]
  },
  "event": [event],
  "position": [playhead_position],
  "type": [asset type],
  "utc": [UTC]
}

Create Session ID

A unique Session ID must be created upon app launch and provided in the URL. This will allow measurement to occur for the entire duration that a user is within the app.

The session ID must be a GUID that is passed with every request and remain consistent throughout each individual session. You can use an existing ID, a random number, or date.now() as shown in the recommended sample code below:

sessionID = Date.now()+String(Math.random()*1000000 >> 0);

Upong exiting the app, the session will need to be terminated using the delete event. Sessions will automatically expire after 30 minutes of cloud inactivity.

Define URL Structure

Define the URL structure using your provided [appid] and a unique [sessionID].

http://sandbox.cloudapi.nielsen.com/nmapi/v2/[appid]/[sessionID]/a?b=[payload]

Configure Payload

All Cloud API requests must contain the following payload data:

  • devInfo: device and app info
  • metadata: asset metadata
  • event metadata: type of event

The payload can be passed through key-values using the Nielsen reserved keys. The specific keys and descriptions are highlighted in the tables included in this section.

Payload Example

The example below should be referenced when following the steps for configuring the request payload.

// 3.1 Configure Payload: devInfo 
payload = {
    "devInfo": {
        "devId": "AD-ID", 
        "apn": "AppName",
        "apv": "1.0",
        "uoo": "false"
    },
    
    // 3.2 Configure Payload: metadata
    "metadata": {
        "static": {}, // object for measuring static content
        "content": { // object for measuring video content
            "type": "content", // "content" for video
            "assetid": "VIDEO-ID123", // unique ID for video
            "isfullepisode": "y", // full episode flag
            "program": "Program Name", // program name
            "title": "Episode Title S3 - EP1", // episode name
            "length": "1800", // content duration in seconds
            "segB": "Custom Segment B", // custom segment
            "segC": "Custom Segment C", // custom segment
            "crossId1": "Standard Episode ID", // episode ID
            "crossId2": "Content Originator ID", // content orginator (required for distributors)
            "airdate": "20161013 20:00:00", // airdate
            "adloadtype": "2" //ad load flag
        },
        "ad": {
            "type": "preroll", // type of ad
            "assetid": "AD-ID123" // unique ID for ad
        }
    },
    
    // 3.3 Configure Payload: events
    "event": "playhead", //event name
    "position": "300", // position in seconds
    "type": "content", //"content" or "ad"
    "utc": "1456448742000" //unix timestamp in milliseconds 
}
Configure Payload: devInfo

An objext "devInfo" will need to be created to capture App and Device information.

Keys Description Values Required
devId unique ID to identify user (e.g. Advertising ID, Roku Device ID) custom Yes
apn app name custom Yes
apv app build version custom Yes
uoo device opt-out status "true" or "false" Yes
Example Example Example Yes

On mobile devices you will need to pass the IDFA/Ad ID as part of the devId parameter. Please see the section below regarding Opt Out and the IDFA/Ad ID.

Accessing the IDFA on iOS

Accessing the ID For Advertisers (IDFA) uses OS level API calls. In order to do this, you must first import the following header file:

#import <AdSupport/ASIdentifierManager.h>

Then to receive the IDFA as a NSString, use similar code to the following:

NSString *idfaString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

You can read more about ASIdentifierManager on Apple's developer website.

Accessing the Ad ID on Android

Accessing the Google Ad ID uses OS level API calls. In order to do this, you must first import Google Play Services. Then to receive the Ad ID, use the AdvertisingIdClient class as such:

public static AdvertisingIdClient.Info getAdvertisingIdInfo (Context context)

You can read more about the AdvertisingIdClient class on Google's developer website.

Example devInfo Object
// create devInfo object
"devInfo": {
  "devId": "AD-ID",
  "apn": "AppName",
  "apv": "1.0",
  "uoo": "false"
},

Configure Payload: metadata

Asset metadata can be passed through "metadata". There are two asset types: "content" for video and "ad" for ads. The metadata received for each asset is used for classification and reporting.

You will need to set up "metadata" objects for "content" and "ad" 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.

Keys Description Values Required
type type of asset "content" Yes
assetid unique ID assigned to asset custom Yes
program name of program (25 character limit) custom Yes
title name of program (25 character limit) custom Yes
length length of content in seconds seconds (86400 for live stream) Yes
segB custom segment B custom
segC custom segment C custom
airdate the airdate in the linear TV YYYYMMDD HH24:MI:SS Yes
isfullepisode full episode flag "y"- full episode, "n"- non full episode Yes
crossId1 standard episode ID custom Yes
crossId2 content originator (only required for distributors) Nielsen
adloadtype type of ad load:

"1" Linear – matches TV ad load

"2" Dynamic – Dynamic Ad Insertion (DAI)

"2" - DCR measures content with dynamic ads Yes
hasAds ads indicator

"1": ads included

"0": ads not included

"1" or "0" Yes
progen program genre abbreviation - see DCR OTT Genre List for accepted values "CV" for Comedy Variety Yes


Example Content Object

// create content object
"content": {
    "type": "content",
    "assetid": "VIDEO-ID123",
    "isfullepisode": "y",
    "program": "Program Name",
    "title": "Episode Title S3 - EP1",
    "length": "1800",
    "segB": "Custom Segment B",
    "segC": "Custom Segment C",
    "crossId1": "Standard Episode ID",
    "crossId2": "Content Originator ID",
    "airdate": "20161013 20:00:00",
    "adloadtype": "2",
    "hasAds": "1", 
    "progen": "CV"
}
Ad Metadata

The ad metadata should be passed for each individual ad.

Keys Description Values Required
type type of ad "preroll", "midroll", or "postroll" Yes
assetid unique ID assigned to ad custom Yes
Example Ad Object
// create ad object
"ad": {
  "type": "preroll",
  "assetid": "AD-ID123"
}

Configure Payload: Events

The last part of the payload is for enabling events so content is measured correctly when viewed. The events and required parameters are included below.

Event Types

The available events are:

Event Description
"playhead" Playhead position in seconds. Must be passed as a whole number every 10 seconds. The final playhead position should also be sent before an asset has changed to properly capture full duration. Playhead is used to handle pause and scrubbing. When content is paused, stop passing playhead position.
"complete" Complete event must be sent when the content has completed playback.
"delete" The delete event must be sent when the session is completed, or terminated. After 30 minutes of inactivity, the session will expire. All creditable duration will be summarized for all asset types when delete occurs (content and ads).
Event Parameters

The following parameters need to be passed when calling events:

Parameter Description Value Required
"event" event type "playhead", "complete", or "delete" Yes
"position" creditable position playhead position in seconds or UTC timestamp in seconds for livestream Yes
"type" asset type "content", "ad" Yes
"utc" Unix timestamp in milliseconds. Must be passed every 10 seconds. "1472760000000" Yes
Example Event

You can call events by passing values in the required parameters:

"devInfo": [deviceInfo],
  "metadata": {
    "static": [static metadata],
    "content": [content metadata],
    "ad": [ad metadata]
  },
  // Event Parameters
  "event": [event], // event name
  "position": [playheadPosition], //position in seconds
  "type": [asset type], // values are "content" or "ad"
  "utc": "1472760000000" //unix timestamp in milliseconds
}

Note: The full payload including "devInfo" and "metadata" must be populated in each event request.

Sample Event Lifecycle

The sample event lifecycle can be used as a reference for identifying the order for calling events and values to pass.

// Start of Session: session ID created when App is opened

// Preroll
Ad Playhead {"event": "playhead", "position": "0", "type": "ad", "utc": "1472760000000"} 
 
// Content
Content Playhead {"event": "playhead", "position": "0", "type": "content", "utc": "1472760000000"} 

// Midroll
Midroll Playhead {"event": "playhead", "position": "0", "type": "ad", "utc": "1472760000000"} 

// Content resumes at 15 minutes
Content Playhead {"event": "playhead", "position": "900", "type": "content", "utc": "1472760000000"} 

// Content completes at 30 minutes
Complete {"event": "complete", "position": "1800", "type": "content", "utc": "1472760000000"} 
 
// Postroll
Ad Playhead {"event": "playhead", "position": "0", "type": "ad", "utc": "1472760000000"} 

//End of Session: The delete event should be called when the App is exited. The values for position and type not required to be passed.
Delete { "event": "delete", "position": "", "type": "", "utc": "1472760000000"}


Sample Event Lifecycle - Detailed Storyline This detailed event sequence provides additional insight for the correct events to call when handling certain playback scenarios.

// SESSION STARTS
// Start of Session: session ID created when App is opened

// PREROLL
// Preroll Start - Start each Ad with a position of "0", resetting to '0' for each Ad, and Ad break.
Ad Playhead {"event": "playhead", "position": "0", "type": "ad", "utc": "1472760000000"} 

// Preroll Stop - End each Ad with the final position of the Ad.
Ad Playhead {"event": "playhead", "position": "15", "type": "ad", "utc": "1472761500000"}
 
// CONTENT 
// Content Start - Start new content streams with a position of "0" incrementing the position every 10 seconds.
Content Playhead {"event": "playhead", "position": "0", "type": "content", "utc": "1472761500000"} 

// Content Stop Before Ad Break - Send a playhead update including the current content positon before an Ad break.
Content Playhead {"event": "playhead", "position": "299", "type": "content", "utc": "1472787400000"}

// MIDROLL
// Midroll Start - Start each Ad with a position of "0", resetting to '0' for each Ad, and Ad break.
Midroll Playhead {"event": "playhead", "position": "0", "type": "ad", "utc": "1472787500000"} 

// Midroll Stop - End each Ad with the final position of the Ad.
Ad Playhead {"event": "playhead", "position": "60", "type": "ad", "utc": "1472793500000"}

// CONTENT
// Content resumes at 5 minutes - Send playhead update with the current resumed position, and begin incrimenting the positon every 10 seconds.
Content Playhead {"event": "playhead", "position": "300", "type": "content", "utc": "1472799500000"} 

// Content completes at 10:12 - Make sure to send in the playhead event with the final content position before sending the complete event.
Final Content Playhead {"event": "playhead", "position": "612", "type": "content", "utc": "1472830700000"} 

Complete {"event": "complete", "position": "612", "type": "content", "utc": "1472830800000"} 

// POSTROLL
// Postroll Start - Start each Ad with a position of "0", resetting to '0' for each Ad, and Ad break.
Ad Playhead {"event": "playhead", "position": "0", "type": "ad", "utc": "1472830900000"} 

// Postroll Stop - End each Ad with the final position of the Ad.
Ad Playhead {"event": "playhead", "position": "45", "type": "ad", "utc": "1472835300000"}

// SESSION ENDS

//End of Session: The delete event should be called when the App is exited. The values for position and type not required to be passed.
Delete { "event": "delete", "position": "", "type": "", "utc": "1472835400000"}


Handling Playhead

Calling "playhead" is critical for accurate duration crediting. You can reference the below guidance to determine the correct playhead position to pass depending on the playback scenario.

Playhead: General

  • Playhead position must start at 0 for each new asset, and be passed at least every 10 seconds.
  • Final postion must be sent at the end of content or an ad

Playhead: Ads

  • The final position must be sent when switching from content to ad, or ad to content.
  • Each ad playhead position should be 0 at ad start.
  • For Ad Pods, playhead must be called, and reset to 0 for each individual ad.
  • The last content position before an Ad should be sent before switching to Ads.
  • When content has resumed following an ad break, the playhead position update must continue where the previous content segment left off.

Playhead: User Actions

  • Upon user scrubbing, the current position must be sent before a user scrubs, and the new position should be sent where the user lands, and begin sending in the 10 second updates thereafter.
  • On pause, send the current position and then discontinue sending playhead event updates.
  • If a user exits a stream early, the last current position must be sent in a playhead update to receive accurate duration.
Interruption Scenarios

As part of configuring events, you will need to handle all possible interruption scenarios such as:

  • Pause / Play
  • Network Loss (Wi-Fi / Airplane Mode / Cellular)
  • Wi-Fi OFF / ON
  • Call Interrupt (SIM or Third party Skype / Hangout call)
  • Alarm Interrupt
  • Content Buffering
  • Device Lock / Unlock (Video players only, not for Audio players)
  • App going Background / Foreground (Video players only, not for Audio players)
  • App Crash or Exit
  • Channel / Station Change Scenario
  • Unplugging of headphone

When playback is temporarily interrupted (e.g. pause, content buffering), the app needs to send the last known playhead position.

  • If an app is sent to background for more than 5 minutes, please create a new session ID. Otherwise, use the same session ID as before.
  • If loss of Internet occurs, please queue the API calls that would have been made. Once Internet connectivity is regained, please spool off the API calls in order of first generated (Note: if doing so, please use the UTC time in milliseconds)

When playback is permanently interrupted, the app needs to send delete immediately.

  • If an app crashes, please create a new session ID. No delete call will be necessary as the previous session will timeout.

Once playback resumes after delete occurs, a new session will need to be created with a unique session ID. All of the required metadata and events will need to be sent.

Note: The session will automatically timeout after 30 minutes of inactivity.

Example Request

Now that we walked through the Cloud API integration steps, your requests should have the following components: Session ID, App ID, and Payload. You can reference the example below when your reviewing your integration.

// 1. Create Session ID
sessionID = Date.now()+String(Math.random()*1000000 >> 0);  // Must be GUID for each viewing session

// 2. Define URL Structure with App ID and Session ID
sessionURL = http://sandbox.cloudapi.nielsen.com/nmapi/v2/[appid]/[sessionID]/a?b=

// 3. Configure Payload
// 3.1 Configure Payload: devInfo 
payload = {
 "devInfo": {
   "devId": "AD-ID", 
   "apn": "AppName",
   "apv": "1.0",
   "uoo": "false"
  },
  
  // 3.2 Configure Payload: metadata
  "metadata": {
    "static": {}, // object for measuring static content
    "content": { // object for measuring video content
      "type": "content", // "content" for video
      "assetid": "VIDEO-ID123", // unique ID for video
      "isfullepisode": "y", // full episode flag
      "program": "Program Name", // program name
      "title": "Episode Title S3 - EP1", // episode name
      "length": "1800", // content duration in seconds
      "segB": "Custom Segment B", // custom segment
      "segC": "Custom Segment C", // custom segment
      "crossId1": "Standard Episode ID", // episode ID
      "crossId2": "Content Originator ID", // content orginator (required for distributors)
      "airdate": "20161013 20:00:00", // airdate
      "adloadtype": "2", // ad load flag
      "hasAds": "1", // content contains ads = 1 / no ads = 0
      "progen": "CV" // program genre abbreviation
    },
    "ad": {
      "type": "preroll", // type of ad
      "assetid": "AD-ID123" // unique ID for ad
    }
  },
    
  // 3.3 Configure Payload: events
  "event": "playhead", //event name
  "position": "300", // position in seconds
  "type": "content", //"content" or "ad"
  "utc": "1456448742000" //unix timestamp in milliseconds 
}

// Append payload to URL
var image = new Image()
image.onerror = function() {
  // wait and send again
}
(new Image).src = sessionURL+encodeURI(JSON.stringify(payload));

Enable Debug Logging

Now that you have set up the Cloud API requests, you can enable debug logging to validate your integration.

GET Request

Display GET Request to console using a name to identify each event (e.g. playhead).

console.log("Event", image);

Payload

Output payload to identify required metadata and events.

console.log("Event Payload", payload);

HTTP Response Code

Confirm request was completed by viewing HTTP response code.

code = msg.GetResponseCode();
console.log("Response Code", code);

You can reference the HTTP Response Code table when reviewing your requests:

Status Code Status Text Description
200 OK request received
403 Forbidden invalid App ID
404 Not Found JSON issue

Opt-Out

Your app must utilize the "Limit Ad Tracking" or "Opt Out of Ad Personalization" feature present on iOS and Android devices, respectively. When a user opts out, the "devId" field should be empty.

You will need to update the User Opt-Out (uoo) status upon each app launch, so that it can be retrieved and populated in the "devInfo" metadata which will be sent in every Cloud API event (playhead, complete, & delete). If a user changes their opt-out status while a session is still active, you will need to start a new session with the new opt-out choice.

You can access whether a user has opted out using [1] on iOS, and [2] on Android devices.

Note: For iOS versions 10 and above, the IDFA will be "zero-ed out" (00000000-0000-0000-0000-000000000000) when a user has enabled Limit Ad Tracking. However, for iOS versions 9 and below this feature does not exist. In these cases do not send the IDFA as per the requirements above

uoo Key Description Values
uoo Device is Opted-In to Nielsen Measurement (Recommended Default Setting) "false"
uoo Device is Opted-Out of Nielsen Measurement "true"
devInfo Opt-In JSON Payload Example
"devInfo": {
    "apn": "Roku Sample App",
    "appver": "1",
    "devId": "7be25cf9-8c40-5cc2-871e-19bf41940288",
    "uoo": "false"
  },
devInfo Opt-Out JSON Payload Example
  "devInfo": {
    "apn": "Mobile Sample App",
    "appver": "1",
    "devId": "",
    "uoo": "true"
  },
Privacy Information Template To Include In Opt-Out Screen

ABOUT NIELSEN MEASUREMENT

Television and the way we watch it have come a long way since Nielsen began measuring TV audiences in 1950. Today, the ability to watch our favorite shows at any time and on multiple devices amplifies the need for exceptionally adept and flexible audience measurement capabilities.

Consumers are changing with the times, and the same goes for us. As technology continues to evolve and media companies try new ways to attract viewers, understanding what consumers are watching — and what they're watching on — is more important than ever. Today, viewing video is a personal and mobile experience — anytime and anywhere. Our capabilities provide relevant metrics that are necessary to inform successful marketing and programming and drive continued growth. As a global information and measurement leader, we are committed to protecting the privacy and security of the data we collect, process and use. While our digital measurement products are not used to identify you in any way, they help us and our clients measure and analyze how consumers engage with media across online, mobile and emerging technologies, and offer insights into consumer behavior.

YOUR CHOICES

Nielsen believes that you should have a choice about whether to contribute to our research and insights. To opt out of Nielsen measurement on this device, you need only to activate the "Limit Ad Tracking" (for iOS devices) or "Opt out of Ads Personalization" (for Android devices) option in your device’s settings. If you have this app on more than one mobile device, you will need to change the settings on each device.

If, after you have opted out, you change your mind and would like to opt back in, please deactivate the "Limit Ad Tracking" (for iOS devices) or "Opt out of Ads Personalization" (for Android devices) option in your device’s settings.

To learn more about our digital measurement products and your choices in regard to them, please visit http://www.nielsen.com/digitalprivacy.

Disclosure Template

Additionally, you must update the App description information from the App Distribution Store with the Nielsen Measurement disclosure below:

This app features Nielsen's proprietary measurement software which will allow you to contribute to market research, like Nielsen's TV Ratings. Please see http://www.nielsen.com/digitalprivacy for more information.

Testing

Before providing an app build to Nielsen for testing, it is important to run validation checks once you have enabled debug logging.

Payload Validation

Ensure that all of the required payload data is populating while testing several videos. The following areas are critical to measurement:

  • devInfo
  • Asset metadata for both content, and ads
  • Events

Player Events

Review event calls:

playhead

  • Playhead position updates every 10 seconds
  • Final playhead position is sent on content, or ad complete
  • Content metadata remains constant throughout an episode, or clip play
  • Ad metadata is populated appropriately for each individual ad
  • Playhead position update resumes after an ad break, and resets to 0 for each individual ad

complete

  • Check that the complete event executes upon content complete
  • Do not execute the complete event for ads

delete

  • Check to see that the delete event occurs upon app exit

GET Request Format

  • Ensure that the event payloads are formatted in JSON
  • Check to see that each of the Cloud API GET requests are properly encoded.

HTTP Response

  • Make sure that each of the Cloud API Get requests are received by the Nielsen Cloud API properly through use of the HTTP Response Code outputs enabled in console.

Opt-Out

  • Test the "uoo" key gets populated accurately for both Opt-In and Opt-Out selections by validating the Cloud API events called after the user Opt-Out/Opt-In selection.

Go Live

After your integration has been certified, you will need to: Change Endpoint and Disable Logging.

Change Endpoint: You will need to update to the production endpoint:

Your production URL structure should now be: https://cloudapi.nielsen.com/nmapi/v2/[appid]/[sessionID]/a?b=[payload]

Disable Logging: You can now disable debug logging.