ctv-Somtag Integration Guide
Resources and Actors
The somtag
library implements the interface for TV clients due to ad operation purpose.
It is not a rendering engine. Its purpose is exposing an api that is meant to:
- Create an ad url based on a set of input parameters in order to target different ad server implementations.
- Interpret a mapping file to map input parameters from the application to output parameter for the ad url.
- Interpret a mapping file to declare the maximum available ad slots and positions for the application.
- Submit ad requests and evaluate their ad responses.
- The signature of ad responses is varying. For convenience, it unifies the responses to a more general format.
- Shares methods to operate on a single ad data object, like submitting tracking requests.
- It does not call an ad server directly.
A request is always proxied by another server instance (somquery).
somtag
has a strong contract to the AdProxy.
The mapping files
reflect the structure of a page, application or any kind of content.
They are responsible to map those taxonomies to any ad server parameters.
A mapping file
is explicitly designed for a use case and
the responsibility for creating and maintenance lays with the ad management team.
In the common approach you add one particular mapping to your application. Nevertheless, if your environment is more complex, it is possible to embed multiple mappings to distribute the use cases over multiple files (and even to change them dynamically).
somquery
is not a resource to load, but an important actor in the system.
It is the "man in the middle" between somtag and an ad server to target, due to:
- Legal requirements in respect to end user privacy
- Device limitations, to improve performance and prevent quirks
Paths
somtag
//ad.71i.de/ctv/somtag/{VERSION}/index.js
mapping file(s)
//ad.71i.de/ctv/mapping/{VERSION}/my-use-case.js
somquery
- Dev Environment //dev-adproxy.eu-central-1.elasticbeanstalk.com
- Stage Environment //stage-adproxy.eu-central-1.elasticbeanstalk.com
- Prod Environment //adproxy.eu-central-1.elasticbeanstalk.com (alias ctv.71i.de)
Version Control
For resources we follow the best practices of semantic version
in the form vMAJOR.MINOR.PATCH-QUALIFIER
.
You can target somtag
or mapping files
on any level of the version string.
- Defining the major version only, eg v1, allows incremental feature development and bug-fixing without any update on publisher side. Only breaking changes are prohibited.
- Defining the major and minor version, eg v1.2, allows bug-fixing only without any update on publisher side.
- Defining the major, minor and patch version, eg v1.2.1, requires updates on publisher side consequently on a bug-fixing level.
- The qualifier - mostly alpha, beta, rc - is also a very strict definition like the patch version, but follows a different deployment logic. Where deployments without a qualifier will create a new folder for x.x.x and update the files of x.x and x, deployments with a qualifier just creating a new folder.
API
Somtag
The somtag
api is exposed on the top level window object.
config
(taxonomy: Taxonomy = {}, options: Options = {}): Somtag
Is meant to be called exactly one time after somtag
is loaded.
It allows for the most static parameters or default values
that are not going to change (often) over multiple content views to be defined.
somtag.config(
{ brand: 'pro7' },
{ proxyUrl: 'http://ctv.71i.de' }
);
See Taxonomy and Options for more details.
info
: String
Used to request build information, where version represents the actual version, build is debug or prod and date shares the creation time.
console.log(somtag.info);
// `${version}-${build} | ${date}`
init
(taxonomy: Taxonomy = {}, options: Options = {}): Promise(LifecycleContext)
Can be called multiple times. When the content in an application changes in a way, that new ads (same slot) can be received, the taxonomy has changed and a new lifecycle should be initiated.
It allows to define the most dynamic parameters or to override default values that are going to change over multiple content views.
somtag.init(
{ clipId: '12345' },
{ mappingFileId: 'videocenter' }
);
See Taxonomy and Options for more details.
LifecycleContext
This is the last chance to setup somtag
more precisely before starting the ad machine.
One of the reasons can be ad midroll scheduling.
At the moment, this is just a defensive look into the future, to have a hook for the publisher in place before lifecycle runtime.
Before calling start, no request will be made, no logic will be processed ... it is all about configuration so far.
start
(): Promise(LifecycleRuntime)
Start a lifecycle / content view.
(If allowed), somtag
is going to request 3rd party vendors, in terms of targeting etc.
After completion, the lifecycle is fully configured and ready to target ads.
LifecycleRuntime
The api to use during a lifecycle / content view to enhance ad experience.
dispose
(): void
Kill a lifecycle instance, to prevent memory leaks.
process
(ad: Ad): AdProcessor
Creates a controller to operate on an Ad interface.
query
(slot: String, index: Int = 1 | callback: Function = undefined, callback: Function = undefined): Promise([...Ad])
Request a list of ads.
The slot defines a phase in your content view, where you want to receive specific ad products. There is no technical limitation about ad slot names, but a convention exist.
Common slot names:
- preroll
- midroll
- postroll
Behind an ad slot, a list of ad positions are defined. They are defined by a related mapping file. The golden rule: A publisher performs requests on a slot level and ad management enriches these slots with positions based on the given taxonomy.
The index
is only required for repeating slots, like the midroll slot.
The callback
argument can be used to increase the user experience.
When calling somtag.query, all ad positions have to be resolved before the Promise can resolve.
Sometimes this may take too long.
In order to avoid too much latency, you can use the callback function to receive a notification when the next position is resolved. This will allow you to start playback in parallel to the ongoing request phase.
lifecycle
.query('midroll', 2, ads => {
if (ads.length === 1) {
// start playing first ad
}
})
.then(ads => {
ads.shift();
// wait for first ad to complete
// and start playing all other ads
})
Keep in mind, somtag
technically does not prevent you from requesting the same slot
twice or multiple slots with the same index. However, this is not best practice.
For example, when you request a preroll you must process every ad that is returned whether it is
playable or not (in terms of tracking).
AdProcessor
A controller to operate on the Ad interface.
track
(event: String): void
Submits all tracking requests for the given event type.
The types of events are aligned with the IAB VAST SPECS
lifecycle
.query('preroll')
.then(ads => {
const ad = lifecycle.process(ads.shift());
ad.track('impression');
})
Interfaces
Options
Options are affecting somtag
only.
They are in charge over the behaviour of somtag
.
An option is a simple key-value pair and is applied on a static somtag.config and dynamic somtag.init configuration levels.
logLevel
: String = 'silent'
Controls the log output of a somtag
instance.
Possible values are:
- trace
- info
- warn
- error
- fatal
The log level can also become defined as query parameter of location.href.
If both are defined, options from the somtag
api takes precedence.
mappingFileId
: String = undefined
Only required when multiple mapping files are loaded. With this option, you can control which mapping to use in a lifecycle. Commonly used in somtag.init.
The id is defined within the loaded mapping file as the id parameter.
proxyUrl
: String
Defines the baseUrl to an AdProxy that implements the interface of somquery. Commonly defined in somtag.config.
For 1st Party Cookie support, you may require a CNAME entry!
Taxonomy
Can be defined on static somtag.config and dynamic somtag.init configuration level.
Taxonomies affects mapping only. They are driven as input values for a mapping file to produce an ad url.
Each individual use case of a mapping file can to be launched from here. Checkout the mapping file docs
mapping file docs
showroom
:String = undefined
Activate a demo campaign (level2) for testing purpose.
The showroom can also be defined as query parameter of location.href.
If both are defined, options from the somtag
api takes precedence.
subsite
:String = undefined
Activate a demo campaign (level1) for testing purpose.
The subsite can also be defined as query parameter of location.href.
If both are defined, options from the somtag
api takes precedence.
Ad
Describes the interface of an ad as an output of somtag.query. It uniforms the spectrum of possible ad responses.
Whenever a new standard is established, or a new ad product is introduced, it directly affects the integration on the publisher host application. To prevent the impact, all possible shapes are transformed to a single format.
That does not mean, that it wouldn't be possible to interact with the original interface.
somquery shares a graphql interface with a zoo of accessors.
We can simply add a new getter or
enable a different kind of return value by endpoint along with a new somtag
method.
So far, an Ad looks like:
debug
: Array
Can be enabled with option logLevel. It delivers additional details about the server-side processing in somquery.
It is an array, because each ad position can follow redirects to 3rd party ad servers. It is resolved on the server, to prevent unnecessary client-server ping-pong. The number of requests and latency become reduced.
body
: String
The original ad server response.
latency
: Int
The response time of an ad server in msec.
reqHeaders
: Array<[key, value]>
The headers that were send to an ad server.
resHeaders
: Array<[key, value]>
The headers that were received from an ad server.
url
: String
The final url request that is send to the ad server.
event
: Array
A list of events to track on different circumstances. Events follows the IAB VAST Standard
The processor lifecycle.process(ad).track(...) operates on this data.
TODO, for some event types a publisher can provide additional information to replace url macros, eg error codes, view time spend etc.
offset
: String
An IAB standard evolution, where ad progress can be tracked in a better way, besides ordinary quartile tracking.
type
: String
Describes the condition, when to submit a tracking request.
url
: String
Url to track.
fallback
: Boolean
Declares the delivered ad as not able to render. With fallback=false this would lead to error tracking and with fallback=true this would lead to impression tracking.
format
: String
The original format of the ad.
At the moment this is version/evolution of the type property, like 2.0, 3.0 etc. For sure, this is going to change, in order to offer the publisher a chance to know about the capabilities of an ad.
id
: String
The campaign identifier in the adserver or a list of identifiers separated by a delimiter, when multiple ad servers were involved.
media
: Array
A list of resources to load and render. Media items are designed for multi-environment delivery. A publisher needs to filter them for the best fit.
type
: String
Mime-Type of the Resource.
url
: String
Path of the Resource.
offset
: String
If an multi ad response (VMAP) is used, the offset acting as a hint when the ad should be display, eg. midrolls.
position
: String
The requested position from the mapping file.
Alternatively, the position could also become delivered from an ad server when taking VMAP into account. A mapping file would only define one url per slot and a list of ads (positions) is received from an ad server response.
slot
: String
The requested slot from the publisher.
Alternatively, the slot could also become delivered from an ad server when taking VMAP into account. A publisher would only perform somtag.start and the rest of the implementation is handled by the ad server.
type
: String
The original type of the ad.
At the moment this is VAST or proprietary types like switchIn. For sure, this is going to change, in order to offer the publisher a chance to decide about the correct placement to render.
Cookies
There are four cookie keys that are used to store a unique ID and comply with privacy requirements.
ad-tracking
: on
or off
To respect end user privacy this cookie controls user tracking.
By default, a user is fully tracked. If set to true, an ad request
is still possible, but with limitations regarding targeting etc.
If the cookie is not set or has any other value than off
it is
interpreted as on
.
71uuid
: String
A unique user ID for tracking purposes. If this cookie is not set, a
new ID is created by somtag
that expires in 7 years.
This ID is only used when ad-tracking = on
anon-uuid
: String
A unique tracking ID that is created by somtag
and stored for 6 months
in case of ad-tracking = off
. If the end user switches to ad-tracking = on
again, this cookie is removed.
sid
: String
A unique Session-ID that is created by somtag
and stored for 2 hours
in case of ad-tracking = off
. If the end user switches to ad-tracking = on
again, this cookie is removed.
FAQ
Why is the Lifecycle API split into Context and Runtime?
In a nutshell, otherwise we always have to check if a Context was started before calling methods from Runtime.