1 Terminology

Term Description:

  • Media owner - 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 Challenges

5.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.


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

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.

5.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.


  • 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?

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.

5.3 Retrieving external resources

An ad may consist of HTML markup to be displayed. This HTML markup will usually use external resources, such as images. Once again, the possibly limited or non-existent Internet connectivity of a player 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!


  • 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.

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.

5.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.


  • 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.

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.
  • ${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).

5.5 Currency conversion

We do not currently support currency conversion. We are considering adding that feature in the future.

That being said, 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. The currency 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 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.


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

6.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.

6.1.1 BidRequest

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.
wseat[...] / emptyWhite listed seats.
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.

6.1.2 Imp

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

6.1.3 ImpExt (Extension)

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.
audbreakdown[...]arrayThis is not implemented yet, but we plan on implementing it in the future.

An array of Audience objects. This is the breakdown of the audience into different demographic groups.
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 are more than 1 screen when dealing with sync groups.

6.1.4 Audience (Extension)

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.

6.1.5 Banner

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.

6.1.6 Video

mimes[...]List of formats supported by the media owner.
protocols[...] / empty This 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
pos7The ad position of the screen. We default to fullscreen (7).
ext{...} A VideoExt instance

6.1.7 VideoExt (Extension)

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

6.1.8 Pmp

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

6.1.9 Deal

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.

6.1.10 App

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 product.
domain\* / emptyAn optional domain for the media owner’s product.
publisher{...}A Publisher object.

6.1.11 Publisher

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

6.1.12 Device

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 hashed screen GUID in the form of a GUID. We hash the screen's GUID for security purposes.
ext{...}A DeviceExt instance.

6.1.13 DeviceExt (Extension)

siteid\* / emptystringThe site id of the screen.
networkid\* / emptystringThe network id of the screen.
deviceloc\* / emptystringThe screen's location code.
dooh{...}DOOHA DOOH instance.

6.1.14 DOOH

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.

6.1.15 Geo

type3Provided by the media owner.

6.1.16 Site

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 product.
domain\* / emptyAn optional domain for the media owner’s product.
page\* / emptyAn optional page for the media owner’s product.
publisher{...}A Publisher object.

6.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": [
            "video": {
                "mimes": [
                "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,
            "ext": {
                "totalaud": 77.1563333,
                "audbreakdown": [
                        "demo": ["AGE-14-19", "GNDR-M"],
                        "aud": 0.05336784
                        "demo": ["AGE-50-59"],
                        "aud": 0.07432529
                        "demo": ["GNDR-F", "AGE-60+"],
                        "aud": 0.14183541
                "screenids": ["screen-1"]
    "app": {
        "id": "screen-1",
        "domain": "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
        "w": 1920,
        "h": 1080,
        "ext": {
            "siteid": "1234",
            "networkid": "network",
            "dooh": {
                "venuetypeid": 105
    "test": 0,
    "at": 1,
    "tmax": 2000,
    "allimps": 0,
    "cur": [

6.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.

6.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.

6.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.

6.3.3 Bid

AttributeExpected ValueNotes
impid\*The ID of the Imp object in the related bid request.
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.
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 5.3.

We support all OpenRTB macros here.
adomainemptyAny value in this field will be ignored.
bundleemptyAny value in this field will be ignored.
iurlemptyAny value in this field will be ignored.
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.
ext{...}A BidExt object. This is optional and can be omitted, but it’s use is highly recommended.

6.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.

Use of a code not present in the “audbreakdown” field of the ImpExt object will cause the bid to be rejected.

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

6.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 example below",
                    "ext": {
                        "impurls": ["List of imp URLs. We support OpenRTB macros."]
                    "id": "7062827105545311234",
                    "impid": "1",
                    "price": 6.0,
                    "adid": "123",
                    "crid": "123",
                    "adomain": [
                    "dealid": "ABCde-1234"
            "seat": "9876"

An example of a VAST XML for a video is shown below. For a picture, the result would be the same, but the type of the <MediaFile> tag would be different (e.g. image/jpeg).

<?xml version="1.0" encoding="utf-8"?>
<VAST version="2.0">
    <Ad id="123">
            <Impression id="impression"><![CDATA[Impression URI]]></Impression>
            <Error><![CDATA[Error URI]]></Error>
                            <Tracking event="firstQuartile"><![CDATA[First quartile tracking URI]]></Tracking>
                            <Tracking event="midpoint"><![CDATA[Second quartile tracking URI]]></Tracking>
                            <MediaFile width="1920" height="1080" type="video/mp4" delivery="progressive"><![CDATA[Media file URI]]></MediaFile>

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.


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.


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.


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


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

Any genderGNDR-\*

Did this page help you?