Skip to main content

Collector API

Introduction

Watching That infrastructure

The Collector receives data sent from web plugins, native sdks or custom integrations and forwards it to our backend processing systems.

The following sections describe how you can create a custom integration script to communicate with the Watching That Collector.

Authentication

Requests to the Collector endpoint must all be sent with an authorization header that looks like:

X-Api-Key: <apiKey>

You can find your api key in your Watching That account.

Failing to set this header or setting it to an invalid value will make the API respond with a 401 Unauthorized http code and the payload of the message will be discarded.

Endpoints

Depending on where you're sending the data from (a server environment for SSAI for example or browser/native), you may use one of the following endpoints:

  • POST https://collector.watchingthat.com/v5/in
  • POST https://c.p2r14.com/v5/in
note

We will change the latter endpoint domain periodically to prevent it being blocked by ad blockers. For server environments we suggest you use the former one as it will always run from the same domain.

These endpoints are expecting data in JSON format as an array of objects. Each object should represent an event that happens during the lifecycle of a video (including its ads). The list of fields from each object can be found in the Event Fields section below. The data must be sent with a application/json content type: Content-Type: application/json.

The general JSON payload of a POST call:

[
{ <event 1 field1>: <value>, <event 1 field2>: <value>, ... },
{ <event 2 field1>: <value>, <event 2 field2>: <value>, ... }
...
]

Examples

curl -X POST \
'https://collector.watchingthat.com/v5/in' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: 12345' \
-d '[ { "type": "init", "rid": "123-abc", "cst": 0 }, { "type": "play", "rid": "123-abc", "cst": 1000 } ]'

Concepts

Before showing you the list of fields you can send to our endpoints, we should explain a few concepts that make our platform tick:

Content Sessions

To be able to group related events together and have a clear picture of what happens during the lifecycle of a video, we have the concept of "content sessions". A content session represents the interval from when the video player initialises the video, goes through playing the video (including any potential preroll/midroll ads), until the video ends (including any postroll ad).

events in a content session

In case your video player is set up to go through a playlist, once a session has ended, another one should be started for the next video.

A session is identified by the rid field: all the events that belong to the same session should have the same rid. It is your responsibility to create a unique rid at the beginning of each session and send it to our endpoint along with the rest of the data.

Note that rid is a required field.

[
{ "rid": "abc123", "type": "init" },
{ "rid": "abc123", "type": "play" },
{ "rid": "foobar-qqq", "type": "imp" }
]

In the example above the first 2 events belong to a session while the third one belongs to another session.

The actual content of the rid field is not important, as long as it is reasonably unique in time. In our plugins we create rid from the current ms timestamp plus a random short string but you can use any uuid-like string.

note

if you are sending data from both server side (SSAI for example) and client side (browser/phone/tv), make sure you're using the same rid in both contexts so we can group all the events of a session together.

Content Session Time

Once a content session has started, events will start occurring at various times during the life of that session. It is important to know the order the events occurred in as well as the time they occurred at as this can give us a lot of hints about things that might go wrong (or well) with a session. The actual timestamp of the event is unimportant and unreliable because of potentially misconfigured clocks on user devices. That's why we use "milliseconds since session start".

The content session time is identified by the cst field.

Note that cst is a required field

You will have to initialise a variable to the current timestamp for the init event and then, for each event, you should send the diff between the now-current time and the time of the init in the cst field:

// during init
const startTime = Date.now();

// for each event, including init:
const eventPayload = { cst: Date.now() - startTime }; // plus any other fields for the event

Ad Sessions

note

Ad sessions are called "Ad slots" in app

Just like we group all events of a content session together by using the rid field, we also group all events of an ad together by using the adGid field. We call this group the "ad session", and it should contain all ad lifecycle events: the ad request for that particular ad, ad load, ad start, impression, quartiles, ad complete and the potential errors.

list of ad session events

Obviously, some of these events might not be present - in case of an error there might not be an impression, for example.

It is your responsibility to create a unique adGid for each new ad and send it to our endpoint along with the rest of the data. The actual content of the adGid field is not important, as long as it is reasonably unique in time.

One suggestion for creating the adGid field is to use rid concatenated with the ad count but any guid string will do.

note

If the same ad plays twice in the same content session or even in different content sessions, the adGid field must be different between the two plays. Don't mistake this for, say, the creative id which can repeat between two ad plays.

[
{ rid: 'abc123', type: 'init' }, // these events are not related to the ad session
{ rid: 'abc123', type: 'play' }, // so they don't have an adGid

{ rid: 'abc123', adGid: 'abc123-0', type: 'serve' }, // these two events belong to the same
{ rid: 'abc123', adGid: 'abc123-0', type: 'imp' }, // ad so they have the same adGid

{ rid: 'abc123', adGid: 'abc123-1', type: 'serve' }, // these three events belong to the same
{ rid: 'abc123', adGid: 'abc123-1', type: 'sa' }, // ad so they have the same adGid
{ rid: 'abc123', adGid: 'abc123-1', type: 'imp' }, // but different from the previous one
];

Type

The type field identifies what sort of event is being sent. See the Event Types table below for a list of the types we support. If the event is an init, send type: 'init', if the event is an impression, send type: 'imp', etc.

Note that type is a required field.

Event fields

This is the complete list of fields an event might have in alphabetical order. In the list below we marked with an asterisk (*) the fields that you should try and send with every event (if you have access to those fields).

FieldTypeRequiredPossible ValuesDescription
aBlint-1, 0, 1Whether an Ad Blocker was detected or not. Use -1 for undetermined.
adANstringAd: Advertiser Name.
adBreakintyes, for ad events-1, 0, 1, ...Ad: The index of the break: 0 for PREROLL, 1/2/3/... for MIDROLL and -1 for POSTROLL
adBreakPosintyes, for ad eventsAd: The position of the ad in the break, starting from 0
adCIdstringAd: Creative Id.
adDIDstringAd: The first deal ID present in the wrapper chain for the current ad, starting from the top. Omit field if unavailable.
adGidstringyes, for ad eventsAd: A unique identifier generated by you that is used to link all events of an ad during a session (ad request, ad load, ad start, impression, errors, quartiles, etc). A different ad during the same session should get a different adGid.
adIdstringAd: Ad ID.
adMgVstringAd Manager SDK Version. This is the version of IMA / Freewheel Ad Manager SDK.
adMUstringAd: Media Url - the url of the video file for the ad.
adSysstringAd: Ad System.
adTypestringPREROLL, MIDROLL, POSTROLLAd: The type of the ad break.
adURLstringAd: Tag Url after macro replacements.
adWCIdstring[]Ad: Selected creative IDs used for wrapper ads. The array must start with the inline ad (innermost) and continue to the outermost wrapper ad. Omit the field or send an empty array if there are no wrapper ads.
adWIdstring[]Ad: IDs used for wrapper ads. The array must start with the inline ad (innermost) and continue to the outermost wrapper ad. Omit the field or send an empty array if there are no wrapper ads.
adWSysstring[]Ad: Names of the ad systems used for wrapper ads. The array must start with the inline ad (innermost) and continue to the outermost wrapper ad. Omit the field or send an empty array if there are no wrapper ads.
autoplaybooleanIs this player autoplaying?
browserstring*The name of the browser the user is using. If you are sending the event from the browser, from the page where the event happened, you may skip this as we'll infer it from the server logs.
countrystring*UK, US, DE, ...2 letter country code for the country of the user watching the ad/video. If you are sending the event from the browser, from the page where the event happened, you may skip this as we'll infer it from the server logs.
cstintyesRelative time of the event from init (init should have cst=0).
customobject*An object with custom data you might want to send to Watching That for analysis. See the custom data docs for more details.
debugstringExtra data you might want to send with the event that should help you find clusters of data in our app.
devicestringThe name of the device the user is using. If you are sending the event from the browser, from the page where the event happened, you may skip this as we'll infer it from the server logs.
deviceTypestring*desktop, phone, tablet, tvThe type of device the user is using.
errstringyes if type is errorOuter error code. For example 900.
err2stringInner Error Code. Sometimes err is too generic and might represent a group of errors. In this case err2 can be used for more context. We use it for the error code coming from ima3.
fifint0, 1Friendly Iframe - whether the iframe of the player allows communication with the rest of the page.
hintPlayer height.
idxint*If the video is part of a playlist, this is the index of the video in that playlist. Starts at 1.
ipstringThe IP address of the user watching the ad/video. This is only used to resolve the country of the user and then removed from our servers. If you're sending the country already, you don't need to send this. If you are sending the event from the browser, from the page where the event happened, you may skip this as we'll infer it from the server logs.
isLiveint*0, 1Whether the media is a live stream (1) or vod (0).
mediaIdstring*The unique code/name you are using for the video of the current session. Useful to group data by video.
originalAdURLstringAd Tag Url before macro replacements.
osstring*The name of the operating system the user is using. If you are sending the event from the browser, from the page where the event happened, you may skip this as we'll infer it from the server logs.
pageTagsstringA list of comma delimited tags relevant for this video.
perint*How much of the ad area is visible at the time of event. Since the user might scroll the page where the video is embedded, an ad might not be 100% visible when playing (or not at all).
playerIdstring*The unique code/name you are using for this player. Useful to group data by player.
plGidstringPlaylist ID - a unique identifier generated by you that is used to link all content sessions in a playlist. Should be created once when the player initialises on a page and never be changed during the lifetime of that player.
plVstring*The version of the video player. This may be different from the v field, depending on your setup.
pustringPage Url - the page where this event happened.
pVisibleint*0, 1Page Visible - indicates whether the page is visible or not. Some errors might occur when the browser is minimised or the tab is not the active one.
ridstringyesRequest ID - unique video session ID that starts from the first event in a video (init) and lasts until the last POSTROLL finishes.
srcstringA short code to identify the app or plugin sending events. We are currently using bcp for "Brightcove plugin" / jwp for "JW plugin" / etc.
ststringThe event subtype. Sometimes the type might be too general. Use a subtype to better segment this event.
streamIdstring*The ID for the video stream supplied by the IMA DAI SDK.
typestringyesinit, play, ...The event type. See below for the meaning of each of these values.
vstringThe version of the app/plugin defined by the src field. Also see the plV field for the version of the video player.
wintPlayer width.
whintWindow/Screen Height.
wwintWindow/Screen Width.

Event Types

During a content session, one or more of the following event types might be sent. Note that some events, like the errors, for example, might appear multiple times in a session.

ValueDescription
initThis marks the start of a session. Use this event to send various data that doesn't need to be repeated for every event. pu, src, v, idx and others are values that don't change during a session and can be safely sent just once here
playVideo Play event. Sent either when the player starts autoplaying or when the user clicks on the play button.
serveSend this when an ad is requested. You should know the ad tag url by now so that should be sent here.
adBreakAn ad break has started
adClickAd Click event
alAd Loaded event
saAd Started event
impImpression event
efqAd First Quartile event
esqAd Second Quartile (midpoint) event
etqAd Third Quartile event
ecpAd Complete event
skipSkip ad event
vreadyVideo Ready, loaded in the player and ready to be interacted with. In a Brightcove player, this is the video_impression event.
vviewVideo View event, recorded when a video is considered to be viewed. It might be the same as c0 but it doesn't have to be. In a Brightcove player, this is the video_view event.
errorError event
c0Content started playing event
c25Content First Quartile event
c50Content Second Quartile (midpoint) event
c75Content Third Quartile event
c95Content reached 95% playthrough
muteUser muted the audio (or changed the volume down to 0)
unmuteUser unmuted the audio (or changed the volume up from 0)

Apart from these types you can also send other event types you might want us to track. See the docs on custom events for more details.