1 Terminology

Term Description:

  • Media owner or Publisher- The owner of the player which ultimately plays the ad.
  • Player - A unit, with one or multiple screens, which plays digital ads.
  • Product - A media owner may classify their players into “products”. For example, all players in malls may be part of a “Mall” product.

2 Goals

The goal of this document is to identify challenges through which a buyer (an advertiser or agency) may use a DSP in order to target and buy ads to be played on a digital signboard and to flesh out the solutions and processes needed to overcome these challenges.

The process tries to leverage as much of the existing OpenRTB 2.5 specification, with as few extensions or modifications as possible.

3 Additional reading

OpenRTB API Specification Version 2.5 Terminology from the OpenRTB API documentation is used extensively in this document. It can be found at https://www.iab.com/guidelines/real-time-bidding-rtb-project/.

4 Scenarios

Two scenarios are considered in this document: open bidding and pre-approved campaigns.

Open bidding
“Open bidding” is the process in which a media owner can send a bid request in order to fill in an open spot in a player’s schedule (or perhaps even all spots) and all (or selected) buyers can bid for the spot through a DSP and provide the content of the ad.

Pre-approved campaigns
“Pre-approved campaigns” is the process where an advertiser or agency and a media owner have an agreement to play an ad in a predetermined schedule. The media owner can then use the advertiser or agency’s DSP to retrieve the creative and report impressions, with the link being made through a Deal ID.

5 Inventory

5.1 Overview

We publish our inventory to files listed at https://exdsps-inventory.hivestack.com/list. We publish excel and json files for each region (China and rest of world). These files contain all of our inventory for the given region.

We generate one file per month per region on the 20th of the previous month. This file is then updated every week of the month on Saturday. We also provide an evergreen file that is updated weekly on Saturdays as well.

Do note that we don't provide an API to make queries on the inventory at this point and that, as such, these files are the only way to access our inventory's data outside of our bid stream. We recommend using the files to seed your DB and updating it in between with the information provided in the bid requests until an updated file is provided to resolve missing information.

5.2 Details

5.2.1 Identifiers

You will notice that we share two IDs: screen ID and OpenRTB UUID. The first one is the ID the MO gave their units, this value is only unique within the MO but the same value can appear in the inventory of more than one MO (typically if they use sequential values). The second one however, is unique to this unit within Hivestack but not typically used by the MO.

6 Challenges

6.1 Audience targeting

The OpenRTB standard was created for a process in which an ad would be served to an audience consisting of a single person. This meant that the focus of targeting information was placed on the device, the app or site displaying the ad, and the single person viewing the ad. But our case results in many people viewing the ad.

Breakdown

  • The current OpenRTB standards provide targeting information for a single person.
  • We need a demographic breakdown of the audience viewing the ad.

Solution
The Imp object has been given an extension (called ImpExt ) which contains extra information about the audience of the player, including the total number of viewers and a demographic breakdown.

In order to correctly target ads and ensure correct billing, support for this extension is required.

Additionally, the Bid object now has a BidExt extension which adds the “targetdemo” field where the bidder can specify the targeted demographics in order to receive a count of the targeted audience for reporting purposes.

6.2 Restrictions on impression reporting methods

The OpenRTB standard itself does not specify exactly how a successful impression should be reported. While the VAST protocol, which features an impression reporting URL, is widely used in video, there is no such simple solution for still images. The most popular method for impression reporting of still images is to send a creative consisting of markup language with either embedded JavaScript which makes the impression call or an invisible image whose loading signals the successful impression. The main problem with this method is not only the previously possible lack of Internet connectivity but communication restrictions that could be placed on a player for security purposes.

Breakdown

  • The internet connectivity of a player may be lacking, restricted, or simply non-existent
  • The most popular method of reporting impressions for a still image is to embed the image in some HTML markup with some JavaScript code tasked with calling an impression reporting URL or with an invisible tracking pixel.
  • How can we report an impression if the JavaScript cannot call an external URL or the invisible tracking pixel cannot be loaded?

Solution
The Bid object has received an extension called BidExt which contains the “impurls” field. If specified, the URL will be called by the media owner once the creative has played. This also frees up the win notice URL to directly serve an image or video rather than going through HTML markup.

If a creative is served through a VAST document, the impression URL found there will also be used. But the actual audience numbers cannot be sent to this URL as applying substitution macros to VAST reporting URLs is not standard behaviour. So it is recommended to always use the “impurls” field.

6.3 Retrieving external resources

An ad may contain a ZIP creative, HTML file, or HTML markup. If the ad is a ZIP creative, anindex.htmlmust be in the archive. When the format is supported for delivery via a VAST, the correct mime types will be sent over the bid stream. These formats usually use external resources, such as images. Once again, a player's possibly limited or non-existent Internet connectivity may preclude the fetching of such resources.

Also, the delay in loading these resources may be unacceptable once comes the time to display the ad. For example, we would not want to display a progressively loading image on the screen because the player could only know it has to load it once it tried displaying the markup!

Breakdown

  • HTML markup will normally reference external sources.
  • Such external resources may be unavailable due to restricted Internet access.
  • It is mostly impossible to guarantee that a player can figure out all the resources needed for a piece of HTML markup, in order to pre-load them before it tries to render the markup.

Solution
There is, unfortunately, no satisfactory solution to this problem. The most obvious solution is to use an image or video directly as the creative rather than using HTML markup. Most reasons why HTML markup is often used (such as impression reporting) are handled by other solutions found in this section.

Note that these problems may not apply to all players, so it is possible to ignore this problem if a buyer is targeting a media owner that it knows can successfully handle their HTML markup content.

6.4 Reporting audience numbers when reporting impressions

Normally, calling an impression/billing reporting URL indicates that a single person has viewed the ad. But an ad playing on a digital billboard can be viewed by multiple people and this number must somehow be reported.

Breakdown

  • Calling an impression/billing reporting URL normally signals a single view.
  • When a creative is played by a digital billboard, it will be seen by multiple people.
  • We must somehow report that number to the DSP for correct impression counting and billing.

Solution
Three substitution macros will be added to help in reporting these numbers. The following macros can be applied to the URL of the “impurls” field of the ImpExt object. Also, these macros can be applied to the HTML markup, but not to the win notice URL (as these numbers are not yet known when the URL is called).

Macro Value:

  • ${TOTAL_IMP} - The total audience count when the ad was played. This macro is populated in the tracking URLs.
  • ${TARGET_IMP} - The total targeted audience count when the ad was played. This is calculated by multiplying the total audience count by the targeted audience concentration for that play.
  • ${AUCTION_PRICE} - Clearing price using the same currency and units as the bid.
  • ${TOTAL_PRICE} - The total price to bill. This is calculated according to the winning price and the total audience number. Here, ${TOTAL_PRICE} = ${TOTAL_IMP} * ${AUCTION_PRICE} / 1000. We divide the auction price by one thousand because it is a CPM (cost per mille).

6.5 Currency conversion

We currently support currency conversion, upon request during the integration process, from any currency to USD. This means bid requests for inventory in any currency can be emitted in the converted USD value and can be answered in USD.

Solution
External DSPs have to make sure that they respond to our bid requests with the same currency specified in the cur field of bid requests. If currency conversion is enabled, the cur field will contain the currency to which the original value has been converted. The currency in the response also has to match the bidfloorcur of the ImpObject the external DSP bids for. We expect a bid response that has the same currency as the bid request.

6.6 Synchronizing ad plays on several units

Some media owners want to have the ability to play ads simultaneously on several units of their inventory. This is especially useful when transacting with sites instead of units, to ensure that all units on the site are playing the same creative.

Solution
The sync group feature allows the synchronization of ad plays on groups of units. When using sync groups, a primary unit will synchronize ad plays on a group of secondary units. The ad scheduled for the primary unit will be played at the same time on all units of the group. In order for sync groups to be able to play the same creative simultaneously, creative files must be provided for all different unit resolutions in the sync group.

❗️

Any missing or non-approved creative file for one of the sync group's unit dimensions will result in the ad not being scheduled to play.

There are two methods to handle sync groups at the bid request level, those can be configured during the integration process and are as follow:

  1. The default method is to send multiple bid requests, one for each resolution in the sync group, each containing a single ImpObject. For this method, a standard bid response as described in section 6.4, containing a single Bid will be accepted for each emitted request.
  2. The second option is to send a single bid request with one ImpObject for each resolution in the sync group. This option requires answering the bid request with a single response containing several Bid objects, each of them with an adm field corresponding to the ImpObject it is answering to. This is reflected by the impid fields in the Bid objects of the response, corresponding to the id of the ImpObject which were present in the bid request.

For the second method, examples of the emitted bid request and expected bid response are illustrated below.

Example of a single bid request for a sync group:

{
   "id":"44ebf533-f884-4432-a581-5f7ed3007c22",
   "imp":[
      {
         "id":"1",
         "banner":{
            "w":1080,
            "h":1920,
            "pos":7,
            "mimes":[
               "image/jpeg",
               "image/png",
               "image/bmp",
               "image/gif",
               "image/webp",
               "text/html",
               "application/html",
               "application/zip"
            ]
         },
         "video":{
            "mimes":[
               "video/avi",
               "video/mpg",
               "video/flv",
               "video/mp4",
               "video/webm",
               "video/quicktime"
               "text/html",
               "application/html",
               "application/zip"
            ],
            "minduration":6,
            "maxduration":6,
            "protocols":[1, 2, 3, 4, 5, 6, 7, 8],
            "w":1080,
            "h":1920,
            "startdelay":0,
            "sequence":0,
            "pos":7,
            "ext": { "audio": 0 }
         },
         "displaymanager":"MANAGER-1",
         "instl":1,
         "bidfloorcur":"EUR",
         "secure":0,
         "pmp":{
            "private_auction":1,
            "deals":[
               {
                  "id":"ABCde-1234",
                  "bidfloor":0.87,
                  "bidfloorcur":"EUR",
                  "wseat":[
                     "seat-id"
                  ],
                  "ext":{
                    "deal_type": 2,
                    "must_bid": 0
                  }
               }
            ]
         },
         "ext":{
            "totalaud":78.1724,
            "screenids":[
               "screen-1",
               "screen-2",
               "screen-3",
               "screen-4"
            ],
            "qty": {
                "multiplier": 78.1724,
                "sourcetype": 1,
                "vendor": "Some impression multiplier measurement vendor"
            }
         }
      },
      {
         "id":"2",
         "banner":{
            "w":1280,
            "h":720,
            "pos":7,
            "mimes":[
               "image/jpeg",
               "image/png",
               "image/bmp"
            ]
         },
         "video":{
            "mimes":[
               "video/avi",
               "video/mpg",
               "video/flv",
               "video/mp4",
               "video/webm",
               "video/quicktime"
            ],
            "minduration":6,
            "maxduration":6,
            "protocols":[1, 2, 3, 4, 5, 6, 7, 8],
            "w":1280,
            "h":720,
            "startdelay":0,
            "sequence":0,
            "pos":7,
            "ext": { "audio": 0 }
         },
         "displaymanager":"MANAGER-1",
         "instl":1,
         "bidfloorcur":"EUR",
         "secure":0,
         "pmp":{
            "private_auction":1,
            "deals":[
               {
                  "id":"ABCde-1234",
                  "bidfloor":0.87,
                  "bidfloorcur":"EUR",
                  "wseat":[
                     "seat-id"
                  ],
                  "ext":{
                    "deal_type": 2,
                    "must_bid": 0
                  }
               }
            ]
         },
         "ext":{
            "totalaud":54.5093,
            "screenids":[
               "screen-5",
               "screen-6",
               "screen-7"
            ]
         }
      },
      {
         "id":"3",
         "banner":{
            "w":1920,
            "h":1080,
            "pos":7,
            "mimes":[
               "image/jpeg",
               "image/png",
               "image/bmp"
            ]
         },
         "video":{
            "mimes":[
               "video/avi",
               "video/mpg",
               "video/flv",
               "video/mp4",
               "video/webm",
               "video/quicktime"
            ],
            "minduration":6,
            "maxduration":6,
            "protocols":[1, 2, 3, 4, 5, 6, 7, 8],
            "w":1920,
            "h":1080,
            "startdelay":0,
            "sequence":0,
            "pos":7,
            "ext": { "audio": 0 }
         },
         "displaymanager":"MANAGER-1",
         "instl":1,
         "bidfloorcur":"EUR",
         "secure":0,
         "pmp":{
            "private_auction":1,
            "deals":[
               {
                  "id":"ABCde-1234",
                  "bidfloor":0.87,
                  "bidfloorcur":"EUR",
                  "wseat":[
                     "seat-id"
                  ],
                  "ext":{
                    "deal_type": 2,
                    "must_bid": 0
                  }
               }
            ]
         },
         "ext":{
            "totalaud":31.2125,

            "screenids":[
               "screen-8",
               "screen-9",
               "screen-10",
               "screen-11"
            ]
         }
      }
   ],
   "app":{
      "id":"screen-1",
      "domain":"domain.com",
      "publisher":{
         "id":"MANAGER-1",
         "name":"Mediaowner",
         "domain":"domain.com"
      }
   },
   "device":{
      "geo":{
         "lat":50.04117,
         "lon":10.22613,
         "type":3,
         "country":"DEU",
         "region":"BY",
         "city":"DESCW",
         "utcoffset":120,
         "zip":"80639"
      },
      "ifa":"57726551-3bc8-fd63-a1e6-6884aa9a6d3e",
      "ext":{
         "siteid":"1234",
         "networkid":"network",
         "dooh":{
            "venuetypeid":205
         }
      }
   },
   "at":1,
   "tmax":2000,
   "allimps":0,
   "cur":[
      "EUR"
   ]
}

Example of a single bid response for a sync group:

{
  "id": "44ebf533-f884-4432-a581-5f7ed3007c22",
  "seatbid": [
    {
      "bid": [
        {
          "id": "7125065197458485130",
          "impid": "1",
          "price": 0.87,
          "adm": "VAST XML, see examples in section 6.4",
          "adomain": ["domain-url.com"],
          "crid": "123",
          "cat": ["IAB3"],
          "dealid": "ABCde-1234",
          "lurl": "A http or https url",
          "burl": "A http or https url",
          "nurl": "A http or https url",
          "ext": {
            "impurls": ["List of imp URLs. We support OpenRTB macros."]
          }
        },
        {
          "id": "7125065197458486410",
          "impid": "2",
          "price": 0.87,
          "adm": "VAST XML, see examples in section 6.4",
          "adomain": ["domain-url.com"],
          "crid": "123",
          "cat": ["IAB3"],
          "dealid": "ABCde-1234",
          "lurl": "A http or https url",
          "burl": "A http or https url",
          "nurl": "A http or https url",
          "ext": {
            "impurls": ["List of imp URLs. We support OpenRTB macros."]
          }
        },
        {
          "id": "7125065197458487178",
          "impid": "3",
          "price": 0.87,
          "adm": "VAST XML, see examples in section 6.4",
          "adomain": ["domain-url.com"],
          "crid": "123",
          "cat": ["IAB3"],
          "dealid": "ABCde-1234",
          "lurl": "A http or https url",
          "burl": "A http or https url",
          "nurl": "A http or https url",
          "ext": {
            "impurls": ["List of imp URLs. We support OpenRTB macros."]
          }
        }
      ],
      "seat": "seat-id"
    }
  ],
  "cur": "EUR"
}

7 Use of the OpenRTB API

This section of the document describes how the OpenRTB standard is used and extended in order to successfully go through the process of allowing buyers to target players to play their ads.

The workflow itself has not changed: when an ad is needed, a request is made, the bids are tallied, the winner is immediately notified using the win notice URL and the creative is retrieved to be played.

In addition to the extensions mentioned in the “Challenges” section, a few useful fields have been added in order to help with targeting by exposing new information such as the audio capabilities of a player or the kind of location it is in.

Legend

TypeDescription
*No specific value, the “Notes” column contains more information.
[...]An array of values or objects.
{...}A sub-object.
emptyOmitted or empty value.

7.1 Request format

The requests sent by Hivestack simulate a fullscreen ad. Each call is made for a single campaign each time it needs content to play. Support for multiple campaigns in a single request may be considered in the future in order to minimize the number of requests.

The request will typically be made in advance so that the content of the ad can be fully retrieved before the ad is planned to play.

Fields that are not specified here will be omitted in the actual request.

7.1.1 BidRequest

KeyValueDescription
id*A unique ID in the form of a GUID.
imp[...]An array containing one or more Imp objects.

Multiple Imp objects are usually used when dealing with unit groups containing units of different screen resolutions.
app{...}An App object.
site{...}A Site object.
device{...}A Device object.
test0 / 10 – Normal billable campaign
1 – Non-billable test campaign
at1 / 2 / 38525121 – First Price
2 – Second Price
3852512 – Pre-approved campaigns only
tmax*The max timeout before closing the connection. 700 ms by default.
wseat[...] / emptyWhite listed seats.
allimps0
cur[...] / emptyList of supported currencies (ISO-4217 alpha codes).

May be empty if the request is for a pre-approved deal.
bcat[...] / emptyBlacklisted iab categories.
badv[...] / emptyBlacklisted advertisers.

7.1.2 Imp

AttributeValueNotes
id*A unique(within the request) sequential number.
banner{...} / emptyA Banner instance offering information for still image content.

If the media owner/player does not support still images, this attribute will be omitted.
video{...} / emptyA Video instance offering information for video, flash or HTML content.

If the media owner/player does not support video content, this attribute will be omitted.
displaymanager*A unique identifier for the media owner. Can be used by the DSP to customize the response.
displaymanagerver* / emptyA version number provided by the media owner. This field may be empty. Can be used to customize the response.
instl1The ad is interstitial (full screen).
bidfloor*The minimum bid required. It is expressed in CPM.
bidfloorcur*The currency of the minimum bid. The currency is specified in ISO-4217 alpha codes (e.g. "USD").
secure0A flag to indicate if HTTPS is used. We currently only support HTTP, which is why we default to 0.
pmp{...} / emptyA Pmp instance describing any marketplaces deals in effect.
ext{...}An ImpExt instance

7.1.3 ImpExt (Extension)

AttributeValueTypeNotes
totalaud*floatThe total number of viewers in the audience. This is equivalent to the value in ${TOTAL_IMP}, unless we are using unit groups and a unit inside the group didn't play.
dataprovider* / emptyintegerAn optional code indicating the source of the audience information.

0 – Other or not specified
1 – Publisher’s own research
10 – GeoPath
11 – Nielsen
12 – Quividi
screenids[...]arrayAn array containing the id(s) of the screen(s). There is more than 1 screen when dealing with sync groups.
screeninfos[{...}, ...]arrayAn array of screen info objects. Each screen info object can contain a name and an external_id, i.e., [{"name": "foo", "external_id": "bar"}, ...]. The availability of the screeninfosThe list of objects is media owner-dependent.
qty{...} / emptyQtyAn optional Qty object, this object includes the impression multiplier, and describes the source of the multiplier value. See Section 7.1.18

7.1.4 Audience (Extension)

AttributeValueTypeNotes
demo[...]array of stringsList of demographic categories of this slice of the audience. Each entry contains a string code describing the demographic. If the array contains multiple entries, they all apply (ex: Male and aged 16-21).

See Appendix A for a description of these codes.
aud*floatA value between 0.0 and 1.0 representing the fraction of the total audience that correspond to all the demographic categories in the “demographics” field.

7.1.5 Banner

AttributeValueNotes
w*Width, in pixels, of the player’s screen.
h*Height, in pixels, of the player’s screen.
pos7The ad position of the screen. We default to fullscreen (7).
mimes[...]List of formats supported by the media owner.

7.1.6 Video

AttributeValueNotes
mimes[...]List of formats supported by the media owner.
minduration*Minimun duration allowed for a video ad, in seconds.
maxduration*Maximum duration allowed for a video ad, in seconds.
protocols[...] / emptyThis value depends on the support offered by the media owner. If empty, the video should be served directly through the response of the win notice URL.
w*Width, in pixels, of the player’s screen.
h*Height, in pixels, of the player’s screen.
startdelay0Not applicable in this case
sequence0
pos7The ad position of the screen. We default to fullscreen (7).
ext{...}A VideoExt instance

7.1.7 VideoExt (Extension)

AttributeValueNotes
audio*0 – No sound
1 – Sound available
2 – Sound required

7.1.8 Pmp

AttributeValueNotes
private_auction0 / 1Always “1” for pre-approved campaigns.
deals[...]An array containing a one or more Deal instances.

7.1.9 Deal

AttributeValueNotes
id*A friendly string identifying the deal.
bidfloor*Minimum bid for the play, expressed in CPM. In the case of pre-approved campaigns, this amount will always be 0.
bidfloorcur*The currency of the minimum bid. The currency is specified in ISO-4217 alpha codes (e.g. "USD").
wseat[...] / emptyWhitelist of seats allowed to bid for this deal.
ext{...} / emptyA DealExt instance

7.1.10 DealExt

AttributeValueNotes
deal_type0 / 1 / 2 / 30 - UNKNOWN (Default)
1 - GUARANTEED
2 - NON_GUARANTEED
3 - PREFERRED
must_bid0 / 10 - False (Default)
1 - True (Only applicable to GUARANTEED deal_type. When True, bidders are expected to bid)

7.1.11 App

AttributeValueNotes
id * / emptyAn optional external ID of the primary unit of the unit group making the ad request.
name* / emptyAn optional name for the media owner’s unit.
domain* / emptyAn optional domain for the media owner’s unit.
publisher{...}A Publisher object.

7.1.12 Publisher

AttributeValueNotes
id*A unique ID representing the media owner.
name*Name of the media owner.
domain*Domain of the media owner.

7.1.13 Device

AttributeValueNotes
ua* / emptyIf the media owner/player supports HTML ads, it may report the user agent string of the internal engine it uses.
geo{...} / emptyA Geo instance. May be omitted if the location is unknown.
h* / emptyPhysical height of the screen in pixels. Omitted if unknown.
w* / emptyPhysical width of the screen in pixels. Omitted if unknown.
ppi* / emptyScreen size as pixels per linear inch. Omitted if unknown.
pxratio1Very unlikely to be any other number.
js0 / 1Support for JavaScript.

Use of JavaScript is not recommended.
flashverVersion of Flash supported by the media owner/player.

Omitted if Flash is either not supported or the media owner cannot guarantee the support of a specific version.
ifa* / emptyThe openRTB UUID of the screen, a value that is unique and that won't change in time for that screen in HS. It can be used as an alternative screen identifier as multiple pubs can have the same screen ID amongst themselves (though the screen ID value will always be unique in a given publisher).

In a handful of markets (Japan mainly) this information can sometimes be omitted.
ext{...}A DeviceExt instance.

7.1.14 DeviceExt (Extension)

AttributeValueTypeNotes⠀
siteid* / emptystringThe site id of the screen.
networkid* / emptystringThe network id of the screen.
deviceloc* / emptystringThe screen's location code.
aspectratiotolerance* / emptyfloatDefines the acceptable stretching tolerance for the aspect ratio of this media owner. Refer to Appendix B for further details.
This value is expressed as a float between 0 and 1, where, for example, 0.1 represents a 10% tolerance.
dooh{...}DOOHDOOH instance.

7.1.15 DOOH

AttributeValueTypeNotes
venuetypeid* / emptyintegerThe venue type id of the screen. You can find more info on the different possible venue types here.

We plan on integrating a list of venue type ids in the future.

7.1.16 Geo

AttributeValueNotes
lat*
long*
type3Provided by the media owner.
country*
region*
city*
zip*Zip code of the unit's location.
utcoffset*

7.1.17 Site

AttributeValueNotes
id * / emptyAn optional external ID of the primary unit of the unit group making the ad request.
name* / emptyAn optional name for the media owner’s unit.
domain* / emptyAn optional domain for the media owner’s unit.
page* / emptyAn optional page for the media owner’s unit.
publisher{...}A Publisher object.

7.1.18 Qty (Extension)

AttributeValueTypeNotes
multiplier*floatThe quantity of billable events which will be deemed to have occurred if this item is purchased. Equivalent to ImpExt.totalaud
sourcetype0 / 1 / 2 / 3intThe source type of the quantity measurement, ie. publisher. Refer to DOOH Multiplier Measurement Source Types enum
vendor*stringIf sourcetype is equal to 1, the top level business domain name of the measurement vendor providing the quantity measurement.

7.2 Bid request sample

Below is a sample of a bid request. It is worth noting that we default to filling the request.site object by default. If needed, we can fill the request.app object instead. Either way, we will always fill the same object on subsequent requests.

{
  "id": "b4f3e018-022e-4ae5-aca6-fa953348688c",
  "imp": [
    {
      "id": "1",
      "banner": {
        "w": 1920,
        "h": 1080,
        "pos": 7,
        "mimes": [
          "image/jpeg",
          "image/png",
          "image/bmp",
          "image/gif",
          "image/webp",
          "text/html",
          "application/html",
          "application/zip"
        ]
      },
      "video": {
        "mimes": [
          "video/avi",
          "video/mpg",
          "video/flv",
          "video/mp4",
          "video/webm",
          "video/quicktime",
          "text/html",
          "application/html",
          "application/zip"
        ],
        "minduration": 5,
        "maxduration": 30,
        "protocols": [1, 2, 3, 4, 5, 6, 7, 8],
        "w": 1920,
        "h": 1080,
        "startdelay": 0,
        "sequence": 0,
        "pos": 7,
        "ext": { "audio": 0 }
      },
      "displaymanager": "MANAGER-1",
      "instl": 1,
      "bidfloor": 0.01,
      "bidfloorcur": "CAD",
      "secure": 0,
      "pmp": {
        "private_auction": 1,
        "deals": [
          {
            "id": "deal-id",
            "bidfloor": 2.0,
            "bidfloorcur": "CAD",
            "wseat": ["seat-id"],
            "ext": {
              "deal_type": 2,
              "must_bid": 0
            }
          }
        ]
      },
      "ext": {
        "totalaud": 77.1563333,
        "screenids": ["screen-1"],
        "screeninfos": [{ "name": "screen-1", "external_id": "screen-1" }],
        "qty": {
          "multiplier": 77.1563333,
          "sourcetype": 2
        }
      }
    }
  ],
  "app": {
    "id": "screen-1",
    "domain": "domain.com",
    "publisher": {
      "id": "MANAGER-1",
      "name": "Mediaowner",
      "domain": "domain.com"
    }
  },
  "site": {
    "id": "screen-1",
    "domain": "domain.com",
    "page": "http://domain.com",
    "publisher": {
      "id": "MANAGER-1",
      "name": "Mediaowner",
      "domain": "domain.com"
    }
  },
  "device": {
    "geo": {
      "lat": 40.137,
      "lon": 10.67641,
      "type": 3,
      "country": "CAN",
      "region": "QC",
      "city": "MONTREAL",
      "utcoffset": 60,
      "zip": "H2Y2P1"
    },
    "w": 1920,
    "h": 1080,
    "ifa": "cff08971-d5f7-4a25-bd8d-dcbb3fc12ae2",
    "ext": {
      "siteid": "1234",
      "networkid": "network",
      "aspectratiotolerance": 0.1,
      "dooh": {
        "venuetypeid": 105
      }
    }
  },
  "test": 0,
  "at": 1,
  "tmax": 2000,
  "allimps": 0,
  "cur": ["CAD"]
}

7.3 Expected bid response

The bid response from the DSP.

If the response does not include any bids, an error code is included in the response or the server returns a 40x/50x response, the Hivestack system will try again up to five times. If it does not receive a successful bid by then, it will assume that there is no content to play (if there are no bids) or there is a problem with the DSP (in case of an error).

Values that are not needed by Hivestack will be ignored. The “expected value” column simply represents what would normally be expected in this scenario. Omitting a field or sending a value different from the “expected value” will not trigger an error or rejection of the response unless marked as mandatory in the OpenRTB specification or if specified otherwise in the “notes” column.

7.3.1 BidResponse

AttributeExpected ValueNotes
id*ID of the bid request (as normal)
seatbid[...]Represents an array of BidSeat objects.
bidid*Any string. Will be saved for logging/tracking purposes.
cur*The currency of the bid. The currency is specified in ISO-4217 alpha codes (e.g. "USD").

Since we don't support currency conversion, this must be the same currency as one of the currencies specified in the bid request.
customdataemptyNot currently supported.
nbremptyNot currently supported.
extemptyNo extensions have currently been agreed upon. Any value will be ignored.

7.3.2 BidSeat

AttributeExpected ValueNotes
bid[...]Represents an array of Bid objects. As in the OpenRTB standard, the bid is in CPM, with the final price being determined by the total number of impressions (not targeted impressions) when the ad is played.
seat*The ID of the buyer's seat.
extemptyNo extensions have currently been agreed upon. Any value will be ignored.

7.3.3 Bid

AttributeExpected ValueNotes
id*
impid*The ID of the Imp object in the related bid request. Each bid object in the bid response must have a unique impid
price*The bid price expressed in CPM.
adidemptyPreloaded ads are not supported. This field can be used as a fallback for creative approval and caching if crid is not available, but use of the crid field is preferred.
nurl*The “${TOTAL_IMP}”, “${TARGET_IMP}” and “${TOTAL_PRICE}” substitutions macros cannot be used in this URL as the actual impression audience numbers are not known yet.

We support all OpenRTB macros here.

The field is not required, but we recommend filling it.
burl*The url called when a winning bid becomes billable.

We support all OpenRTB macros here.

The field is not required, but we recommend filling it.
lurl*The url called when a bid has lost.

We support all OpenRTB macros here.

The field is not required, but we recommend filling it.
adm*This field usually contains the picture or the video. The picture or the video should be VAST XMLs. We do not support HTML or Javascript in this field for the reasons mentioned in 6.3.

We support all OpenRTB macros here.

Examples of the expected VAST XML formats can be found in section 7.4.
adomain[...]An array of advertiser domains, only the first value of the array is used, to check if the advertiser domain is denylisted and for reporting features.
The expected format isdomain.com or https://domain.com. Including a trailing /or a path after the domain (e.g. https://domain.com/path) will result in issues when validating the advertiser.
bundleemptyAny value in this field will be ignored.
iurlemptyAny value in this field will be ignored, unless support for this field has been explicitly requested by the DSP, during the integration process.
In that case this can be the url of the image creative, the field will be ignored if adm is populated.
cidemptyAny value in this field will be ignored.
crid*A unique identifier for the creative. Used for creative approval and caching. If this field is not specified, the adid will be used as a fallback, but use of this field is preffered.
cat[...]An array of IAB content categories for the creative.
attr[...] / emptyAny values will be ignored.
dealid*
h*
w*
ext{...}A BidExt object. This is optional and can be omitted, but it’s use is highly recommended.

7.3.4 BidExt (Extension)

AttributeExpected ValueTypeNotes
impurl*string (URL)This field has been deprecated in favour of the "impurls" field.
impurls*array of strings (URLs)A list of URLs to call to submit an impression when the creative is played, thus confirming the billing of the play.

Can be used as an alternative in cases where there is no other way to submit such a URL. For example, in cases where the win notice URL directly returns the creative.

Substitution macros can be used in the URL. Including the “${TOTAL_IMP}”, “${TARGET_IMP}” and “${TOTAL_PRICE}” macros.

This parameter is optional.
targetdemo[...]array of stringsThe list of targeted demographics. This list will be used to calculate the number of targeted impressions (for the “${TARGET_IMP}” substitution macro).

Each entry in the array is a string with the code of the targeted demographic. As long as person is included in at least one of the values for each demographic type specified, then they are considered part of the target.

For example, the ["GNDR-M", "AGE-15-17", "AGE-18-24"] array will target males which are also in either the 15-17 or 18-24 age ranges.

If this field is omitted, or the whole BidExt object is omitted, Hivestack will assume that no demographic is specifically targeted.

imptrackers[...]array of stringsAny value in this field will be ignored, unless support for this field has been explicitly requested by the DSP, during the integration process.

A list of URLs to call to submit an impression when the creative is played, thus confirming the billing of the play.

Can be used as an alternative in cases where there is no other way to submit such a URL. For example, in cases where the win notice URL directly returns the creative.

Substitution macros can be used in the URL. Including the “${TOTAL_IMP}”, “${TARGET_IMP}” and “${TOTAL_PRICE}” macros.

This parameter is optional.

7.4 Bid response sample

Here is an example of a bid response. The VAST XML is usually sent in the adm field of a Bid instance. To make it more readable, the adm value is displayed further ahead. Although it is not shown in the example, we support VAST redirections (i.e. <VASTAdTagURI>) and we always unwrap intermediate VASTs.

{
  "id": "d212ea04-443f-4dd4-8eb7-084ed71d1429",
  "cur": "CAD",
  "seatbid": [
    {
      "bid": [
        {
          "adm": "VAST XML, see examples below",
          "ext": {
            "impurls": ["List of imp URLs. We support OpenRTB macros."]
          },
          "nurl": "A http or https url",
          "burl": "A http or https url",
          "lurl": "A http or https url",
          "id": "7062827105545311234",
          "impid": "1",
          "price": 6.0,
          "adid": "123",
          "crid": "123",
          "adomain": ["domain-url.com"],
          "dealid": "ABCde-1234"
        }
      ],
      "seat": "9876"
    }
  ]
}

An example of a VAST XML for a video is shown below.

<?xml version="1.0" encoding="utf-8"?>
<VAST version="2.0">
    <Ad id="123">
        <InLine>
            <AdSystem>DSP</AdSystem>
            <AdTitle><![CDATA[Title]]></AdTitle>
            <Impression><![CDATA[Impression URI]]></Impression>
            <Error><![CDATA[Error URI]]></Error>
            <Creatives>
                <Creative>
                    <Linear>
                        <Duration>00:00:05</Duration>
                        <TrackingEvents>
                            <Tracking event="firstQuartile"><![CDATA[First quartile tracking URI]]></Tracking>
                            <Tracking event="midpoint"><![CDATA[Second quartile tracking URI]]></Tracking>
                        </TrackingEvents>
                        <MediaFiles>
                            <MediaFile width="1920" height="1080" type="video/mp4" delivery="progressive"><![CDATA[Media file URI]]></MediaFile>
                        </MediaFiles>
                    </Linear>
                </Creative>
            </Creatives>
        </InLine>
    </Ad>
</VAST>

For a picture, the result is similar, but the type of the <MediaFile> tag reflects the format of the creative file (e.g. image/jpeg) as shown below.

❗️

For images, do not use bitrate="null" in the <MediaFile> tag, as this is not supported. Simply omit the property or set a numeric value such as bitrate="0"

<?xml version="1.0" encoding="utf-8"?>
<VAST version="2.0">
    <Ad id="123">
        <InLine>
            <AdSystem>DSP</AdSystem>
            <AdTitle><![CDATA[Title]]></AdTitle>
            <Impression><![CDATA[Impression URI]]></Impression>
            <Error><![CDATA[Error URI]]></Error>
            <Creatives>
                <Creative>
                    <Linear>
                        <Duration>00:00:05</Duration>
                        <TrackingEvents>
                            <Tracking event="firstQuartile"><![CDATA[First quartile tracking URI]]></Tracking>
                            <Tracking event="midpoint"><![CDATA[Second quartile tracking URI]]></Tracking>
                        </TrackingEvents>
                        <MediaFiles>
                            <MediaFile width="1920" height="1080" type="image/jpeg" delivery="progressive"><![CDATA[Media file URI]]></MediaFile>
                        </MediaFiles>
                    </Linear>
                </Creative>
            </Creatives>
        </InLine>
    </Ad>
</VAST>

8 Sellers.json File

Our Sellers.json file allows the identity of the final seller of a bid request to be discovered. Learn more about the Sellers.json file from IAB Tech Lab here.

8.1 Seller

AttributeValueNotes
seller_id*Seller identifier, same as Publisher.Id property
of an OpenRTB request
name*The name of the company (the legal
entity) that is paid for inventory that
is transacted under the given
seller_id
domain*The business domain name of the
company (the legal entity) that is
paid for inventory that is transacted
under the given seller_id.
seller_typePUBLISHER / INTERMEDIARY / BOTHPUBLISHER - the inventory sold through this
account is on a site, app, or other
medium owned by the named entity
and the advertising system pays
them directly.

INTERMEDIARY - the inventory sold
through this account is not owned
by the named entity or the
advertising system does not pay
them directly.

BOTH - both types of inventory are
transacted by this seller.
ext{...}An optional SellerExt object. See section 8.2

8.2 SellerExt

AttributeValueNotes
impression_multiplier_verifier{...}A ImpressionMultiplierVerifier object to provide transparency on how publishers verify their impression multipliers for each unit. See Section 8.3

8.3 ImpressionMultiplierVerifier

AttributeValueNotes
sourcetype0 / 1 / 2 / 3Iab Lab Multiplier Measurement Source Type Enum
sourcetype_description*Iab Lab Multiplier Measurement Source Type Enum Description
vendor*If sourcetype is equal to 1, the top level business domain name of the measurement vendor providing the quantity measurement
notes*Optional notes field to describe in more detail how the seller collects impression multiplier data

9 Custom Loss Reason Codes

ValueDescription
1000Not all units in the sync group were bid on
1001Bids for units in sync group do not match
1004Deal name too long
1005Deal name invalid

Appendix A. Demographic codes

Because media owners may organize their demographic categories differently, the demographic code system was designed to be as flexible as possible. The codes are designed such that they completely describe the demographic without referring to a common table, being overly long or hard to parse.

There are two kinds of demographics: value ranges and discrete values.

Values ranges represent demographics that cover a part of a spectrum of values, such as age and household income. Values ranges use the following format: “[type]-[min]-[max]”. Either or both the “min” or “max” parts can be replaced with “*” in order to signify that there is no minimum or maximum. Also, in order to shorten the numbers, the “K”, “M”, and “B” suffixes can be used for thousands, millions, and billions. See below for a list of types and examples.

Discrete values represent demographics that have discrete possible values, such as gender. Each value can be a number or a code. The following format is used: “[type]-[value]”. If the value is numeric, the “<” (ex: “ABC-<10”) or “+” (ex: “ABC-10+”) characters indicate that lower or higher values are also included. The “*” character can also be used as a placeholder for all possible values. See below for a list of types and examples.

Currently supported demographic types

Note: The demographic codes presented here are the recommended defaults. A supplier may use custom codes to better fit their demographic data. If you are receiving unexpected codes, please contact Hivestack support.

Age

The age demographic uses the “AGE” type code and is made of ranges in which both the
minimum and maximum are included. Once again, there are no predefined or fixed ranges, any interval can be used.

Examples:

TargetCode
All agesAGE-*-*
18 to 24 years oldAGE-18-24
65 or olderAGE-65-*

Household income

The household income demographic uses the “HHI” type code and is made of ranges in which the minimum is included and the maximum is excluded. The currency should be inferred as the one in circulation in the country of the player.

Examples:

TargetCode
$0 - $24,999HHI-0-25K
$40,000 - $59,999HHI-40K-60K
$100,000 or moreHHI-100K-*
$500,000 - $999,999HHI-500K-1M

Gender

The gender uses the “GNDR” type code and corresponds to one of the following codes:

TargetCode
Any genderGNDR-*
MaleGNDR-M
femaleGNDR-F
OtherGNDR-O
UnknownGNDR-?

Appendix B. Aspect Ratio Matching

When determining whether a creative can play on a screen, Hivestack compares the aspect ratio of the screen and the creative. If the aspect ratio of the creative is within 10% of the screen aspect ratio, in either direction, we allow it to play on that screen. This means any creative with aspect ratio between 90% and 110% of a particular screen’s aspect ratio has a chance to play on that screen.

To ensure that portrait and landscape screens can scale equally, we calculate the aspect ratio of both the creative and the screen based on the resolution of the screen:

  • if the screen is portrait: aspect ratio = height / width
  • if the screen is landscape: aspect ratio = width / height

Once we have the screen aspect ratio, we can calculate the acceptable aspect ratios for creatives wanting to play on that screen. Subtract 10% to find the minimum value, and add 10% to find the maximum value. To illustrate, here are a few examples:

Screen 1Screen 2Screen 3
Screen dimensions1920 w x 1080 h1400 w x 400 h1080 w x 1920 h
Screen aspect ratio1.7778 (w / h)3.5 (w / h)1.7778 (h / w)
Compatible creative aspect ratios1.6000 to 1.9556 (w / h)3.1500 to 3.8500 (w / h)1.6000 to 1.9556 (h / w)

Note that Hivestack is not the player which runs the creatives. We are simply allowing creatives to be sent to a screen for a given campaign. How the creative is actually displayed on those screens is outside of our control.

Also note that some media owners have a different tolerance than the default 10% for aspect ratio matching. The tolerance is still subtracted from and added to the screen aspect ratio in order to find the range of acceptable creative aspect ratios.

Changelog

Date (MM/DD/YYYY)Changes
04/01/2025Added the description of aspectratiotolerancein section 7.1.14.
03/21/2025Update the description of ifa in section 7.1.13 to clarify the purpose of this attribute.
01/23/2025Updated the description of adomain in section 7.3.3 to better reflect format restrictions.
01/15/2025Updated section 5 to describe inventory report weekly update and evergreen file.
11/13/2024Added section 9 to list the custom loss reason codes we use.
06/18/2024Added a description of screeninfos to section 7.1.3 . Added a screeninfos example to the sample bid request in 7.2.
05/08/2024Updated the first paragraph of section 6.3 . Updated the mime types in examples of bid requests in sections 6.6 and 7.2 to addapplication/htmland application/zipto the banner and video mimes lists.
03/18/2024Updated the description of adomain in section 7.3.3
03/06/2024Added the "zip" property to bid requests examples in sections 6.6 and 7.2 . Added a description of "zip" to section 7.1.16
12/08/2023Added Appendix B
09/11/2023Added descriptions of "minduration" and "maxduration" in Section 7.1.6
05/29/2023Added deal type preferred to Section 7.1.10
05/04/2023Removed mentions of non implemented "audbreakdown" from sections 6.6, 7.1.3, 7.2 and 7.3.4
01/27/2023Added Section 8.1 to describe all the fields and values we support in the Seller object(Sellers.json).

Updated Section 8.2 and Section 8.3 to reflect changes in Section 8.1
01/26/2023Changed all references of "product" to "unit" in sections 7.1.11 and 7.1.17
01/24/2023Added Section 8 to describe the extension we added to our Sellers.json file

Section 7.1.3 added qty field to ImpExt

Added Section 7.1.18 to describe Qty extension added to ImpExt.

Adjusted the bid request samples of sections 6.6 and 7.2 to reflect changes to section Section 7.1.3 and Section 7.1.18
01/18/2023Section 6.4 Added an explanation of the TARGET_IMP macro value calculation.

Section 7.3.3 Specified that each bid object must have a unique impid in the same bid response.

Section 7.1.9 Added mention of the ext attribute.

Added Section 7.1.10 and adjusted following sections numbering.

Adjusted the bid request samples of sections 6.6 and 7.2 to reflect changes to sections 7.1.9 and 7.1.10