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.
Requests to the Collector endpoint must all be sent with an authorization header that looks like:
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.
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:
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 JSON payload fields section below.
The data must be sent with a
application/json content type:
The general JSON payload of a POST call:
Before showing you the list of fields you can send to our endpoints, we should explain a few concepts that make our platform tick:
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).
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
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.
ridis a required field.
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.
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.
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
cstis 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
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
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.
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.
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.
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
type: 'init', if the event is an impression, send
type: 'imp', etc.
typeis a required field.
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).
|aBl||int||-1, 0, 1||Whether an Ad Blocker was detected or not. Use -1 for undetermined.|
|adAN||string||Ad: Advertiser Name.|
|adBreak||int||yes, for ad events||-1, 0, 1, ...||Ad: The index of the break: 0 for PREROLL, 1/2/3/... for MIDROLL and -1 for POSTROLL|
|adBreakPos||int||yes, for ad events||Ad: The position of the ad in the break, starting from 0|
|adCId||string||Ad: Creative Id.|
|adDID||string||Ad: The first deal ID present in the wrapper chain for the current ad, starting from the top. Omit field if unavailable.|
|adGid||string||yes, for ad events||Ad: 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 |
|adId||string||Ad: Ad ID.|
|adMgV||string||Ad Manager SDK Version. This is the version of IMA / Freewheel Ad Manager SDK.|
|adMU||string||Ad: Media Url - the url of the video file for the ad.|
|adSys||string||Ad: Ad System.|
|adType||string||PREROLL, MIDROLL, POSTROLL||Ad: The type of the ad break.|
|adURL||string||Ad: Tag Url after macro replacements.|
|adWCId||string||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.|
|adWId||string||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.|
|adWSys||string||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.|
|autoplay||boolean||Is this player autoplaying?|
|browser||string||*||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.|
|country||string||*||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.|
|cst||int||yes||Relative time of the event from init (init should have cst=0).|
|custom||object||*||An object with custom data you might want to send to Watching That for analysis. See the custom data docs for more details.|
|debug||string||Extra data you might want to send with the event that should help you find clusters of data in our app.|
|device||string||The 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.|
|deviceType||string||*||desktop, phone, tablet, tv||The type of device the user is using.|
|err||string||yes if ||Outer error code. For example |
|err2||string||Inner Error Code. Sometimes |
|fif||int||0, 1||Friendly Iframe - whether the iframe of the player allows communication with the rest of the page.|
|idx||int||*||If the video is part of a playlist, this is the index of the video in that playlist. Starts at 1.|
|ip||string||The 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.|
|isLive||int||*||0, 1||Whether the media is a live stream (1) or vod (0).|
|mediaId||string||*||The unique code/name you are using for the video of the current session. Useful to group data by video.|
|originalAdURL||string||Ad Tag Url before macro replacements.|
|os||string||*||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.|
|pageTags||string||A list of comma delimited tags relevant for this video.|
|per||int||*||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).|
|playerId||string||*||The unique code/name you are using for this player. Useful to group data by player.|
|plGid||string||Playlist 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.|
|plV||string||*||The version of the video player. This may be different from the |
|pu||string||Page Url - the page where this event happened.|
|pVisible||int||*||0, 1||Page 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.|
|rid||string||yes||Request ID - unique video session ID that starts from the first event in a video (init) and lasts until the last POSTROLL finishes.|
|src||string||A short code to identify the app or plugin sending events. We are currently using |
|st||string||The event subtype. Sometimes the type might be too general. Use a subtype to better segment this event.|
|streamId||string||*||The ID for the video stream supplied by the IMA DAI SDK.|
|type||string||yes||init, play, ...||The event type. See below for the meaning of each of these values.|
|v||string||The version of the app/plugin defined by the |
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.
|init||This marks the start of a session. Use this event to send various data that doesn't need to be repeated for every event. |
|play||Video Play event. Sent either when the player starts autoplaying or when the user clicks on the play button.|
|serve||Send this when an ad is requested. You should know the ad tag url by now so that should be sent here.|
|adBreak||An ad break has started|
|adClick||Ad Click event|
|al||Ad Loaded event|
|sa||Ad Started event|
|efq||Ad First Quartile event|
|esq||Ad Second Quartile (midpoint) event|
|etq||Ad Third Quartile event|
|ecp||Ad Complete event|
|skip||Skip ad event|
|vready||Video Ready, loaded in the player and ready to be interacted with. In a Brightcove player, this is the |
|vview||Video View event, recorded when a video is considered to be viewed. It might be the same as |
|c0||Content started playing event|
|c25||Content First Quartile event|
|c50||Content Second Quartile (midpoint) event|
|c75||Content Third Quartile event|
|c95||Content reached 95% playthrough|
|mute||User muted the audio (or changed the volume down to 0)|
|unmute||User 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.