Skip to content

Commit

Permalink
gpid docs (#3421)
Browse files Browse the repository at this point in the history
  • Loading branch information
bretg authored Nov 19, 2021
1 parent 3d83cee commit 6a4809d
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 97 deletions.
2 changes: 1 addition & 1 deletion _data/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@
subgroup: 8

- sbSecId: 1
title: Prebid Ad Slot
title: Prebid Ad Slot and GPID
link: /features/pbAdSlot.html
isHeader: 0
isSectionHeader: 0
Expand Down
86 changes: 78 additions & 8 deletions dev-docs/modules/gpt-pre-auction.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,25 @@ sidebarType : 1

## Overview

This module enables targeting and tracking at the ad server adunit level.
This module enables bidder targeting and tracking at the ad server ad slot level.

Enabled by default if compiled into your package, this module will add the [Prebid Ad Slot](/features/pbAdSlot.html) and matching GAM ad unit name to each ad unit's first-party data before bid requests are sent to the adapters.
This module is enabled by default if it's compiled into your PBJS package. It will add the [Prebid Ad Slot and GPID](/features/pbAdSlot.html) along with the matching GAM ad unit name to each ad unit's first-party data before bid requests are sent to the adapters.

* **Prebid.js Adapters** - will be able to utilize these values as:
* AdUnit.ortb2Imp.ext.gpid="/1111/home-left"
* AdUnit.ortb2Imp.ext.data.adserver.name="gam"
* AdUnit.ortb2Imp.ext.data.adserver.adslot="/1111/home"
* AdUnit.ortb2Imp.ext.data.pbadslot="/1111/home-left"
* **Prebid Server Adapters** - will see the OpenRTB as:
* imp[].ext.gpid
* imp[].ext.data.adserver.name
* imp[].ext.data.adserver.adslot
* imp[].ext.data.pbadslot

{: .alert.alert-info :}
The Prebid Ad Slot didn't get broad adoption, so it's likely that
someday we'll deprecate it in favor of the more standard GPID.

## Configuration

{: .alert.alert-info :}
Expand Down Expand Up @@ -67,23 +73,87 @@ pbjs.setConfig({

## How It Works

When this module is on, it uses the BEFORE_REQUEST_BIDS event to insert functionality that:
When this module is turned on, it uses the BEFORE_REQUEST_BIDS event to insert functionality that:

- loops through each adunit in the auction
- maps the adunit to the GPT slot using the same algorithm as setTargetingForGPTAsync including customGptSlotMatching
- maps the PBJS adunit to the GPT slot using the same algorithm as setTargetingForGPTAsync including customGptSlotMatching

### Defining the AdServer name and adslot

If GPT slot matching succeeds:

- it sets the Adunit ortb2Imp.ext.data.adserver.name to 'gam'
- it copies the resulting GPT slot name to ortb2Imp.ext.data.adserver.adslot

### Defining Prebid Ad Slot

The customPbAdSlot function is called if it was specified, writing the results to ortb2Imp.ext.data.pbadslot.
If there's no customPbAdSlot, a default algorithm is used to determine ortb2Imp.ext.data.pbadslot:

If there's no customPbAdSlot function, a default algorithm is used to determine ortb2Imp.ext.data.pbadslot:

- first use the AdUnit's ortb2Imp.ext.data.pbadslot if defined
- else, see if the AdUnit.code corresponds to a div and if so, try to retrieve a data element from the div called data-adslotid.
- else, see if the AdUnit.code corresponds to a div-id and if so, try to retrieve a data element from the div called data-adslotid.
- else if the GPT slot matching succeeded, use the GPT slot name
- else, just use the AdUnit.code, assuming that that's the ad unit slot
- else, just use the AdUnit.code

### Defining GPID

Here's what the module does to define GPID:

1. If AdUnit.ortb2Imp.ext.gpid already exists, don't do anything. Assume the publisher or another module has provided the value.
2. Otherwise, if a customPbAdSlot function was defined by the publisher and the result is not empty, then copy that value to AdUnit.ortb2Imp.ext.gpid.
3. Otherwise, if a value was found for GAM AdSlot, copy that to AdUnit.ortb2Imp.ext.gpid

## Example customPbAdSlot function

The following customPbAdSlot function will work for many publishers. Assumptions:
- AdUnits have been registered with [pbjs.addAdUnits](/dev-docs/publisher-api-reference/addAdUnits.html).
- AdUnit.code is either the GPT slot name or the div-id.
- The site has unique (non-random) div-ids.

If either of these isn't the case, you'll need to supply your own function.

```
// Use adunit.ortb2Imp.ext.data.pbadslot if it exists.
// compare adunit.code to find a single matching slot in GPT
// if there is a single slot match, just use that slot name
// finally, there must be multiple slots that match. Define pbadslot as slot#div
pbjs.setConfig({
gptPreAuction: {
enabled: true, // enabled by default
customPbAdSlot: function(adUnitCode, adServerAdSlot) {
// get adunit object
au=pbjs.adUnits.filter(au => au.code==adUnitCode);
if (au.length==0) {
return;
}
// use pbadslot if supplied
if (au[0].ort2bImp && au[0].ort2bImp.ext && au[0].ort2bImp.ext.data && au[0].ort2bImp.ext.data.pbadslot) {
return au[0].ort2bImp.ext.data.pbadslot;
}
// confirm that GPT is set up
if (!(googletag && googletag.apiReady)) {
return;
}
// find all GPT slots with this name
var gptSlots = googletag.pubads().getSlots().filter(function(gpt) {
return gpt.getAdUnitPath() == adServerAdSlot;
});
if (gptSlots.length==0) {
return; // should never happen
}
if (gptSlots.length==1) {
return adServerAdSlot;
}
// else the adunit code must be div id. append it.
return adServerAdSlot+"#"+adUnitCode;
}
});
};
```

# Further Reading
- [Prebid Ad Slot](/features/pbAdSlot.html)
- [Prebid Ad Slot and GPID](/features/pbAdSlot.html)
213 changes: 125 additions & 88 deletions features/pbAdSlot.md
Original file line number Diff line number Diff line change
@@ -1,114 +1,151 @@
---
layout: page_v2
title: Prebid Ad Slot
description: The Prebid Ad Slot
title: Prebid Ad Slot and GPID
description: Prebid Ad Slot and GPID
sidebarType: 1
---

# Prebid Ad Slot
# The Prebid Ad Slot and the GPID
{:.no_toc}

The Prebid AdUnit 'code' is a mixed attribute that's generally either the GPT slot name or the HTML div ID. The undecided nature of the 'code' makes it harder to utilize for reporting and auction targeting.
* TOC
{:toc}

The `Prebid Ad Slot` is an optional inventory management convention allowing publishers to supply a descriptive and stable label for each ad on the page. This makes it possible to have more granular reporting and better deal targeting.
Prebid Ad Slot and the Global Placement ID (GPID) are overlapping conventions that allow publishers to identify ad inventory on their pages so bidders and reporting systems can better deal with their sites.

## Background

It all starts with how publishers decide to label their ad slots: the places on their pages
where ads can be served. In some ad servers like GAM, these things are called "ad units".
Most publishers use unique ad slot names, but some publishers utilize the same name for every ad slot on their page. e.g. "/homepage" might be the name for 5 different slots.

It's the case of 'same ad slot names' that Prebid Ad Slot and GPID are
meant to address.

### The Prebid.js AdUnit

When Prebid.js was developed in 2015, they needed a data structure that would link each ad slot to the bidders and parameters involved in the auction for that slot. Thus was born the Prebid.js [AdUnit](/dev-docs/adunit-reference.html). The AdUnit 'code' is what links this object to the adserver's ad slot. Because some pubs use the same ad slot name everywhere, AdUnit.code is a mixed attribute that can be either the ad slot name **or** the HTML div ID. The undecided nature of AdUnit.code makes it hard to utilize for reporting and auction targeting.

### The Prebid Ad Slot

The 'Prebid Ad Slot' was developed in Prebid.js v3 as an optional inventory management convention allowing publishers to supply a descriptive and stable label for each ad on the page. This makes it possible to have more granular reporting and better deal targeting.
However, the PB ad slot is not an industry standard convention, so didn't gain
much traction.

### The GPID

The Global Placement ID (GPID) was an initiative in the Fall of 2021 led
by the TradeDesk to solve the problem of inventory identification in an industry-wide way. i.e. Buyers want to be able to identify ad slots in a unique way even
when the publisher uses the same ad slot name multiple times.

The original suggestion for GPID was to simply append the HTML div element id (aka the 'div-id') to the ad slot name. But some publishers generate div-ids randomly, so the definition of GPID has become:

```
imp[].ext.gpid: ADSLOTNAME#UNIQUIFIER
```
Where ADSLOTNAME is the ad server's slot name (e.g. /1111/homepage) and UNIQUIFIER is something that makes the ADSLOTNAME different from others. Normally it's a
div-id, but if div-ids are random, it can be something else. The "#UNIQUIFIER" is only required if the ADSLOTNAME isn't unique enough on its own.

{: .alert.alert-info :}
The Prebid Ad Slot was introduced with Prebid.js 3.x.
The Prebid Ad Slot didn't ever get broad adoption, so it's likely that
someday we'll deprecate it in favor of the more standard GPID.

## A Scenario
## Defining Prebid Ad Slot and GPID

1. The publisher utilizes the same 'slotname' in the page for multiple holes-in-the-page, differentiating in the ad server by size. e.g.
- defineSlot('/1111/homepage', [[300,250]], 'div-293rj893p9wje9we9fj');
- defineSlot('/1111/homepage', [[728,90]], 'div-j98s9u9usj987665da');
- defineSlot('/1111/homepage', [[160,600]], 'div-B2q3s4gseshekhsei9sh');
2. In order to be able to display the right ad in the right hole, the Prebid AdUnit therefore sets the 'code' to the div ID instead of the slotname.
3. The div ID in this case is a random number, not very useful for reporting.
4. Therefore, to get a stable ID that's useful from a business perspective to identify a hole-in-the-page, the publisher
decides to add another identifier... the Prebid Ad Slot.
5. The publisher adds a function to the page that annotates each Prebid AdUnit in the auction with the `pbadslot`.
6. Participating bid adapters read the `pbadslot` and can target deals to them.
7. Participating analytics adapters read the `pbadslot` for more granular reporting.

Example page function:
{% highlight js %}

// Use adunit.ortb2Imp.ext.data.pbadslot if it exists. Otherwise, if the
// the adunit.code is a div ID, then look for a data-adslotid attribute, then look a matching slot in GPT
// Otherwise, just use the AdUnit.code
var setPbAdSlot = function setPbAdSlot(adUnits) {
// set pbadslot for all ad units
adUnits.forEach(function (adUnit) {
if (!adUnit.ortb2Imp) {
adUnit.ortb2Imp = {}
}
if (!adUnit.ortb2Imp.ext) {
adUnit.ortb2Imp.ext = {};
}
if (!adUnit.ortb2Imp.ext.data) {
adUnit.ortb2Imp.ext.data = {};
}

// use existing pbadslot if it is already set
if (adUnit.ortb2Imp.ext.data.pbadslot) {
return;
}

// check if AdUnit.code has a div with a matching id value
const adUnitCodeDiv = document.getElementById(adUnit.code);
if (adUnitCodeDiv) {
// try to retrieve a data element from the div called data-adslotid.
if (adUnitCodeDiv.dataset.adslotid) {
adUnit.ortb2Imp.ext.data.pbadslot = adUnitCodeDiv.dataset.adslotid;
return;
}
// Else if AdUnit.code matched a div and it's a banner mediaType and googletag is present
if (adUnit.mediaTypes && typeof adUnit.mediaTypes === 'object' && adUnit.mediaTypes.banner && adUnit.mediaTypes.banner.sizes && window.googletag && googletag.apiReady) {
var gptSlots = googletag.pubads().getSlots();
// look up the GPT slot name from the div.
var linkedSlot = gptSlots.find(function (gptSlot) {
return (gptSlot.getSlotElementId() === adUnitCodeDiv.id);
});
if (linkedSlot) {
adUnit.ortbImp.ext.data.pbadaslot = linkedSlot.getAdUnitPath();
return;
}
}
}
// Else, just use the AdUnit.code, assuming that it's an ad unit slot
adUnit.ortb2Imp.ext.data.pbadslot = adUnit.code;
});
};
There are two ways a publisher can inject these values into the header bidding auctions:

pbjs.onEvent('beforeRequestBids', setPbAdSlot);
1. Supply them manually on the PBJS AdUnits
2. Install the [GPT Pre-Auction module](/dev-docs/modules/gpt-pre-auction.html)

{% endhighlight %}
### Defining them on the PBJS Ad Unit

## How It Works
#### Example 1 - unique ad slot names

The Prebid Ad Slot is just a convention -- it's a form of adunit-specific first party data
stored under `adunit.ortb2Imp.ext.data.pbadslot`.
It can be utilized by any code ready to look for it.
In this example, there's no need for the "UNIQUIFIER" string because every ad slot
on the publisher page is already unique.

It's intended to be specified via Prebid.js in one of two ways:
```
pbjs.addAdUnits({
code: '/1111/homepage-leftnav',
ortb2Imp: {
ext: {
gpid: "/1111/homepage-leftnav",
data: {
pbadslot: "/1111/homepage-leftnav"
}
}
},
mediaTypes: ...
bids: ...
});
```

#### Example 2 - duplicate ad slots

In this example, the publisher's ad slots all have the same name, but at least
the div-ids are unique.

```
pbjs.addAdUnits({
code: 'div-leftnav',
ortb2Imp: {
ext: {
gpid: "/1111/homepage#div-leftnav",
data: {
pbadslot: "/1111/homepage#div-leftnav"
}
}
},
mediaTypes: ...
bids: ...
});
```

1. Either directly on the AdUnit itself
2. Or defined during the run of a function before the auction
#### Example 3 - duplicate ad slots, random div IDs

The function could determine the pbadslot in any way that produces a stable value useful for targeting and reporting.
Some scenarios that could be supported:
In this example, the publisher utilizes the same 'slotname' in the page for multiple holes-in-the-page, differentiating in the ad server by size. They also use random div-ids. e.g.
- defineSlot('/1111/homepage', [[300,250]], 'div-293rj893p9wje9we9fj');
- defineSlot('/1111/homepage', [[728,90]], 'div-j98s9u9usj987665da');

- parse a substring of the ad server's slot name
- use a custom div data element ID, else the AdUnit.code
- use the AdUnit.ortb2Imp.ext.data.pbadslot as a default rather than primary
- support a different ad server
```
pbjs.addAdUnits({
code: 'div-293rj893p9wje9we9fj',
ortb2Imp: {
ext: {
gpid: "/1111/homepage#300x250",
data: {
pbadslot: "/1111/homepage#300x250"
}
}
},
mediaTypes: ...
bids: ...
},{
code: 'div-j98s9u9usj987665da',
ortb2Imp: {
ext: {
gpid: "/1111/homepage#728x90",
data: {
pbadslot: "/1111/homepage#728x90"
}
}
},
mediaTypes: ...
bids: ...
});
```

## Prebid Server

The OpenRTB location for the Prebid Ad Slot is `imp[].ext.data.pbadslot`:
The Prebid Server Bid Adapter just sends the values to the conventional OpenRTB locations:
- Prebid Ad Slot is `imp[].ext.data.pbadslot`
- GPID is `imp[].ext.gpid`

Mobile and AMP Stored Requests should place the values there as desired.

- The Prebid SDK will place the value there.
- AMP Stored Requests should place the value there if desired.
- Server-side bid and anlytics adapters may be modified to read the value.
Server-side bid and anlytics adapters may be modified to read the value.

## Further Reading

- The [onEvent()](/dev-docs/publisher-api-reference/onEvent.html) function
- [GPT Pre-Auction Module](/dev-docs/modules/gpt-pre-auction.html)
- [Ad Unit Reference](/dev-docs/adunit-reference.html)

0 comments on commit 6a4809d

Please sign in to comment.