Back to Publisher API Reference
+ +diff --git a/.gitignore b/.gitignore index c300c925e6..79e892f73a 100755 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ Gemfile.lock .jekyll-metadata *ads.txt.bkp* .sass-cache + +# Files generated by `npm install` +node_modules/ diff --git a/.sass-cache/a8ae1fbf8fe3cf0ae44282e4f927a25624204c54/main.scssc b/.sass-cache/a8ae1fbf8fe3cf0ae44282e4f927a25624204c54/main.scssc new file mode 100644 index 0000000000..6db4f74c3a Binary files /dev/null and b/.sass-cache/a8ae1fbf8fe3cf0ae44282e4f927a25624204c54/main.scssc differ diff --git a/Gemfile b/Gemfile index a0483f2507..cdaf1cdfe5 100755 --- a/Gemfile +++ b/Gemfile @@ -1,2 +1,2 @@ source 'https://rubygems.org' -gem 'github-pages', '>= 30' \ No newline at end of file +gem 'github-pages', '>= 30' diff --git a/README.md b/README.md index 8bf538b48f..b63ccaf775 100755 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ The site uses [Jekyll](https://jekyllrb.com/), which is written in the [Ruby](ht For CSS, the site uses Laravel Mix to build CSS from Sass (scss-flavored) source files. Under the hood Laravel Mix uses Webpack. 1. follow the instructions at https://nodejs.dev to install Node.js for your OS -1. `npm install` to install packages for building assets +1. `npm ci` to install packages for building assets 1. build assets as described below diff --git a/_assets/sass/components/_autocomplete-filter.scss b/_assets/sass/components/_autocomplete-filter.scss new file mode 100644 index 0000000000..71eb86a31e --- /dev/null +++ b/_assets/sass/components/_autocomplete-filter.scss @@ -0,0 +1,12 @@ +.pb-content { + .autocomplete-filter { + padding: 10px 15px; + border: 1px solid #b3c1cc; + background-color: rgba(236, 243, 245, 0.35); + + &:focus { + outline: none; + } + } +} + diff --git a/_assets/sass/components/_bidder-list.scss b/_assets/sass/components/_bidder-list.scss index 55db573e20..53abc427a8 100644 --- a/_assets/sass/components/_bidder-list.scss +++ b/_assets/sass/components/_bidder-list.scss @@ -1,14 +1,4 @@ .pb-content { - .bidder-filter { - padding: 10px 15px; - border: 1px solid #b3c1cc; - background-color: rgba(236, 243, 245, 0.35); - - &:focus { - outline: none; - } - } - .c-bidder-list-group { h4 { color: #797f90; diff --git a/_assets/sass/main.scss b/_assets/sass/main.scss index 29af1a2147..ad4090dbd6 100644 --- a/_assets/sass/main.scss +++ b/_assets/sass/main.scss @@ -34,6 +34,7 @@ @import 'components/social-media'; @import 'components/table'; @import 'components/download-form'; +@import 'components/autocomplete-filter'; @import 'components/bidder-list'; @import 'components/search'; diff --git a/_data/dropdown_v2.yml b/_data/dropdown_v2.yml index a2e3139ba7..268f618bad 100644 --- a/_data/dropdown_v2.yml +++ b/_data/dropdown_v2.yml @@ -349,7 +349,7 @@ sectionId: 4 sectionName: Resources title: Prebid.org - link: http://www.prebid.org + link: https://www.prebid.org needsDivider: 1 isHeader: 0 isSubSectionStart: 1 @@ -358,7 +358,7 @@ sectionId: 4 sectionName: Resources title: Blog - link: http://www.prebid.org/blog + link: https://www.prebid.org/blog needsDivider: 0 isHeader: 0 isSubSectionStart: 1 diff --git a/_data/message.yml b/_data/message.yml deleted file mode 100644 index 987d4697f4..0000000000 --- a/_data/message.yml +++ /dev/null @@ -1,4 +0,0 @@ -#-------------Message---------------- -- messageId: 1 - messageText: Register for our webinar on Aug 27, 2020: How to Make Prebid the Supply Path Buyers Choose - messageCreateDt: 08_04_2020 diff --git a/_data/sidebar.yml b/_data/sidebar.yml index 8219b1f587..27cea0a38e 100644 --- a/_data/sidebar.yml +++ b/_data/sidebar.yml @@ -180,7 +180,7 @@ - sbSecId: 1 title: Native Ads - link: /dev-docs/examples/native-ad-example.html + link: /formats/native.html isHeader: 0 isSectionHeader: 0 sectionTitle: @@ -234,6 +234,15 @@ isSectionHeader: 0 sectionTitle: subgroup: 1 + +- sbSecId: 1 + title: Meta Bid Filtering + link: /dev-docs/examples/meta-bid-filtering.html + Item: 1 + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 1 - sbSecId: 1 title: Troubleshooting @@ -1326,21 +1335,13 @@ subgroup: 1 - sbSecId: 4 - title: 'JW Player (Hosted)' + title: 'JW Player (Self-Hosted)' link: /examples/video/instream/jwplayer/pb-ve-jwplayer-hosted.html isHeader: 0 isSectionHeader: 0 sectionTitle: subgroup: 1 -- sbSecId: 4 - title: 'JW Player (Playlist)' - link: /examples/video/instream/jwplayer/pb-ve-jwplayer-playlist.html - isHeader: 0 - isSectionHeader: 0 - sectionTitle: - subgroup: 1 - - sbSecId: 4 title: 'Kaltura' link: /examples/video/instream/kaltura/pb-ve-kaltura.html @@ -1399,29 +1400,13 @@ subgroup: 1 - sbSecId: 4 - title: 'JW Player (Hosted)' + title: 'JW Player (Self-Hosted)' link: /examples/video/server/jwplayer/pbs-ve-jwplayer-hosted.html isHeader: 0 isSectionHeader: 0 sectionTitle: subgroup: 1 -- sbSecId: 4 - title: 'JW Player (Playlist)' - link: /examples/video/server/jwplayer/pbs-ve-jwplayer-playlist.html - isHeader: 0 - isSectionHeader: 0 - sectionTitle: - subgroup: 1 - -- sbSecId: 4 - title: 'JW Player (Player 7)' - link: /examples/video/server/jwplayer/pbs-ve-jwplayer-jwplayer7.html - isHeader: 0 - isSectionHeader: 0 - sectionTitle: - subgroup: 1 - - sbSecId: 4 title: 'Kaltura' link: /examples/video/server/kaltura/pbs-ve-kaltura.html @@ -1737,6 +1722,14 @@ sectionTitle: subgroup: 3 +- sbSecId: 5 + title: Programmatic Guaranteed + link: /prebid-server/features/pg/pbs-pg-idx.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 3 + - sbSecId: 5 title: Developers link: @@ -1934,7 +1927,7 @@ - sbSecId: 6 title: Native - link: /dev-docs/show-native-ads.html + link: /prebid/native-implementation.html isHeader: 0 isSectionHeader: 0 sectionTitle: @@ -2046,3 +2039,41 @@ isSectionHeader: 0 sectionTitle: subgroup: 0 + +#-------------- Prebid Identity --------------| + +- sbSecId: 9 + title: + link: + isHeader: 0 + isSectionHeader: 1 + sectionTitle: Prebid Identity + sectionId: prebid-identity + subgroup: 1000 + sbCollapseId: prebid-identity + +- sbSecId: 9 + title: invis + link: + isHeader: 1 + headerId: invis + isSectionHeader: 0 + sectionTitle: + subgroup: 0 + +- sbSecId: 9 + title: Identity Overview + link: /identity/prebid-identity.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 0 + +- sbSecId: 9 + title: SharedID + link: /identity/sharedid.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 0 + diff --git a/_includes/adops/adops-gam-video-setup.html b/_includes/adops/adops-gam-video-setup.html index 4583b57ea4..1825186ccd 100644 --- a/_includes/adops/adops-gam-video-setup.html +++ b/_includes/adops/adops-gam-video-setup.html @@ -29,7 +29,7 @@
1. For each line item you create, click on the Creatives tab, click the ADD CREATIVE button, and choose the size you're entering.
@@ -75,18 +70,21 @@4. Set the Duration to 1.
+4. Set the Duration to the max length of video ads you serve. If you don't know what the max length is, set it to 30.
+ +In the past Prebid used to recommend setting duration to 0 or 1, but GAM now requires that this field reflect the actual video ad length. Since ads flowing through header bidding are going to differ in length, choose a value that matches a common ad length like 15 or 30.
The resulting creative should look something like the following:

Back to Publisher API Reference
+ +- On the JSFiddle example below, click Result to see the result. -
- -- Click Edit in JSFiddle to open the example in a new tab. -
-For tips and troubleshooting info, see:
+ On the JSFiddle example below: +
+
+ pbjs.setConfig()
-- See the the API reference for more detail.
+- See the the API reference for more detail.
jsfiddle_link: jsfiddle.net/Prebid_Examples/vq05dhnj/2/embedded/html,result
diff --git a/dev-docs/examples/meta-bid-filtering.md b/dev-docs/examples/meta-bid-filtering.md
new file mode 100644
index 0000000000..6fe914df06
--- /dev/null
+++ b/dev-docs/examples/meta-bid-filtering.md
@@ -0,0 +1,15 @@
+---
+layout: example
+title: Meta Bid Filtering
+left_nav_override: Examples
+description: Bid filtering on meta object example
+sidebarType: 1
+
+about:
+- Bidders can supply metadata about the bid such as advertiser domain. See the "meta" fields in the bid response for the full list.
+- This is an example that filters bid responses based on the metadata object.
+
+jsfiddle_link: jsfiddle.net/Prebid_Examples/0s4eug1d/18/embedded/html,result
+
+code_height: 2300
+---
diff --git a/dev-docs/faq.md b/dev-docs/faq.md
index 0767e28a96..805f7a1256 100644
--- a/dev-docs/faq.md
+++ b/dev-docs/faq.md
@@ -50,11 +50,11 @@ In both scenarios, your goal should be to see your inventory fill at the highest
There is an analysis from the Prebid team here which may be useful:
-[How many bidders should I work with?]({{site.baseurl}}/blog/how-many-bidders-for-header-bidding)
+[How many bidders should I work with?](https://prebid.org/blog/how-many-bidders-for-header-bidding)
## Does Prebid.js cache bids?
-It can. Versions 1.x of Prebid.js would re-consider previous bids under limited circumstances. In Prebid.js 2.0 and later, the [`useBidCache`](/dev-docs/publisher-api-reference.html#setConfig-Use-Bid-Cache) option can be used to enable this functionality.
+It can. Versions 1.x of Prebid.js would re-consider previous bids under limited circumstances. In Prebid.js 2.0 and later, the [`useBidCache`](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Use-Bid-Cache) option can be used to enable this functionality.
The "limited bid caching" feature applies only:
@@ -66,7 +66,7 @@ The "limited bid caching" feature applies only:
Since the storage is in the browser, cached bids only apply to a single page context. If the user refreshes the page, the bid is lost.
Each bid adapter defines the amount of time their bids can be cached and reconsidered.
-This setting is called “Time to Live” (TTL), documented in the pbjs.getBidResponse [parameter table here]({{site.baseurl}}/dev-docs/publisher-api-reference.html#module_pbjs.getBidResponses).
+This setting is called “Time to Live” (TTL), documented in the pbjs.getBidResponse [parameter table here](/dev-docs/publisher-api-reference/getBidResponses.html).
Examples of scenarios where a bid may be reconsidered in Prebid.js:
@@ -81,13 +81,13 @@ Here's how it works:
1. When all the new bids are back or the timeout is reached, Prebid.js considers both the new bids on that AdUnit and previously cached bids.
1. Previously cached bids will be discarded if they've reached their TTL or if they have status `targetingSet` or `rendered`.
1. A cached bid may be used if its CPM beats the new bids.
-1. Bids that win are removed from the pool. This is automatic for display and native ads, and can be done manually by the publisher for video ads by using the [markWinningBidAsUsed]({{site.github.url}}/dev-docs/publisher-api-reference.html#module_pbjs.markWinningBidAsUsed) function.
+1. Bids that win are removed from the pool. This is automatic for display and native ads, and can be done manually by the publisher for video ads by using the [markWinningBidAsUsed](/dev-docs/publisher-api-reference/markWinningBidAsUsed.html) function.
## Some of my demand partners send gross bids while others send net bids; how can I account for this difference?
You will want to adjust the gross bids so that they compete fairly with the rest of your demand, so that you are seeing the most revenue possible.
-In Prebid.js, you can use a `bidCpmAdjustment` function in [the `bidderSettings` object]({{site.baseurl}}/dev-docs/publisher-api-reference.html#module_pbjs.bidderSettings) to adjust any bidder that sends gross bids.
+In Prebid.js, you can use a `bidCpmAdjustment` function in [the `bidderSettings` object](/dev-docs/publisher-api-reference/bidderSettings.html) to adjust any bidder that sends gross bids.
## Does Prebid.js support synchronous ad server tags?
@@ -131,7 +131,7 @@ Prebid.org does not support any version of Prebid.js prior to the previous versi
## How can I change the price granularity for different ad units?
-If you need different [price granularities]({{site.baseurl}}/dev-docs/publisher-api-reference.html#setConfig-Price-Granularity) for different AdUnits (e.g. video and display), the only way for now is to make sure the auctions don't run at the same time. e.g. Run one of them first, then kick off the other in the bidsBackHandler. e.g. here's one approach:
+If you need different [price granularities](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Price-Granularity) for different AdUnits (e.g. video and display), the only way for now is to make sure the auctions don't run at the same time. e.g. Run one of them first, then kick off the other in the bidsBackHandler. e.g. here's one approach:
1. Call `setConfig` to define the priceGranularity for the first set of AdUnits
1. Initiate the first auction with `requestBids`
@@ -144,11 +144,11 @@ The handling of this scenario will be improved in a future release.
## How can I control how many targeting variables are sent to my ad server?
-One way to limit the number of bytes sent to the ad server is to send only the winning bid by disabling the [enableSendAllBids](/dev-docs/publisher-api-reference.html#setConfig-Send-All-Bids) option. However, there are optimization and reporting
+One way to limit the number of bytes sent to the ad server is to send only the winning bid by disabling the [enableSendAllBids](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Send-All-Bids) option. However, there are optimization and reporting
benefits for sending more than one bid.
Once you find the right balance for your application, you can specify
-what's sent to the ad server with [targetingControls.auctionKeyMaxChars](/dev-docs/publisher-api-reference.html#setConfig-targetingControls) and/or [sendBidsControl.bidLimit](/dev-docs/publisher-api-reference.html#setConfig-Send-Bids-Control)
+what's sent to the ad server with [targetingControls.auctionKeyMaxChars](/dev-docs/publisher-api-reference/setConfig.html#setConfig-targetingControls) and/or [sendBidsControl.bidLimit](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Send-Bids-Control)
## Can I run multiple different versions of Prebid.js concurrently?
@@ -160,8 +160,21 @@ It's technically possible, but we don't recommend doing this:
If all this wasn't enough to warn you away from trying, it should work if you name the PBJS global differently for each instance (https://github.com/prebid/Prebid.js/blob/master/package.json#L20)
+## Can I filter bid responses that don't meet my criteria?
+
+Yes. Many bidders provide metadata about the bid that can be used in troubleshooting
+and filtering. See the [list of bid response metadata](/dev-docs/bidder-adaptor.html#interpreting-the-response) and the [filtering example](/dev-docs/examples/meta-bid-filtering.html).
+
+## Does Prebid.js resolve the AUCTION_PRICE macro?
+
+Yes, but in a way that could cause discrepancies in reporting. It's recommended
+that [bid adapters resolve OpenRTB macros](/dev-docs/bidder-adaptor.html#resolve-openrtb-macros-in-the-creatives) themselves before giving them to Prebid.js.
+
+For historic reasons, Prebid will resolve the AUCTION_PRICE macro, but it will be after currency conversion and any bid adjustments.
+This differs from how OpenRTB defines this value as being the clearing price in the bid currency. Header Bidding is a first-price auction, the best candidate for “clearing price” is the original bid itself.
+
## Related Reading
-+ [Prebid.js Dev Tips]({{site.baseurl}}/dev-docs/troubleshooting-tips.html)
-+ [Prebid.js Common Issues]({{site.baseurl}}/dev-docs/common-issues.html)
++ [Prebid.js Troubleshooting Guide](/troubleshooting/troubleshooting-guide.html)
++ [Prebid.js Common Issues](/dev-docs/common-issues.html)
+ [Prebid.js issues tagged 'question'](https://github.com/prebid/Prebid.js/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Aquestion%20)
diff --git a/dev-docs/integrate-with-the-prebid-analytics-api.md b/dev-docs/integrate-with-the-prebid-analytics-api.md
index 59a49042b1..15aec64b6b 100644
--- a/dev-docs/integrate-with-the-prebid-analytics-api.md
+++ b/dev-docs/integrate-with-the-prebid-analytics-api.md
@@ -71,7 +71,7 @@ Analytics adapter for Example.com. Contact prebid@example.com for information.
1. Create a JS file under `modules` with the name of the bidder suffixed with 'AnalyticsAdapter', e.g., `exAnalyticsAdapter.js`
-2. Create an analytics adapter to listen for [Prebid events](/dev-docs/publisher-api-reference.html#module_pbjs.onEvent) and call the analytics library or server. See the existing *AnalyticsAdapter.js files in the repo under [modules](https://github.com/prebid/Prebid.js/tree/master/modules).
+2. Create an analytics adapter to listen for [Prebid events](/dev-docs/publisher-api-reference/onEvent.html) and call the analytics library or server. See the existing *AnalyticsAdapter.js files in the repo under [modules](https://github.com/prebid/Prebid.js/tree/master/modules).
3. There are two types of analytics adapters. The example here focuses on the 'endpoint' type. See [AnalyticsAdapter.js](https://github.com/prebid/Prebid.js/blob/master/src/AnalyticsAdapter.js) for more info on the 'bundle' type.
diff --git a/dev-docs/modules/adpod.md b/dev-docs/modules/adpod.md
index 519b1a1a87..0519cd9db6 100644
--- a/dev-docs/modules/adpod.md
+++ b/dev-docs/modules/adpod.md
@@ -2,7 +2,7 @@
layout: page_v2
page_type: module
title: Module - Adpod
-description: Adds functions to validate, cache, and modify long-form video bids.
+description: Enables developers to add support for a new adserver that handles ad pod (long-form) videos.
module_code : adpod
display_name : Adpod
enable_download : true
diff --git a/dev-docs/modules/bidViewable.md b/dev-docs/modules/bidViewable.md
index 41aa46272b..a9da963a12 100644
--- a/dev-docs/modules/bidViewable.md
+++ b/dev-docs/modules/bidViewable.md
@@ -1,15 +1,16 @@
---
layout: page_v2
page_type: module
-title: Module - Bid Viewable Event
-description: Triggers BID_VIEWABLE event when a rendered PBJS-Bid is viewable according to [Active View criteria](https://support.google.com/admanager/answer/4524488)
+title: Module - Bid Viewability - GAM
+description: Triggers a BID_VIEWABLE event when a rendered bid is viewable according to Active View criteria
module_code : bidViewability
-display_name : Bid Viewable Event
+display_name : Bid Viewability - GAM
enable_download : true
+vendor_specific: true
sidebarType : 1
---
-# Bid Viewable Event
+# Bid Viewability - GAM
{:.no_toc}
* TOC
@@ -17,35 +18,39 @@ sidebarType : 1
## Overview
-This optional module will trigger a BID_VIEWABLE event which can be consumed by Analytics adapters, bidders will need to implement `onBidViewable` method to capture this event
-
+This optional module will trigger a BID_VIEWABLE event which can be consumed by Analytics adapters. In addition, the winning bidder can implement an `onBidViewable` method to capture this event.
Notes:
-- The module does not work with adservers other than GAM and only with GPT integration.
-- The GPT API is used to find when a bid is viewable, See https://developers.google.com/publisher-tag/reference#googletag.events.impressionviewableevent .
+- The module does not work with adservers other than GAM and only with GPT integration. See the [other Bid Viewable Event](/dev-docs/modules/bidViewableIO.html) module for an ad server independent version.
+- The GPT API is used to find when a bid is viewable. See [GPT documentation](https://developers.google.com/publisher-tag/reference#googletag.events.impressionviewableevent) for more details.
- This event is fired when an impression becomes viewable, according to [Active View criteria](https://support.google.com/admanager/answer/4524488).
-- Logic used to find a matching Prebid.js bid for a GPT slot is ` (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode) ` this logic can be changed by using param ` customMatchFunction `
- When a rendered PBJS bid is viewable the module will trigger BID_VIEWABLE event, which can be consumed by the winning bidder and analytics adapters
- The module works with Banner, Outsteam and Native creatives
-Instead of listening for events, bidders may supply a ` bid.vurls ` array and this module may fire those pixels when the viewability signal is received. Publishers can control this with module config ` firePixels: true `. Please note that GDPR and USP related parameters will be added to the given URLs.
+Instead of listening for events, bidders may supply a `bid.vurls` array and this module may fire those pixels when the viewability signal is received. Publishers can control this with module config ` firePixels: true `. Please note that GDPR and USP related parameters will be added to the given URLs.
{: .alert.alert-warning :}
-This feature doesn't seem to work with [Instream Video](/dev-docs/examples/instream-banner-mix.html), as GPT's impressionViewable event is not triggered for instream-video-creative
+This feature doesn't work with [Instream Video](/dev-docs/examples/instream-banner-mix.html), as GPT's impressionViewable event is not triggered for instream-video-creative
+
+The default logic used to find a matching Prebid.js bid for a GPT slot is
+```
+(bid, slot) => (slot.getAdUnitPath() === bid.adUnitCode ||
+ slot.getSlotElementId() === bid.adUnitCode)
+```
## Configuration
{: .table .table-bordered .table-striped }
-| Field | Scope | Type | Description |
-|----------+---------+--------+---------------------------------------------------------------------------------------|
-| `bidViewability` | Required | Object | Configuration object for instream tracking |
+| Field | Scope | Type | Description |
+|----------+---------+--------+-----------------------------------------|
+| `bidViewability` | Required | Object | Configuration object |
| `bidViewability.enabled` | Required | Boolean | when set to true, the module will emit BID_VIEWABLE when applicable. Default: `false` |
| `bidViewability.firePixels` | Optional | Boolean | when set to true, will fire the urls mentioned in `bid.vurls` which should be array of URLs. Default: `false` |
-| `bidViewability.customMatchFunction` | Optional | function(bid, slot) | when passed this function will be used to `find` the matching winning bid for the GPT slot. Default value is ` (bid, slot) => (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode) ` |
+| `bidViewability.customMatchFunction` | Optional | function(bid, slot) | this function will be used to find the matching winning bid for the GPT slot. See above for the default. |
## Example of setting module config
{% highlight js %}
- pbjs.setConfig({
+ pbjs.setConfig({
bidViewability: {
enabled: true,
firePixels: true,
@@ -63,3 +68,8 @@ This feature doesn't seem to work with [Instream Video](/dev-docs/examples/instr
console.log('got bid details in bidViewable event', bid);
});
{% endhighlight %}
+
+## Related Reading
+
+- [Building a PBJS analytics adapter](/dev-docs/integrate-with-the-prebid-analytics-api.html)
+- [Building a PBJS bidder adapter](/dev-docs/bidder-adaptor.html)
diff --git a/dev-docs/modules/bidViewableIO.md b/dev-docs/modules/bidViewableIO.md
new file mode 100644
index 0000000000..b483bc5b80
--- /dev/null
+++ b/dev-docs/modules/bidViewableIO.md
@@ -0,0 +1,66 @@
+---
+layout: page_v2
+page_type: module
+title: Module - Bid Viewability - Ad Server Independent
+description: Triggers a BID_VIEWABLE event when a rendered bid is viewable according to an approximation of IAB viewability criteria
+module_code : bidViewabilityIO
+display_name : Bid Viewability - Ad Server Independent
+enable_download : true
+sidebarType : 1
+---
+
+# Bid Viewability - Ad Server Independent
+{:.no_toc}
+
+* TOC
+{:toc}
+
+## Overview
+
+This optional module will trigger a BID_VIEWABLE event which can be consumed by Analytics adapters. In addition, the winning bidder can implement an `onBidViewable` method to capture this event.
+
+Notes:
+- The module works with any adserver, or with no ad server at all.
+- Publishers using GAM/GPT might consider using the [Bid Viewable Event - GAM](/dev-docs/modules/bidViewable.html) module
+- Requires the site to polyfill the [IntersectionObserver API](https://github.com/w3c/IntersectionObserver/tree/main/polyfill) (v1) to find when a bid is viewable. This implementation assumes that the publisher and the bidder are acting in good faith, and does not attempt to detect any bad behavior from either party. We assume that the ad is rendered into the element it has been told to render into, and is not hidden or obfuscated at any time.
+- This event is fired when an impression becomes viewable, according to IAB's viewability guidelines
+- When a rendered PBJS bid is determined to be viewable this module will trigger a BID_VIEWABLE event, which can be consumed by the winning bidder and analytics adapters
+- The module works with Banner creatives, with additional support to come.
+
+## Known Issues
+
+{: .alert.alert-warning :}
+This feature is not intended to be a perfect measure of viewability. It is however intended to be a reasonable approximation of a bids viewability for creative types that are supported.
+
+1. Only supports Banner creatives
+2. Only works on browsers that support or on sites that have [polyfilled the IntersectionObserver API](https://github.com/w3c/IntersectionObserver/tree/main/polyfill)
+3. Results can only be trusted if both the publisher and winning bidder are assumed to be acting in good faith.
+
+## Configuration
+
+{: .table .table-bordered .table-striped }
+| Field | Scope | Type | Description |
+|----------+---------+--------+---------------------------------------------------------------------------------------|
+| `bidViewabilityIO` | Required | Object | Configuration object for viewability tracking for supported media types (IO stands for IntersectionObserver) |
+| `bidViewabilityIO.enabled` | Required | Boolean | when set to true, the module will emit BID_VIEWABLE when applicable. Default: `false` |
+
+## Example of setting module config
+{% highlight js %}
+ pbjs.setConfig({
+ bidViewabilityIO: {
+ enabled: true,
+ }
+ });
+{% endhighlight %}
+
+## Example of consuming BID_VIEWABLE event
+{% highlight js %}
+ pbjs.onEvent('bidViewable', function(bid){
+ console.log('got bid details in bidViewable event', bid);
+ });
+{% endhighlight %}
+
+## Related Reading
+
+- [Building a PBJS analytics adapter](/dev-docs/integrate-with-the-prebid-analytics-api.html)
+- [Building a PBJS bidder adapter](/dev-docs/bidder-adaptor.html)
diff --git a/dev-docs/modules/browsiRtdProvider.md b/dev-docs/modules/browsiRtdProvider.md
index 6d269adf3a..062f47f45f 100644
--- a/dev-docs/modules/browsiRtdProvider.md
+++ b/dev-docs/modules/browsiRtdProvider.md
@@ -7,6 +7,7 @@ page_type: module
module_type: rtd
module_code : browsiRtdProvider
enable_download : true
+vendor_specific: true
sidebarType : 1
---
diff --git a/dev-docs/modules/categoryTranslation.md b/dev-docs/modules/categoryTranslation.md
index 6ba65349f7..cb1bd0f987 100644
--- a/dev-docs/modules/categoryTranslation.md
+++ b/dev-docs/modules/categoryTranslation.md
@@ -2,7 +2,7 @@
layout: page_v2
page_type: module
title: Module - Category Translation
-description: Converts IAB sub category to ad server group.
+description: Converts IAB category to ad server category for long-form videos.
module_code : categoryTranslation
display_name : CategoryTranslation
enable_download : true
@@ -24,7 +24,7 @@ The module provides the following:
## How to use the module:
1. A Prebid.js package is built that contains this module and the Ad server module. Prebid supports [FreeWheel](/dev-docs/modules/freewheel.html) and Google Ad Manager ad servers.
-2. The inclusion of this module and long-form ad server module causes Prebid to download a mapping file to local storage. The user also has the option to provide their own mapping file.
+2. The inclusion of this module and long-form ad server module causes Prebid to download a mapping file to local storage. The user also has the option to provide their own mapping file. The default ad server is Freewheel. To hook to the DFP video ad server module you must configure it in the mapping url.
3. At runtime, brand category translation happens as needed.
diff --git a/dev-docs/modules/consentManagement.md b/dev-docs/modules/consentManagement.md
index e28579f9f8..f3ea32002f 100644
--- a/dev-docs/modules/consentManagement.md
+++ b/dev-docs/modules/consentManagement.md
@@ -2,10 +2,11 @@
layout: page_v2
page_type: module
title: Consent Management - GDPR
-description: Module to consume and distribute GDPR consent information to bidder adapters
+description: If you have users in Europe, this module works with your Consent Management Platform to pass consent info to bidders and help align with EU regulations. See also the GDPR Enforcement module.
module_code : consentManagement
display_name : Consent Management - GDPR
enable_download : true
+recommended: true
sidebarType : 1
---
@@ -22,7 +23,7 @@ sidebarType : 1
{% include /alerts/alert_important.html content=legalNotice %}
{: .alert.alert-warning :}
-Prebid.org is working on updates that will enable support for reading and parsing TCF 2.0 consent strings. See the [blog post](/blog/tcf2) for timelines.
+Prebid.org is working on updates that will enable support for reading and parsing TCF 2.0 consent strings. See the [blog post](https://prebid.org/blog/tcf2) for timelines.
## Overview
@@ -58,7 +59,7 @@ Please start by understanding the IAB's [TCF Implementation Guide](https://githu
To utilize this module, a Consent Management Platform (CMP) compatible with the [IAB TCF v1.1 spec](https://iabeurope.eu/all-news/the-iab-europe-transparency-consent-framework-tcf-steering-group-votes-to-extend-technical-support-for-tcf-v1-1/) or [IAB TCF v2.0 spec](https://iabeurope.eu/tcf-2-0/) needs to be implemented on the site to interact with the user and obtain their consent choices. It's important to understand the details of how the CMP works before integrating it with Prebid.js
-In general, implementation details for CMPs are not covered by Prebid.org, but we do recommend to that you place the CMP code before the Prebid.js code in the head of the page in order to ensure the CMP's framework is loaded before the Prebid code executes. In addition, the community is collecting a set of [CMP best practices](/dev-docs/cmp-best-practices.html).
+In general, implementation details for CMPs are not covered by Prebid.org, but we do recommend to that you place the CMP code before the Prebid.js code in the head of the page in order to ensure the CMP's framework is loaded before the Prebid code executes. In addition, the community is collecting a set of [CMP best practices](/dev-docs/cmp-best-practices.html).
Once the CMP is implemented, simply include this module into your build and add a `consentManagement` object in the `setConfig()` call. Adapters that support this feature will then be able to retrieve the consent information and incorporate it in their requests.
@@ -318,8 +319,8 @@ Here are some things that publishers can do to control various activities:
1. If the current page view is known to be in GDPR scope, make sure the adapters are aware of it even on the first page where CMP hasn't been activated by setting the defaultGdprScope: `consentManagement.gdpr.defaultGdprScope: true`
2. If the user hasn't consented to Purpose 1:
- - Set [deviceAccess: false](/dev-docs/publisher-api-reference.html#setConfig-deviceAccess)
- - Don't enable [userSync](/dev-docs/publisher-api-reference.html#setConfig-Configure-User-Syncing)
+ - Set [deviceAccess: false](/dev-docs/publisher-api-reference/setConfig.html#setConfig-deviceAccess)
+ - Don't enable [userSync](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Configure-User-Syncing)
- Don't enable [userId](/dev-docs/modules/userId.html) modules
3. If you're working with bidders that don't support GDPR, consider dynamically populating adunits as needed. See the list below for bidders supporting GDPR.
diff --git a/dev-docs/modules/consentManagementUsp.md b/dev-docs/modules/consentManagementUsp.md
index c365dd0ce5..ddfa9be3fc 100644
--- a/dev-docs/modules/consentManagementUsp.md
+++ b/dev-docs/modules/consentManagementUsp.md
@@ -2,10 +2,11 @@
layout: page_v2
page_type: module
title: Consent Management - US Privacy
-description: Module to consume and distribute US Privacy information to bidder adapters
+description: If you have users in California, this module works with your Consent Management Platform to pass CCPA/US-Privacy data to bidders.
module_code : consentManagementUsp
display_name : Consent Management - US Privacy
enable_download : true
+recommended: true
sidebarType : 1
---
diff --git a/dev-docs/modules/currency.md b/dev-docs/modules/currency.md
index 94a79fb63d..bc8dd3562d 100644
--- a/dev-docs/modules/currency.md
+++ b/dev-docs/modules/currency.md
@@ -2,7 +2,7 @@
layout: page_v2
page_type: module
title: Module - Currency
-description: Converts bids to the ad server currency
+description: Converts bid currency into ad server currency based on data in a supplied exchange rate file.
module_code : currency
display_name : Currency
enable_download : true
@@ -17,7 +17,7 @@ sidebarType : 1
This module supports the conversion of multiple bidder currencies into a single currency
used by the publisher's ad server. In previous versions of Prebid, this was accomplished
-by using [BidderSettings.bidCpmAdjustment]({{site.baseurl}}/dev-docs/publisher-api-reference.html#module_pbjs.bidderSettings), but that's a static value not changed except when
+by using [BidderSettings.bidCpmAdjustment]({{site.baseurl}}/dev-docs/publisher-api-reference/bidderSettings.html), but that's a static value not changed except when
the web development team makes a manual update.
Publishers may continue to use the bidCpmAdjustment approach, or may begin using this optional module, gaining automatic updates as currency exchange rates fluctuate. Here's how it works at a high level:
@@ -181,8 +181,9 @@ pbjs.setConfig({
}
});
{% endhighlight %}
-Note that the `defaultRates` attribute is optional, but recommended in case
-there's an issue loading the currency file.
+
+{: .alert.alert-warning :}
+Note that the `defaultRates` attribute is optional, but recommended in case there's an issue loading the currency file.
In this example, the publisher is providing their own `conversionRateFile`:
{% highlight js %}
@@ -248,7 +249,7 @@ a currency object that may contain several parameters:
| granularityMultiplier | `decimal` | How much to scale the price granularity calculations. Defaults to 1. | 108 |
| conversionRateFile | `URL` | Optional path to a file containing currency conversion data. See below for the format. Prebid.org hosts a file as described in the next section. | `https://example.com/rates.json` |
| rates | object | This optional argument allows you to specify the rates with a JSON object, subverting the need for the conversionRateFile parameter. If this argument is specified, the conversion rate file will not be loaded. | { 'USD': { 'CNY': 6.8842, 'GBP': 0.7798, 'JPY': 110.49 } } |
-| defaultRates | `object` | An optional parameter that defines a default rate that can be used if the currency file cannot be loaded. This option isn't used when the `rates` parameter is supplied. | { 'USD': { 'GPB': 0.75 }} |
+| defaultRates | `object` | An optional **but highly recommended** parameter that defines a default rate that can be used if the currency file cannot be loaded. This option isn't used when the `rates` parameter is supplied. | { 'USD': { 'GPB': 0.75 }} |
| bidderCurrencyDefault | `object` | This is an optional argument to provide publishers a way to define which currency is used by a particular bidder. This option was provided as a transition until such a time that most bidder adapters define currency on bid response and is kept for legacy 0.x integrations. | { "bidderXYZ": "GBP" } |
## Currency Rate Conversion File
diff --git a/dev-docs/modules/dfp_express.md b/dev-docs/modules/dfp_express.md
index 598fb1c126..fef264c9db 100644
--- a/dev-docs/modules/dfp_express.md
+++ b/dev-docs/modules/dfp_express.md
@@ -2,10 +2,11 @@
layout: page_v2
page_type: module
title: Module - Google Ad Manager Express
-description: Simplified installation mechanism for publishers that have Google Ad Manager in their pages
+description: A simplified installation mechanism for publishers that have Google Publisher Tag (GPT) ad calls in their pages.
module_code : express
display_name : Google Ad Manager Express
enable_download : true
+vendor_specific: true
sidebarType : 1
---
diff --git a/dev-docs/modules/dfp_video.md b/dev-docs/modules/dfp_video.md
index 8477587a42..e9219ac3b6 100644
--- a/dev-docs/modules/dfp_video.md
+++ b/dev-docs/modules/dfp_video.md
@@ -2,31 +2,32 @@
layout: page_v2
page_type: module
title: Module - Google Ad Manager Video
-description: Addition of DFP Video to the Prebid package
+description: Required for serving instream video through Google Ad Manager.
module_code : dfpAdServerVideo
-display_name : DFP Video
+display_name : Google Ad Manager Video Support
enable_download : true
+vendor_specific: true
sidebarType : 1
---
-# DFP Video
+# Google Ad Manager Video
{:.no_toc}
-This module is required to use the Prebid Instream video examples with DFP Adserver. For instructions showing how to add this module to Prebid.js, see below.
+This module is required to use the Prebid Instream video examples with Google Ad Manager. For instructions showing how to add this module to Prebid.js, see below.
### Step 1: Prepare the base Prebid file as usual
The standard options:
-- Build from a locally-cloned git repo
-- Receive the email package from the Prebid [Download]({{site.baseurl}}/download.html) page
-
+- Build from a locally-cloned git repo
+- Receive the email package from the Prebid [Download](/download.html) page
+
### Step 2: Integrate into your prebid.js configuration
-The method exposes the [`pbjs.adServers.dfp.buildVideoUrl`]({{site.baseurl}}/dev-docs/publisher-api-reference.html#module_pbjs.adServers.dfp.buildVideoUrl) method to use. For an example, see the DFP video guide linked below.
+The method exposes the [`pbjs.adServers.dfp.buildVideoUrl`]({{site.baseurl}}/dev-docs/publisher-api-reference/adServers.dfp.buildVideoUrl.html) method to use. For an example, see the DFP video guide linked below.
## Further Reading
-+ [Show Video Ads with DFP]({{site.baseurl}}/dev-docs/show-video-with-a-dfp-video-tag.html)
++ [Show Video Ads with GAM](/dev-docs/show-video-with-a-dfp-video-tag.html)
diff --git a/dev-docs/modules/dgkeywordRtdProvider.md b/dev-docs/modules/dgkeywordRtdProvider.md
new file mode 100644
index 0000000000..217971cc31
--- /dev/null
+++ b/dev-docs/modules/dgkeywordRtdProvider.md
@@ -0,0 +1,59 @@
+---
+layout: page_v2
+title: Digital Garage Keyword Module
+display_name: Digital Garage Keyword
+description: Digital Garage Keyword
+page_type: module
+module_type: rtd
+module_code : dgkeywordRtdProvider
+enable_download : true
+vendor_specific: true
+sidebarType : 1
+---
+
+# Digital Garage Keyword Module
+{:.no_toc}
+
+* TOC
+{:toc}
+
+## Integration
+
+1) Compile the Digital Garage Keyword Module and Appnexus Bid Adapter into your Prebid build:
+
+```
+gulp build --modules="dgkeywordRtdProvider,appnexusBidAdapter,..."
+```
+
+2) Use `setConfig` to instruct Prebid.js to initilize the dgkeyword module, as specified below.
+
+## Configuration
+
+This module is configured as part of the `realTimeData.dataProviders`
+
+```javascript
+var DGKEYWORD_TIMEOUT = 1000;
+pbjs.setConfig({
+ realTimeData: {
+ auctionDelay: DGKEYWORD_TIMEOUT,
+ dataProviders: [{
+ name: 'dgkeyword',
+ waitForIt: true,
+ params: {
+ timeout: DGKEYWORD_TIMEOUT
+ }
+ }]
+ }
+});
+```
+
+Syntax details:
+
+{: .table .table-bordered .table-striped }
+| Name |Type | Description | Notes |
+| :------------ | :------------ | :------------ |:------------ |
+| name | String | Real time data module name | Always 'dgkeyword' |
+| waitForIt | Boolean | Should be `true` if there's an `auctionDelay` defined (optional) | `false` |
+| params | Object | | |
+| params.timeout | Integer |timeout (ms)| 1000 |
+
diff --git a/dev-docs/modules/enrichmentFpdModule.md b/dev-docs/modules/enrichmentFpdModule.md
new file mode 100644
index 0000000000..857c4f2129
--- /dev/null
+++ b/dev-docs/modules/enrichmentFpdModule.md
@@ -0,0 +1,61 @@
+---
+layout: page_v2
+page_type: module
+title: Module - First Party Data Enrichment
+description: Injects additional data into the auction stream, including: domain, keywords, and page url.
+module_code : enrichmentFpdModule
+display_name : First Party Data Enrichment
+enable_download : true
+recommended: true
+sidebarType : 1
+---
+
+# First Party Data Enrichment Module
+{:.no_toc}
+
+This module adds a number of First Party Data (FPD) fields from the environment.
+
+Add it to the Prebid.js build with this command:
+```
+gulp build --modules=enrichmentFpdModule
+```
+
+If included in the build, it will automatically perform the enrichments unless controlled with setConfig:
+
+```
+pbjs.setConfig({
+ firstPartyData: {
+ skipEnrichments: true // defaults to false
+ }
+});
+```
+
+## How it works
+
+When the first auction on the page is run, this module merges a number of values into the `ortb2` object. Specific details below.
+
+If the publisher needs to refresh the enriched FPD after the first auction, this can be done using a function provided by this module:
+
+```
+pbjs.refreshFpd();
+```
+
+## Enrichments
+
+{: .table .table-bordered .table-striped }
+| Page Source | ortb2 field | Notes |
+|---+---+---|
+| page URL | site.page | Uses pbjs getRefererInfo().canonicalUrl |
+| referer URL | site.ref | Uses pbjs getRefererInfo().referer |
+| host domain | site.domain | Pulled from the getRefererInfo().canonicalUrl the host domain is used with the www component dropped. |
+| aggregated domain | site.publisher.domain | The highest level domain in which cookies can be set. |
+| viewport width | device.w | Hunts for window.innerWidth, window.document.documentElement.clientWidth, window.document.body.clientWidth |
+| viewport height | device.w | Hunts for window.innerHeight, window.document.documentElement.clientHeight, window.document.body.clientHeight |
+| meta keywords | site.keywords | Looks for a meta tag. e.g. |
+| currency | cur | Collects the currency defined by the [Currency module](/dev-docs/modules/currency.html). |
+
+
+# Related Reading
+- [Prebid.js First Party Data feature](/features/firstPartyData.html)
+- [First Party Data Validation Module](/dev-docs/modules/validationFpdModule)
+- [OpenRTB 2.5](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf)
diff --git a/dev-docs/modules/floors.md b/dev-docs/modules/floors.md
index 380ba312e9..e5d652df1d 100644
--- a/dev-docs/modules/floors.md
+++ b/dev-docs/modules/floors.md
@@ -2,7 +2,7 @@
layout: page_v2
page_type: module
title: Module - Price Floors
-description: Determine and enforce auction price floors
+description: Configure and enforce minimum bids.
module_code : priceFloors
display_name : Price Floors
enable_download : true
@@ -17,11 +17,11 @@ sidebarType : 1
## Overview
-The Floors module provides an open source framework in Prebid for Publishers to configure Prebid price floors on their own or to work with a vendor who can provide floors.
+The Price Floors Module provides an open source framework in Prebid for Publishers to configure Prebid price floors on their own or to work with a vendor who can provide floors.
A ‘floor’ is defined as the lowest CPM price a bid will need to meet for each Prebid auction. It’s a way for publishers to signal to bidders the price to beat, thereby protecting the value of their inventory.
-The module provides several ways for Prebid floors to be defined, that are used by bidder adapters to read floors and enforced on bid responses in any supported currency. The floors utilized by the Prebid.js floors module are defined by one or more set of rules containing any or all of the following dimensions:
+The module provides several ways for Prebid floors to be defined, that are used by bidder adapters to read floors and enforced on bid responses in any supported currency. The floors utilized by the Price Floors Module are defined by one or more set of rules containing any or all of the following dimensions:
- AdUnit
@@ -32,31 +32,31 @@ The module provides several ways for Prebid floors to be defined, that are used
- "custom dimensions"
{: .alert.alert-warning :}
-When using GPT Slot name, the gpt library is required to load first. Failing to do so may yield unexpected results and could impact revenue performance.
+When using GPT Slot name, the GPT library is required to load first. Failing to do so may yield unexpected results and could impact revenue performance.
-The entire set of Prebid floors selected by the Floors Module for a given auction is called a “Rule Location”. A Rule Location can be any one of:
+The entire set of floors selected by the Price Floors Module for a given auction is called a "Rule Location". A Rule Location can be any one of:
1. Within the AdUnit (AdUnit)
2. Within setConfig (Package)
3. Retrieved from a real-time data service (Dynamic)
{: .alert.alert-info :}
-Even though floors are defined with five pre-configured dimensions, it’s possible to extend the list of dimensions to attributes of the page, user, auction or other data by supplying a dimension matching function. For example, a publisher can provide a matching function that returns the device type to allow the price floor module to use device type as an attribute within a prebid floor rules file.
+Even though floors are defined with five pre-configured dimensions, it’s possible to extend the list of dimensions to attributes of the page, user, auction or other data by supplying a dimension matching function. For example, a publisher can provide a matching function that returns the device type to allow the Floor module to use device type as an attribute within a prebid floor rules file.
## How it Works
-There are several places where the Floor module changes the behavior of the Prebid.js auction process. Below is a diagram describing the general flow of the Floors Module:
+There are several places where the Floor module changes the behavior of the Prebid.js auction process. Below is a diagram describing the general flow of the Price Floors Module:

-1. When building the Prebid.js package, the Floors module (and any analytics adapters) needs to be included with 'gulp build --modules=floors,...'
-2. As soon as the setConfig({floors}) call is initiated, the Floors Module will build an internal hash table for each auction derived from a Rule Location (one of Dynamic, setConfig or adUnit)
- - a. If an endpoint URL (a Dynamic Floor) is defined, the Floors Module will attempt to fetch floor data from the Floor Provider's endpoint. When requestBids is called, the Floors Module will delay the auction up to the supplied amount of time in floors.auctionDelay or as soon as the dynamic endpoint returns data, whichever is first.
-3. Bid Adapters are responsible for utilizing the getFloors() from the bidRequest object for each ad slot media type, size combination. The Floors Module will perform currency conversion if the bid adapter requests floors in a different currency from the defined floor data currency.
+1. When building the Prebid.js package, the Price Floors Module (and any analytics adapters) needs to be included with 'gulp build --modules=priceFloors,...'
+2. As soon as the setConfig({floors}) call is initiated, the Price Floors Module will build an internal hash table for each auction derived from a Rule Location (one of Dynamic, setConfig or adUnit)
+ - a. If an endpoint URL (a Dynamic Floor) is defined, the Price Floors Module will attempt to fetch floor data from the Floor Provider's endpoint. When requestBids is called, the Price Floors Module will delay the auction up to the supplied amount of time in floors.auctionDelay or as soon as the dynamic endpoint returns data, whichever is first.
+3. Bid Adapters are responsible for utilizing the getFloor() from the bidRequest object for each ad slot media type, size combination. The Price Floors Module will perform currency conversion if the bid adapter requests floors in a different currency from the defined floor data currency.
4. Bid Adapters will pass the floor values to their bidding endpoints, to request bids, responding with any bids that meet or exceed the provided floor
-5. Bid adapters will submit bids to back to Prebid core, where the Floors Module will perform enforcement on each bid
-6. The Floors Module will mark all bids below the floor as bids rejected. Prebid core will submit all eligible bids to the publisher ad server
- - a. The Floors module emits floor event / bid data to Analytics adapters to allow Floor Providers a feedback loop on floor performance for model training
+5. Bid adapters will submit bids to back to Prebid core, where the Price Floors Module will perform enforcement on each bid
+6. The Price Floors Module will mark all bids below the floor as bids rejected. Prebid core will submit all eligible bids to the publisher ad server
+ - a. The Price Floors Module emits floor event / bid data to Analytics adapters to allow Floor Providers a feedback loop on floor performance for model training
## Defining Floors
@@ -106,6 +106,9 @@ Below are some basic principles of ad unit floor definitions:
];
{% endhighlight %}
+{: .alert.alert-info :}
+When defining floors at the adUnit level, the Price Floors Module requires the floors object to be defined in setConfig, even if the definition is an empty object as shown below: {% highlight js %}pbjs.setConfig({ floors: {} });{% endhighlight %}
+
Floor definitions are set in the “values” object containing one or more rules, where the rule is the criteria that needs to be met for that given ad unit, with an associated CPM floor. In the above example, the floors are enforced when the bid from a bidder matches the “mediaType” and “size” combination. Since many bid adapters are not able to ingest floors per size, a simpler setup can be:
{% highlight js %}
@@ -123,7 +126,7 @@ floors: {
}
{% endhighlight %}
-For more advanced publisher setups, values can accept a “\*” to denote a catch all when a bid comes back that the floors module does not have an exact match and for bid adapters who are not able to use a floor per size, the bid adapter will automatically receive the “\*” rule’s floor if available. Example setup can be:
+For more advanced publisher setups, values can accept a “\*” to denote a catch-all when a bid comes back that the Price Floors Module does not have an exact match and for bid adapters who are not able to use a floor per size, the bid adapter will automatically receive the “\*” rule’s floor if available. Example setup can be:
{% highlight js %}
floors: {
@@ -188,7 +191,7 @@ pbjs.setConfig({
});
{% endhighlight %}
-By defining floor data with setConfig, the Floors module will map GPT ad slots to AdUnits as needed. It does this in the same way as the setTargetingForGPTAsync() function – first looking for an AdUnit.code that matches the slot name, then looking for an AdUnit.code that matches the div id of the named GPT slot.
+By defining floor data with setConfig, the Price Floors Module will map GPT ad slots to AdUnits as needed. It does this in the same way as the setTargetingForGPTAsync() function – first looking for an AdUnit.code that matches the slot name, then looking for an AdUnit.code that matches the div id of the named GPT slot.
Here’s another example that includes more fields:
@@ -203,10 +206,10 @@ pbjs.setConfig({
fields: [ 'domain', 'gptSlot', 'mediaType', 'size']
},
values: {
- 'www.plublisher.com|/1111/homepage/top-rect|banner|300x250': 0.80,
- 'www.publisher.com|/1111/homepage/top-rect|video|300x250': 2.20,
- 'www.plublisher.com|/1111/homepage/left-nav|banner|300x250': 1.77,
- 'www.publisher.com|/1111/homepage/left-nav|video|300x250': 2.88
+ 'www.examplepub.com|/1111/homepage/top-rect|banner|300x250': 0.80,
+ 'www.examplepub.com|/1111/homepage/top-rect|video|300x250': 2.20,
+ 'www.examplepub.com|/1111/homepage/left-nav|banner|300x250': 1.77,
+ 'www.examplepub.com|/1111/homepage/left-nav|video|300x250': 2.88
...
}
}
@@ -237,7 +240,7 @@ pbjs.setConfig({
});
{% endhighlight %}
-The floors module is flexible to handle floors set in multiple locations. Like in the below example a publisher can configure Dynamic floors in addition to Package floors (in setConfig). While the floors module is only able to use one set of rules (either Package, adUnit or Dynamic) defined as a Floor Location, setting floors in the Package will be utilized when the Dynamic floors fail to return data or another error condition occurs with the Dynamic fetch.
+The Price Floors Module is flexible to handle floors set in multiple locations. Like in the below example a publisher can configure Dynamic floors in addition to Package floors (in setConfig). While the Price Floors Module is only able to use one set of rules (either Package, adUnit or Dynamic) defined as a Floor Location, setting floors in the Package will be utilized when the Dynamic floors fail to return data or another error condition occurs with the Dynamic fetch.
{% highlight js %}
pbjs.setConfig({
@@ -269,7 +272,7 @@ pbjs.setConfig({
## Floors Syntax
-The examples above covered several different scenarios where floors can be applied. Below we will cover the syntax and definition of the floors data schema. As of Prebid.js version 3.24, the Floors module supports a second data schema with the ability to add new schemas to future-proof the needs of additional design changes while keeping backwards compatibility.
+The examples above covered several different scenarios where floors can be applied. Below we will cover the syntax and definition of the floors data schema. As of Prebid.js version 3.24, the Price Floors Module supports a second data schema with the ability to add new schemas to future-proof the needs of additional design changes while keeping backwards compatibility.
### Schema 1
@@ -279,23 +282,23 @@ Schema 1 restricts floors providers or publishers to applying only one data grou
{: .table .table-bordered .table-striped }
| Param | Type | Description | Default |
|---+---+---+---+---|
-| floorMin | float | The mimimum CPM floor used by the Floors Module (as of 4.13). The Floors Module will take the greater of floorMin and the matched rule CPM when evaluating getFloor() and enforcing floors. | - |
+| floorMin | float | The mimimum CPM floor used by the Price Floors Module (as of 4.13). The Price Floors Module will take the greater of floorMin and the matched rule CPM when evaluating getFloor() and enforcing floors. | - |
| floorProvider | string | Optional atribute (as of prebid version 4.1) used to signal to the Floor Provider's Analytics adapter their floors are being applied. They can opt to log only floors that are applied when they are the provider. If floorProvider is supplied in both the top level of the floors object and within the data object, the data object's configuration shall prevail.| - |
-| enforcement | object | Controls the enforcement behavior within the Floors Module.| - |
-| skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the Floors Module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail. | 0 |
-| enforcement.enforceJS | boolean | If set to true, the floors module will provide floors to bid adapters for bid request matched rules and suppress any bids not exceeding a matching floor. If set to false, the prebid floors module will still provide floors for bid adapters, there will be no floor enforcement.| true |
-| enforcement.enforcePBS | boolean | If set to true, the Prebid.js floors module will signal to Prebid Server to pass floors to it’s bid adapters and enforce floors. If set to false, the pbjs should still pass matched bid request floor data to PBS, however no enforcement will take place. | false |
+| enforcement | object | Controls the enforcement behavior within the Price Floors Module.| - |
+| skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the Price Floors Module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail. | 0 |
+| enforcement.enforceJS | boolean | If set to true, the Price Floors Module will provide floors to bid adapters for bid request matched rules and suppress any bids not exceeding a matching floor. If set to false, the Price Floors Module will still provide floors for bid adapters, there will be no floor enforcement.| true |
+| enforcement.enforcePBS | boolean | If set to true, the Price Floors Module will signal to Prebid Server to pass floors to it’s bid adapters and enforce floors. If set to false, the pbjs should still pass matched bid request floor data to PBS, however no enforcement will take place. | false |
| enforcement.floorDeals | boolean | Enforce floors for deal bid requests. | false |
-| enforcement.bidAdjustment | boolean | If true, the Floors Module will use the bidAdjustment function to adjust the floor per bidder. If false (or no bidAdjustment function is provided), floors will not be adjusted. Note: Setting this parameter to false may have unexpected results, such as signaling a gross floor when expecting net or vice versa. | true |
+| enforcement.bidAdjustment | boolean | If true, the Price Floors Module will use the bidAdjustment function to adjust the floor per bidder. If false (or no bidAdjustment function is provided), floors will not be adjusted. Note: Setting this parameter to false may have unexpected results, such as signaling a gross floor when expecting net or vice versa. | true |
| endpoint | object | Controls behavior for dynamically retrieving floors. | - |
| endpoint.url | string | URL of endpoint to retrieve dynamic floor data. | - |
-| data | object (required) | Floor data used by the Floors Module to pass floor data to bidders and floor enforcement. | - |
+| data | object (required) | Floor data used by the Price Floors Module to pass floor data to bidders and floor enforcement. | - |
| data.floorProvider | string | Optional atribute (as of prebid version 4.2) used to signal to the Floor Provider's Analytics adapter their floors are being applied. They can opt to log only floors that are applied when they are the provider. If floorProvider is supplied in both the top level of the floors object and within the data object, the data object's configuration shall prevail.| - |
| data.currency | string | Currency of floor data. Floor Module will convert currency where necessary. See Currency section for more details. | 'USD' |
-| data.skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the Floors Module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail. | 0 |
-| data.floorsSchemaVersion | string | The Floors Module supports two versions of the data schema. Version 1 allows for only one model to be applied in a given data set, whereas Version 2 allows you to sample multiple models selected by supplied weights. If no schema version is provided, the Floors Module will assume version 1 for the sake of backwards compatiblity. For schema version 2 see the next section. | 1 |
+| data.skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the Price Floors Module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail. | 0 |
+| data.floorsSchemaVersion | integer | The module supports two versions of the data schema. Version 1 allows for only one model to be applied in a given data set, whereas Version 2 allows you to sample multiple models selected by supplied weights. If no schema version is provided, the module will assume version 1 for the sake of backwards compatiblity. For schema version 2 see the next section. | 1 |
| data.modelVersion | string | Used by floor providers to train on model version performance. The expectation is a floor provider’s analytics adapter will pass the model verson back for algorithm training. | - |
-| data.modelTimestamp | int | Epoch timestamp associated with modelVersion. Can be used to track model creation of floor file for post auction analysis.| - |
+| data.modelTimestamp | integer | Epoch timestamp associated with modelVersion. Can be used to track model creation of floor file for post auction analysis.| - |
| data.schema | object |allows for flexible definition of how floor data is formatted. | - |
| data.schema.delimiter | string | Character separating the floor keys. | '\|' |
| data.schema.fields | array of strings | Supported values are: gptSlot, adUnitCode, mediaType, size | - |
@@ -311,14 +314,14 @@ Schema 1 restricts floors providers or publishers to applying only one data grou
### Schema 2
-Schema 2 allows floors providers to A / B one or more floor groups, determined at auction time.
+Schema 2 allows floors providers to A/B-test one or more floor groups, determined at auction time.
The following principles apply to schema 2:
- The below attributes are required:
- data.floorsSchemaVersion to be set to 2
- A valid modelGroups object must be set
- The field modelGroups.modelWeight is required for each model group
- - If one of the model weights is missing, no schema 2 floor will be set and the Floors Module will look in other locations for floor definitions
+ - If one of the model weights is missing, no schema 2 floor will be set and the Price Floors Module will look in other locations for floor definitions
- If common attributes are set in both the modelGroups and root level of the data object, modelGroups attributes prevail
- The Schema 2 data model can only be applied in Package level (i.e. directly in setConfig) or Dynamic level
- Sampling weights are applied at the auction level. Each new auction the dice will be rolled
@@ -330,27 +333,27 @@ While some attributes are common in both schema versions, for completeness, all
{: .table .table-bordered .table-striped }
| Param | Type | Description | Default |
|---+---+---+---+---|
-| floorMin | float | The mimimum CPM floor used by the Floors Module (as of 4.13). The Floors Module will take the greater of floorMin and the matched rule CPM when evaluating getFloor() and enforcing floors. | - |
+| floorMin | float | The mimimum CPM floor used by the module (as of 4.13). The module will take the greater of floorMin and the matched rule CPM when evaluating getFloor() and enforcing floors. | - |
| floorProvider | string | Optional atribute (as of prebid version 4.1) used to signal to the Floor Provider's Analytics adapter their floors are being applied. They can opt to log only floors that are applied when they are the provider. If floorProvider is supplied in both the top level of the floors object and within the data object, the data object's configuration shall prevail.| - |
-| enforcement | object | Controls the enforcement behavior within the Floors Module.| - |
-| skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the Floors Module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail. | 0 |
-| enforcement.enforceJS | boolean | If set to true, the floors module will provide floors to bid adapters for bid request matched rules and suppress any bids not exceeding a matching floor. If set to false, the prebid floors module will still provide floors for bid adapters, but there will be no floor enforcement.| true |
-| enforcement.enforcePBS | boolean | If set to true, the Prebid.js floors module will signal to Prebid Server to pass floors to it’s bid adapters and enforce floors. If set to false, Prebid.js should still pass matched bid request floor data to Prebid Server, however no enforcement will take place. | false |
+| enforcement | object | Controls the enforcement behavior within the module.| - |
+| skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail. | 0 |
+| enforcement.enforceJS | boolean | If set to true, the module will provide floors to bid adapters for bid request matched rules and suppress any bids not exceeding a matching floor. If set to false, the module will still provide floors for bid adapters, but there will be no floor enforcement.| true |
+| enforcement.enforcePBS | boolean | If set to true, the module will signal to Prebid Server to pass floors to it’s bid adapters and enforce floors. If set to false, Prebid.js should still pass matched bid request floor data to Prebid Server, however no enforcement will take place. | false |
| enforcement.floorDeals | boolean | Enforce floors for deal bid requests. | false |
-| enforcement.bidAdjustment | boolean | If true, the Floors Module will use the bidAdjustment function to adjust the floor per bidder. If false (or no bidAdjustment function is provided), floors will not be adjusted. Note: Setting this parameter to false may have unexpected results, such as signaling a gross floor when expecting net or vice versa. | true |
+| enforcement.bidAdjustment | boolean | If true, the module will use the bidAdjustment function to adjust the floor per bidder. If false (or no bidAdjustment function is provided), floors will not be adjusted. Note: Setting this parameter to false may have unexpected results, such as signaling a gross floor when expecting net or vice versa. | true |
| endpoint | object | Controls behavior for dynamically retrieving floors. | - |
| endpoint.url | string | URL of endpoint to retrieve dynamic floor data. | - |
-| data | object (required) | Floor data used by the Floors Module to pass floor data to bidders and floor enforcement. | - |
+| data | object (required) | Floor data used by the module to pass floor data to bidders and floor enforcement. | - |
| data.floorProvider | string | Optional atribute (as of prebid version 4.2) used to signal to the Floor Provider's Analytics adapter their floors are being applied. They can opt to log only floors that are applied when they are the provider. If floorProvider is supplied in both the top level of the floors object and within the data object, the data object's configuration shall prevail.| - |
-| data.currency | string | Currency of floor data. Floors Module will convert currency where necessary. See Currency section for more details. | 'USD' |
-| data.skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the Floors Module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail.| 0 |
-| data.floorsSchemaVersion | string | The Floors Module supports two version of the data schema. Version 1 allows for only one model to be applied in a given data set, whereas Version 2 allows you to sample multiple models selected by supplied weights. If no schema version is provided, the Floors Module will assume version 1 for the sake of backwards compatiblity.| 1 |
+| data.currency | string | Currency of floor data. The module will convert currency where necessary. See Currency section for more details. | 'USD' |
+| data.skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the module is in floors mode. If skipRate is supplied in both the root level of the floors object and within the data object, the skipRate configuration within the data object shall prevail.| 0 |
+| data.floorsSchemaVersion | string | The module supports two version of the data schema. Version 1 allows for only one model to be applied in a given data set, whereas Version 2 allows you to sample multiple models selected by supplied weights. If no schema version is provided, the module will assume version 1 for the sake of backwards compatiblity.| 1 |
| data.modelTimestamp | int | Epoch timestamp associated with modelVersion. Can be used to track model creation of floor file for post auction analysis.| - |
| data.modelGroups | array of objects | Array of model objects to be used for A/B sampling multiple models. This field is only used when data.floorsSchemaVersion = 2 | - |
| data.modelGroups[].currency | string | Currency of floor data. Floor Module will convert currency where necessary. See Currency section for more details. | 'USD' |
-| data.modelGroups[].skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the Floors Module is in floors mode. | 0 |
+| data.modelGroups[].skipRate | integer | skipRate is a random function whose input value is any integer 0 through 100 to determine when to skip all floor logic, where 0 is always use floor data and 100 is always skip floor data. The use case is for publishers or floor providers to learn bid behavior when floors are applied or skipped. Analytics adapters will have access to model version (if defined) when skipped is true to signal the module is in floors mode. | 0 |
| data.modelGroups[].modelVersion | string | Used by floor providers to train on model version performance. The expectation is a floor provider’s analytics adapter will pass the model verson back for algorithm training. | - |
-| data.modelGroups[].modelWeight | integer | Used by the Floors Module to determine when to apply the specific model. All weights will be normalized and appllied at runtime. Futher clarification will be provided in examples below. | - |
+| data.modelGroups[].modelWeight | integer | Used by the module to determine when to apply the specific model. All weights will be normalized and applied at runtime. Futher clarification will be provided in examples below. | - |
| data.schema | object | Allows for flexible definition of how floor data is formatted. | - |
| data.modelGroups[].schema.delimiter | string | Character separating the floor keys. | '\|' |
| data.modelGroups[].schema.fields | array of strings | Supported pre-defined values are: gptSlot, adUnitCode, mediaType, size | - |
@@ -367,65 +370,70 @@ While some attributes are common in both schema versions, for completeness, all
Model weights add up to 100 and are sampled at a 25%, 25%, 50% distribution. Additionally, each model group has diffirent schema fields:
{% highlight js %}
-{
- "currency": "EU",
- "skipRate": 20,
- "floorsSchemaVersion":2,
- "modelGroups": [
- {
- "modelWeight":25,
- "modelVersion": "Model1",
- "schema": {
- "fields": [ "domain", "gptSlot", "mediaType", "size" ]
- },
- "values": {
- "www.publisher.com|/1111/homepage/top-banner|banner|728x90": 1.00,
- "www.publisher.com|/1111/homepage/top-rect|banner|300x250": 1.20,
- "www.publisher.com|/1111/homepage/top-rect|banner|300x600": 1.80,
- ...
- "www.domain.com|/1111/homepage/top-banner|banner|728x90": 2.11
- ...
- "www.publisher.com|*|*|*": 0.80,
- },
- "default": 0.75
- },
- {
- "modelWeight": 25,
- "modelVersion": "Model2",
- "schema": {
- "fields": [ "domain", "mediaType", "size" ]
- },
- "values": {
- "www.publisher.com|banner|728x90": 1.00,
- "www.publisher.com|banner|300x250": 1.20,
- "www.publisher.com|banner|300x600": 1.80,
- ...
- "www.domain.com|banner|728x90": 2.11
- ...
- "www.publisher.com|*|*|*": 0.80,
- },
- "default": 0.75
- },
- {
- "modelWeight": 50,
- "modelVersion": "Model3",
- "schema": {
- "fields": [ "gptSlot", "mediaType", "size" ]
- },
- "values": {
- "/1111/homepage/top-banner|banner|728x90": 1.00,
- "/1111/homepage/top-rect|banner|300x250": 1.20,
- "/1111/homepage/top-rect|banner|300x600": 1.80,
- ...
- "/1111/homepage/top-banner|banner|728x90": 2.11
- ...
- "*|banner|*": 0.80,
- },
- "default": 0.75
- }
- ]
-
-}
+pbjs.setConfig({
+ floors: {
+ enforcement: { ... },
+ ...
+ data: {
+ "currency": "EU",
+ "skipRate": 20,
+ "floorsSchemaVersion":2,
+ "modelGroups": [
+ {
+ "modelWeight":25,
+ "modelVersion": "Model1",
+ "schema": {
+ "fields": [ "domain", "gptSlot", "mediaType", "size" ]
+ },
+ "values": {
+ "www.publisher.com|/1111/homepage/top-banner|banner|728x90": 1.00,
+ "www.publisher.com|/1111/homepage/top-rect|banner|300x250": 1.20,
+ "www.publisher.com|/1111/homepage/top-rect|banner|300x600": 1.80,
+ ...
+ "www.domain.com|/1111/homepage/top-banner|banner|728x90": 2.11
+ ...
+ "www.publisher.com|*|*|*": 0.80,
+ },
+ "default": 0.75
+ },
+ {
+ "modelWeight": 25,
+ "modelVersion": "Model2",
+ "schema": {
+ "fields": [ "domain", "mediaType", "size" ]
+ },
+ "values": {
+ "www.publisher.com|banner|728x90": 1.00,
+ "www.publisher.com|banner|300x250": 1.20,
+ "www.publisher.com|banner|300x600": 1.80,
+ ...
+ "www.domain.com|banner|728x90": 2.11
+ ...
+ "www.publisher.com|*|*|*": 0.80,
+ },
+ "default": 0.75
+ },
+ {
+ "modelWeight": 50,
+ "modelVersion": "Model3",
+ "schema": {
+ "fields": [ "gptSlot", "mediaType", "size" ]
+ },
+ "values": {
+ "/1111/homepage/top-banner|banner|728x90": 1.00,
+ "/1111/homepage/top-rect|banner|300x250": 1.20,
+ "/1111/homepage/top-rect|banner|300x600": 1.80,
+ ...
+ "/1111/homepage/top-banner|banner|728x90": 2.11
+ ...
+ "*|banner|*": 0.80,
+ },
+ "default": 0.75
+ }
+ ]
+ }
+ }
+});
{% endhighlight %}
*Example 2*
@@ -436,66 +444,69 @@ model2 = 50 -> 50 / (20 + 50) = 71% of auctions model 2 will be applied
Additionally skipRate is supplied at model group level where model1 will skip floors 20% of times when model1 is selected, whereas model2 will skip 50% of auctions when model2 is selected.
{% highlight js %}
-{
- "currency": "EU",
- "floorsSchemaVersion":2,
- "modelGroups": [
- {
- "modelWeight":25,
- "skipRate": 20,
- "modelVersion": "Model1",
- "schema": {
- "fields": [ "domain", "gptSlot", "mediaType", "size" ]
- },
- "values": {
- "www.publisher.com|/1111/homepage/top-banner|banner|728x90": 1.00,
- "www.publisher.com|/1111/homepage/top-rect|banner|300x250": 1.20,
- "www.publisher.com|/1111/homepage/top-rect|banner|300x600": 1.80,
- ...
- "www.domain.com|/1111/homepage/top-banner|banner|728x90": 2.11
- ...
- "www.publisher.com|*|*|*": 0.80,
- },
- "default": 0.75
- },
- {
- "modelWeight": 50,
- "skipRate": 50,
- "modelVersion": "Model2",
- "schema": {
- "fields": [ "gptSlot", "mediaType", "size" ]
- },
- "values": {
- "/1111/homepage/top-banner|banner|728x90": 1.00,
- "/1111/homepage/top-rect|banner|300x250": 1.20,
- "/1111/homepage/top-rect|banner|300x600": 1.80,
- ...
- "/1111/homepage/top-banner|banner|728x90": 2.11
- ...
- "*|banner|*": 0.80,
- },
- "default": 0.75
- }
- ]
-
-}
+pbjs.setConfig({
+ floors: {
+ enforcement: { ... },
+ ...
+ data: {
+ "currency": "EU",
+ "floorsSchemaVersion":2,
+ "modelGroups": [
+ {
+ "modelWeight":25,
+ "skipRate": 20,
+ "modelVersion": "Model1",
+ "schema": {
+ "fields": [ "domain", "gptSlot", "mediaType", "size" ]
+ },
+ "values": {
+ "www.publisher.com|/1111/homepage/top-banner|banner|728x90": 1.00,
+ "www.publisher.com|/1111/homepage/top-rect|banner|300x250": 1.20,
+ "www.publisher.com|/1111/homepage/top-rect|banner|300x600": 1.80,
+ ...
+ "www.domain.com|/1111/homepage/top-banner|banner|728x90": 2.11
+ ...
+ "www.publisher.com|*|*|*": 0.80,
+ },
+ "default": 0.75
+ },
+ {
+ "modelWeight": 50,
+ "skipRate": 50,
+ "modelVersion": "Model2",
+ "schema": {
+ "fields": [ "gptSlot", "mediaType", "size" ]
+ },
+ "values": {
+ "/1111/homepage/top-banner|banner|728x90": 1.00,
+ "/1111/homepage/top-rect|banner|300x250": 1.20,
+ "/1111/homepage/top-rect|banner|300x600": 1.80,
+ ...
+ "/1111/homepage/top-banner|banner|728x90": 2.11
+ ...
+ "*|banner|*": 0.80,
+ },
+ "default": 0.75
+ }
+ ]
+ }
+ }
+});
{% endhighlight %}
## Custom Schema Fields
-Custom schema fields are fields the Floors Module does not support out of the box. To use a custom schema field, one needs to perform twp steps:
+Out of the box, the Price Floors Module only supports looking up floors by AdUnit, GPT Slot, MediaType, ad size, and domain. Custom schema fields can be added to support other lookup dimensions. Here are the steps:
-1. Create lookup function to give the Floors Module context of the value of custom fields for that given auction
+1. Create a lookup function to give context of the value of custom fields for that given auction
1. Define, Set and Map Custom Schema Attributes
### Create Lookup Function
-Create a function to allow the Floors Module to understand context of a given auction. In the below example, we must create a lookup function to give the Floors Module what deviceType this auction is.
-
-Here is an example lookup function:
+Create a function to allow the module to understand context of a given auction. In the below example, a lookup function provides details about what deviceType this auction is for.
+e.g.
{% highlight js %}
-
function deviceTypes (bidRequest, bidResponse) {
//while bidRequest and bidResponse are not required for this function, they are available for custom attribute mapping
@@ -514,9 +525,9 @@ Here is an example lookup function:
### Define, Set and Map Custom Schema Attributes
-After defining a lookup function for the given context of the auction, the custom schema field(s) need to be defined in the `floors.schema.fields` array. Once your custom field is defined you can assign rule values in `floors.data.values` derived from said field(s). The last step would be to supply the lookup function(s) that map from each custom field to a value of the context wthin that auction by using the `floors.additionalSchemaFields` attribute as seen below.
+After defining a lookup function for the given context of the auction, the custom schema field(s) need to be defined in the `floors.schema.fields` array. Once your custom field is defined you can assign rule values in `floors.data.values` derived from these field(s). The last step would be to supply the lookup function(s) that map from each custom field to a value of the context wthin that auction by using the `floors.additionalSchemaFields` attribute as seen below.
-In the below example, `deviceType` is a custom field not currently supported by default in the Floors Module whose values are one of "mobile", "desktop" or "tablet".
+In the below example, `deviceType` is a custom field not currently supported by default in the Price Floors Module whose values are one of "mobile", "desktop" or "tablet".
{% highlight js %}
@@ -551,28 +562,26 @@ In the below example, `deviceType` is a custom field not currently supported by
{% endhighlight %}
-
-
## Rule Handling
### Rule Location Priority
-As defined in the overview, a Rule Location is where a particular rule is located, either defined in the Ad Unit, within setConfig or via a fetch from the browser (named Dynamic) for fresh rules. It may be possible (rather more than likely) that floor rules can be set in one or more locations for a given Prebid auction (i.e. on requestBids). At auction, the Floors Module will only ever use rules from one Rule Location, decided at run-time. Each auction will be assigned an immutable set of rules from one Rule Location, even if the rules change prior to auction complete.
+As defined in the overview, a Rule Location is where a particular rule is located, either defined in (1) the Ad Unit, (2) within setConfig or (3) via a fetch from the browser. It's likely that floor rules are set in one or more location for a given Prebid auction. During an auction, the Price Floors Module will only ever use rules from one Rule Location, decided at run-time. Each auction will be assigned an immutable set of rules from one Rule Location, even if the rules change prior to auction complete.
-The Floors Module will use the below prioritization scheme on determining which Rule Location is selected at run-time:
+The module uses the below prioritization scheme on determining which Rule Location is selected at run-time:
-- Dynamic
+- dynamic
- setConfig
- adUnit
### Rule Selection Process
-The job of the Prebid floors module is to select a matching Prebid floor rule for enforcement \(when a bid adapter bids in the auction\) given the context of each Ad Unit. With the usage of “\*” values in rules definitions \(where “\*” applies when no specific value matches\) multiple Prebid floor rules can match for a given ad unit auction.
+The job of the Price Floors Module is to select a matching floor rule for enforcement given the context of each Ad Unit. With the usage of “\*” values in rules definitions multiple floor rules can match for a given ad unit auction.
-The Prebid Floors module algorithm will produce a list of every possible permutation for each ad unit auction based on the defined schema types. The best matching rule for each enforced bid request and getFloor is based on specificity of values \(meaning match an exact value\) weighted from left to right, where the specificity of a value in the left most column would match over a rule with it’s “\*” equivalent if “\*” is supplied.
+The module algorithm will produce a list of every possible permutation for each ad unit auction based on the defined schema types. The best matching rule for each enforced bid request and call to `getFloor()` is based on specificity of values \(meaning match an exact value\) weighted from left to right, where the specificity of a value in the left most column would match over a rule with its “\*” equivalent if “\*” is supplied.
-Priority order behavior where “\_” is a specific value, and the “\*” is a catch all
+Priority order behavior where “\_” is a specific value, and the “\*” is a catch-all
Priority order for one column rule sets:
@@ -643,7 +652,7 @@ mediaType = banner
Size = 300x600
Domain context = www.website.com
-The Price Floor Module produces an internal hash table of all possible permutations of “banner”, “300x600”, “www.website.com” and “\*” with the most specific hash values up top, weighting rules priority from left column specific values to right. Each left value will weigh more than the subsequent column’s specific values. The Floors Module attempt to find the matching rule by cycling through each below possible rule (from top to bottom) against the above rule provider data set.
+The Floor module produces an internal hash table of all possible permutations of “banner”, “300x600”, “www.website.com” and “\*” with the most specific hash values up top, weighting rules priority from left column specific values to right. Each left value will weigh more than the subsequent column’s specific values. The module attempts to find the matching rule by cycling through each below possible rule (from top to bottom) against the above rule provider data set.
{% highlight js %}
{
@@ -842,14 +851,14 @@ As a floor provider, your goal is to provide effective floors, with minimal page
- Work with publishers on setting appropriate auction delays to retrieve dynamic data
- Implement client-side caching (such as max-age headers) whenever possible
- Evaluate data freshness vs frequency of new fetches to the CDN to reduce unnecessary calls
-- Be aware of file sizes returned to the browser, implementing trimmiming algorithms for extremely large data sets
+- Be aware of file sizes returned to the browser, implementing trimming algorithms for extremely large data sets
{% endcapture %}
{% include /alerts/alert_important.html content=warning_note %}
-For Dynamic fetches, the floors module will perform a GET request to the supplied endpoint, that must return valid JSON, formatted like the data object in the “setConfig” Package configuration.
+For Dynamic fetches, the Price Floors Module will perform a GET request to the supplied endpoint, that must return valid JSON, formatted like the data object in the “setConfig” Package configuration.
-On rule creation, we recommend supplying various rules with catch all \(“\*”\) values with associated floors. This is to accommodate bid adapters who cannot retrieving floors on a per size basis, as well as using various permutations of rules with “\*” values to match auctions that do not have an exact match on a specific rule. Please refer to the Rule Selection Process when determining floors as attribute order and number of “\*”s may have an impact on which rule is selected.
+On rule creation, we recommend supplying various rules with catch-all \(“\*”\) values with associated floors. This is to accommodate bid adapters who cannot retrieve floors on a per size basis, as well as using various permutations of rules with “\*” values to match auctions that do not have an exact match on a specific rule. Please refer to the Rule Selection Process when determining floors as attribute order and number of “\*”s may have an impact on which rule is selected.
#### Example Dynamic fetch
@@ -977,39 +986,41 @@ Floors Schema version 2
### Bid Adapter Interface
-The Prebid Floors Module is capable of handling an arbitrarily large set of floor rules of any combination of supported dimensions. To reduce the need for each bid adapter to process each and every rule in the selected rule data set, an encapsulated function (getFloor) was created to allow bid adapters to query the Floors Module for a floor for each mediaType, size and currency the bid adapter needs.
+The Prebid Floors Module is capable of handling an arbitrarily large set of floor rules of any combination of supported dimensions. To reduce the need for each bid adapter to process each and every rule in the selected rule data set, an encapsulated function (getFloor) was created to allow bid adapters to query the module for a floor for each mediaType, size and currency the bid adapter needs.
-If the price floors module is enabled for a given auction, the Floors Module will add to the bidRequest object the getFloor function. All bid adapters are recommended to call getFloor to retrieve a desired floor. The job of the getFloor function will be to return the floor CPM of a matched rule based on the rule selection process (written out above), using the getFloor inputs.
+If the Price Floors Module is enabled for a given auction, it will add the getFloor() function to the bidRequest object. All bid adapters are recommended to call the getFloor() to retrieve a desired floor. The job of this function is to return the floor CPM of a matched rule based on the rule selection process (written out above), using the getFloor() inputs.
-Intended changes for bid adapters:
+Changes for bid adapters:
-
-1. Check for presence of getFloor within the bidRequest obect
-1. If getFloors exists, call getFloor with desired parameters
+1. Check for presence of getFloor() within the bidRequest obect
+1. If getFloor() exists, call it with desired parameters
1. Parse floor and currency response
1. Pass floor and / or currency to bid adapter endpoint
-getFloor takes in a single object with the following params:
+getFloor() takes in a single object with the following params:
{% highlight js %}
-
- getFloor({
+ if (typeof bidRequest.getFloor === 'function') {
+ floorInfo = bidRequest.getFloor({
currency: string,
- mediaType: string //Required
+ mediaType: string,
size : [ w, h] OR "*"
});
-
+}
{% endhighlight %}
+{: .alert.alert-warning :}
+Consider how floors will behave in multi-currency scenarios. A common pitfall is requesting floors without specifying currency, or specifying the wrong currency back to the bid adapter's platform. This may lead to bidders requesting one currency and bidding in an alternate currency.
+
+
{: .table .table-bordered .table-striped }
| Param | Type | Description | Default |
|---+---+---+---|
-| bidRequest | object | bidRequest object passed to buildRequests function | none |
-| mediaType | string | The media type within the current bidRequest context to receive a floor from the Floors Module. Floors Module will return best matching floor. Possible values are one of “banner”, “video”, “Native” or "\*" | "banner" |
-| size | Size array or ‘\*’ (required) | The size within the current bidRequest context to receive a floor from the Floors Module. Defaults to ‘\*’Array of size [w, h] for a specific size. If your bid adapter cannot handle size specific floors, use ‘\*’ to retrieve catch all size floor if defined by the publisher or floor provider | "\*" |
+| mediaType | string | The media type within the current bidRequest context to receive a floor from the module. It will return best matching floor. Possible values are one of “banner”, “video”, “Native” or "\*" | "banner" |
+| size | Size array or ‘\*’ (required) | The size within the current bidRequest context to receive a floor from the module. Defaults to ‘\*’Array of size [w, h] for a specific size. If your bid adapter cannot handle size specific floors, use ‘\*’ to retrieve catch-all size floor if defined by the publisher or floor provider | "\*" |
| currency | String | The desired currency to return the floor in. Please refer to the currency section to understand how currency conversion is applied. If no currency is supplied, the floor module will assume USD. If the Floor Module cannot convert a floor to the supplied currency, bid adapters will be required to handle the supplied floor. | "USD" |
-#### getFloor Response
+#### getFloor() Response
{% highlight js %}
@@ -1028,9 +1039,9 @@ Or empty object if a floor was not found for a given input
{% endhighlight %}
-#### Example getFloor scenarios
+#### Example getFloor() scenarios
-Example rules file used for getFloor
+Example rules file used for getFloor()
{% highlight js %}
@@ -1053,16 +1064,16 @@ Example rules file used for getFloor
{% endhighlight %}
-**Example getFloor 1**
+**Example getFloor() 1**
-getFloor for media type Banner for a bid request in the context of the gpt slot “/1111/homepage/top-rect” where the bid adapter does not support floors per size.
+getFloor() for media type Banner for a bid request in GPT slot “/1111/homepage/top-rect” where the bid adapter does not support floors per size.
{% highlight js %}
getFloor({
currency: 'USD',
mediatype: ‘banner’,
- Size: ‘*’
+ size: ‘*’
});
{% endhighlight %}
@@ -1075,7 +1086,7 @@ getFloor for media type Banner for a bid request in the context of the gpt slot
}
{% endhighlight %}
-To aid in the accuracy of floor selection when using size ”\*” in getFloor, the Floors Module has built-in smart rule selection when an ad unit in the internal bidRequest to the bid adapters interface has one ad unit type and one size. In the above example, if the ad unit within the bidRequest object has an ad unit type of “banner” with only one size, say “300x250”, the Floors Module will intelligently select the rule with "banner\|300x250" in it, as opposed to the "banner\|\*" rule producing the following response:
+To aid in the accuracy of floor selection when using size ”\*” in getFloor(), the Price Floors Module has built-in smart rule selection when an ad unit in the internal bidRequest to the bid adapters interface has one ad unit type and one size. In the above example, if the ad unit within the bidRequest object has an ad unit type of “banner” with only one size, say “300x250”, the module will intelligently select the rule with "banner\|300x250" in it, as opposed to the "banner\|\*" rule producing the following response:
{% highlight js %}
{
@@ -1085,9 +1096,9 @@ To aid in the accuracy of floor selection when using size ”\*” in getFloor,
{% endhighlight %}
-**Example getFloor 2**
+**Example getFloor() 2**
-getFloor for media type Banner for a bid requests in the context of the gpt slot “/1111/homepage/top-rect” with size of 300x600 where bid adapter does support floors per size.
+getFloor() for media type Banner for a bid requests in GPT slot “/1111/homepage/top-rect” with size of 300x600 where bid adapter does support floors per size.
{% highlight js %}
getFloor({
@@ -1106,7 +1117,7 @@ getFloor({
}
{% endhighlight %}
-Here are some examples of how a bid adapter may wish to configure their adapter to handle getFloor function:
+Here are some examples of how a bid adapter may wish to configure their adapter to handle getFloor() function:
For a bid adapter who does not wish to handle making a request for each size in a given bid request they can leverage the \* attribute which is meant to be a skewed average for a floor.
@@ -1115,7 +1126,7 @@ For a bid adapter who does not wish to handle making a request for each size in
let floorInfo = bidRequest.getFloor({
currency: 'USD',
mediaType: 'banner',
- size: '\*'
+ size: '*'
});
data['adapter_floor'] = floorInfo.currency === 'USD' ? floorInfo.floor : undefined;
}
@@ -1123,23 +1134,23 @@ For a bid adapter who does not wish to handle making a request for each size in
### Analytics Adapter Interface
-Price Floors providers will most likely rely heavily on their associated (or their partner’s) prebid analytics adapter in order to make the most informed and optimal price floor rule sets. Because of this, the price floors module needs to relay important information about the flooring and decisions made in the lifecycle of an auction.
+Floor providers rely on an analytics adapter in order to make the most informed and optimal price floor rule sets. Because of this, the Price Floors Module needs to relay important information about the flooring and decisions made in the lifecycle of an auction.
-The price floors module will do this by leveraging the already existing implementation for prebid analytics adapters by exposing floorData information onto the bidRequest and bidResponse objects. Thus, when an analytics adapter hooks into these prebid events, it will be able to pick out the price floors data and pass it along to their servers.
+The module will do this by leveraging the already-existing implementation for analytics adapters by exposing floorData information onto the bidRequest and bidResponse objects. Thus, when an analytics adapter hooks into these objects, it will be able to pick out the price floors data and pass it along to their servers.
**bidRequest**: Bid Requests objects are updated to contain some basic top level information which a floor provider may need:
{: .table .table-bordered .table-striped }
| bidRequest.floorData. | Type | Description | example |
|---+---+---+---+---|
-| fetchStatus | String | Provides details on the status of a fetch for a JSON floors file when fetches are attempted. Valid values are: 'success' (when fetch returns an http 200 status), 'timeout' (when fetch results not returned before either auction delay or prebid timeout) or 'error' (any http status other than 200 or other error condition). To determine if fetch succeeds but returns invalid floors data, refer to the location field to infer invalid data if 'fetch' is not resultant value. | ‘success’ |
-| floorMin | float | The mimimum CPM floor used by the Floors Module (as of 4.13). The Floors Module will take the greater of floorMin and the matched rule CPM when evaluating getFloor() and enforcing floors. | 0.10 |
+| fetchStatus | String | Provides details on the status of a fetch for a JSON floors file when fetches are attempted. Valid values are: 'success' (when fetch returns an http 200 status), 'timeout' (when fetch results not returned before either auction delay or prebid timeout) or 'error' (any http status other than 200 or other error condition). Note: if data is received successfully, but isn't valid upon parsing, fetchStatus will be 'success', but the `location` field (below) will have a value other than 'fetch' because the system will fall back to another source. | ‘success’ |
+| floorMin | float | The mimimum CPM floor used by the module (as of 4.13). The module will take the greater of floorMin and the matched rule CPM when evaluating getFloor() and enforcing floors. Note that the currency of this floor is the same as bidResponse.floorData.floorCurrency. | 0.10 |
| floorProvider | string | Optional atribute (as of prebid version 4.1) used to signal to the Floor Provider's Analytics adapter their floors are being applied. They can opt to log only floors that are applied when they are the provider. If floorProvider is supplied in both the top level of the floors object and within the data object, the data object's configuration shall prevail.| "rubicon" |
-| location | String | Where the Floors Module derived the rule set. Values are one of 'adUnit', 'setConfig', 'fetch' or 'noData'. If the Floors Module code is invoked and no floors object is able to be found (either by error or other condition) the floorsModule will set location to 'noData'. When on data is found, it is up to the analtyics adapter to decide what to log. All available values will be provided in teh bidRequest object. | ‘fetch’ |
+| location | String | Where the module derived the rule set. Values are one of 'adUnit', 'setConfig', 'fetch' or 'noData'. If the module code is invoked and no floors object is able to be found (either by error or other condition) the floorsModule will set location to 'noData'. When on data is found, it is up to the analtyics adapter to decide what to log. All available values will be provided in the bidRequest object. | ‘fetch’ |
| modelVersion | String | The name of the model| ‘floor-model-4.3’ |
| modelWeight | integer | The weight of the model selected (for schema 2 version only)| 50 |
| modelTimestamp | integer | Epoch timestamp associated with the modelVersion to be used for post auction analysis.| 1607126814 |
-| skipRate | integer | skipRate will be populated when a skip rate is configured in the Prebid Floors Module, even if the skipRate is evaluated to false. Skip Rate is used to determine when to skip all floors logic. | 15 |
+| skipRate | integer | skipRate will be populated when a skip rate is configured in the module, even if the skipRate is evaluated to false. Skip Rate is used to determine when to skip all floors logic. | 15 |
| skipped | Boolean | Whether the skipRate resolved to be true or false| true |
**bidResponse**: When a bid response is being processed it is important for analytics adapters to know the decision which was made and the context of the rule selection. Here is the data which is attached to each bidResponse:
@@ -1157,28 +1168,29 @@ The price floors module will do this by leveraging the already existing implemen
### Prebid Server Interface
-Not supported in initial build. S2S config support will be coming in the subsequent release.
+The PrebidServerBidAdapter calls `getFloor()` like any other bid adapter
+and passes it to the server side as imp.bidfloor and imp.bidfloorcur.
## Currency
-The floors module will default the floor CPM currency with any associated rule to USD if none is supplied in the data object of the floors configuration. For any non-USD currency support, a publisher is required to specify the desired currency. If you are working with a floor provider, please speak to them about supplying the desired currency for your integration.
+The Price Floors Module defaults the floor currency to USD if none is supplied in the data object of the floors configuration. For any non-USD currency support, a publisher is required to specify the desired currency. If you are working with a floor provider, please speak to them about supplying the desired currency for your integration.
{% capture warning_note %}
-For publishers seeking to perform currency conversions within the floors module (for example if the floors data currency is not the same as a bid adapter’s supported currency), failure to include the currency module may result in unexpected behavior and / or may impact revenue performance.
+For publishers requiring currency conversions (for example if the floors data currency is not the same as a bid adapter’s supported currency), **failure to include the currency module may result in unexpected behavior** and / or may impact revenue performance.
{% endcapture %}
{% include /alerts/alert_warning.html content=warning_note %}
Currency conversion can occur in two areas of the Floor Module code:
-- On the **getFloor** call when Bid Adapters request a floor
+- On the **getFloor()** call when Bid Adapters request a floor
- On the **enforcement** side when each bidder submits a bidResponse
-**getFloor**
+**Currency and getFloor()**
-The job of the getFloor method is to retrieve an appropriate floor for the requesting Bid Adapter, for a given auction context. If a Bid Adapter performs a getFloor call with a currency different than the currency of the floor data, the Floors Module will attempt to perform a currency conversion, utilizing the convertCurrency function in the global Prebid object.
+The job of the getFloor() function is to retrieve an appropriate floor for the requesting Bid Adapter, for a given auction context. If a Bid Adapter performs a getFloor() call with a currency different than the currency of the floor data, the module will attempt to perform a currency conversion, utilizing the convertCurrency function in the global Prebid object.
-If a currency conversion is successful in getFloor, the resulting floor will be returned to the requesting Bid Adapter. If the conversion failed, the Floors Module will return the original floor currency defined within the selected rule location data set.
+If a currency conversion is successful in getFloor(), the resulting floor will be returned to the requesting Bid Adapter. If the conversion failed, the module will return the original floor currency defined within the selected rule location data set.
Example Rule:
currency = ‘USD’,
@@ -1201,7 +1213,7 @@ If successfully returned the requested currency:
}
{% endhighlight %}
-If unsuccessfully returned the requested currency:
+If currency conversion is unsuccessful:
{% highlight js %}
{
@@ -1220,9 +1232,9 @@ Currency conversion can fail for the following reasons:
- Bidder passes in a currency code which does not have a conversion rate
- Floors was set with a currency which does not have a conversion rate
-**Enforcement**
+**Currency and Floor Enforcement**
-Enforcement in the Floors module occurs when bidders respond (i.e. bid) with a bidResponse object into the Prebid auction. The Floors Module will read the bid submitted within each valid bidResponse and its associated currency, performing currency conversion where necessary.
+Enforcement in the Price Floors Module occurs when bidders respond with a bidResponse object into the Prebid auction. The module reads the bid submitted within each valid bidResponse and its associated currency, performing currency conversion where necessary.
There exist three locations where currencies can differ within enforcement:
@@ -1230,14 +1242,14 @@ There exist three locations where currencies can differ within enforcement:
- Price Floor Currency: Currency set in the price floors data object
- bidResponse Currency: The currency the bidder returned with their bidResponse back to Prebid
-When a bid adapter submits a bid into the auction, the currency module will first determine if any conversion logic is necessary, afterwhich the bid is passed to the Floors Module. If currency conversion occurs at this stage, the bidResponse object will have the following attributes:
+When a bid adapter submits a bid into the auction, the currency module will first determine if any conversion logic is necessary, afterwhich the bid is passed to the module. If currency conversion occurs at this stage, the bidResponse object will have the following attributes:
- Cpm: The adServerCurrency converted CPM currency
- Currency: The currency the adServerCurrency was set in
- originalCpm: The original CPM the bidder responded with
- originalCurrency: The original currency the bidder responded with
-Below is a chart explaining the behavior of currency conversion, if necessary, within the Floors Module when comparing bid CPM to floor CPM for enforcement:
+Below is a chart explaining the behavior of currency conversion, if necessary, within the module when comparing bid CPM to floor CPM for enforcement:
{: .table .table-bordered .table-striped }
| bid.currency | bid.originalCurrency | floor.currency | result |
@@ -1256,6 +1268,8 @@ If the currency function is unable to derive the correct cpm in any of the scena
## Floors Providers
{: .table }
-| Partners| Contact |
-|
| Contact Magnite (Formerly Rubicon Project) support at [globalsupport@mangite.com](mailto:globalsupport@magnite.com) to use Magnite as a floor provider. |
-| pubx.ai | Reach out to PubX at [hello@pubx.ai](mailto:hello@pubx.ai) to learn more about our AI-powered dynamic floor optimization. |
+| Partner | Contact | About |
+|
| [globalsupport@magnite.com](mailto:globalsupport@magnite.com) | Magnite data-science applied to dynamic floors
+| pubx.ai | [hello@pubx.ai](mailto:hello@pubx.ai) | AI-powered dynamic floor optimization |
+| Assertive Yield | [assertiveyield.com](https://assertiveyield.com) | Holistic flooring covering Prebid, Amazon, GAM UPR, RTB and more |
+| OpenX | Reach out to OpenX at [apollo@openx.com] | Dynamic floor optimization and more |
diff --git a/dev-docs/modules/freewheel.md b/dev-docs/modules/freewheel.md
index 24cba9286f..2aa357c750 100644
--- a/dev-docs/modules/freewheel.md
+++ b/dev-docs/modules/freewheel.md
@@ -2,10 +2,11 @@
layout: page_v2
page_type: module
title: Module - Freewheel
-description: Returns targeting key/value pairs for adpod mediaType adUnits.
+description: Passes key value targeting to Freewheel SDK for adpod mediaType adUnits.
module_code : freeWheelAdserverVideo
-display_name : Freewheel
+display_name : Freewheel Video Support
enable_download : true
+vendor_specific: true
sidebarType : 1
---
diff --git a/dev-docs/modules/gdprEnforcement.md b/dev-docs/modules/gdprEnforcement.md
index 03acfeb352..2afd260ac9 100644
--- a/dev-docs/modules/gdprEnforcement.md
+++ b/dev-docs/modules/gdprEnforcement.md
@@ -2,10 +2,11 @@
layout: page_v2
page_type: module
title: GDPR Enforcement Module
-description: Module to enforce GDPR consent
+description: If you have users in Europe, you'll want this module that enforces GDPR consent
module_code : gdprEnforcement
display_name : GDPR Enforcement
enable_download : true
+recommended: true
sidebarType : 1
---
diff --git a/dev-docs/modules/geoedgeRtdProvider.md b/dev-docs/modules/geoedgeRtdProvider.md
index a9c4367cef..42113e0086 100644
--- a/dev-docs/modules/geoedgeRtdProvider.md
+++ b/dev-docs/modules/geoedgeRtdProvider.md
@@ -7,6 +7,7 @@ page_type: module
module_type: rtd
module_code : geoedgeRtdProvider
enable_download : true
+vendor_specific: true
sidebarType : 1
---
diff --git a/dev-docs/modules/gpt-pre-auction.md b/dev-docs/modules/gpt-pre-auction.md
index dad9aecaf0..504b648e59 100644
--- a/dev-docs/modules/gpt-pre-auction.md
+++ b/dev-docs/modules/gpt-pre-auction.md
@@ -2,10 +2,12 @@
layout: page_v2
page_type: module
title: Module - GPT Pre-Auction
-description: Adds PB Ad Slot and matching GAM ad unit name to each ad unit's first-party data before bid requests are sent to the adapters
+description: If you run GAM, this module generates the 'global placement id' that's becoming required for successful auctions.
module_code : gptPreAuction
display_name : GPT Pre-Auction
enable_download : true
+recommended: true
+vendor_specific: true
sidebarType : 1
---
@@ -22,13 +24,13 @@ This module enables targeting and tracking at the ad server adunit 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.
* **Prebid.js Adapters** - will be able to utilize these values as:
- * AdUnit.fpd.context.adServer.name="gam"
- * AdUnit.fpd.context.adServer.adSlot="/1111/home"
- * AdUnit.fpd.context.pbAdSlot="/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.context.data.adserver.name
- * imp[].ext.context.data.adserver.adslot
- * imp[].ext.context.data.pbadslot
+ * imp[].ext.data.adserver.name
+ * imp[].ext.data.adserver.adslot
+ * imp[].ext.data.pbadslot
## Configuration
@@ -38,10 +40,14 @@ into the Prebid.js package.
Optional initialization parameters:
-- enabled (on by default)
-- customGptSlotMatching function
-- customPbAdSlot function
+{: .table .table-bordered .table-striped }
+| Param | Required? | Type | Description | Example |
+| enabled | no | boolean | allows turning off of module. Default value is true | true |
+| customGptSlotMatching | no | function | GPT slot matching function should match the customSlotMatching function sent to [setTargetingForGptAsync](/dev-docs/publisher-api-reference/setTargetingForGPTAsync.html) | |
+| customPbAdSlot | no | function | Custom PB AdSlot function | |
+| mcmEnabled | no | boolean | Removes extra network IDs when Multiple Customer Management is active. Default is false. | true |
+For example:
```
pbjs.setConfig({
gptPreAuction: {
@@ -53,7 +59,8 @@ pbjs.setConfig({
customGptSlotMatching: function(gptSlotObj) {
...
return true; // or false
- }
+ },
+ mcmEnabled: true
}
});
```
@@ -67,13 +74,13 @@ When this module is on, it uses the BEFORE_REQUEST_BIDS event to insert function
If GPT slot matching succeeds:
-- it sets fpd.context.adserver.name to 'gam'
-- it copies the resulting GPT slot name to fpd.context.adserver.adSlot
+- it sets the Adunit ortb2Imp.ext.data.adserver.name to 'gam'
+- it copies the resulting GPT slot name to ortb2Imp.ext.data.adserver.adslot
-The customPbAdSlot function is called if it was specified, writing the results to fpd.context.pbAdSlot.
-If there's no customPbAdSlot, a default algorithm is used to determine fpd.context.pbAdSlot:
+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:
-- first use the AdUnit's context.pbAdSlot if defined
+- 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 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
diff --git a/dev-docs/modules/haloRtdProvider.md b/dev-docs/modules/haloRtdProvider.md
index fafea35dc7..6e9be1b0d5 100644
--- a/dev-docs/modules/haloRtdProvider.md
+++ b/dev-docs/modules/haloRtdProvider.md
@@ -7,26 +7,35 @@ page_type: module
module_type: rtd
module_code : haloRtdProvider
enable_download : true
+vendor_specific: true
sidebarType : 1
---
-# Audigent Halo RTD Segmentation Module
+# Audigent Halo Real-time Data Submodule
{:.no_toc}
* TOC
{:toc}
-Audigent is a next-generation data management platform and a first-of-a-kind
-"data agency" containing some of the most exclusive content-consuming audiences
-across desktop, mobile and social platforms.
+Audigent is a next-generation, first-party data management platform and the
+world’s first "data agency", powering the programmatic landscape and DTC
+eCommerce with actionable first-party audience and contextual data from
+retailers, lifestyle publishers, content creators, athletes and artists.
+
+The Halo real-time data module in Prebid has been built so publishers
+can maximize the power of their first-party audiences and contextual data.
+This module provides both an integrated cookieless Halo identity, contextual
+targeting and audience segmentation solution that seamlessly and easily
+integrates into your existing Prebid deployment.
+
+Users, devices, content, cohorts and other features are identified and utilized
+to augment every bid request with targeted, first-party data-derived segments
+before being submitted to supply-side platforms. Enriching the bid request with
+robust first-party audience and contextual data, Audigent's Halo RTD module
+helps optimize targeting and header-bidding performance. For more information,
+please visit https://audigent.com or contact our Prebid integration team at
+prebid@audigent.com.
-This real-time data module provides quality user segmentation that can be
-attached to bid request objects destined for different SSPs in order to optimize
-targeting and increase publisher revenue. Audigent maintains a large database
-of first-party Tradedesk Unified ID, Audigent Halo ID and other id provider
-mappings to various third-party segment types that are utilizable across
-different SSPs. With this module, these segments can be retrieved and supplied
-to the SSP in real-time during the bid request cycle.
## Publisher Usage
@@ -34,15 +43,12 @@ Compile the Halo RTD module into your Prebid build:
`gulp build --modules=userId,unifiedIdSystem,rtdModule,haloRtdProvider,appnexusBidAdapter`
-Add the Audigent Halo RTD provider to your Prebid config. For any adapters
-that you would like to retrieve segments for, add a mapping in the 'mapSegments'
-parameter. In this example we will configure publisher 1234 to retrieve
-appnexus segments from Audigent. See the "Parameter Descriptions" below for
-more detailed information of the configuration parameters. Currently,
-OpenRTB compatible fpd data will be added for any bid adapter in the
-"mapSegments" objects. Automated bid augmentation exists for some bidders.
-Please work with your Audigent Prebid support team (prebid@audigent.com) on
-which version of Prebid.js supports which bidders automatically.
+Add the Halo RTD provider to your Prebid config. In this example we will configure
+publisher 1234 to retrieve segments from Audigent. See the
+"Parameter Descriptions" below for more detailed information of the
+configuration parameters. Please work with your Audigent Prebid support team
+(prebid@audigent.com) on which version of Prebid.js supports different bidder
+and segment configurations.
```
pbjs.setConfig(
@@ -54,9 +60,6 @@ pbjs.setConfig(
name: "halo",
waitForIt: true,
params: {
- mapSegments: {
- appnexus: true,
- },
segmentCache: false,
requestParams: {
publisherId: 1234
@@ -77,21 +80,21 @@ pbjs.setConfig(
| name | String | Real time data module name | Always 'halo' |
| waitForIt | Boolean | Required to ensure that the auction is delayed until prefetch is complete | Optional. Defaults to false |
| params | Object | | |
-| params.mapSegments | Boolean | Dictionary of bidders you would like to supply Audigent segments for. Maps to boolean values, but also allows functions for custom mapping logic. The function signature is (bid, segments) => {}. | Required |
+| params.handleRtd | Function | A passable RTD handler that allows custom adunit and ortb2 logic to be configured. The function signature is (bidConfig, rtd, rtdConfig, pbConfig) => {}. | Optional |
| params.segmentCache | Boolean | This parameter tells the Halo RTD module to attempt reading segments from a local storage cache instead of always requesting them from the Audigent server. | Optional. Defaults to false. |
| params.requestParams | Object | Publisher partner specific configuration options, such as optional publisher id and other segment query related metadata to be submitted to Audigent's backend with each request. Contact prebid@audigent.com for more information. | Optional |
+| params.haloIdUrl | String | Parameter to specify alternate haloid endpoint url. | Optional |
+
+## Publisher Customized RTD Handling
-## Overriding & Adding Segment Mappers
As indicated above, it is possible to provide your own bid augmentation
-functions. This is useful if you know a bid adapter's API supports segment
-fields which aren't specifically being added to request objects in the Prebid
-bid adapter. You can also override segment mappers by passing a function
-instead of a boolean to the Halo RTD segment module. This might be useful
-if you'd like to use custom logic to determine which segments are sent
-to a specific backend.
+functions rather than simply merging supplied data. This is useful if you
+want to perform custom bid augmentation and logic with Halo real-time data
+prior to the bid request being sent. Simply add your custom logic to the
+optional handleRtd parameter and provide your custom RTD handling logic there.
Please see the following example, which provides a function to modify bids for
-a bid adapter called adBuzz and overrides the appnexus segment mapper.
+a bid adapter called adBuzz and perform custom logic on bidder parameters.
```
pbjs.setConfig(
@@ -103,19 +106,14 @@ pbjs.setConfig(
name: "halo",
waitForIt: true,
params: {
- mapSegments: {
- // adding an adBuzz segment mapper
- adBuzz: function(bid, segments) {
- bid.params.adBuzzCustomSegments = [];
- for (var i = 0; i < segments.length; i++) {
- bid.params.adBuzzCustomSegments.push(segments[i].id);
- }
- },
- // overriding the appnexus segment mapper to exclude certain segments
- appnexus: function(bid, segments) {
- for (var i = 0; i < segments.length; i++) {
- if (segments[i].id != 'exclude_segment') {
- bid.params.user.segments.push(segments[i].id);
+ handleRtd: function(bidConfig, rtd, rtdConfig, pbConfig) {
+ var adUnits = bidConfig.adUnits;
+ for (var i = 0; i < adUnits.length; i++) {
+ var adUnit = adUnits[i];
+ for (var j = 0; j < adUnit.bids.length; j++) {
+ var bid = adUnit.bids[j];
+ if (bid.bidder == 'adBuzz' && rtd['adBuzz'][0].value != 'excludeSeg') {
+ bid.params.adBuzzCustomSegments.push(rtd['adBuzz'][0].id);
}
}
}
@@ -132,6 +130,11 @@ pbjs.setConfig(
}
```
+The handleRtd function can also be used to configure custom ortb2 data
+processing. Please see the examples available in the haloRtdProvider_spec.js
+tests and work with your Audigent Prebid integration team (prebid@audigent.com)
+on how to best configure your own Halo RTD & Open RTB data handlers.
+
## Testing
To view an example of available segments returned by Audigent's backends:
diff --git a/dev-docs/modules/iabCatagoryTranslation.md b/dev-docs/modules/iabCatagoryTranslation.md
deleted file mode 100644
index 7831fbd198..0000000000
--- a/dev-docs/modules/iabCatagoryTranslation.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-layout: page_v2
-page_type: module
-title: Module - IAB Category Translation
-description: Converts between ad agency brand categories and IAB brand categories.
-module_code : CategoryTranslation
-display_name : CategoryTranslation
-enable_download : true
-sidebarType : 1
----
-
-# IAB Category Translation
-
-{:.no_toc}
-
-This module converts the IAB sub category to FreeWheel industry group identifiers. The FreeWheel identifiers ensure competitve separation of industries and products.
-
-Each bid request must return one [IAB subcategory](https://support.aerserv.com/hc/en-us/articles/207148516-List-of-IAB-Categories).
-
-The module provides the following:
-
-- Converts IAB subcategories to a FreewWheel industry group identifier.
-
-## How to use the module:
-
-1. A Prebid.js package is built that contains this module and the [FreeWheel](/dev-docs/modules/freewheel.html) module.
-2. The inclusion of this module causes Prebid to download a mapping file to local storage. The user also has the option to provide their own mapping file.
-3. At runtime, brand category translation happens as needed.
-
-
-## Using A Custom Map File
-The IAB Category Translation module uses a default mapping file to convert adserver categories to IAB sub categories. If a publisher prefers to use their own mapping file they will need to set the URL location of that file. They can do so by adding the following to their Prebid.js configuration:
-
-```
-pbjs.setConfig({
- "brandCategoryTranslation": {
- "translationFile": "| Module | +Description | +
|---|---|
| {{page.display_name}} | +{{page.description}} | +
| Module | Description | +RTD? | ||
|---|---|---|---|---|
| {{page.title}} | +{{page.display_name}} | {{page.description}} | + {% if page.module_type == "rtd" %}yes | {% else %}no | {% endif %}
| Module | +Description | +RTD? | +|
|---|---|---|---|
| {{page.display_name}} | +{{page.description}} | + {% if page.module_type == "rtd" %}yes | {% else %}no | {% endif %} +
- If you define 'adserverTargeting' in your own bidderSettings object, the setPriceGranularity method won't have any effect, since it assumes you are setting your own custom values.
-
- If you define 'adserverTargeting' in your own bidderSettings object, the setPriceGranularity method won't have any effect, since it assumes you are setting your own custom values.
-
/pbjs_demo.html?pbjs_debug=true See [Prebid.js troubleshooting tips](/dev-docs/troubleshooting-tips.html) for more information.
-
-Turn on debugging permanently in the page:
-{% highlight js %}
-pbjs.setConfig({ debug: true });
-{% endhighlight %}
-
-{: .alert.alert-warning :}
-Note that turning on debugging for Prebid Server causes most server-side adapters to consider it a test request, meaning that they won't count on reports.
-
-
-
-#### Device Access
-
-You can prevent Prebid.js from reading or writing cookies or HTML localstorage by setting this flag:
-
-{% highlight js %}
-pbjs.setConfig({ deviceAccess: false });
-{% endhighlight %}
-
-This can be useful in GDPR, CCPA, COPPA or other privacy scenarios where a publisher has determined that header bidding should not read from or write the user's device.
-
-
-
-#### Bidder Timeouts
-
-Set a global bidder timeout:
-
-{% highlight js %}
-pbjs.setConfig({ bidderTimeout: 3000 });
-{% endhighlight %}
-
-{: .alert.alert-warning :}
-**Bid Timeouts and JavaScript Timers**
-Note that it's possible for the timeout to be triggered later than expected, leading to a bid participating in the auction later than expected. This is due to how [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) works in JS: it queues the callback in the event loop in an approximate location that *should* execute after this time but *it is not guaranteed*.
-With a busy page load, bids can be included in the auction even if the time to respond is greater than the timeout set by Prebid.js. However, we do close the auction immediately if the threshold is greater than 200ms, so you should see a drop off after that period.
-For more information about the asynchronous event loop and `setTimeout`, see [How JavaScript Timers Work](https://johnresig.com/blog/how-javascript-timers-work/).
-
-#### Max Requests Per Origin
-
-
-
-Since browsers have a limit of how many requests they will allow to a specific domain before they block, Prebid.js
-will queue auctions that would cause requests to a specific origin to exceed that limit. The limit is different
-for each browser. Prebid.js defaults to a max of `4` requests per origin. That value can be configured with
-`maxRequestsPerOrigin`.
-
-{% highlight js %}
-// most browsers allow at least 6 requests, but your results may vary for your user base. Sometimes using all
-// `6` requests can impact performance negatively for users with poor internet connections.
-pbjs.setConfig({ maxRequestsPerOrigin: 6 });
-
-// to emulate pre 1-x behavior and have all auctions queue (no concurrent auctions), you can set it to `1`.
-pbjs.setConfig({ maxRequestsPerOrigin: 1 });
-{% endhighlight %}
-
-#### Disable Ajax Timeout
-
-
-
-Prebid core adds a timeout on XMLHttpRequest request to terminate the request once auction is timedout. Since Prebid is ignoring all the bids after timeout it does not make sense to continue the request after timeout. However, you have the option to disable this by using `disableAjaxTimeout`.
-
-{% highlight js %}
-pbjs.setConfig({ disableAjaxTimeout: true });
-{% endhighlight %}
-
-#### Set Timeout Buffer
-
-
-
-Prebid core adds a timeout buffer to extend the time that bidders have to return a bid after the auction closes. This buffer is used to offset the "time slippage" of the setTimeout behavior in browsers. Prebid.js sets the default value to 400ms. You can change this value by setting `timeoutBuffer` to the amount of time you want to use. The following example sets the buffer to 300ms.
-
-{% highlight js %}
-pbjs.setConfig({ timeoutBuffer: 300 });
-{% endhighlight %}
-
-#### Send All Bids
-
-
-
-When enableSendAllBids is **true** (the default), the page will send keywords for all bidders to your ad server. The ad server can then make the decision on which bidder will win. Some ad servers, such as Google Ad Manager, can then generate reporting on historical bid prices from all bidders.
-
-However, there will be a set of ad server targeting values for each bidder, so if you run many bidders this could cause an issue with how much data is being sent to the ad server.
-
-There are several ways to address the issue of sending too much data to the ad server:
-
-1. Set `enableSendAllBids` to **false**. This will minimize the number of targeting variables sent to the ad server; only the top bid will be sent.
-1. Define the `auctionKeyMaxChars` setting. This allows you to establish a limit on the number of bytes sent to the ad server. See [targetingControls](#setConfig-targetingControls) for more details.
-1. Set `enableSendAllBids` to **false** and `targetingControls.alwaysIncludeDeals` to **true**. This will send the top bid and any deals.
-1. Set `enableSendAllBids` to **false**, `targetingControls.alwaysIncludeDeals` to **true**, and `auctionKeyMaxChars`. This will send the top bid and any deals up to the maximum number of characters.
-
-Note that targeting config must be set before either `pbjs.setTargetingForGPTAsync()` or `pbjs.getAdserverTargeting()` is called.
-
-##### Example results where enableSendAllBids is true
-
-{% highlight bash %}
-{
- "hb_adid_audienceNetw": "1663076dadb443d",
- "hb_pb_audienceNetwor": "9.00",
- "hb_size_audienceNetw": "300x250",
- "hb_format_audienceNe": "banner",
- "hb_source_audienceNe": "client",
- "hb_adid_rubicon": "3485968928",
- "hb_pb_rubicon": "8.00",
- "hb_size_rubicon": "300x250",
- "hb_deal_rubicon": "11111111",
- "hb_format_rubicon": "banner",
- "hb_source_rubicon": "client",
- "hb_adid_appnexus": "191f4aca0c0be8",
- "hb_pb_appnexus": "10.00",
- "hb_size_appnexus": "300x250",
- "hb_format_appnexus": "banner",
- "hb_source_appnexus": "client",
- // the winning bid is copied to attributes without a suffix
- "hb_bidder": "appnexus",
- "hb_adid": "191f4aca0c0be8",
- "hb_pb": "10.00",
- "hb_size": "300x250",
- "hb_format": "banner"
-}
-{% endhighlight %}
-
-You can see how the number of ad server targeting variable could get large
-when many bidders are present.
-
-{% capture noteAlert %}
-The Prebid recommendation is to leave `enableSendAllBids` as **true** when ad server targeting volume is not a concern. This approach is more transparent and leaves the decisioning in the ad server.
-{% endcapture %}
-
-{% include alerts/alert_note.html content=noteAlert %}
-
-##### Example of setting enableSendAllBids to false
-
-Turning off `enableSendAllBids` will cause the system to return only the
-winning bid. However, this could be a problem if you need to support [deals](/adops/deals.html), as often a deal may be chosen to win over an open market bid.
-
-To make sure that deal bids are sent along with the winning bid in the enableSendAllBids:false scenario, use the `alwaysIncludeDeals` flag that's part of [targetingControls](#setConfig-targetingControls):
-
-```javascript
-pbjs.setConfig({
- enableSendAllBids: false,
- targetingControls: {
- alwaysIncludeDeals: true
- }
-});
-```
-
-
-
-#### Configure Send Bids Control
-
-
-
-The `sendBidsControl` object passed to `pbjs.setConfig` provides the publisher with the ability to adjust the targeting behavior when [sendAllBids](#setConfig-Send-All-Bids) is enabled.
-
-{: .table .table-bordered .table-striped }
-| Attribute | Type | Description |
-|------------+---------+---------------------------------|
-| `bidLimit` | integer | The maximum number of bids the system can add to ad server targeting. |
-| `dealPrioritization` | boolean | When `true`, bids with deals are prioritized before bids without deals. |
-
-##### Details on the bidLimit setting
-
-Below is an example config containing `bidLimit`:
-
-```javascript
-pbjs.setConfig({
- sendBidsControl: {
- bidLimit: 2
- }
-});
-```
-When this property is set, the value assigned to `bidLimit` is the maximum number of bids that will be sent to the ad server. If `bidLimit` is set to 0, sendAllBids will have no maximum bid limit and *all* bids will be sent. This setting can be helpful if you know that your ad server has a finite limit to the amount of query characters it will accept and process.
-
-{: .alert.alert-info :}
-Note that this feature overlaps and can be used in conjunction with [targetingControls.auctionKeyMaxChars](/dev-docs/publisher-api-reference.html#setConfig-targetingControls). Please see that section for tips on controlling the number of characters being sent to the ad server.
-
-#### Use Bid Cache
-
-
-
-Prebid.js currently allows for [caching and reusing bids in a very narrowly defined scope](/dev-docs/faq.html#does-prebidjs-cache-bids).
-However, if you'd like, you can disable this feature and prevent Prebid.js from using anything but the latest bids for
-a given auction.
-
-{: .alert.alert-warning :}
-This option is available in version 1.39 as true-by-default and became false-by-default as of Prebid.js 2.0. If you want to use this
-feature in 2.0 and later, you'll need to set the value to true.
-
-{% highlight js %}
-pbjs.setConfig({ useBidCache: true })
-{% endhighlight %}
-
-
-#### Bidder Order
-
-Set the order in which bidders are called:
-
-{% highlight js %}
-pbjs.setConfig({ bidderSequence: "fixed" }) /* default is "random" */
-{% endhighlight %}
-
-
-
-#### Page URL
-
-Override the Prebid.js page referrer algorithm.
-
-a{% highlight js %}
-pbjs.setConfig({ pageUrl: "https://example.com/index.html" )
-{% endhighlight %}
-
-
-
-#### Publisher Domain
-
-Set the publisher's domain where Prebid is running, for cross-domain iframe communication:
-
-{% highlight js %}
-pbjs.setConfig({ publisherDomain: "https://www.theverge.com" )
-{% endhighlight %}
-
-
-
-#### Price Granularity
-
-This configuration defines the price bucket granularity setting that will be used for the `hb_pb` keyword.
-
-{% highlight js %}
-pbjs.setConfig({ priceGranularity: "medium" })
-{% endhighlight %}
-
-Standard values:
-
-+ `"low"`: $0.50 increments, capped at $5 CPM
-+ `"medium"`: $0.10 increments, capped at $20 CPM (the default)
-+ `"high"`: $0.01 increments, capped at $20 CPM
-+ `"auto"`: Applies a sliding scale to determine granularity as shown in the [Auto Granularity](#autoGranularityBucket) table below.
-+ `"dense"`: Like `"auto"`, but the bid price granularity uses smaller increments, especially at lower CPMs. For details, see the [Dense Granularity](#denseGranularityBucket) table below.
-+ `customConfigObject`: If you pass in a custom config object (as shown in the [Custom CPM Bucket Sizing](#customCPMObject) example below), you can have much finer control over CPM bucket sizes, precision, and caps.
-
-
-
-##### Auto Granularity
-
-{: .table .table-bordered .table-striped }
-| CPM | Granularity | Example |
-|---------------------+----------------------------------+--------|
-| CPM <= $5 | $0.05 increments | $1.87 floored to $1.85 |
-| CPM <= $10 and > $5 | $0.10 increments | $5.09 floored to $5.00 |
-| CPM <= $20 and > $10 | $0.50 increments | $14.26 floored to $14.00 |
-| CPM > $20 | Caps the price bucket at $20 | $24.82 floored to $20.00 |
-
-
-
-##### Dense Granularity
-
-{: .table .table-bordered .table-striped }
-| CPM | Granularity | Example |
-|------------+-------------------------------+---------|
-| CPM <= $3 | $0.01 increments | $1.87 floored to $1.87 |
-| CPM <= $8 and >$3 | $0.05 increments | $5.09 floored to $5.05 |
-| CPM <= $20 and >$8 | $0.50 increments | $14.26 floored to $14.00 |
-| CPM > $20 | Caps the price bucket at $20 | $24.82 floored to $20.00 |
-
-
-
-##### Custom CPM Bucket Sizing
-
-To set up your own custom CPM buckets, create an object like the following, and pass it into `setConfig`:
-
-```javascript
-const customConfigObject = {
- "buckets" : [{
- "precision": 2, //default is 2 if omitted - means 2.1234 rounded to 2 decimal places = 2.12
- "max" : 5,
- "increment" : 0.01 // from $0 to $5, 1-cent increments
- },
- {
- "max" : 8,
- "increment" : 0.05 // from $5 to $8, round down to the previous 5-cent increment
- },
- {
- "max" : 40,
- "increment" : 0.5 // from $8 to $40, round down to the previous 50-cent increment
- }]
-};
-
-//set custom config object
-pbjs.setConfig({
- priceGranularity: customConfigObject
-})
-```
-
-Here are the rules for CPM intervals:
-
-- `max` and `increment` must be specified
-- A range's minimum value is assumed to be the max value of the previous range. The first interval starts at a min value of 0.
-- `precision` is optional and defaults to 2
-
-{% capture warning-granularity %}
-As of Prebid.js 3.0, the 'min' parameter is no longer supported in custom granularities.
-/pbjs_demo.html?pbjs_debug=true See [Prebid.js troubleshooting guide](/troubleshooting/troubleshooting-guide.html) for more information.
+
+Turn on debugging permanently in the page:
+{% highlight js %}
+pbjs.setConfig({ debug: true });
+{% endhighlight %}
+
+{: .alert.alert-warning :}
+Note that turning on debugging for Prebid Server causes most server-side adapters to consider it a test request, meaning that they won't count on reports.
+
+
+
+#### Device Access
+
+You can prevent Prebid.js from reading or writing cookies or HTML localstorage by setting this flag:
+
+{% highlight js %}
+pbjs.setConfig({ deviceAccess: false });
+{% endhighlight %}
+
+This can be useful in GDPR, CCPA, COPPA or other privacy scenarios where a publisher has determined that header bidding should not read from or write the user's device.
+
+
+
+#### Bidder Timeouts
+
+Set a global bidder timeout:
+
+{% highlight js %}
+pbjs.setConfig({ bidderTimeout: 3000 });
+{% endhighlight %}
+
+{: .alert.alert-warning :}
+**Bid Timeouts and JavaScript Timers**
+Note that it's possible for the timeout to be triggered later than expected, leading to a bid participating in the auction later than expected. This is due to how [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) works in JS: it queues the callback in the event loop in an approximate location that *should* execute after this time but *it is not guaranteed*.
+With a busy page load, bids can be included in the auction even if the time to respond is greater than the timeout set by Prebid.js. However, we do close the auction immediately if the threshold is greater than 200ms, so you should see a drop off after that period.
+For more information about the asynchronous event loop and `setTimeout`, see [How JavaScript Timers Work](https://johnresig.com/blog/how-javascript-timers-work/).
+
+#### Max Requests Per Origin
+
+
+
+Since browsers have a limit of how many requests they will allow to a specific domain before they block, Prebid.js
+will queue auctions that would cause requests to a specific origin to exceed that limit. The limit is different
+for each browser. Prebid.js defaults to a max of `4` requests per origin. That value can be configured with
+`maxRequestsPerOrigin`.
+
+{% highlight js %}
+// most browsers allow at least 6 requests, but your results may vary for your user base. Sometimes using all
+// `6` requests can impact performance negatively for users with poor internet connections.
+pbjs.setConfig({ maxRequestsPerOrigin: 6 });
+
+// to emulate pre 1-x behavior and have all auctions queue (no concurrent auctions), you can set it to `1`.
+pbjs.setConfig({ maxRequestsPerOrigin: 1 });
+{% endhighlight %}
+
+#### Disable Ajax Timeout
+
+
+
+Prebid core adds a timeout on XMLHttpRequest request to terminate the request once auction is timedout. Since Prebid is ignoring all the bids after timeout it does not make sense to continue the request after timeout. However, you have the option to disable this by using `disableAjaxTimeout`.
+
+{% highlight js %}
+pbjs.setConfig({ disableAjaxTimeout: true });
+{% endhighlight %}
+
+#### Set Timeout Buffer
+
+
+
+Prebid core adds a timeout buffer to extend the time that bidders have to return a bid after the auction closes. This buffer is used to offset the "time slippage" of the setTimeout behavior in browsers. Prebid.js sets the default value to 400ms. You can change this value by setting `timeoutBuffer` to the amount of time you want to use. The following example sets the buffer to 300ms.
+
+{% highlight js %}
+pbjs.setConfig({ timeoutBuffer: 300 });
+{% endhighlight %}
+
+#### Send All Bids
+
+
+
+When enableSendAllBids is **true** (the default), the page will send keywords for all bidders to your ad server. The ad server can then make the decision on which bidder will win. Some ad servers, such as Google Ad Manager, can then generate reporting on historical bid prices from all bidders.
+
+However, there will be a set of ad server targeting values for each bidder, so if you run many bidders this could cause an issue with how much data is being sent to the ad server.
+
+There are several ways to address the issue of sending too much data to the ad server:
+
+1. Set `enableSendAllBids` to **false**. This will minimize the number of targeting variables sent to the ad server; only the top bid will be sent.
+1. Define the `auctionKeyMaxChars` setting. This allows you to establish a limit on the number of bytes sent to the ad server. See [targetingControls](#setConfig-targetingControls) for more details.
+1. Set `enableSendAllBids` to **false** and `targetingControls.alwaysIncludeDeals` to **true**. This will send the top bid and any deals.
+1. Set `enableSendAllBids` to **false**, `targetingControls.alwaysIncludeDeals` to **true**, and `auctionKeyMaxChars`. This will send the top bid and any deals up to the maximum number of characters.
+
+Note that targeting config must be set before either `pbjs.setTargetingForGPTAsync()` or `pbjs.getAdserverTargeting()` is called.
+
+##### Example results where enableSendAllBids is true
+
+{% highlight bash %}
+{
+ "hb_adid_audienceNetw": "1663076dadb443d",
+ "hb_pb_audienceNetwor": "9.00",
+ "hb_size_audienceNetw": "300x250",
+ "hb_format_audienceNe": "banner",
+ "hb_source_audienceNe": "client",
+ "hb_adid_rubicon": "3485968928",
+ "hb_pb_rubicon": "8.00",
+ "hb_size_rubicon": "300x250",
+ "hb_deal_rubicon": "11111111",
+ "hb_format_rubicon": "banner",
+ "hb_source_rubicon": "client",
+ "hb_adid_appnexus": "191f4aca0c0be8",
+ "hb_pb_appnexus": "10.00",
+ "hb_size_appnexus": "300x250",
+ "hb_format_appnexus": "banner",
+ "hb_source_appnexus": "client",
+ // the winning bid is copied to attributes without a suffix
+ "hb_bidder": "appnexus",
+ "hb_adid": "191f4aca0c0be8",
+ "hb_pb": "10.00",
+ "hb_size": "300x250",
+ "hb_format": "banner"
+}
+{% endhighlight %}
+
+You can see how the number of ad server targeting variable could get large
+when many bidders are present.
+
+{% capture noteAlert %}
+The Prebid recommendation is to leave `enableSendAllBids` as **true** when ad server targeting volume is not a concern. This approach is more transparent and leaves the decisioning in the ad server.
+{% endcapture %}
+
+{% include alerts/alert_note.html content=noteAlert %}
+
+##### Example of setting enableSendAllBids to false
+
+Turning off `enableSendAllBids` will cause the system to return only the
+winning bid. However, this could be a problem if you need to support [deals](/adops/deals.html), as often a deal may be chosen to win over an open market bid.
+
+To make sure that deal bids are sent along with the winning bid in the enableSendAllBids:false scenario, use the `alwaysIncludeDeals` flag that's part of [targetingControls](#setConfig-targetingControls):
+
+```javascript
+pbjs.setConfig({
+ enableSendAllBids: false,
+ targetingControls: {
+ alwaysIncludeDeals: true
+ }
+});
+```
+
+
+
+#### Configure Send Bids Control
+
+
+
+The `sendBidsControl` object passed to `pbjs.setConfig` provides the publisher with the ability to adjust the targeting behavior when [sendAllBids](#setConfig-Send-All-Bids) is enabled.
+
+{: .table .table-bordered .table-striped }
+| Attribute | Type | Description |
+|------------+---------+---------------------------------|
+| `bidLimit` | integer | The maximum number of bids the system can add to ad server targeting. |
+| `dealPrioritization` | boolean | When `true`, bids with deals are prioritized before bids without deals. |
+
+##### Details on the bidLimit setting
+
+Below is an example config containing `bidLimit`:
+
+```javascript
+pbjs.setConfig({
+ sendBidsControl: {
+ bidLimit: 2
+ }
+});
+```
+When this property is set, the value assigned to `bidLimit` is the maximum number of bids that will be sent to the ad server. If `bidLimit` is set to 0, sendAllBids will have no maximum bid limit and *all* bids will be sent. This setting can be helpful if you know that your ad server has a finite limit to the amount of query characters it will accept and process.
+
+{: .alert.alert-info :}
+Note that this feature overlaps and can be used in conjunction with [targetingControls.auctionKeyMaxChars](#setConfig-targetingControls). Please see that section for tips on controlling the number of characters being sent to the ad server.
+
+#### Use Bid Cache
+
+
+
+Prebid.js currently allows for [caching and reusing bids in a very narrowly defined scope](/dev-docs/faq.html#does-prebidjs-cache-bids).
+However, if you'd like, you can disable this feature and prevent Prebid.js from using anything but the latest bids for
+a given auction.
+
+{: .alert.alert-warning :}
+This option is available in version 1.39 as true-by-default and became false-by-default as of Prebid.js 2.0. If you want to use this
+feature in 2.0 and later, you'll need to set the value to true.
+
+{% highlight js %}
+pbjs.setConfig({ useBidCache: true })
+{% endhighlight %}
+
+
+#### Bidder Order
+
+Set the order in which bidders are called:
+
+{% highlight js %}
+pbjs.setConfig({ bidderSequence: "fixed" }) /* default is "random" */
+{% endhighlight %}
+
+
+
+#### Page URL
+
+Override the Prebid.js page referrer for some bidders.
+
+{% highlight js %}
+pbjs.setConfig({ pageUrl: "https://example.com/index.html" })
+{% endhighlight %}
+
+
+
+#### Publisher Domain
+
+{: .alert.alert-warning :}
+This API is deprecated. Please use 'pageUrl' instead.
+
+Set the publisher's domain where Prebid is running, for cross-domain iframe communication:
+
+{% highlight js %}
+pbjs.setConfig({ publisherDomain: "https://www.theverge.com" )
+{% endhighlight %}
+
+
+
+#### Price Granularity
+
+This configuration defines the price bucket granularity setting that will be used for the `hb_pb` keyword.
+
+{% highlight js %}
+pbjs.setConfig({ priceGranularity: "medium" })
+{% endhighlight %}
+
+Standard values:
+
++ `"low"`: $0.50 increments, capped at $5 CPM
++ `"medium"`: $0.10 increments, capped at $20 CPM (the default)
++ `"high"`: $0.01 increments, capped at $20 CPM
++ `"auto"`: Applies a sliding scale to determine granularity as shown in the [Auto Granularity](#autoGranularityBucket) table below.
++ `"dense"`: Like `"auto"`, but the bid price granularity uses smaller increments, especially at lower CPMs. For details, see the [Dense Granularity](#denseGranularityBucket) table below.
++ `customConfigObject`: If you pass in a custom config object (as shown in the [Custom CPM Bucket Sizing](#customCPMObject) example below), you can have much finer control over CPM bucket sizes, precision, and caps.
+
+
+
+##### Auto Granularity
+
+{: .table .table-bordered .table-striped }
+| CPM | Granularity | Example |
+|---------------------+----------------------------------+--------|
+| CPM <= $5 | $0.05 increments | $1.87 floored to $1.85 |
+| CPM <= $10 and > $5 | $0.10 increments | $5.09 floored to $5.00 |
+| CPM <= $20 and > $10 | $0.50 increments | $14.26 floored to $14.00 |
+| CPM > $20 | Caps the price bucket at $20 | $24.82 floored to $20.00 |
+
+
+
+##### Dense Granularity
+
+{: .table .table-bordered .table-striped }
+| CPM | Granularity | Example |
+|------------+-------------------------------+---------|
+| CPM <= $3 | $0.01 increments | $1.87 floored to $1.87 |
+| CPM <= $8 and >$3 | $0.05 increments | $5.09 floored to $5.05 |
+| CPM <= $20 and >$8 | $0.50 increments | $14.26 floored to $14.00 |
+| CPM > $20 | Caps the price bucket at $20 | $24.82 floored to $20.00 |
+
+
+
+##### Custom CPM Bucket Sizing
+
+To set up your own custom CPM buckets, create an object like the following, and pass it into `setConfig`:
+
+```javascript
+const customConfigObject = {
+ "buckets" : [{
+ "precision": 2, //default is 2 if omitted - means 2.1234 rounded to 2 decimal places = 2.12
+ "max" : 5,
+ "increment" : 0.01 // from $0 to $5, 1-cent increments
+ },
+ {
+ "max" : 8,
+ "increment" : 0.05 // from $5 to $8, round down to the previous 5-cent increment
+ },
+ {
+ "max" : 40,
+ "increment" : 0.5 // from $8 to $40, round down to the previous 50-cent increment
+ }]
+};
+
+//set custom config object
+pbjs.setConfig({
+ priceGranularity: customConfigObject
+})
+```
+
+Here are the rules for CPM intervals:
+
+- `max` and `increment` must be specified
+- A range's minimum value is assumed to be the max value of the previous range. The first interval starts at a min value of 0.
+- `precision` is optional and defaults to 2
+
+{% capture warning-granularity %}
+As of Prebid.js 3.0, the 'min' parameter is no longer supported in custom granularities.
+Prebid Support for Enforcing TCF 2.0
Summary of Prebid TCF 2.0 Enforcement
Full Enforcement (Prebid Server Only)
Prebid.js Functional Requirements
Prebid SDK Functional Requirements
Prebid Server Functional Requirements
The IAB's Transparency and Consent Framework version 2.0 for enhanced support of GDPR is scheduled to take effect Apr 1 2020. It's a major update from TCF 1.1 which Prebid currently supports, and is not compatible with the previous release.
The key changes are:
References
Important Legal Note: Prebid.org cannot provide legal advice about GDPR or any other governmental regulation. Our aim is to provide a toolkit of functionality that will let publishers configure header bidding as defined by their legal counsel. We will consider feature suggestions, and review any code offered by the community. Enforcement of Purpose 2 (basic ad selection) looks to be one of the bigger areas of concern because the TCF policy could be interpreted to be a form of ad blocking. You will need to work with your legal counsel to determine how you intend to handle this scenario. Prebid.js and Prebid Server offer publishers the ability to enforce or not-enforce purposes individually. As an example of the kind of flexibility we aim to offer (*), here are some options you could discuss with your lawyers:
(*) - Note on phasing: Please be aware that Prebid.js and Prebid Server will likely not deliver on the full TCF functionality by April 1st. Our initial goal for both products is to support Purpose 1 (Device Access) enforcement by that date. The ability to enforce the other purposes will be developed as soon as we can. (**) Did we mention that you cannot rely on this document to learn how to configure your header bidding for GDPR? Seriously, talk to your lawyers. |
General
Prebid.js
Prebid Server
Prebid SDK
TCF Field | In-scope Activities | System | Enforcement | Publisher/ Host Company Controls |
Purpose 1 - Store and/or access information on a device | usersync pixels, user ID modules, and device storage | Prebid.js and Prebid Server and Prebid SDK | May result in preventing one or more uesrsync activities for one or more vendors. | Do not enforce purpose 1 Do not enforce purpose 1 for vendor V Enforce purpose 1 at the vendor level only. |
Purpose 2 - Select basic ads | call bid adapters | Prebid.js and Prebid Server | May result in skipping one or more bid adapters. All configured modules will be called as usual unless all bidders are eliminated. | Do not enforce purpose 2 Do not enforce purpose 2 for vendor V Enforce purpose 2 at the vendor level only. |
Purpose 4 - Select Personalized Ads | call bid adapters with userIds | Prebid.js and Prebid Server | May result in removing the userIds before calling one or more bid adapters. | Do not enforce purpose 4 Do not enforce purpose 4 for vendor V Enforce purpose 4 at the vendor level only. |
Purpose 7 - Measure ad performance | initiate analytics | Prebid.js and Prebid Server | May result in skipping one or more analytics adapters. | Do not enforce purpose 7 Do not enforce purpose 7 for vendor V Enforce purpose 7 at the vendor level only. |
Special Feature 1 - Use precise geolocation data | passing lat/long to server-side bid adapters | Prebid Server | May result in rounding lat/long values and IP address before sending to server-side adapters. | Do not enforce Special Feature 1 |
Special Purpose 2 - Technically deliver ads or content | n/a | Special Purposes do not require consent. If a publisher’s legal team wants to consider SP2, Prebid software should not be called. | ||
PurposeOneConsent | n/a | Prebid does not provide specific support for enforcing this flag. Instead, publishers may use the provided controls for Purpose 1 and other Prebid configuration to control whether the user’s device is accessed. | ||
Prebid offers publishers several controls for whether consent/legal basis confirmation is even performed. The following flowchart shows how the controls
The goal of 'basic enforcement' is to confirm that there's enough evidence of consent to pass data on to vendors who have access to the GVL and can fully parse and enforce.
Before allowing a Purpose for a given Vendor, one of these scenarios must be true: :
In terms of the TCF 2.0 fields, Purpose P is ok for vendor V if either of these is true:
Before allowing Special Feature 1, SpecialFeatureOptIns[1] must be true.
The big difference between 'basic' and 'full' enforcement is that Prebid Server has the GVL available to examine vendor legal bases.
Before allowing an activity that falls under a specific Purpose for a given Vendor, one of these 6 basic scenarios needs to be true:
Note that there are many more scenarios where the activity would not be allowed.
The technical definition in terms of the TCF 2.0 fields follows. Purpose P is ok for vendor V if any of these is true:
Before allowing Special Feature 1, SpecialFeatureOptIns[1] must be true.
1) An optional module must be available for reading the IAB TCF 2.0 API data. Publishers will include this module in their Prebid.js package when they need to support EEA users.
2) Prebid.js must support scenarios where the TCF string parsing functions are not available. If the codebase for parsing the TCF string is significant, it should be made an optional module separate from the enforcement functions. A key goal of Prebid.js is to include only the code that publishers need for their particular use case. The technical design should consider whether it makes sense to bundle all of these components together, or break them into 2 or 3 separate modules:
3) Prebid.js must support the following publisher controls:
Here's a set of proposed configurations within the existing consentManagement config object:
Param | Type | Description | Details |
gdpr.allowAuctionWithoutConsent | boolean | Available in 3.x only, defines behavior for backwards compatibility. | For 3.x: If true, consider all Purposes as not enforceable. If false, consider only Purpose 2 enforceable. |
gdpr.consentData | object | Consent data provided statically. | Used when cmpApi is "static". |
gdpr.defaultGdprScope | boolean | ||
gdpr.rules | object | Lets the publisher override the defaults set by the enforceMode | |
gdpr.rules[].purpose | string | Possible values are "storage", "basicAds", "personalizedAds", and "measurement" corresponding to Purposes 1,2,4, and 7 respectively. | For some reason, people tend to prefer using the string names rather than the numbers. |
gdpr.rules[].enforcePurpose | boolean | Whether to enforce this purpose or not. Overrides the setting from enforceMode. | The default in PBJS 3.x will be to enforce no purposes, and in 4.0 to enforce Purpose 1 and no others. |
gdpr.rules[].enforceVendor | boolean | Whether to enforce vendor consent/legal basis for this purpose or not.. | The default in PBJS 3.x will be to enforce no purposes, and in 4.0 to enforce Purpose 1 and no others. |
gdpr.rules[].vendorExceptions | array of strings | Which biddercodes or module names should be treated as the opposite of the enforceVendor flag. | If enforceVendor=false, then vendorExceptions are those that will be treated as true. If enforce=true, then vendorExceptions are those that will be treated as false. |
Example configurations:
pbjs.setConfig({ consentManagement: { gdpr: { cmpApi: 'iab', defaultGdprScope: true/false (0/1?) timeout: 3000, // allowAuctionWithoutConsent: false, // deprecated rules: [{ // don’t enforce Purpose 1 except for bidderA. // this means that TCF approval is only considered // for this one bidder. purpose: "storage", enforcePurpose: false, enforceVendor: false, vendorExceptions: ["bidderA"] },{ // Allow the user to object to vendors for Purpose 2 // but don’t allow them to turn off header bidding // altogether. // The exception is bidderB, which the user will // not be allowed to reject purpose: "basicAds", enforcePurpose: false, enforceVendor: true, vendorExceptions: ["bidderB"] },{ // allow the user to have their userId removed from // header bidding except for bidders A and B purpose: "personalizedAds", enforcePurpose: true, enforceVendor: true vendorExceptions: ["bidderA","bidderB"] },{ // analytics adapters are ok
purpose: "measurement", enforcePurpose: false, enforcePurpose: false }] } } }); |
You may notice that the examples above provide more flexibility than TCF requires. This allows publishers to establish custom legal bases in consultation with their legal counsel.
4) If the 'gdprApplies' flag is defined and is false, then Prebid.js may assume that GDPR is not in scope and therefore doesn't need to be enforced. All Purposes will be set to enforce=false.
4) There should be a way for bidAdapters to supply a GVL ID for each alias they support.
5) The aliasBidder() function should be extended to support specification of a GVL ID. e.g.
pbjs.aliasBidder('appnexus', 'newAlias', 999);
6) If a bidder code isn't associated with a GVL ID, enforcement should assume that the vendor is not allowed unless the publisher has specifically named their bidder code.
7) Analytics adapters must be associated with a GVL ID and/or a "name" to allow the system to determine which analytics adapter(s) are permitted to operate in the current context.
8) User ID modules and Real Time Data modules should be associated with a GVL ID and/or a "name" to allow the system to determine which modules are permitted to operate in the current context.
9) The system must be able to verify vendor consent in two ways:
10) The internal interface to bid adapters should remain the same: bidrequest.gdprConsent
11) The OpenRTB interface to Prebid Server should remain the same:
12) The system must support all the activity enforcement noted in the 'Summary of Prebid TCF 2.0 Enforcement' section.
13) If consentManagement.gdpr is configured but no consent string is available, the system must assume that the user does not consent to either purpose or vendor. Activities may still take place if the publisher has configured the relevant Purposes as 'not enforced'.
13) Bid adapters must do one of the following for all device access activities (reading or setting cookies or local storage):
14) Prebid core must make the following information available to analytics adapters:
15) It should be possible for a pub to define a mapping between a module code and a GVL ID
pbjs.setConfig({
gvlMapping: {
“id5”: 9999
“bidderX”: 8888
}
1) Prebid SDK must accept the following optional parameters to support TCF 2.0. It’s assumed the app will pass these values directly or indirectly from a mobile CMP.
2) When a request is defined to be GDPR in-scope, the SDK must confirm that the ‘deviceAccessConsent’ flag is true. Here’s the truth table for when the SDK is allowed to access the device ID:
deviceAccessConsent=true | deviceAccessConsent=false | deviceAccessConsent undefined | |
GDPR scope=false | Yes, read IDFA | No, don’t read IDFA | Yes, read IDFA |
GDPR scope=true | Yes, read IDFA | No, don’t read IDFA | No, don’t read IDFA |
GDPR scope undefined | Yes, read IDFA | No, don’t read IDFA | Yes, read IDFA |
3) The SDK must pass the consent data to Prebid Server on the same OpenRTB attributes as defined in TCF 1.1:
1) Optional configuration must be available for host companies to turn on and off enforcing GDPR with IAB TCF 2.0 API data. There should be global and publisher account level configuration. The default should be to enforce.
2) If enforcement is turned on for this request, Prebid Server must be able to determine whether it's in-scope for GDPR processing. If any of the following conditions are true, the request is in-scope:
3) Prebid Server must support the following host company controls:
4) Prebid Server must give host company config to say what to do with the purposeOneTreatment - both as a default and for each account:
The implementation of this “PurposeOneTreatmentInterpretation flag modifies the flowchart above: it may short-circuit the logic, jumping straight to Yes or No without a normal enforcement check.
5) It must be possible for a Host Company to define its GVL ID to use for confirming user user consent for setting cookies.
Example configuration/DB entries:
gdpr.host-vendor-id: 52
gdpr.enabled: true/false // default true
gdpr.purpose.P.enforcePurpose: no/basic/full // default full
gdpr.purpose.P.enforceVendors: true/false // default true
gdpr.purpose.P.vendorExceptions: list of biddercodes
gdpr.specialfeature.S.enforce: true/false // default true
gdpr.specialfeature.S.vendorExceptions: list of biddercodes
gdpr.purposeOneTreatmentInterpretation: ignore/no-access-allowed/access-allowed
account.A.gdpr.enabled: true/false // default true
account.A.gdpr.purpose.P.enforcePurpose
account.A.gdpr.purpose.P.enforceVendors
account.A.gdpr.purpose.P.vendorExceptions
account.A.gdpr.specialfeature.S.enforce
account.A.gdpr.specialfeature.S.vendorExceptions
account.A.gdpr.purposeOneTreatmentInterpretation
geolocation.VENDOR.server: url // location of geo lookup service
6) There should be a way for bidAdapters to supply a GVL ID for each alias they support.
7) The external definition of aliases should be extended to support specification of a GVL ID. e.g.
"ext": {
"prebid": {
"aliases": { // existing feature
"districtm": "appnexus"
},
"aliasgvlids": { // new feature
"districtm": 144
}
}
}
8) Prebid Server's enforcement should be "Full" mode unless it doesn't have access to the proper GVL version.
9) Prebid Server should be able to read the TCF2.0 GVL that's specified in the consent string. If it does not have immediate access to that version of the GVL, it may downgrade enforcement to "Basic". The assumption is that subsequent requests for that version of the GVL will succeed. The system should log any usage of Basic Enforcement.
10) If a bidder code isn't associated with a GVL ID, enforcement should assume that the vendor is not allowed unless the publisher has specifically named the bidder code as a configured exception.
11) Analytics adapters must be associated with a GVL ID and/or a "name" to allow the system to determine which analytics adapter(s) are permitted to operate in the current context.
12) User ID modules and Real Time Data modules should be associated with a GVL ID and/or a "name" to allow the system to determine which modules are permitted to operate in the current context.
13) The system must be able to verify vendor consent in two ways:
14) The internal interface to bid adapters should remain the same.
15) The OpenRTB interface to Prebid Server should remain the same:
16) The system must support all the activity enforcement noted in the 'Summary of Prebid TCF 2.0 Enforcement' section.
17) If GDPR is being enforced but no consent string is available, the system must assume that the user does not consent to either purpose or vendor. Activities may still take place if the Host Company has configured the relevant Purposes as 'not enforced'.
18) Prebid Server core must make the following information available to analytics adapters:
\ No newline at end of file +
Prebid Support for Enforcing TCF 2.0
Summary of Prebid TCF 2.0 Enforcement
Full Enforcement (Prebid Server Only)
Prebid.js Functional Requirements
Prebid SDK Functional Requirements
Prebid Server Functional Requirements
The IAB's Transparency and Consent Framework version 2.0 for enhanced support of GDPR is scheduled to take effect Apr 1 2020. It's a major update from TCF 1.1 which Prebid currently supports, and is not compatible with the previous release.
The key changes are:
References
Important Legal Note: Prebid.org cannot provide legal advice about GDPR or any other governmental regulation. Our aim is to provide a toolkit of functionality that will let publishers configure header bidding as defined by their legal counsel. We will consider feature suggestions, and review any code offered by the community. Enforcement of Purpose 2 (basic ad selection) looks to be one of the bigger areas of concern because the TCF policy could be interpreted to be a form of ad blocking. You will need to work with your legal counsel to determine how you intend to handle this scenario. Prebid.js and Prebid Server offer publishers the ability to enforce or not-enforce purposes individually. As an example of the kind of flexibility we aim to offer (*), here are some options you could discuss with your lawyers:
(*) - Note on phasing: Please be aware that Prebid.js and Prebid Server will likely not deliver on the full TCF functionality by April 1st. Our initial goal for both products is to support Purpose 1 (Device Access) enforcement by that date. The ability to enforce the other purposes will be developed as soon as we can. (**) Did we mention that you cannot rely on this document to learn how to configure your header bidding for GDPR? Seriously, talk to your lawyers. |
General
Prebid.js
Prebid Server
Prebid SDK
TCF Field | In-scope Activities | System | Enforcement | Publisher/ Host Company Controls |
Purpose 1 - Store and/or access information on a device | usersync pixels, user ID modules, and device storage | Prebid.js and Prebid Server and Prebid SDK | May result in preventing one or more uesrsync activities for one or more vendors. | Do not enforce purpose 1 Do not enforce purpose 1 for vendor V Enforce purpose 1 at the vendor level only. |
Purpose 2 - Select basic ads | call bid adapters | Prebid.js and Prebid Server | May result in skipping one or more bid adapters. All configured modules will be called as usual unless all bidders are eliminated. | Do not enforce purpose 2 Do not enforce purpose 2 for vendor V Enforce purpose 2 at the vendor level only. |
Purpose 4 - Select Personalized Ads | call bid adapters with userIds | Prebid.js and Prebid Server | May result in removing the userIds before calling one or more bid adapters. | Do not enforce purpose 4 Do not enforce purpose 4 for vendor V Enforce purpose 4 at the vendor level only. |
Purpose 7 - Measure ad performance | initiate analytics | Prebid.js and Prebid Server | May result in skipping one or more analytics adapters. | Do not enforce purpose 7 Do not enforce purpose 7 for vendor V Enforce purpose 7 at the vendor level only. |
Special Feature 1 - Use precise geolocation data | passing lat/long to server-side bid adapters | Prebid Server | May result in rounding lat/long values and IP address before sending to server-side adapters. | Do not enforce Special Feature 1 |
Special Purpose 2 - Technically deliver ads or content | n/a | Special Purposes do not require consent. If a publisher’s legal team wants to consider SP2, Prebid software should not be called. | ||
PurposeOneConsent | n/a | Prebid does not provide specific support for enforcing this flag. Instead, publishers may use the provided controls for Purpose 1 and other Prebid configuration to control whether the user’s device is accessed. | ||
Prebid offers publishers several controls for whether consent/legal basis confirmation is even performed. The following flowchart shows how the controls
The goal of 'basic enforcement' is to confirm that there's enough evidence of consent to pass data on to vendors who have access to the GVL and can fully parse and enforce.
Before allowing a Purpose for a given Vendor, one of these scenarios must be true: :
In terms of the TCF 2.0 fields, Purpose P is ok for vendor V if either of these is true:
Before allowing Special Feature 1, SpecialFeatureOptIns[1] must be true.
The big difference between 'basic' and 'full' enforcement is that Prebid Server has the GVL available to examine vendor legal bases.
Before allowing an activity that falls under a specific Purpose for a given Vendor, one of these 6 basic scenarios needs to be true:
Note that there are many more scenarios where the activity would not be allowed.
The technical definition in terms of the TCF 2.0 fields follows. Purpose P is ok for vendor V if any of these is true:
Before allowing Special Feature 1, SpecialFeatureOptIns[1] must be true.
1) An optional module must be available for reading the IAB TCF 2.0 API data. Publishers will include this module in their Prebid.js package when they need to support EEA users.
2) Prebid.js must support scenarios where the TCF string parsing functions are not available. If the codebase for parsing the TCF string is significant, it should be made an optional module separate from the enforcement functions. A key goal of Prebid.js is to include only the code that publishers need for their particular use case. The technical design should consider whether it makes sense to bundle all of these components together, or break them into 2 or 3 separate modules:
3) Prebid.js must support the following publisher controls:
Here's a set of proposed configurations within the existing consentManagement config object:
Param | Type | Description | Details |
gdpr.allowAuctionWithoutConsent | boolean | Available in 3.x only, defines behavior for backwards compatibility. | For 3.x: If true, consider all Purposes as not enforceable. If false, consider only Purpose 2 enforceable. |
gdpr.consentData | object | Consent data provided statically. | Used when cmpApi is "static". |
gdpr.defaultGdprScope | boolean | ||
gdpr.rules | object | Lets the publisher override the defaults set by the enforceMode | |
gdpr.rules[].purpose | string | Possible values are "storage", "basicAds", "personalizedAds", and "measurement" corresponding to Purposes 1,2,4, and 7 respectively. | For some reason, people tend to prefer using the string names rather than the numbers. |
gdpr.rules[].enforcePurpose | boolean | Whether to enforce this purpose or not. Overrides the setting from enforceMode. | The default in PBJS 3.x will be to enforce no purposes, and in 4.0 to enforce Purpose 1 and no others. |
gdpr.rules[].enforceVendor | boolean | Whether to enforce vendor consent/legal basis for this purpose or not.. | The default in PBJS 3.x will be to enforce no purposes, and in 4.0 to enforce Purpose 1 and no others. |
gdpr.rules[].vendorExceptions | array of strings | Which biddercodes or module names should be treated as the opposite of the enforceVendor flag. | If enforceVendor=false, then vendorExceptions are those that will be treated as true. If enforce=true, then vendorExceptions are those that will be treated as false. |
Example configurations:
pbjs.setConfig({ consentManagement: { gdpr: { cmpApi: 'iab', defaultGdprScope: true/false (0/1?) timeout: 3000, // allowAuctionWithoutConsent: false, // deprecated rules: [{ // don’t enforce Purpose 1 except for bidderA. // this means that TCF approval is only considered // for this one bidder. purpose: "storage", enforcePurpose: false, enforceVendor: false, vendorExceptions: ["bidderA"] },{ // Allow the user to object to vendors for Purpose 2 // but don’t allow them to turn off header bidding // altogether. // The exception is bidderB, which the user will // not be allowed to reject purpose: "basicAds", enforcePurpose: false, enforceVendor: true, vendorExceptions: ["bidderB"] },{ // allow the user to have their userId removed from // header bidding except for bidders A and B purpose: "personalizedAds", enforcePurpose: true, enforceVendor: true vendorExceptions: ["bidderA","bidderB"] },{ // analytics adapters are ok
purpose: "measurement", enforcePurpose: false, enforcePurpose: false }] } } }); |
You may notice that the examples above provide more flexibility than TCF requires. This allows publishers to establish custom legal bases in consultation with their legal counsel.
4) If the 'gdprApplies' flag is defined and is false, then Prebid.js may assume that GDPR is not in scope and therefore doesn't need to be enforced. All Purposes will be set to enforce=false.
4) There should be a way for bidAdapters to supply a GVL ID for each alias they support.
5) The aliasBidder() function should be extended to support specification of a GVL ID. e.g.
pbjs.aliasBidder('appnexus', 'newAlias', 999);
6) If a bidder code isn't associated with a GVL ID, enforcement should assume that the vendor is not allowed unless the publisher has specifically named their bidder code.
7) Analytics adapters must be associated with a GVL ID and/or a "name" to allow the system to determine which analytics adapter(s) are permitted to operate in the current context.
8) User ID modules and Real Time Data modules should be associated with a GVL ID and/or a "name" to allow the system to determine which modules are permitted to operate in the current context.
9) The system must be able to verify vendor consent in two ways:
10) The internal interface to bid adapters should remain the same: bidrequest.gdprConsent
11) The OpenRTB interface to Prebid Server should remain the same:
12) The system must support all the activity enforcement noted in the 'Summary of Prebid TCF 2.0 Enforcement' section.
13) If consentManagement.gdpr is configured but no consent string is available, the system must assume that the user does not consent to either purpose or vendor. Activities may still take place if the publisher has configured the relevant Purposes as 'not enforced'.
13) Bid adapters must do one of the following for all device access activities (reading or setting cookies or local storage):
14) Prebid core must make the following information available to analytics adapters:
15) It should be possible for a pub to define a mapping between a module code and a GVL ID
pbjs.setConfig({
gvlMapping: {
“id5”: 9999
“bidderX”: 8888
}
1) Prebid SDK must accept the following optional parameters to support TCF 2.0. It’s assumed the app will pass these values directly or indirectly from a mobile CMP.
2) When a request is defined to be GDPR in-scope, the SDK must confirm that the ‘deviceAccessConsent’ flag is true. Here’s the truth table for when the SDK is allowed to access the device ID:
deviceAccessConsent=true | deviceAccessConsent=false | deviceAccessConsent undefined | |
GDPR scope=false | Yes, read IDFA | No, don’t read IDFA | Yes, read IDFA |
GDPR scope=true | Yes, read IDFA | No, don’t read IDFA | No, don’t read IDFA |
GDPR scope undefined | Yes, read IDFA | No, don’t read IDFA | Yes, read IDFA |
3) The SDK must pass the consent data to Prebid Server on the same OpenRTB attributes as defined in TCF 1.1:
1) Optional configuration must be available for host companies to turn on and off enforcing GDPR with IAB TCF 2.0 API data. There should be global and publisher account level configuration. The default should be to enforce.
2) If enforcement is turned on for this request, Prebid Server must be able to determine whether it's in-scope for GDPR processing. If any of the following conditions are true, the request is in-scope:
3) Prebid Server must support the following host company controls:
4) Prebid Server must give host company config to say what to do with the purposeOneTreatment - both as a default and for each account:
The implementation of this “PurposeOneTreatmentInterpretation flag modifies the flowchart above: it may short-circuit the logic, jumping straight to Yes or No without a normal enforcement check.
5) It must be possible for a Host Company to define its GVL ID to use for confirming user user consent for setting cookies.
Example configuration/DB entries:
gdpr.host-vendor-id: 52
gdpr.enabled: true/false // default true
gdpr.purpose.P.enforcePurpose: no/basic/full // default full
gdpr.purpose.P.enforceVendors: true/false // default true
gdpr.purpose.P.vendorExceptions: list of biddercodes
gdpr.specialfeature.S.enforce: true/false // default true
gdpr.specialfeature.S.vendorExceptions: list of biddercodes
gdpr.purposeOneTreatmentInterpretation: ignore/no-access-allowed/access-allowed
account.A.gdpr.enabled: true/false // default true
account.A.gdpr.purpose.P.enforcePurpose
account.A.gdpr.purpose.P.enforceVendors
account.A.gdpr.purpose.P.vendorExceptions
account.A.gdpr.specialfeature.S.enforce
account.A.gdpr.specialfeature.S.vendorExceptions
account.A.gdpr.purposeOneTreatmentInterpretation
geolocation.VENDOR.server: url // location of geo lookup service
6) There should be a way for bidAdapters to supply a GVL ID for each alias they support.
7) The external definition of aliases should be extended to support specification of a GVL ID. e.g.
"ext": {
"prebid": {
"aliases": { // existing feature
"districtm": "appnexus"
},
"aliasgvlids": { // new feature
"districtm": 144
}
}
}
8) Prebid Server's enforcement should be "Full" mode unless it doesn't have access to the proper GVL version.
9) Prebid Server should be able to read the TCF2.0 GVL that's specified in the consent string. If it does not have immediate access to that version of the GVL, it may downgrade enforcement to "Basic". The assumption is that subsequent requests for that version of the GVL will succeed. The system should log any usage of Basic Enforcement.
10) If a bidder code isn't associated with a GVL ID, enforcement should assume that the vendor is not allowed unless the publisher has specifically named the bidder code as a configured exception.
11) Analytics adapters must be associated with a GVL ID and/or a "name" to allow the system to determine which analytics adapter(s) are permitted to operate in the current context.
12) User ID modules and Real Time Data modules should be associated with a GVL ID and/or a "name" to allow the system to determine which modules are permitted to operate in the current context.
13) The system must be able to verify vendor consent in two ways:
14) The internal interface to bid adapters should remain the same.
15) The OpenRTB interface to Prebid Server should remain the same:
16) The system must support all the activity enforcement noted in the 'Summary of Prebid TCF 2.0 Enforcement' section.
17) If GDPR is being enforced but no consent string is available, the system must assume that the user does not consent to either purpose or vendor. Activities may still take place if the Host Company has configured the relevant Purposes as 'not enforced'.
18) Prebid Server core must make the following information available to analytics adapters:
diff --git a/dev-docs/show-long-form-video-with-gam.md b/dev-docs/show-long-form-video-with-gam.md index 1891608559..b14d30180f 100644 --- a/dev-docs/show-long-form-video-with-gam.md +++ b/dev-docs/show-long-form-video-with-gam.md @@ -167,7 +167,7 @@ hb_pb_cat_dur = '10.00_10s' **4. Implement Custom Price Buckets** -By default, Prebid.js caps all CPMs at $20. With sell side video there may be an expecation to see CPMs over $20. In order to receive those bids, custom price buckets need to be implemented by setting the [priceGranularity](/dev-docs/publisher-api-reference.html#setConfig-Price-Granularity) object of the `setConfig` method. +By default, Prebid.js caps all CPMs at $20. With sell side video there may be an expecation to see CPMs over $20. In order to receive those bids, custom price buckets need to be implemented by setting the [priceGranularity](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Price-Granularity) object of the `setConfig` method. For instructions on setting custom price buckets, view the [Custom Price Granularity Buckets](/dev-docs/examples/custom-price-buckets.html) documentation on prebid.org. diff --git a/dev-docs/show-multi-format-ads.md b/dev-docs/show-multi-format-ads.md index 6515a93c01..4d6bc1cb8d 100644 --- a/dev-docs/show-multi-format-ads.md +++ b/dev-docs/show-multi-format-ads.md @@ -34,7 +34,7 @@ Prebid multi-format ad units allow direct competition between banner, native, an At a high level, Prebid.js supports multi-format ads as follows: -1. An ad unit may define a [`mediaTypes`]({{site.baseurl}}/dev-docs/publisher-api-reference.html#addAdUnits-MediaTypes) object to specify one or more supported formats and their respective properties. +1. An ad unit may define a [`mediaTypes`](/dev-docs/publisher-api-reference/addAdUnits.html#addAdUnits-MediaTypes) object to specify one or more supported formats and their respective properties. 2. Each bidder specified on a given ad unit will be eligible to bid if the bidder supports at least one of the media types specified via `adUnit.mediaTypes`. 3. Prebid.js sends bid requests to each eligible bidder. @@ -76,7 +76,11 @@ The ad unit below supports the banner, native, and video media types. }, video: { context: 'outstream', - playerSize: [640, 480] + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 }, }, bids: [ diff --git a/dev-docs/show-native-ads.md b/dev-docs/show-native-ads.md index 8e47637677..f028b58528 100644 --- a/dev-docs/show-native-ads.md +++ b/dev-docs/show-native-ads.md @@ -267,7 +267,7 @@ it will respond to that request with the actual asset values for that `adId` in }, { "key": "clickUrl", - "value": "http://prebid.org/dev-docs/show-native-ads.html" + "value": "https://prebid.org/dev-docs/show-native-ads.html" } ] } diff --git a/dev-docs/show-outstream-video-ads.md b/dev-docs/show-outstream-video-ads.md index e7021607ee..6b4a9dde66 100644 --- a/dev-docs/show-outstream-video-ads.md +++ b/dev-docs/show-outstream-video-ads.md @@ -39,7 +39,11 @@ var videoAdUnits = [{ mediaTypes: { video: { context: 'outstream', - playerSize: [640, 480] + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 } }, bids: [{ @@ -47,7 +51,7 @@ var videoAdUnits = [{ params: { placementId: 13232385, video: { - skippable: true, + skip: 1, playback_method: ['auto_play_sound_off'] } } @@ -95,6 +99,11 @@ pbjs.addAdUnit({ video: { context: 'outstream', playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 + // but a renderer passed in here would apply only to this mediaType. // This renderer would override the above renderer if it exists. renderer: { @@ -121,7 +130,11 @@ pbjs.addAdUnit({ mediaTypes: { video: { context: 'outstream', - playerSize: [640, 480] + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 } }, renderer: { @@ -188,9 +201,9 @@ pbjs.que.push(function () { For more information, see the API documentation for: -+ [requestBids]({{site.github.url}}/dev-docs/publisher-api-reference.html#module_pbjs.requestBids) -+ [getHighestCpmBids]({{site.github.url}}/dev-docs/publisher-api-reference.html#module_pbjs.getHighestCpmBids) -+ [renderAd]({{site.github.url}}/dev-docs/publisher-api-reference.html#module_pbjs.renderAd) ++ [requestBids](/dev-docs/publisher-api-reference/requestBids.html) ++ [getHighestCpmBids](/dev-docs/publisher-api-reference/getHighestCpmBids.html) ++ [renderAd](/dev-docs/publisher-api-reference/renderAd.html) ## Working Examples diff --git a/dev-docs/show-prebid-ads-on-amp-pages.md b/dev-docs/show-prebid-ads-on-amp-pages.md index ad6a833cbb..e03048365e 100644 --- a/dev-docs/show-prebid-ads-on-amp-pages.md +++ b/dev-docs/show-prebid-ads-on-amp-pages.md @@ -91,34 +91,40 @@ that doesn't come from /amp parameters: } } }, - "imp": [ - { - "id": "some-impression-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { + "imp": [{ + "id": "some-impression-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "prebid": { + "bidder": { "bidderA": { // Insert parameters here }, "bidderB": { // Insert parameters here } - } + } } - ] + } + }] } - ``` This basic OpenRTB record will be enhanced by the parameters from the call to the [/amp endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html). ### AMP content page +First ensure that the amp-ad component is imported in the header. + +``` + +``` +This script provides code libraries that will convert `
/pbjs_demo.html?pbjs_debug=true. This will add two types of messages to your browser's developer console:
-
-1. Prebid.js suppresses Javascript errors in the normal mode to not break the rest of your page. Adding the `pbjs_debug` parameter will expose the Javascript errors.
-2. You'll find additional debug messages. Filter the messages by string `MESSAGE:`. For example:
-
-{{page.description }}
-Important: - This example uses a test version of Prebid.js hosted on our CDN that is not recommended for production use. It includes all available adapters. Production implementations should build from source or customize the build using the Download page to make sure only the necessary bidder adapters are included.
-Warning: - Do not forget to exchange the placementId in the code examples with your own placementId!
-
-
-<script async src="//acdn.adnxs.com/prebid/not-for-prod/prebid.js"></script>
-<script>
- var pbjs = pbjs || {};
- pbjs.que = pbjs.que || [];
-
- var PREBID_TIMEOUT = 700;
-
- var firstPlay = true;
-
- var tempTag = false;
- var invokeVideoPlayer = function(url) {
- tempTag = url;
- }
-
- var videoAdUnit = {
- code: 'video1',
- mediaTypes: {
- video: {
- playerSize: [640, 480],
- context: 'instream'
- }
- },
- bids: [{
- bidder: 'appnexus',
- params: {
- placementId: 13232361, // Add your own placement id here
- video: {
- skipppable: true,
- playback_method: ['auto_play_sound_off']
- }
- }
- }]
- };
-
- var requestVideoAd = function() {
-
- pbjs.requestBids({
- bidsBackHandler: function(bids) {
- var videoUrl = pbjs.adServers.dfp.buildVideoUrl({
- adUnit: videoAdUnit,
- params: {
- iu: '/19968336/prebid_cache_video_adunit',
- cust_params: {
- section: 'blog',
- anotherKey: 'anotherValue'
- },
- output: 'vast'
- }
- });
- invokeVideoPlayer(videoUrl);
- }
- });
- }
-
- pbjs.que.push(function() {
- // add your ad units to the bid request
- pbjs.addAdUnits(videoAdUnit);
-
- pbjs.setConfig({
- debug: true,
- cache: {
- url: 'https://prebid.adnxs.com/pbc/v1/cache'
- }
- });
-
- requestVideoAd();
- });
-
-</script>
-
-
-
-
-<!--player div-->
-<div id="myElement1"></div>
-<!-- replace this script with the libraries script of your player -->
- <script src="https://content.jwplatform.com/libraries/72xIKEe6.js"></script>
- <script>
- var adTag = "";
- var playerInstance = jwplayer('myElement1');
-
- invokeVideoPlayer = function(url) {
- adTag = url;
- console.log("MESSAGE: invoking the video player");
-
- // if this is our first time invoking the player, we also need to create the player
- // and the event listeners
- if (firstPlay) {
- playerInstance.setup({
- "playlist": "https://content.jwplatform.com/feeds/ae4tmw2D.json",
- "width": 640,
- "height": 480,
- "advertising": {
- "client": "vast",
- },
- });
-
- // set firstPlay to false to make sure we don't call setup() on our player a second time
- firstPlay = false;
-
- // beforePlay gets triggered before each content video plays
- // we play the ad tag being stored in the variable adTag, which we refresh
- // each time a content video plays by calling requestVideoAd
- playerInstance.on("beforePlay", function() {
- playerInstance.playAd(adTag);
- console.log("MESSAGE: refreshing the ad slot");
- pbjs.que.push(function() {
- requestVideoAd();
- });
- });
-
- // if our playlist ends and does not repeat, we want to play the last ad we got
- playerInstance.on("beforeComplete", function() {
- if (playerInstance.getPlaylistIndex() === playerInstance.getPlaylist().length - 1) {
- playerInstance.playAd(adTag);
- }
- });
- }
- }
-
- // if prebid returned an ad before the browser reached the end of the page,
- // the version of invokeVideoPlayer we defined in the header has stored the url in tempTag,
- // so we call invokeVideoPlayer with the stored url we stored
- if (tempTag) {
- invokeVideoPlayer(tempTag);
- tempTag = false;
- }
-
-</script>
-
-
-
- The button will be enabled only during ads
-- Click here to see an example of integrating Prebid with a JW Platform account. -
-- Click here to see an example of using Prebid to show a new ad between JW Player playlist items. -
- - - diff --git a/examples/video/legacy/jwPlaylistUniqueAds.html b/examples/video/legacy/jwPlaylistUniqueAds.html deleted file mode 100644 index d58b27b0cb..0000000000 --- a/examples/video/legacy/jwPlaylistUniqueAds.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - -- Click here to see an example of integrating Prebid Server with JW Player 7. -
-- Click here to see an example of integrating Prebid Server with a JW Platform account. -
- - - - diff --git a/examples/video/legacy/jwplayer7-pbserver-demo.html b/examples/video/legacy/jwplayer7-pbserver-demo.html deleted file mode 100644 index 62ab2d974f..0000000000 --- a/examples/video/legacy/jwplayer7-pbserver-demo.html +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - -- Click here to see an example of integrating Prebid Server with a JW Platform account. -
- - - - diff --git a/examples/video/legacy/jwplaylist-pbserver-demo.html b/examples/video/legacy/jwplaylist-pbserver-demo.html deleted file mode 100644 index aa9055bcde..0000000000 --- a/examples/video/legacy/jwplaylist-pbserver-demo.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - -- In scelerisque sem sed tortor posuere sagittis. Fusce scelerisque odio at tincidunt ultricies. Fusce egestas, erat non finibus dictum, nulla arcu viverra nibh, at bibendum ligula nisi egestas magna. Nulla eu finibus nulla. Pellentesque at mi eget turpis - consequat scelerisque. Sed lacinia, nisi sit amet egestas vestibulum, elit odio iaculis leo, et lacinia risus enim non lacus. Cras nec neque eget nunc gravida maximus. Ut hendrerit convallis sollicitudin. Donec cursus erat vel metus gravida, - et pretium justo iaculis. Curabitur condimentum blandit augue, quis interdum leo. Vivamus dapibus est nec dui efficitur, eu imperdiet nulla sollicitudin. Suspendisse laoreet velit vitae arcu mollis, ac interdum lorem venenatis. Aenean - nec purus varius, accumsan ex at, luctus arcu. Quisque consectetur tortor eros, placerat lacinia eros aliquam a. Proin non porttitor libero. -
-- Proin eget vulputate est. Nunc sit amet neque a tortor ullamcorper suscipit non eu neque. Quisque at massa in metus feugiat rutrum. Nulla et orci orci. Aliquam erat volutpat. Cras tincidunt metus lectus, sed suscipit augue mollis vitae. Sed quis condimentum - tortor, sit amet consectetur erat. Nulla pellentesque turpis lacus, eu venenatis massa fringilla at. Duis sed pharetra turpis. Maecenas vel porttitor neque. Praesent quis felis sapien. Donec suscipit euismod dui, vitae fermentum nisi ornare - in. -
-- Suspendisse tempor felis accumsan orci finibus, imperdiet mollis arcu imperdiet. In eu dolor condimentum, pulvinar nisl a, sollicitudin nunc. Ut vel lectus libero. Praesent rhoncus leo tortor, at mollis nulla sagittis eget. Quisque tempus tempor augue - sed rutrum. Sed vitae volutpat quam. Proin vestibulum eros metus, a luctus erat condimentum eu. Vivamus ullamcorper ultricies dui, ac malesuada leo finibus semper. Cras diam augue, imperdiet sed efficitur id, aliquam sed purus. Praesent - eget turpis quis sapien interdum sagittis. Vivamus placerat nunc a tempus fermentum. Praesent laoreet leo at tellus porta, ut viverra tortor pharetra. Quisque elit velit, eleifend eget imperdiet vel, suscipit ac nisi. Aliquam egestas mauris - ut massa fringilla laoreet. -
-Prebid Outstream Video Ad
- -- Quisque ac luctus nisi, vitae ornare arcu. Proin fermentum sapien vitae odio vestibulum porta. Suspendisse faucibus sapien enim, et faucibus urna tempus et. Integer porttitor justo sed faucibus blandit. Morbi semper lectus vitae semper facilisis. Quisque - molestie accumsan arcu, eget bibendum dui euismod et. Sed in mattis lacus, nec lacinia sem. Fusce sed tortor posuere, iaculis justo varius, elementum est. -
-- Etiam condimentum, eros commodo semper tristique, lorem leo pharetra massa, eget cursus justo enim id urna. Sed imperdiet mauris vitae ante bibendum elementum. Etiam eu dui porttitor leo imperdiet cursus. Maecenas consequat, neque a dapibus viverra, nunc - velit volutpat nibh, ut cursus sem tortor ac arcu. Praesent convallis lacus vel nisi aliquam, in posuere libero scelerisque. Curabitur et lacinia nisl. Nunc id ligula neque. Phasellus non eros et leo ultrices ultricies. Nulla facilisi. - Donec ut augue urna. Suspendisse sodales nisi at ex faucibus, et tempus magna fermentum. Proin non arcu interdum, pulvinar est at, vehicula odio. Morbi nec maximus sem. Ut eu tristique urna. -
-- Pellentesque eget quam sem. Nam interdum eleifend leo, mattis sagittis metus ornare tristique. Cras pretium odio lectus, vitae viverra massa consequat eget. Suspendisse porttitor pretium lectus in scelerisque. Phasellus euismod porta lectus eget pharetra. - Ut et viverra mi, ut imperdiet lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nunc tempus sapien sit amet tortor rhoncus dignissim. Sed at augue et sem lacinia feugiat. Nulla vitae convallis - urna. Morbi scelerisque erat quis nibh pretium, non elementum elit consectetur. Proin in feugiat nisl. -
-- Morbi et ipsum purus. Integer ut pulvinar metus. Fusce maximus ex nec purus sollicitudin gravida. Vivamus dapibus volutpat erat nec tristique. Aliquam mi dolor, pretium non elementum quis, viverra non est. Pellentesque egestas, lectus a posuere imperdiet, - nisi sem elementum neque, eu volutpat arcu turpis venenatis magna. Curabitur non neque consectetur, vulputate urna sed, vestibulum lacus. Aenean mollis, risus non pulvinar egestas, lectus lectus finibus dui, sit amet pretium metus mauris - vitae nibh. In non ultricies odio. -
-- Donec dictum sem ac risus molestie lobortis. Maecenas at justo vehicula, iaculis orci eget, eleifend nunc. In non justo imperdiet, blandit leo in, interdum mi. Proin feugiat libero et erat dictum efficitur. Nunc auctor lacus feugiat erat euismod cursus. - Sed vehicula ante vel quam pretium blandit. Maecenas congue quis mauris vitae efficitur. Cras sit amet justo at sem dictum ornare vitae eu ex. Nunc ornare odio nec leo consectetur cursus. Mauris eu dolor tellus. Etiam dignissim ut nunc - et mollis. Cras at pulvinar velit, ut tincidunt velit. Cras vitae fermentum ante. Aenean interdum dolor in scelerisque consectetur. -
-- Curabitur auctor leo sit amet massa faucibus ultrices. Maecenas dignissim libero ac cursus cursus. Curabitur eget sapien leo. Phasellus pretium blandit facilisis. Proin egestas urna a sagittis tempus. Donec in nibh ex. Vestibulum efficitur felis aliquam - urna ultrices, at gravida nibh pretium. Morbi dictum vulputate pretium. Donec at nisi rutrum, pharetra nunc a, placerat felis. Quisque rhoncus congue fermentum. Quisque pharetra est at nisl sagittis suscipit. Maecenas scelerisque porta - eleifend. Mauris nulla leo, consectetur at eros vel, elementum pretium diam. -
-- In nisi libero, porta ut ullamcorper a, dapibus nec velit. Vestibulum congue rhoncus congue. Nulla a libero sit amet risus feugiat hendrerit id placerat ex. In hac habitasse platea dictumst. Pellentesque ut ullamcorper risus. Nunc et ipsum nisi. Vivamus - a interdum diam, hendrerit pellentesque orci. -
-- Vestibulum ut massa blandit, maximus sem vitae, vulputate mauris. Nam condimentum velit a facilisis dignissim. Nunc venenatis pharetra dapibus. Praesent ullamcorper risus sit amet molestie consectetur. Cras mauris felis, consequat et enim a, ultricies - pretium enim. Nulla porttitor nunc mi, sed posuere magna venenatis non. Donec lobortis consectetur mauris, fermentum auctor dui dignissim sed. Sed vel venenatis urna. Donec velit velit, imperdiet non vulputate non, eleifend sed nisi. -
-- Proin et turpis velit. Donec tempus dictum dolor, eget eleifend lacus. Donec eu felis in ante iaculis ultrices. Mauris varius, turpis quis venenatis convallis, enim dolor ornare justo, in dictum ipsum purus quis dolor. Ut condimentum feugiat lectus ut - auctor. Maecenas luctus consequat erat, nec pretium urna pulvinar in. Donec gravida rhoncus aliquet. Cras aliquet odio eget orci hendrerit, non posuere velit dignissim. Nunc tempus aliquam iaculis. Nunc viverra lobortis mauris et malesuada. - Donec congue suscipit mauris. Phasellus efficitur, leo at mollis maximus, lorem mauris pretium urna, nec scelerisque ante neque eu erat. Nam rhoncus malesuada velit nec ultricies. -
-- Proin blandit in arcu sed porttitor. Morbi in erat vel risus mollis interdum. Proin vel odio semper, porttitor risus sed, tristique odio. Donec viverra massa et dui scelerisque, ac sagittis odio viverra. Aliquam lacinia enim sit amet dapibus ultrices. - Nulla mollis, massa eget interdum egestas, lectus eros pretium eros, vel consectetur velit odio vel odio. Proin euismod aliquam finibus. Phasellus facilisis mollis est, non consequat lectus volutpat nec. -
-- Ut vel ultricies erat. Pellentesque non ipsum quis odio ornare tempus in cursus ex. In a turpis non quam pulvinar tincidunt. Maecenas tortor neque, dapibus a quam aliquet, dictum pellentesque leo. Sed aliquet tellus est, in tempus magna congue ut. Phasellus - at tincidunt lorem, id fringilla risus. Nunc vel pulvinar massa. Aliquam erat volutpat. Phasellus semper interdum justo at eleifend. Curabitur feugiat quam sed mollis facilisis. -
-- Quisque consectetur sem a elit aliquet facilisis. Quisque dignissim velit at quam rhoncus dignissim. Proin feugiat sem at turpis ultrices imperdiet. Integer vel eros vel ante ultricies dapibus vitae eget dui. Fusce sollicitudin semper tortor at molestie. - Pellentesque nec metus sed mauris aliquet iaculis. Mauris malesuada tortor nec mi dictum, feugiat euismod enim gravida. Vestibulum dapibus ut nulla vel euismod. Nunc lobortis, mauris at pretium faucibus, ligula diam venenatis nulla, in - mattis sapien arcu feugiat dolor. In at dui leo. Cras elementum condimentum turpis. -
-- Donec eget dolor ac nulla lobortis bibendum. Praesent commodo accumsan ligula eget commodo. Suspendisse sit amet dignissim metus. Sed ut eros viverra, viverra lectus eget, ornare eros. Mauris elementum lacinia dapibus. Donec magna nisl, suscipit quis - mattis eget, tincidunt sed sapien. Curabitur elementum nulla eget lorem gravida dapibus. Nunc vel dolor et libero pretium interdum vitae eget mauris. Vestibulum et erat in nulla sollicitudin luctus ut quis nulla. -
-- Maecenas iaculis pellentesque quam at fringilla. Donec dui elit, suscipit eget varius id, suscipit efficitur metus. Nulla rutrum ultrices tempor. Vivamus hendrerit justo ac fermentum euismod. Vestibulum tempus pulvinar tempus. Curabitur congue neque luctus - dolor vehicula, non efficitur metus fringilla. Nam a imperdiet ex. Integer at est hendrerit, rutrum justo eu, ornare odio. Etiam convallis sapien a purus vehicula, eget gravida purus semper. Fusce ex enim, volutpat ac feugiat et, rhoncus - vel tortor. Aenean ultrices libero sed neque fermentum tempor. Morbi tincidunt dui turpis, non mollis est dignissim at. Suspendisse molestie convallis interdum. Donec sit amet fermentum purus. -
-- Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam et ex orci. Vivamus rutrum est vel porta imperdiet. Cras ultricies tortor dolor, nec mollis felis ullamcorper vel. Praesent scelerisque vehicula sem, nec feugiat - mauris tempus ac. Donec at enim non sem commodo sodales. Ut sit amet risus sit amet ante viverra venenatis. Aliquam sodales mollis est eget ultricies. Etiam pulvinar sapien et ipsum elementum pharetra. -
-- Nam blandit metus erat, sit amet congue ipsum cursus sed. In a commodo ante, sit amet tincidunt quam. Aenean lobortis et nibh in venenatis. Aliquam faucibus purus quis neque consectetur, quis consequat risus maximus. Proin mollis imperdiet felis, eget - tempus ipsum scelerisque ut. Sed euismod interdum augue sed varius. Sed volutpat tellus ut risus porta accumsan. -
-- Mauris aliquet eu arcu sed pharetra. Duis nec leo volutpat libero finibus malesuada in eget velit. Aliquam facilisis urna mauris, et aliquam ipsum dictum finibus. Donec eget mi fermentum, vehicula odio at, molestie orci. In a hendrerit lectus. Aenean - congue ipsum ac imperdiet suscipit. Maecenas eleifend pretium metus id mollis. -
-- Ut vel ultricies erat. Pellentesque non ipsum quis odio ornare tempus in cursus ex. In a turpis non quam pulvinar tincidunt. Maecenas tortor neque, dapibus a quam aliquet, dictum pellentesque leo. Sed aliquet tellus est, in tempus magna congue ut. Phasellus - at tincidunt lorem, id fringilla risus. Nunc vel pulvinar massa. Aliquam erat volutpat. Phasellus semper interdum justo at eleifend. Curabitur feugiat quam sed mollis facilisis. -
-- Quisque consectetur sem a elit aliquet facilisis. Quisque dignissim velit at quam rhoncus dignissim. Proin feugiat sem at turpis ultrices imperdiet. Integer vel eros vel ante ultricies dapibus vitae eget dui. Fusce sollicitudin semper tortor at molestie. - Pellentesque nec metus sed mauris aliquet iaculis. Mauris malesuada tortor nec mi dictum, feugiat euismod enim gravida. Vestibulum dapibus ut nulla vel euismod. Nunc lobortis, mauris at pretium faucibus, ligula diam venenatis nulla, in - mattis sapien arcu feugiat dolor. In at dui leo. Cras elementum condimentum turpis. -
-- Donec eget dolor ac nulla lobortis bibendum. Praesent commodo accumsan ligula eget commodo. Suspendisse sit amet dignissim metus. Sed ut eros viverra, viverra lectus eget, ornare eros. Mauris elementum lacinia dapibus. Donec magna nisl, suscipit quis - mattis eget, tincidunt sed sapien. Curabitur elementum nulla eget lorem gravida dapibus. Nunc vel dolor et libero pretium interdum vitae eget mauris. Vestibulum et erat in nulla sollicitudin luctus ut quis nulla. -
-- Maecenas iaculis pellentesque quam at fringilla. Donec dui elit, suscipit eget varius id, suscipit efficitur metus. Nulla rutrum ultrices tempor. Vivamus hendrerit justo ac fermentum euismod. Vestibulum tempus pulvinar tempus. Curabitur congue neque luctus - dolor vehicula, non efficitur metus fringilla. Nam a imperdiet ex. Integer at est hendrerit, rutrum justo eu, ornare odio. Etiam convallis sapien a purus vehicula, eget gravida purus semper. Fusce ex enim, volutpat ac feugiat et, rhoncus - vel tortor. Aenean ultrices libero sed neque fermentum tempor. Morbi tincidunt dui turpis, non mollis est dignissim at. Suspendisse molestie convallis interdum. Donec sit amet fermentum purus. -
-- In scelerisque sem sed tortor posuere sagittis. Fusce scelerisque odio at tincidunt ultricies. Fusce egestas, erat non finibus dictum, nulla arcu viverra nibh, at bibendum ligula nisi egestas magna. Nulla eu finibus nulla. Pellentesque at mi eget turpis - consequat scelerisque. Sed lacinia, nisi sit amet egestas vestibulum, elit odio iaculis leo, et lacinia risus enim non lacus. Cras nec neque eget nunc gravida maximus. Ut hendrerit convallis sollicitudin. Donec cursus erat vel metus gravida, - et pretium justo iaculis. Curabitur condimentum blandit augue, quis interdum leo. Vivamus dapibus est nec dui efficitur, eu imperdiet nulla sollicitudin. Suspendisse laoreet velit vitae arcu mollis, ac interdum lorem venenatis. Aenean - nec purus varius, accumsan ex at, luctus arcu. Quisque consectetur tortor eros, placerat lacinia eros aliquam a. Proin non porttitor libero. -
-- Proin eget vulputate est. Nunc sit amet neque a tortor ullamcorper suscipit non eu neque. Quisque at massa in metus feugiat rutrum. Nulla et orci orci. Aliquam erat volutpat. Cras tincidunt metus lectus, sed suscipit augue mollis vitae. Sed quis condimentum - tortor, sit amet consectetur erat. Nulla pellentesque turpis lacus, eu venenatis massa fringilla at. Duis sed pharetra turpis. Maecenas vel porttitor neque. Praesent quis felis sapien. Donec suscipit euismod dui, vitae fermentum nisi ornare - in. -
-- Suspendisse tempor felis accumsan orci finibus, imperdiet mollis arcu imperdiet. In eu dolor condimentum, pulvinar nisl a, sollicitudin nunc. Ut vel lectus libero. Praesent rhoncus leo tortor, at mollis nulla sagittis eget. Quisque tempus tempor augue - sed rutrum. Sed vitae volutpat quam. Proin vestibulum eros metus, a luctus erat condimentum eu. Vivamus ullamcorper ultricies dui, ac malesuada leo finibus semper. Cras diam augue, imperdiet sed efficitur id, aliquam sed purus. Praesent - eget turpis quis sapien interdum sagittis. Vivamus placerat nunc a tempus fermentum. Praesent laoreet leo at tellus porta, ut viverra tortor pharetra. Quisque elit velit, eleifend eget imperdiet vel, suscipit ac nisi. Aliquam egestas mauris - ut massa fringilla laoreet. -
-Prebid Outstream Video Ad
-- Quisque ac luctus nisi, vitae ornare arcu. Proin fermentum sapien vitae odio vestibulum porta. Suspendisse faucibus sapien enim, et faucibus urna tempus et. Integer porttitor justo sed faucibus blandit. Morbi semper lectus vitae semper facilisis. Quisque - molestie accumsan arcu, eget bibendum dui euismod et. Sed in mattis lacus, nec lacinia sem. Fusce sed tortor posuere, iaculis justo varius, elementum est. -
-- Etiam condimentum, eros commodo semper tristique, lorem leo pharetra massa, eget cursus justo enim id urna. Sed imperdiet mauris vitae ante bibendum elementum. Etiam eu dui porttitor leo imperdiet cursus. Maecenas consequat, neque a dapibus viverra, nunc - velit volutpat nibh, ut cursus sem tortor ac arcu. Praesent convallis lacus vel nisi aliquam, in posuere libero scelerisque. Curabitur et lacinia nisl. Nunc id ligula neque. Phasellus non eros et leo ultrices ultricies. Nulla facilisi. - Donec ut augue urna. Suspendisse sodales nisi at ex faucibus, et tempus magna fermentum. Proin non arcu interdum, pulvinar est at, vehicula odio. Morbi nec maximus sem. Ut eu tristique urna. -
-- Pellentesque eget quam sem. Nam interdum eleifend leo, mattis sagittis metus ornare tristique. Cras pretium odio lectus, vitae viverra massa consequat eget. Suspendisse porttitor pretium lectus in scelerisque. Phasellus euismod porta lectus eget pharetra. - Ut et viverra mi, ut imperdiet lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nunc tempus sapien sit amet tortor rhoncus dignissim. Sed at augue et sem lacinia feugiat. Nulla vitae convallis - urna. Morbi scelerisque erat quis nibh pretium, non elementum elit consectetur. Proin in feugiat nisl. -
-- Morbi et ipsum purus. Integer ut pulvinar metus. Fusce maximus ex nec purus sollicitudin gravida. Vivamus dapibus volutpat erat nec tristique. Aliquam mi dolor, pretium non elementum quis, viverra non est. Pellentesque egestas, lectus a posuere imperdiet, - nisi sem elementum neque, eu volutpat arcu turpis venenatis magna. Curabitur non neque consectetur, vulputate urna sed, vestibulum lacus. Aenean mollis, risus non pulvinar egestas, lectus lectus finibus dui, sit amet pretium metus mauris - vitae nibh. In non ultricies odio. -
-- Donec dictum sem ac risus molestie lobortis. Maecenas at justo vehicula, iaculis orci eget, eleifend nunc. In non justo imperdiet, blandit leo in, interdum mi. Proin feugiat libero et erat dictum efficitur. Nunc auctor lacus feugiat erat euismod cursus. - Sed vehicula ante vel quam pretium blandit. Maecenas congue quis mauris vitae efficitur. Cras sit amet justo at sem dictum ornare vitae eu ex. Nunc ornare odio nec leo consectetur cursus. Mauris eu dolor tellus. Etiam dignissim ut nunc - et mollis. Cras at pulvinar velit, ut tincidunt velit. Cras vitae fermentum ante. Aenean interdum dolor in scelerisque consectetur. -
-- Curabitur auctor leo sit amet massa faucibus ultrices. Maecenas dignissim libero ac cursus cursus. Curabitur eget sapien leo. Phasellus pretium blandit facilisis. Proin egestas urna a sagittis tempus. Donec in nibh ex. Vestibulum efficitur felis aliquam - urna ultrices, at gravida nibh pretium. Morbi dictum vulputate pretium. Donec at nisi rutrum, pharetra nunc a, placerat felis. Quisque rhoncus congue fermentum. Quisque pharetra est at nisl sagittis suscipit. Maecenas scelerisque porta - eleifend. Mauris nulla leo, consectetur at eros vel, elementum pretium diam. -
-- In nisi libero, porta ut ullamcorper a, dapibus nec velit. Vestibulum congue rhoncus congue. Nulla a libero sit amet risus feugiat hendrerit id placerat ex. In hac habitasse platea dictumst. Pellentesque ut ullamcorper risus. Nunc et ipsum nisi. Vivamus - a interdum diam, hendrerit pellentesque orci. -
-- Vestibulum ut massa blandit, maximus sem vitae, vulputate mauris. Nam condimentum velit a facilisis dignissim. Nunc venenatis pharetra dapibus. Praesent ullamcorper risus sit amet molestie consectetur. Cras mauris felis, consequat et enim a, ultricies - pretium enim. Nulla porttitor nunc mi, sed posuere magna venenatis non. Donec lobortis consectetur mauris, fermentum auctor dui dignissim sed. Sed vel venenatis urna. Donec velit velit, imperdiet non vulputate non, eleifend sed nisi. -
-<script async src="//acdn.adnxs.com/prebid/not-for-prod/prebid.js"></script> -<script type="text/javascript" src="http://ssl.p.jwpcdn.com/player/v/8.0.5/jwplayer.js"></script> +<script type="text/javascript" src="https://ssl.p.jwpcdn.com/player/v/8.0.5/jwplayer.js"></script> <script type="text/javascript"> - jwplayer.key = "F4+phNkFZ4+I3UhfSN6h8JPbxdnsto3caVMq+A=="; //Test Key - replace this with your own valid JWPlayer license key
+ jwplayer.key = "YOUR_JW_PLAYER_KEY"; //Test Key - replace this with your own valid JWPlayer license key
</script> <script> @@ -72,21 +72,18 @@Place this code in the page header.
code: 'video1', mediaTypes: { video: { - playerSize: [640, 480], context: 'instream', + playerSize: [640, 480], mimes: ['video/mp4'], protocols: [1, 2, 3, 4, 5, 6, 7, 8], - playbackmethod: [2] + playbackmethod: [2], + skip: 1 } }, bids: [{ bidder: 'appnexus', params: { - placementId: 13232361, // Add your own placement id here
- video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } + placementId: 13232361 // Add your own placement id here
} }] }; @@ -102,7 +99,7 @@Place this code in the page header.
debug: true, enableSendAllBids: true, s2sConfig: { - endpoint: 'http://prebid.adnxs.com/pbs/v1/openrtb2/auction', + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', enabled: true, accountId: 'c9d412ee-3cc6-4b66-9326-9f49d528f13e', bidders: ['appnexus'] @@ -112,7 +109,6 @@Place this code in the page header.
pbjs.addAdUnits(videoAdUnit); // add your ad units to the bid request
- pbjs.requestBids({ bidsBackHandler: function(bids) { console.log("got some bids"); @@ -153,7 +149,7 @@Place this code in the page body.
console.log("starting player with url " + url); jwPlayerInstance.setup({ - "file": "http://mirrors.standaloneinstaller.com/video-sample/jellyfish-25-mbps-hd-hevc.mp4", + "file": "https://vjs.zencdn.net/v/oceans.mp4", "width": 640, "height": 480, "autostart": true, @@ -188,13 +184,13 @@Place this code in the page body.
invokeVideoPlayer = function(url) { console.log("starting player with url " + url); jwPlayerInstance.setup({ - "file": "http://mirrors.standaloneinstaller.com/video-sample/jellyfish-25-mbps-hd-hevc.mp4", + "file": "https://vjs.zencdn.net/v/oceans.mp4", "width": 640, "height": 480, "autostart": true, "mute": true, "advertising": { - client: "vast", + client: "vast" } }); @@ -209,4 +205,4 @@Place this code in the page body.
} - \ No newline at end of file + diff --git a/examples/video/server/jwplayer/pbs-ve-jwplayer-jwplayer7.html b/examples/video/server/jwplayer/pbs-ve-jwplayer-jwplayer7.html deleted file mode 100644 index b97f5253f2..0000000000 --- a/examples/video/server/jwplayer/pbs-ve-jwplayer-jwplayer7.html +++ /dev/null @@ -1,203 +0,0 @@ ---- -layout: video_sample -title: Prebid Video | Prebid Server Example with JW Player (Player7) -description: An example of a pre-roll ad using Prebid Server and JW Player (Player7). -videoType: pbs-jw04 -isVideo: true -sidebarType: 4 ---- - - - --- - - - - \ No newline at end of file diff --git a/examples/video/server/jwplayer/pbs-ve-jwplayer-platform.html b/examples/video/server/jwplayer/pbs-ve-jwplayer-platform.html index a791d730db..f5a15deb27 100644 --- a/examples/video/server/jwplayer/pbs-ve-jwplayer-platform.html +++ b/examples/video/server/jwplayer/pbs-ve-jwplayer-platform.html @@ -1,14 +1,12 @@ --- layout: video_sample -title: Prebid Video | Prebid Server Example with JW Player (Platform) +title: Prebid Video | Prebid Server Example with JW Player (Platform) description: An example of a pre-roll ad using Prebid Server and JW Player (Platform). videoType: pbs-jw01 isVideo: true sidebarType: 4 --- - ----- - -{{ page.title }}
-{{page.description }}
--- - - - - - - -Important: - This example uses a test version of Prebid.js hosted on our CDN that is not recommended for production use. It includes all available adapters. Production implementations should build from source or customize the build using the Download page to make sure only the necessary bidder adapters are included.
-- -- -Warning: - Do not forget to exchange the placementId in the code examples with your own placementId!
--- - -Place this code in the page header.
-- -<script type="text/javascript" src="http://ssl.p.jwpcdn.com/player/v/7.2.4/jwplayer.js"></script> -<script type="text/javascript"> - jwplayer.key = "YEUwUA9wRFeDcydr"; //Test Key - replace this with your own valid JWPlayer license key -</script> -<script> - var pbjs = pbjs || {}; - pbjs.que = pbjs.que || []; - - /* PRE-DEFINE `invokeVideoPlayer` - - Because we have no way of knowing when all the bids will be - returned from Prebid we can't be sure that the browser will - reach the point where `invokeVideoPlayer` is defined before - `bidsBackHandler` fires and tries to call it. - - To prevent an "`invokeVideoPlayer` not defined" error, we - pre-define it before we make the call to Prebid, and redefine - it later on with the code to create the player and play the - ad. - - In this first version, it simply stores the winning VAST to - use later. */ - - var tempTag = false; - var invokeVideoPlayer = function(url) { - tempTag = url; - }; - - /* Prebid video ad unit */ - - var videoAdUnit = { - code: 'video1', - mediaTypes: { - video: { - playerSize: [640, 480], - context: 'instream', - mimes: ['video/mp4'], - protocols: [1, 2, 3, 4, 5, 6], - playbackmethod: [2] - } - }, - bids: [{ - bidder: 'appnexus', - params: { - placementId: 13232361, // Add your own placement id here- -
- video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } - } - }] - }; - - pbjs.que.push(function() { - - // configure prebid to use prebid cache and prebid server - // make sure to add your own accountId to your s2sConfig object
- pbjs.setConfig({ - cache: { - url: 'https://prebid.adnxs.com/pbc/v1/cache' - }, - debug: true, - enableSendAllBids: true, - s2sConfig: { - endpoint: 'http://prebid.adnxs.com/pbs/v1/openrtb2/auction', - enabled: true, - accountId: 'c9d412ee-3cc6-4b66-9326-9f49d528f13e', - bidders: ['appnexus'] - } - }); - - pbjs.addAdUnits(videoAdUnit); // add your ad units to the bid request
- pbjs.requestBids({ - bidsBackHandler: function(bids) { - var videoUrl = pbjs.adServers.dfp.buildVideoUrl({ - adUnit: videoAdUnit, - params: { - iu: '/19968336/prebid_cache_video_adunit', - cust_params: { - section: 'blog', - anotherKey: 'anotherValue' - }, - output: 'vast' - } - }); - invokeVideoPlayer(videoUrl); - } - }); - }); - -</script> - --- -Place this code in the page body.
-- -<script> - var jwPlayerInstance = jwplayer("playerContainerJW"); - invokeVideoPlayer = function(url) { - console.log("starting player with url " + url); - jwPlayerInstance.setup({ - "file": "https://content.jwplatform.com/feeds/ae4tmw2D.json", - "width": 640, - "height": 480, - "autostart": true, - "mute": true, - "advertising": { - client: "vast", - } - }); - - jwPlayerInstance.on('beforePlay', function() { - jwPlayerInstance.playAd(url); - }); - }; - - if (tempTag) { - invokeVideoPlayer(tempTag); - tempTag = false; - } - -</script> - --@@ -65,21 +63,18 @@Place this code in the page header.
code: 'video1', mediaTypes: { video: { - playerSize: [640, 480], - context: 'instream', - mimes: ['video/mp4'], - protocols: [1, 2, 3, 4, 5, 6, 7, 8], - playbackmethod: [2] + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 } }, bids: [{ bidder: 'appnexus', params: { - placementId: 13232361, // Add your own placement id here.
- video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } + placementId: 13232361 // Add your own placement id here.
} }] }; @@ -94,7 +89,7 @@Place this code in the page header.
}, debug: true, s2sConfig: { - endpoint: 'http://prebid.adnxs.com/pbs/v1/openrtb2/auction', + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', enabled: true, accountId: 'c9d412ee-3cc6-4b66-9326-9f49d528f13e', bidders: ['appnexus'] @@ -134,7 +129,7 @@Place this code in the page body.
<!-- This line loads a player without loading any video content --> <!-- Replace this with the correct url for your player --> -<script src="https://content.jwplatform.com/libraries/72xIKEe6.js"></script> +<script src="YOUR_JW_URL"></script> <script> // we initialize our player instance, specifying the div to load it into
var playerInstance = jwplayer('myElement1'); @@ -143,17 +138,18 @@Place this code in the page body.
// this calls setup on the player we initialized // this will use the settings defined in the player we loaded above unless you override them here
playerInstance.setup({ - // this line loads a playlist from your jwplatform account (in either json or rss format) - // this can also be a single media file by specifying "file" : "content.jwplatform.com/videos/VIDEOKEY.mp4" - // Replace this with the correct url for your playlist
- "playlist": "https://content.jwplatform.com/feeds/ae4tmw2D.json", + "file": "https://vjs.zencdn.net/v/oceans.mp4", + // or "file" could be replaced with "playlist" and a URL + // from your JW Platform account in either json or rss format. "width": 640, "height": 480, + "autostart": true, + "mute": true, // we enable vast advertising for this player
"advertising": { "client": "vast", // url is the vast tag url that we passed in when we called invokeVideoPlayer in the header
- "tag": url, + "tag": url } }); } @@ -174,7 +170,7 @@Place this code in the page body.
- + - \ No newline at end of file + diff --git a/examples/video/server/jwplayer/pbs-ve-jwplayer-playlist.html b/examples/video/server/jwplayer/pbs-ve-jwplayer-playlist.html deleted file mode 100644 index f2eb304e67..0000000000 --- a/examples/video/server/jwplayer/pbs-ve-jwplayer-playlist.html +++ /dev/null @@ -1,248 +0,0 @@ ---- -layout: video_sample -title: Prebid Video | Prebid Server Example with JW Player (Playlist) -description: An example of a pre-roll ad using Prebid Server and JW Player (Playlist). -videoType: pbs-jw03 -isVideo: true -sidebarType: 4 ---- - - - --- - - - - - \ No newline at end of file diff --git a/examples/video/server/kaltura/pbs-ve-kaltura.html b/examples/video/server/kaltura/pbs-ve-kaltura.html index 63f2d0eb13..5bf385058e 100644 --- a/examples/video/server/kaltura/pbs-ve-kaltura.html +++ b/examples/video/server/kaltura/pbs-ve-kaltura.html @@ -68,21 +68,18 @@---- - -{{ page.title }}
-{{page.description }}
--- - - - - - - -Important: - This example uses a test version of Prebid.js hosted on our CDN that is not recommended for production use. It includes all available adapters. Production implementations should build from source or customize the build using the Download page to make sure only the necessary bidder adapters are included.
--- -Warning: - Do not forget to exchange the placementId in the code examples with your own placementId!
--- - -Place this code in the page header.
-- - -<script> - var pbjs = pbjs || {}; - pbjs.que = pbjs.que || []; - - var PREBID_TIMEOUT = 700; - - var firstPlay = true; - - var tempTag = false; - var invokeVideoPlayer = function(url) { - tempTag = url; - } - - var videoAdUnit = { - code: 'video1', - sizes: [640, 480], - mediaTypes: { - video: { - context: 'instream', - mimes: ['video/mp4'], - protocols: [1, 2, 3, 4, 5, 6, 7, 8], - playbackmethod: [2] - } - }, - bids: [{ - bidder: 'appnexus', - params: { - placementId: 13232361, // Add your own placement id here- -
- video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } - } - }] - }; - - var requestVideoAd = function() { - - pbjs.requestBids({ - bidsBackHandler: function(bids) { - var videoUrl = pbjs.adServers.dfp.buildVideoUrl({ - adUnit: videoAdUnit, - params: { - iu: '/19968336/prebid_cache_video_adunit', - cust_params: { - section: 'blog', - anotherKey: 'anotherValue' - }, - output: 'vast' - } - }); - invokeVideoPlayer(videoUrl); - } - }); - }; - - pbjs.que.push(function() { - // configure prebid to use prebid cache and prebid server - // make sure to add your own accountId to your s2sConfig object
- pbjs.setConfig({ - cache: { - url: 'https://prebid.adnxs.com/pbc/v1/cache' - }, - debug: true, - s2sConfig: { - endpoint: 'http://prebid.adnxs.com/pbs/v1/openrtb2/auction', - enabled: true, - accountId: 'c9d412ee-3cc6-4b66-9326-9f49d528f13e', - bidders: ['appnexus'] - } - }); - - pbjs.addAdUnits(videoAdUnit); // add your ad units to the bid request
- - requestVideoAd(); - }); - -</script> - --- -Place this code in the page body.
-- -<div id="myElement1"></div> - -<!--video placeholder | this should be formatted per the needs of each player--> -<div id="myElement1"></div> -<script> - var adTag = ""; - var playerInstance = jwplayer('myElement1'); - - invokeVideoPlayer = function(url) { - adTag = url; - console.log("MESSAGE: invoking the video player"); - - // if this is our first time invoking the player, we also need to create the player - // and the event listeners-
- if (firstPlay) { - playerInstance.setup({ - "playlist": "https://content.jwplatform.com/feeds/ae4tmw2D.json", - "width": 640, - "height": 480, - "advertising": { - "client": "vast", - }, - }); - - // set firstPlay to false to make sure we don't call setup() on our player a second time - firstPlay = false;
- - // beforePlay gets triggered before each content video plays - // we play the ad tag being stored in the variable adTag, which we refresh - // each time a content video plays by calling requestVideoAd
- playerInstance.on("beforePlay", function() { - playerInstance.playAd(adTag); - console.log("MESSAGE: refreshing the ad slot"); - pbjs.que.push(function() { - requestVideoAd(); - }); - }); - - // if our playlist ends and does not repeat, we want to play the last ad we got
- playerInstance.on("beforeComplete", function() { - if (playerInstance.getPlaylistIndex() === playerInstance.getPlaylist().length - 1) { - playerInstance.playAd(adTag); - } - }); - } - } - - // if prebid returned an ad before the browser reached the end of the page, - // the version of invokeVideoPlayer we defined in the header has stored the url in tempTag, - // so we call invokeVideoPlayer with the stored url we stored
- if (tempTag) { - invokeVideoPlayer(tempTag); - tempTag = false; - } - -</script> - - -Place this code in the page header.
code: 'video1', mediaTypes: { video: { - playerSize: [640, 480], context: 'instream', + playerSize: [640, 480], mimes: ['video/mp4'], protocols: [1, 2, 3, 4, 5, 6, 7, 8], - playbackmethod: [2] + playbackmethod: [2], + skip: 1 } }, bids: [{ bidder: 'appnexus', params: { - placementId: 13232361, // Add your own placement id here.
- video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } + placementId: 13232361 // Add your own placement id here.
} }] }; @@ -97,7 +94,7 @@Place this code in the page header.
}, debug: true, s2sConfig: { - endpoint: 'http://prebid.adnxs.com/pbs/v1/openrtb2/auction', + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', enabled: true, accountId: 'c9d412ee-3cc6-4b66-9326-9f49d528f13e', bidders: ['appnexus'] @@ -143,7 +140,7 @@Place this code in the page body.
Add the script for your Kaltura player. This will be part of the code you will copy-paste from Kaltura. --> -<script src="http://cdnapi.kaltura.com/p/2222001/sp/222200100/embedIframeJs/uiconf_id/37440401/partner_id/2222001"></script> +<script src="https://cdnapi.kaltura.com/p/2222001/sp/222200100/embedIframeJs/uiconf_id/37440401/partner_id/2222001"></script> <script> invokeVideoPlayer = function(url) { @@ -155,7 +152,7 @@Place this code in the page body.
the code you will copy paste from Kaltura. Documentation for kWidget available here: - http://player.kaltura.com/docs/kwidget */ + https://player.kaltura.com/docs/kwidget */ kWidget.embed({ "targetId": "myPlayer", @@ -229,7 +226,7 @@Place this code in the page body.
Add the script for your Kaltura player. This will be part of the code you will copy-paste from Kaltura. --> - + - \ No newline at end of file + diff --git a/examples/video/server/ooyala/pbs-ve-ooyala.html b/examples/video/server/ooyala/pbs-ve-ooyala.html index 7492ec603d..6bbe7c407e 100644 --- a/examples/video/server/ooyala/pbs-ve-ooyala.html +++ b/examples/video/server/ooyala/pbs-ve-ooyala.html @@ -50,7 +50,7 @@Place this code in the page header.
The scripts themselves and a guide for choosing which ones you need can be found here: - http://help.ooyala.com/video-platform/documentation/concepts/pbv4_plugins.html + https://help.ooyala.com/video-platform/documentation/concepts/pbv4_plugins.html --> <!-- CORE PLAYER REQUIRED --> @@ -99,21 +99,18 @@Place this code in the page header.
code: 'video1', mediaTypes: { video: { - playerSize: [640, 480], context: 'instream', + playerSize: [640, 480], mimes: ['video/mp4'], protocols: [1, 2, 3, 4, 5, 6, 7, 8], - playbackmethod: [2] + playbackmethod: [2], + skip: 1 } }, bids: [{ bidder: 'appnexus', params: { - placementId: 13232361, // Add your own placement id here.
- video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } + placementId: 13232361 // Add your own placement id here.
} }] }; @@ -128,7 +125,7 @@Place this code in the page header.
}, debug: true, s2sConfig: { - endpoint: 'http://prebid.adnxs.com/pbs/v1/openrtb2/auction', + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', enabled: true, accountId: 'c9d412ee-3cc6-4b66-9326-9f49d528f13e', // replace this with your account id
bidders: ['appnexus'] @@ -209,7 +206,7 @@Place this code in the page body.
For more information see the Ooyala docs: - http://help.ooyala.com/video-platform/concepts/pbv4_ads_dev_google_ima.html: + https://help.ooyala.com/video-platform/concepts/pbv4_ads_dev_google_ima.html: Make sure the ad parameters are properly formatted JSON. */ @@ -313,7 +310,7 @@Place this code in the page body.
For more information see the Ooyala docs: - http://help.ooyala.com/video-platform/concepts/pbv4_ads_dev_google_ima.html: + https://help.ooyala.com/video-platform/concepts/pbv4_ads_dev_google_ima.html: Make sure the ad parameters are properly formatted JSON. */ @@ -372,4 +369,4 @@Place this code in the page body.
- \ No newline at end of file + diff --git a/examples/video/server/radiant/pbs-ve-radiant.html b/examples/video/server/radiant/pbs-ve-radiant.html index 1b8f4abe42..d64d43b0ec 100644 --- a/examples/video/server/radiant/pbs-ve-radiant.html +++ b/examples/video/server/radiant/pbs-ve-radiant.html @@ -84,21 +84,18 @@Place this code in the page body.
code: 'video1', mediaTypes: { video: { - playerSize: [640, 480], - context: 'instream', - mimes: ['video/mp4'], - protocols: [1, 2, 3, 4, 5, 6, 7, 8], - playbackmethod: [2] + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 } }, bids: [{ bidder: 'appnexus', params: { - placementId: 13232361, // Add your own placement id here. - video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } + placementId: 13232361 // Add your own placement id here. } }] }; @@ -236,21 +233,18 @@Place this code in the page body.
code: 'video1', mediaTypes: { video: { - playerSize: [640, 480], - context: 'instream', - mimes: ['video/mp4'], - protocols: [1, 2, 3, 4, 5, 6, 7, 8], - playbackmethod: [2] + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 } }, bids: [{ bidder: 'appnexus', params: { - placementId: 13232361, // Add your own placement id here. - video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } + placementId: 13232361 // Add your own placement id here. } }] }; @@ -262,7 +256,6 @@Place this code in the page body.
cache: { url: 'https://prebid.adnxs.com/pbc/v1/cache' }, - debug: true, enableSendAllBids: true, s2sConfig: { endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', diff --git a/examples/video/server/videojs/pbs-ve-videojs.html b/examples/video/server/videojs/pbs-ve-videojs.html index 1154a644d2..cb3172c5eb 100644 --- a/examples/video/server/videojs/pbs-ve-videojs.html +++ b/examples/video/server/videojs/pbs-ve-videojs.html @@ -25,9 +25,9 @@{{ page.title }}
@@ -82,21 +82,18 @@Place this code in the page header.
code: 'video1', mediaTypes: { video: { - playerSize: [640, 480], context: 'instream', + playerSize: [640, 480], mimes: ['video/mp4'], - protocols: [1, 2, 3, 4, 5, 6], - playbackmethod: [2] + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 } }, bids: [{ bidder: 'appnexus', params: { - placementId: 13232361, // Add your own placement id here. - video: { - skippable: true, - playback_method: ['auto_play_sound_off'] - } + placementId: 13232361 // Add your own placement id here. } }] }; @@ -111,7 +108,7 @@Place this code in the page header.
}, debug: true, s2sConfig: { - endpoint: 'http://prebid.adnxs.com/pbs/v1/openrtb2/auction', + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', enabled: true, accountId: 'c9d412ee-3cc6-4b66-9326-9f49d528f13e', // replace this with your account id
bidders: ['appnexus'] @@ -153,9 +150,9 @@Place this code in the page body.
<div class="example-video-container"> <video id="vid1" class="video-js vjs-default-skin vjs-big-play-centered" controls data-setup='{}' width='640' height='480'> - <source src="http://vjs.zencdn.net/v/oceans.mp4" type='video/mp4'/> - <source src="http://vjs.zencdn.net/v/oceans.webm" type='video/webm'/> - <source src="http://vjs.zencdn.net/v/oceans.ogv" type='video/ogg'/> + <source src="https://vjs.zencdn.net/v/oceans.mp4" type='video/mp4'/> + <source src="https://vjs.zencdn.net/v/oceans.webm" type='video/webm'/> + <source src="https://vjs.zencdn.net/v/oceans.ogv" type='video/ogg'/> </video> </div> @@ -286,4 +283,4 @@Place this code in the page body.
- \ No newline at end of file + diff --git a/faq/prebid-server-faq.md b/faq/prebid-server-faq.md index 47d4df962e..8ae4ce15de 100644 --- a/faq/prebid-server-faq.md +++ b/faq/prebid-server-faq.md @@ -82,7 +82,7 @@ See the [Prebid Server Privacy Feature Page](/prebid-server/features/pbs-privacy For Prebid.js-initated server requests, we've found that cookie match rates are about what can be expected given the constraints: -- The [/cookie_sync](/prebid-server/developers/pbs-cookie-sync.html) process is initiated by Prebid.js the moment the [s2sConfig](https://docs.prebid.org/dev-docs/publisher-api-reference.html#setConfig-Server-to-Server) is parsed. +- The [/cookie_sync](/prebid-server/developers/pbs-cookie-sync.html) process is initiated by Prebid.js the moment the [s2sConfig](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Server-to-Server) is parsed. - A limited number of bidders will be synced at once. PBS-Go will sync all the bidders listed in the `bidders` array. PBS-Java will sync all of them and possibly additional bidders. Publishers can change the number of syncs by specifying `userSyncLimit` on the s2sConfig. - Privacy settings (e.g. GDPR) can affect sync rate. e.g. If a lot of your traffic is in the EEA, it's going to be harder to set cookies. @@ -120,6 +120,10 @@ The AMP endpoint is somewhat different because it doesn't receive the openrtb - ## How does Prebid Server determine the winner of a given impression? +Prebid Server doesn't decide the overall winner... that's the job of the +ad server. However, there are two decisions it does make that influence +which bids are submitted to the ad server. + **Decision 1**: best bid from each bidder on each impression Prebid Server returns one bid from each bidder for each impression object. If there @@ -130,6 +134,9 @@ are multiple bids from a given bidder for a given imp[], here how it chooses: - highest CPM - random tiebreaker +Note: if the request allows [multibid](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#multibid-pbs-java-only), then several bid responses from the same bidder may +be returned to the client. + **Decision 2**: which bidder for each imp[] object gets the hb_pb, hb_size, and hb_bidder targeting values This is only done when ext.prebid.targeting is specified. @@ -142,3 +149,56 @@ first decision: - highest CPM - random tiebreaker +## Can I host Prebid Server for myself or others? + +Yes. See the [PBS Hosting](/prebid-server/hosting/pbs-hosting.html) page to get started. + +You don't need to be a [Prebid.org member](https://prebid.org/membership/), but joining would help in case you need extra +support with any technical hurdles. + +## I'm hosting Prebid Server - how can I get in the loop? + +The best way would be to [join Prebid.org](https://prebid.org/membership/) and +participate in the [Prebid Server PMC](https://prebid.org/project-management-committees/). + +Another way is to [register for our host company mailing list](/prebid-server/hosting/pbs-hosting.html#optional-registration). + +## Why doesn't Prebid Server resolve OpenRTB macros? + +Prebid Server is not a full-fledged SSP. Any DSP bid adapters should keep this in mind when it comes to assuming SSP functionality like resolving OpenRTB macros. We debated building this functionality into PBS, but realized it would take precious milliseconds away from the overall header bidding auction to scan kilobytes of bidder creatives for the 9 different OpenRTB macros. Since so few bidders require this functionality, it makes sense to have those adapters do it themselves. + +If an adapter doesn't resolve its own macros, AUCTION_PRICE will eventually get resolved by the [Prebid Universal Creative](https://github.com/prebid/prebid-universal-creative), but by then the bid price will be in the ad server currency and quantized by the price granularity. This will likely cause reporting discrepancies. + +## Does Prebid Server support region-specific endpoints for bidders? + +Yes. This is handled by the PBS host company in their datacenter config. +Bidders that want to make use of region-specific endpoints will need to work +with each PBS host company: + +- determine which regions the host company supports +- map the regions to the bidder's endpoints +- the host company overrides the bidder's default auction endpoint when they deploy the configuration for each region. + +We recognize that it's inconvenient for bidders to be required to have this +conversation with each host company, but there's really not a better way +in an open source project. Any number of companies may choose to host +PBS and we cannot constrain them into a defined set of regions. + +## Can bidder endpoints differ by publisher? + +You may not use an endpoint domain as a bidder parameter. Prebid Server is not +an open proxy. If absolutely necessary, you may specify a portion of the +domain as a parameter to support geo regions or account specific servers. +However, this is discouraged and may degrade the performance of your adapter +since the server needs to maintain more outgoing connections. Host companies +may choose to disable your adapter if it uses a dynamically configured domain. + +e.g. this config is not allowed because the entire domain name is a variable: + +``` +endpoint: "https://{host}/path" +``` +but this would be ok: +``` +endpoint: "https://{host}.example.com/path" +``` diff --git a/features/InterstitialAds.md b/features/InterstitialAds.md new file mode 100644 index 0000000000..e034212528 --- /dev/null +++ b/features/InterstitialAds.md @@ -0,0 +1,78 @@ +--- +layout: page_v2 +title: Prebid.js Interstitial Ads +description: Interstitial Ads - Prebid.js +sidebarType: 1 +--- + +# Interstitial Ads - Prebid.js +{: .no_toc} + +* TOC +{:toc} + +Interstitails ads are often placed at natural transition points of the user's experince, such as moving from one page to the next. These ads are generally center aligned overlaying user content. + +This document covers how to setup interstitial ad units. + +{: .alert.alert-warning :} +Please check with each of your bidders to ensure they're reading the interstitial flag from the standard Prebid location. + + +## How It Works + +The intended flow for publishers is the following: +- Publisher traffics interstitial line item with appropriate size(s) ([GAM example](https://support.google.com/admanager/answer/9840201?hl=en)) +- Publisher defines ad server interstitial slot on the page ([GAM Example](https://developers.google.com/publisher-tag/samples/display-web-interstitial-ad)) +- Publisher defines the appropriate interstitial ad sizes within appriate adUnit.mediaType and supplies the adUnit Interstitial flag within the [AdUnit.ortb2Imp](/dev-docs/adunit-reference.html#adUnit-interstitial-example) config +- Prebid requests bids for interstitial adUnits and invokes the ad server call from the requestBids callback + +## Ad Sizes +Publishers are intended to set the desired size in the respective adUnit. + +The below sizes are specials sizes to indicate the ad will be full screen for mobile or tablet devices: +- 320x480: Fullscreen mobile phone portrait ad +- 480x320: Fullscreen mobile phone landscape ad +- 768x1024: Fullscreen tablet portrait ad +- 1024x768: Fullscreen tablet landscape ad + +## In-Page Example + +The Prebid Interstitial flag reflects the OpenRTB standard, specifying it at the imp level. + + +### Supplying Interstitial Flag + +If an attribute is specific to an AdUnit, it can be passed this way: + +{% highlight js %} +pbjs.addAdUnits({ + code: "test-div", + mediaTypes: { + banner: { + sizes: [[300,250]] + } + }, + ortb2Imp: { + instl:1 + }, + ... +}); +{% endhighlight %} + + + +## How Bid Adapters Should Read Interstitial Flag + +To access global data, a Prebid.js bid adapter needs only to retrive the interstitial flag from the adUnit like this: + +{% highlight js %} +utils.deepAccess(bidRequest.ortb2Imp, 'instl') +{% endhighlight %} + + +The assumption is that bid adapters will copy the values to the appropriate protocol location for their endpoint. + +## Related Topics + +- The [AdUnit Reference](/dev-docs/adunit-reference.html) diff --git a/features/firstPartyData.md b/features/firstPartyData.md index 7543f8f5d9..1f7e9131e6 100644 --- a/features/firstPartyData.md +++ b/features/firstPartyData.md @@ -31,9 +31,9 @@ which can be used for more than just First Party Data. Publishers supply First Party Data (FPD) by specifying attributes as configuration or on a Prebid.js AdUnit: -- Global site or user data that applies to all AdUnits and all bidders. Use [`setConfig()`](/dev-docs/publisher-api-reference.html#setConfig-fpd) +- Global site or user data that applies to all AdUnits and all bidders. Use [`setConfig()`](/dev-docs/publisher-api-reference/setConfig.html#setConfig-fpd) - AdUnit-specific data that applies to all bidders. Define [AdUnit.ortb2Imp](/dev-docs/adunit-reference.html#first-party-data) -- Bidder-specific site or user data that applies to all AdUnits. Use [`setBidderConfig()`](/dev-docs/publisher-api-reference.html#module_pbjs.setBidderConfig) +- Bidder-specific site or user data that applies to all AdUnits. Use [`setBidderConfig()`](/dev-docs/publisher-api-reference/setBidderConfig.html) ## In-Page Examples @@ -62,11 +62,11 @@ pbjs.setConfig({ content: { userrating: "4", data: [{ - "name": "www.dataprovider1.com", - "ext": { "taxonomyname": "iab_content_taxonomy" }, - "segment": [ - { "id": "687" }, - { "id": "123" } + name: "www.dataprovider1.com", + ext: { segtax: 4 }, + segment: [ + { id: "687" }, + { id: "123" } ] }] }, @@ -83,7 +83,7 @@ pbjs.setConfig({ keywords: "a,b", data: [{ name: "dataprovider.com", - ext: { taxonomyname: "iab_audience_taxonomy" }, + ext: { segtax: 4 }, segment: [ { id: "1" } ] @@ -122,7 +122,7 @@ pbjs.addAdUnits({ ortb2Imp: { ext: { data: { - pbAdSlot: "homepage-top-rect", + pbadslot: "homepage-top-rect", adUnitSpecificAttribute: "123" } } @@ -134,14 +134,14 @@ pbjs.addAdUnits({ {: .alert.alert-info :} Prebid does not support AdUnit-specific **user** data, nor does it support bidder-specific AdUnit First Party Data. You could implement either of -these scenarios with a publisher-specific callback on the [`requestBids` event](/dev-docs/publisher-api-reference.html#module_pbjs.onEvent) +these scenarios with a publisher-specific callback on the [`requestBids` event](/dev-docs/publisher-api-reference/onEvent.html) {: .alert.alert-warning :} If you're using PBJS version 4.29 or before, replace the following in the example above: 'ortb2Imp.ext.data' with 'fpd.context.data'. ### Supplying Bidder-Specific Data -Use the [`setBidderConfig()`](/dev-docs/publisher-api-reference.html#module_pbjs.setBidderConfig) function to supply bidder-specific data. In this example, only bidderA and bidderB will get access to the supplied +Use the [`setBidderConfig()`](/dev-docs/publisher-api-reference/setBidderConfig.html) function to supply bidder-specific data. In this example, only bidderA and bidderB will get access to the supplied global data. {% highlight js %} @@ -177,9 +177,92 @@ pbjs.setBidderConfig({ // different bidders can receive different data }); {% endhighlight %} +### Supplying App Content Data + +Occasionally, an app which embeds a webview might run Prebid.js. In this case, the app object is often specified for OpenRTB, and the site object would be invalid. When this happens, one should specify app.content.data in place of site.content.data. + +{% highlight js %} +pbjs.setConfig({ + ortb2: { + app: { + name: "myappname", + keywords: "power tools, drills", + content: { + data: [ + { + name: "www.dataprovider1.com", + ext: { + segtax: 6 + }, + segment: [ + { + id: "687" + }, + { + id: "123" + } + ] + }, + { + name: "www.dataprovider1.com", + ext: { + segtax: 7 + }, + segment: [ + { + id: "456" + }, + { + id: "789" + } + ] + } + ] + } + } + } +) + +{% endhighlight %} + +## Segments and Taxonomy + +The [IAB](https://iab.com) offers standard content and audience taxonomies for categorizing sites and users. Prebid supports defining these values as first party data in `site.content.data` or `user.data` as shown in the examples above. + +{: .alert.alert-warning :} +Segment support is still under development. You can follow the [Prebid.js discussion](https://github.com/prebid/Prebid.js/issues/6057) if you'd like. + +``` + user: { + data: [{ + name: "dataprovider.com", // who resolved the segments + ext: { segtax: 4 }, // taxonomy used to encode the segments + segment: [ + { id: "1" } + ] + }], +``` + +The new extension is `segtax`, which identifies the specific taxonomy used to +determine the provided segments. This model supports using taxonomies other +than IAB taxonomies, but all taxonomies must be registered with the IAB to be +assigned a number. Once the IAB finalizes the process, we'll place a link +here to their page. For now, here's the beta table defining the segtax values: + +{: .table .table-bordered .table-striped } +| Segtax ID | Taxonomy Type | Version | Description | +|-----------+---------------+---------+-------------| +| 1 | Content | 1.x | IAB - Content Taxonomy version 1 | +| 2 | Content | 2.x | [IAB - Content Taxonomy version 2](https://iabtechlab.com/wp-content/uploads/2020/12/IABTechLab_Content_Taxonomy_2-2_Final.xlsx) | +| 4 | Audience | 1.1 | [IAB - Audience Taxonomy version 1.1](https://iabtechlab.com/wp-content/uploads/2020/07/IABTL-Audience-Taxonomy-1.1-Final.xlsx) | + +{: .alert.alert-info :} +The [IAB version of this table](https://github.com/InteractiveAdvertisingBureau/AdCOM/blob/master/AdCOM%20v1.0%20FINAL.md#list--category-taxonomies-) is associated with ADCOM. Publishers should check with their SSPs and DSPs to confirm which +segment taxonomies they support. + ## How Bid Adapters Should Read First Party Data -To access global data, a Prebid.js bid adapter needs only to call [`getConfig()`](/dev-docs/publisher-api-reference.html#module_pbjs.getConfig), like this: +To access global data, a Prebid.js bid adapter needs only to call [`getConfig()`](/dev-docs/publisher-api-reference/getConfig.html), like this: {% highlight js %} config.getConfig('ortb2')) diff --git a/features/pbAdSlot.md b/features/pbAdSlot.md index 8b72ebb6a7..05478a0f76 100644 --- a/features/pbAdSlot.md +++ b/features/pbAdSlot.md @@ -23,29 +23,32 @@ The Prebid Ad Slot was introduced with Prebid.js 3.x. 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, or pbAdSlot. -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. +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.fpd.context.pbAdSlot if it exists. Otherwise, if the +// 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 + // set pbadslot for all ad units adUnits.forEach(function (adUnit) { - if (!adUnit.fpd) { - adUnit.fpd = {} + if (!adUnit.ortb2Imp) { + adUnit.ortb2Imp = {} } - if (!adUnit.fpd.context) { - adUnit.fpd.context = {}; + 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.fpd.context.pbAdSlot) { + // use existing pbadslot if it is already set + if (adUnit.ortb2Imp.ext.data.pbadslot) { return; } @@ -54,7 +57,7 @@ var setPbAdSlot = function setPbAdSlot(adUnits) { if (adUnitCodeDiv) { // try to retrieve a data element from the div called data-adslotid. if (adUnitCodeDiv.dataset.adslotid) { - adUnit.fpd.context.pbAdSlot = 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 @@ -65,13 +68,13 @@ var setPbAdSlot = function setPbAdSlot(adUnits) { return (gptSlot.getSlotElementId() === adUnitCodeDiv.id); }); if (linkedSlot) { - adUnit.fpd.context.pbAdSlot = linkedSlot.getAdUnitPath(); + adUnit.ortbImp.ext.data.pbadaslot = linkedSlot.getAdUnitPath(); return; } } } // Else, just use the AdUnit.code, assuming that it's an ad unit slot - adUnit.fpd.context.pbAdSlot = adUnit.code; + adUnit.ortb2Imp.ext.data.pbadslot = adUnit.code; }); }; @@ -82,7 +85,7 @@ pbjs.onEvent('beforeRequestBids', setPbAdSlot); ## How It Works The Prebid Ad Slot is just a convention -- it's a form of adunit-specific first party data -stored under `adunit.fpd.context.pbAdSlot`. +stored under `adunit.ortb2Imp.ext.data.pbadslot`. It can be utilized by any code ready to look for it. It's intended to be specified via Prebid.js in one of two ways: @@ -90,17 +93,17 @@ It's intended to be specified via Prebid.js in one of two ways: 1. Either directly on the AdUnit itself 2. Or defined during the run of a function before the auction -The function could determine the pbAdSlot in any way that produces a stable value useful for targeting and reporting. +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: - parse a substring of the ad server's slot name - use a custom div data element ID, else the AdUnit.code -- use the AdUnit.fpd.context.pbAdSlot as a default rather than primary +- use the AdUnit.ortb2Imp.ext.data.pbadslot as a default rather than primary - support a different ad server ## Prebid Server -The OpenRTB location for the Prebid Ad Slot is `imp[].ext.context.data.pbadslot`: +The OpenRTB location for the Prebid Ad Slot is `imp[].ext.data.pbadslot`: - The Prebid SDK will place the value there. - AMP Stored Requests should place the value there if desired. @@ -108,5 +111,4 @@ The OpenRTB location for the Prebid Ad Slot is `imp[].ext.context.data.pbadslot` ## Further Reading -- The [onEvent()](/dev-docs/publisher-api-reference.html#module_pbjs.onEvent) function - +- The [onEvent()](/dev-docs/publisher-api-reference/onEvent.html) function diff --git a/features/timeouts.md b/features/timeouts.md index a6269666a7..d3d592b91b 100644 --- a/features/timeouts.md +++ b/features/timeouts.md @@ -26,13 +26,13 @@ header bidding activities. Determining this value is a delicate balance: too sho may go down due to delaying the ad server call to the point where users have left the page. Publishers must determine the value that works for them, considering a balance of factors: average user time on page, direct sellthrough, value of different ad channels, and average user network delay. -3. **Timout Buffer** - The JavaScript timer environment is not perfectly accurate +3. **Timeout Buffer** - The JavaScript timer environment is not perfectly accurate because competing JavaScript on the page can delay the header bidding auction or the recognition that auction results have returned. By default, Prebid.js adds a 400ms buffer to the Auction Timeout to account for the noisy environment. Publishers can -change this default value with the [`timeoutBuffer`](/dev-docs/publisher-api-reference.html#setConfig-timeoutBuffer) configuration. +change this default value with the [`timeoutBuffer`](/dev-docs/publisher-api-reference/setConfig.html#setConfig-timeoutBuffer) configuration. 4. **Prebid Server s2sConfig Timeout** - In order to make sure that Prebid Server bids can get back to the client in time for the ad server call, publishers -should consider setting [s2sConfig.timeout](/dev-docs/publisher-api-reference.html#setConfig-Server-to-Server) to a value lower than the Auction Timeout. How much lower depends on average user network delay, but should probably be within the range of 50%-75% of the Auction Timeout. This value is sent in the Prebid Server OpenRTB as `tmax`. +should consider setting [s2sConfig.timeout](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Server-to-Server) to a value lower than the Auction Timeout. How much lower depends on average user network delay, but should probably be within the range of 50%-75% of the Auction Timeout. This value is sent in the Prebid Server OpenRTB as `tmax`. 5. **Timeout Adjustment** - In order to minimize the chance of missing the client-side ad server call, Prebid Server shaves off a safety buffer and responds to the client a little before the `tmax` value time is up. The Prebid Server host company sets two configurable values (`auction.timeout-adjustment-ms` and `auction.cache.expected-request-time-ms`), which can be expected to shave 30-100ms off of `tmax`. For example, if tmax=1000 and the Prebid Server host company has 40ms of safety margin configured, @@ -56,6 +56,6 @@ off the Timeout Adjustment. ## Related Resources -- [Prebid.js timeoutBuffer](/dev-docs/publisher-api-reference.html#setConfig-timeoutBuffer) +- [Prebid.js timeoutBuffer](/dev-docs/publisher-api-reference/setConfig.html#setConfig-timeoutBuffer) - [FAQ: What should I set my timeouts to?](/dev-docs/faq.html#what-should-my-timeouts-be) -- [Prebid.js s2sConfig](/dev-docs/publisher-api-reference.html#setConfig-Server-to-Server) +- [Prebid.js s2sConfig](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Server-to-Server) diff --git a/formats/video.md b/formats/video.md index 8316a7a702..00e6391101 100644 --- a/formats/video.md +++ b/formats/video.md @@ -23,8 +23,8 @@ Video ads are supported by both Prebid.js and Prebid Server. - [Getting started with video](/prebid-video/video-getting-started.html) - [Outstream video ads](/dev-docs/show-outstream-video-ads.html) -- [Prebid Server video ads](/use-cases/pbs-pbjs.html) -- [Prebid Server Long Form Video](r/use-cases/pbs-lfv.html) +- [Prebid Server video ads](/prebid-server/use-cases/pbs-pbjs.html) +- [Prebid Server Long Form Video](/prebid-server/use-cases/pbs-lfv.html) ### Prebid.js bid adapters that support instream and outstream video ads diff --git a/guide.md b/guide.md index 0cf5e9e7da..434d04a776 100644 --- a/guide.md +++ b/guide.md @@ -9,14 +9,32 @@ sidebarType: 0 # Prebid Website Maintenance Guide -v 1.1 -Sept 7, 2019 +v 1.2 +Sept 24, 2021 *** +## Reviewing Pull Requests and Issues + +Being a reviewer means you're in weekly rotation where you keep an eye on pull requests (PRs) and issues opened in this repo. + +### PR Review Guidelines + +1. Make sure no inappropriate changes are made. This covers obvious things like bad language and content, but we also don't allow overt marketing language on the site. Phrases like "we're the best BLAH" or "number one FOOZIT" need to be toned down. +2. Make sure competitors aren't messing with each other's docs. This can be hard to tell because we don't know which github handles belong to which companies, but in general, if a destructive or suspicious change is being made to a doc, check on the Prebid Slack channel to confirm that the affected company approves the change. +3. Make sure the change doesn't break formatting. It's not always necessary to preview locally, but for large changes, it's worthwhile verifying visually because markdown can be cranky. +4. Help the author with basic readability - if you as a reviewer don't understand a sentence, probably others will have trouble too. Push back and ask questions about what they're really trying to say. +5. We don't generally merge a docs PR until the related code is released. Prebid.js releases happen on Weds or Thurs, and people really like to have their docs PRs merged shortly after the code is released. For Prebid Server, it's ok to merge the docs after the code is merged. +6. Fix broken or out-of-date things you run across. At least flag it in the team slack channel so we can fix it someday. +7. Bid Adapter Guidelines + 1. Check the front-matter: required fields are title and either pbjs or pbs. + 2. Every adapter needs a parameters table that contains exactly 5 columns in this order: Name, Scope, Description, Example, Type. + 3. Discourage full-page HTML examples. Better to have just the bidder-specific logic and a pointer to a standard Prebid.js example. + 4. All headers must be level 3, 4, or 5. + ## Core Technologies -The Prebid website is developed using [Jekyll](https://jekyllrb.com/), a static site generator which uses the following technology to create and style HTML pages. +The Prebid website is developed using [GitHub pages](https://pages.github.com/) and [Jekyll](https://jekyllrb.com/), a static site generator which uses the following technology to create and style HTML pages. See the [main README file](https://github.com/prebid/prebid.github.io/blob/master/README.md) for instructions on how to set this up. **Markdown**: The majority of the content is written in Markdown language. Jekyll transform this into raw HTML. @@ -34,11 +52,18 @@ Learn more about [Liquid](https://help.shopify.com/en/themes/liquid/basics) **CSS**: The site builds on the base Bootstrap template with custom CSS stored in the style.css file. -*** +### Environment + +- prebid.org is built with Wordpress. We call it "the marketing site". We generally use a contracting company to make major updates there so it's pretty. But if you know Wordpress, we may give you permissions to do minor updates there. +- docs.prebid.org is the Github pages site. We call it "the docs site". +- dev.prebid.org is served through Netlify from the 'dev' branch of the repo. It's often out of date and only used for major projects or for sharing major docs for external review. +- stage.prebid.org is also served through Netlify, but from the 'staging' branch. You should assume it's out of date. + +On the rare occasions where we need to use the 'dev' or 'stage' sites, we just check with each other to make sure it's not already being used for something. ## Site Config -The _config.yml file (note underscore prefix) sets the base configuration for the site. Refer to [Jekyll](https://jekyllrb.com/docs/configuration/) documentation on which properties can be set in the _congig.yml file. +The _config.yml file (note underscore prefix) sets the base configuration for the site. Refer to [Jekyll](https://jekyllrb.com/docs/configuration/) documentation on which properties can be set in the _config.yml file. *** @@ -73,10 +98,6 @@ The layout directory contains HTML files that, in conjunction with CSS and JS fi The includes directory contains HTML files that can be included within files, such as a file for the header and footer. -**_posts** - -The posts directory contains the files that make up the content of the blog section of the site. Unlike the layouts and includes directories, the posts files are written in Markdown. A blog.html file in the layout directory provides the formatting for these Markdown files. - **_bidders** The bidders directory is not a standard part of Jekyll; it’s a special use directory specifically for the Prebid.org site. The files in this directory are used to construct the table of partners on the partners/partners.html page. @@ -99,65 +120,12 @@ The JS directory contains the Javascript files required for the Prebid.org site. #### CSS -**style.css** - -This file contains custom CSS classes and modifications to Bootstrap classes. The file is broken up into the various sections relating to navigaton, homepage and content pages. - -*Navbar* -The navbar class is a Bootstrap class. It controls the formatting of the top level navigation. Portions of it have been modified specifically for Prebid formatting. - -*Dropdown* -The dropdown class is a Boostrap class. It controls the formatting and functionality of the dropdown items of the top navigation. Portions of it have been modified specifically for Prebid formatting. - -*Sidebar* -The sidebar class is a Boostrap class. It controls the formatting and functionality of the dropdown items of the top navigation. Portions of it have been modified specifically for Prebid formatting. Additional custom classes have been created for specific formatting or functionality required by Prebid. - -*Homepage* -The classes in the homepage secton are custom classes created to format the top portion of the Prebid website homepage. - -*Container* -A custom container class created for the Prebid website. - -*Hover Effect* -A custom series of classes created to control the formatting functionalty of the icon buttons on the Prebid website homepage. - -*Message* -A custom series of classes created to control the formatting of the message box on the Prebid website homepage. - -*Benfits* -A custom series of classes created to control the formatting of the Benefits section of the Prebid website homepage. - -*Carousel* -The carousel class is a Bootstrap class. It controls the formatting and functionality of the carousel displayed on the homepage. Portions of it have been modified specifically for Prebid formatting. Additional custom classes have been created for specific formatting or functionality required by Prebid. - -*Partners* -A custom series of classes created to control the formatting of the [partners](/partners/partners.html) page. - -*Blog* -A custom series of classes created to control the formatting of the blog pages. - -*Content Pages* -A custom series of classes created to control the formatting of the content on the interior pages. - -*Footer* -A custom class created to control the formatting of the footer. - -**Responsivenes** - -The CSS file has multiple @media sections that handle the formatting of the website pages at specific screen widths. Those widths (in pixels) are: - -| Width | Device | -| --- | --- | -| 1300 | Small browsers | -| 1024 | Large tablets e.g. iPadPro | -| 768 | Regular tablets e.g. iPads | -| 414 | Large phones e.g. iPhone 8 Plus | -| 375 | Newer phones e.g. iPhone X | -| 360 | Older phones e.g. Galaxy S5 | -| 320 | Very old phones e.g. iPhone 5 | - - -*** +1. Styles all come from /assets/css/main-bundle.css +1. These are generated from /_assets/sass +1. To make a change, edit the relevant sass file +1. Generate the css file from sass with 'npm run dev/prod' +1. Commit all the changes including assets/css/main-bundle.css +1. the _assets directory is not part of the _site tree ## Data Models @@ -277,49 +245,9 @@ Each menu item is represented in the YML map as a collection of key value pairs **Code Use** This data file is read in the page_v2.html file using Liquid. -blog entry for more info. - messageCreateDt: 01_08_2019 -``` - -| Key | Type | Example | Use | -| ----- | ------ | ------ | ------ | -| messageId | int | 0 | A unique identifier for each message | -| messageText | string | A message | The displayed text. (Use HTML formatting for links.) | -| messageCreateDt | string | 01_08_2019 | Date the message was created, for historical purposes. | - **Code Use** This data file is read in the home.html file using Liquid. - +``` + +If custom configurations are needed, define the pubcid_options object before inclusion of the script. Below is an example to switch from using local storage to cookie: + +``` + + +``` + +#### Configuration + +Below are the available configuration options for the PubCID script. + +{: .table .table-bordered .table-striped } +| Parameter Name | Type | Description | | Example | +| --- | --- | --- | --- | --- | +| create | boolean | If true, then an id is created automatically by the script if it's missing. Default is true. If your server has a component that generates the id instead, then this should be set to false | | `true` | +| expInterval | decimal | Expiration interval in minutes. Default is 525600, or 1 year | | `525600` | +| extend | boolean | If true, the the expiration time is automatically extended whenever the script is executed even if the id exists already. Default is true. If false, then the id expires from the time it was initially created. | For publisher server support only. If true, the publisher's server will create the (pubcid) cookie. Default is true. | `true` | +| pixelUrl | string (optional) | For publisher server support only. Where to call out to for a server cookie. | | `/wp-json/pubcid/v1/extend/` +| type | string | Type of storage. It's possible to specify one of the following: 'html5', 'cookie'. Default is 'html5' priority, aka local storage, and fall back to cookie if local storage is unavailable. | If true, the expiration time of the stored IDs will be refreshed during each page load. Default is false. | `cookie` | + +#### Example Configurations + +Always use cookies and create an ID that expires in 30 days after creation. + +``` +{ + type: 'cookie', + extend: false, + expInterval: 43200 +} +``` + +Using a SharedId Endpoint implementation, create the cookie once, which will be allowed to expire before it is created again. + +``` +{ + type: 'cookie', + pixelUrl: '/wp-json/pubcid/v1/extend/', + create: false, + extend: false +} + +``` + +### SharedId First Party Endpoint + +Add server-side support for SharedId to better handle the ever-increasing restrictions on cookies in modern web browsers by having the SharedId first party cookie written and extended by your web server. + +#### CMS + +PubCID/SharedId plugins are available for Wordpress and Drupal. Because the CMS can cache pages to improve scalability, it's impractical to set unique cookies during page generation. Instead these plugins require a dynamic endpoint that serves back a blank pixel along with a unique cookie value. The client side script needs one additional parameter for this URL. Please consult the corresponding plugin documents for default values: + +1. Wordpress : Install directly from the [Wordpress admin page](https://wordpress.org/plugins/publisher-common-id/). Install from [GITHUB](https://github.com/prebid/sharedid-wordpress) +2. Drupal : Install from [Github](https://github.com/prebid/sharedid-drupal). + +#### Endpoint Implementations + +The Wordpress and Drupal plugins require that the host company integrate a new endpoint into their webserver that can receive request from the page and set a unique cookie. +Below are some examples for how to implement this function in various languages or platforms. It is up to the site owner to integrate an appropriate script for their specific scenario. + +##### JAVA +```JAVA +public class PubCid { + private static final String pubcidCookieName = "_pubcid"; + private static final int expireTime = (int) TimeUnit.DAYS.toSeconds(365); //store cookie for 1 year + + /** + * Returns the pubcid cookie found in the user's list of cookies. + * Always update the expire time to another year so that the cookie persists. + * + * @param cookies User's list of cookies + * @return the pubcid cookie if found, null otherwise + */ + public static Cookie getPubcidCookie(Cookie[] cookies) { + + Cookie pubcidCookie = fetchPubcidCookie(cookies); + if (pubcidCookie != null) + pubcidCookie.setMaxAge(expireTime); + + return pubcidCookie; + } + + /** + * Simple function to test if the user has a pubcid cookie + * + * @param cookies User's list of cookies + * @return true if the cookie is found, false otherwise + */ + public static boolean hasPubcidCookie(Cookie[] cookies) { + return fetchPubcidCookie(cookies) != null; + } + + /** + * Local function to find the pubcid cookie within the user's list of cookie + * + * @param cookies User's list of cookies + * @return pubcid cookie if found, null otherwise + */ + private static Cookie fetchPubcidCookie(Cookie[] cookies) { + if (cookies == null) return null; + return Arrays.stream(cookies) + .filter(e -> e.getName().equals(pubcidCookieName)) + .findFirst() + .orElse(null); + } +} +``` +##### PHP +```PHP +$cookie_name = '_pubcid'; +$cookie_path = '/'; +$max_age = 365; + +$value = NULL; + +// See if the cookie exist already + +if (isset($_COOKIE[$cookie_name ])) + $value = $_COOKIE[$cookie_name]; + +// Obtain site domain if defined +if (defined(COOKIE_DOMAIN)) + $cookie_domain = COOKIE_DOMAIN; +else + $cookie_domain = ""; + +// Update the cookie +if (isset($value)) { + setcookie( + $cookie_name, + $value, + time() + $max_age * DAY_IN_SECONDS, + $cookie_path, + $cookie_domain + ); +} +``` +##### Node.js +```Node +const express = require('express'); +const cookieParser = require('cookie-parser'); +const app = express(); +const port = 3000; + +app.use(cookieParser()); + +app.get('/', function(req, res) { + + // Check for existence of _pubcid cookie + let value = req.cookies['_pubcid']; + + // If pubcid exists, then update its expiration time + if (value) { + res.cookie('_pubcid', value, {domain: '.example.com', path: '/', expires: new Date(Date.now() + 1000*60*60*24*365)}); + } + + res.render('index'); +}); + +app.listen(port, ()=>console.log(`App listening on port ${port}`)); +``` +##### Apache +```Apache +# Add to httpd.conf +# Requires mod_headers and mod_env + +# Capture _pubcid cookie value if available +SetEnvIf Cookie "(^|;\ *)_pubcid=([^;\ ]+)" PUBCID_VALUE=$2 +SetEnvIf Cookie "(^|;\ *)_pubcid=([^;\ ]+)" HAVE_PUBCID=1 + +# Add _pubcid cookie if it exists to the response with 1 year expiration time +Header add Set-Cookie "_pubcid=%{PUBCID_VALUE}e;Domain=.example.com;Path=/;Max-Age=31536000" env=HAVE_PUBCID +``` +##### Nginx +```Nginx +# Add to a location directive + + location /example { + set $pubcid_value $cookie__pubcid; + if ($pubcid_value) { + add_header Set-Cookie "_pubcid=$pubcid_value;Domain=.example.com;Path=/;Max-Age=31536000"; + } + } +``` + +## Related Topics + +- [Prebid Identity Overview](/identity/prebid-identity.html) +- [Prebid.js User ID modules](/dev-docs/modules/userId.html) diff --git a/overview/ga-analytics.md b/overview/ga-analytics.md index 503ac5ca0f..004a08a5a9 100644 --- a/overview/ga-analytics.md +++ b/overview/ga-analytics.md @@ -24,7 +24,7 @@ It includes: - Bidder bid/win price analysis by geo, domain, with price range distribution. - Bid latency by bidder, geo, and domain. -- Seamless integration with your Google Analytics account and scheduled reports delivered to your mailbox. +- Seamless integration with your Google Analytics account and scheduled reports delivered to your mailbox.
@@ -32,15 +32,15 @@ It includes: The day starts from making sure the bidders are not generating less revenue: - + Something is not right here - total revenue from yesterday dropped quite a bit. This could be caused by certain bidders were down or experienced technical issues. Let's take a look at the bidder timeout rate: - + Bidder timeout seems okay. The problem might then be caused by bidders' lower bid rate: - + Here we go. Bidder 1 and 4 bid much less than usual. You may want to drill down even further - Prebid.js Analytics also provides: @@ -59,7 +59,7 @@ To understand exactly how much time per bidder spent, the Analytics Platform all
- + You might derive: @@ -72,7 +72,7 @@ Similar query for bidders' bid CPM:
- + > **Try out the product and explore the demo dashboard here!** This will be the base of your dashboard! @@ -91,5 +91,3 @@ Prebid.js has a seamless integration with Google Analytics and Google Spreadshee - [Analytics for Prebid]({{site.baseurl}}/overview/analytics.html) (Overview and list of analytics providers) - [Integrate with the Prebid Analytics API]({{site.baseurl}}/dev-docs/integrate-with-the-prebid-analytics-api.html) (For developers) - - diff --git a/overview/how-many-bidders-for-header-bidding.md b/overview/how-many-bidders-for-header-bidding.md index 9de7e733bf..1ce008e967 100644 --- a/overview/how-many-bidders-for-header-bidding.md +++ b/overview/how-many-bidders-for-header-bidding.md @@ -3,7 +3,7 @@ layout: page_v2 title: Optimize header bidding setup head_title: Optimize header bidding setup -description: An analysis of the optimal number of bidders to work with for header bidding, to optimize yield and user experience. +description: An analysis of the optimal number of bidders to work with for header bidding, to optimize yield and user experience. pid: 10 @@ -23,7 +23,7 @@ While helping publishers run header bidding, we hear the same questions asked ma * How many bidders should I work with? * How can I maximize revenue while maintaining a good user experience? -We've all heard anecdotally a webpage should not have more than 10 bidders' bids, or the page should not wait for longer than 1 second before it sends the bids to the ad server. Are they true? +We've all heard anecdotally a webpage should not have more than 10 bidders' bids, or the page should not wait for longer than 1 second before it sends the bids to the ad server. Are they true? Luckily, the publishers using Prebid.js are curious about these questions too. We thus ran A/B tests and collected real data from pages running header bidding. We measured overall revenue & latency versus the number of bidders and how long the ad server waits for. @@ -31,7 +31,7 @@ Luckily, the publishers using Prebid.js are curious about these questions too. W ### Q1: How is revenue affected by different factors? -{: .pb-lg-img :} +{: .pb-lg-img :} (_the above data is normalized to CPM = 1 for anonymity_) Revenue is mainly determined by: @@ -53,17 +53,17 @@ Conclusions: ##### 3. Revenue actually drops if the page waits for too long -* This could be caused by users leaving the page, when the ads took too long to load. +* This could be caused by users leaving the page, when the ads took too long to load.
### Q2: How is page content load time affected? -{: .pb-lg-img :} +{: .pb-lg-img :} _(The above page has on average 130 HTTP requests, 1.5MB data transferred per refresh)_ -Page content load time is critical to measure user experience. Your page's content taking 200 millisecond to load delivers a MUCH BETTER experience than if it takes 2 seconds. +Page content load time is critical to measure user experience. Your page's content taking 200 millisecond to load delivers a MUCH BETTER experience than if it takes 2 seconds. In this test, we measured the front section's load time. We define the front section as what's visible to the user when they open the webpage. For example, when the above graph's Y-axis is at 100ms, it means that the front section took 100ms to load before a user can see it. @@ -71,15 +71,15 @@ Conclusions: ##### Page content load time is NOT really affected by the number of bidders or by how long the page waits. -* The front section continues to load between 60 to 120ms, unaffected by the given factors. -* **This is expected**, as Prebid.js sends out bids asynchronously and they **do NOT block** the page content from loading. Modern browsers also prioritize the page content load over asynchronous Javascript scripts. +* The front section continues to load between 60 to 120ms, unaffected by the given factors. +* **This is expected**, as Prebid.js sends out bids asynchronously and they **do NOT block** the page content from loading. Modern browsers also prioritize the page content load over asynchronous Javascript scripts.
### Q3: How about ad load time? -{: .pb-lg-img :} +{: .pb-lg-img :} _(The above page has on average 130 HTTP requests, 1.5MB data transferred per refresh)_ Ad load time measures how long a user has to wait before he/she can see the ad. This is less important than the page's content load time. However, the initial blank space in the ad unit, or the page elements shifting around due to a late ad load, can both demage the user experience. @@ -90,7 +90,7 @@ Conclusions: * This makes perfect sense. It's important to note that the ads load at around 1200ms even when the adserver waits for 2 seconds, because most of the bids come back within 1200ms and Prebid.js stops the adserver from waiting. -##### 2. When your ad server waits for < a threshold (500ms in this case), working with more bids take longer for the ads to load. +##### 2. When your ad server waits for < a threshold (500ms in this case), working with more bids take longer for the ads to load. * This makes sense, because sending out more bid requests takes longer. @@ -102,7 +102,7 @@ Conclusions: ### Recommendations: -Every webpage is different. Every site's users are different. Different publishers will put different weights on revenue vs. user experience. Our main recommendation is: **Create the above 3 graphs.** They will help you understand how many bids you should work with and how long your page should wait for. +Every webpage is different. Every site's users are different. Different publishers will put different weights on revenue vs. user experience. Our main recommendation is: **Create the above 3 graphs.** They will help you understand how many bids you should work with and how long your page should wait for. Prebid.js is a good place to start for free : ) @@ -115,5 +115,3 @@ Note that the above data is collected by pages that run true header bidding auct * Ad server only waits for a limited amount of time, ignoring all bids that come after. If your page does not run a true header bidding auction, the above analysis may not apply. - - diff --git a/overview/how-to-simplify-line-item-setup.md b/overview/how-to-simplify-line-item-setup.md index a3c18c9784..6d3d392ebf 100644 --- a/overview/how-to-simplify-line-item-setup.md +++ b/overview/how-to-simplify-line-item-setup.md @@ -43,27 +43,27 @@ In this section, we'll learn how to remove the creative size dimension for heade Let's first clarify what "different set of line items for different creative sizes" means. In this scenario, a line item's creative is only of one size. In Google Ad Manager, this looks like: -{: .pb-md-img :} +{: .pb-md-img :} Because a site would have many creative sizes, with this setup you need X number of line item sets for X number of creative sizes. There's a reason bidders recommend different set of line items for different creative sizes. If we simply attach all creative sizes to a line item, the line item wouldn't know which size of creative to choose. Consider this case: -* Your line item has all creatives of different sizes attached. +* Your line item has all creatives of different sizes attached. * Your ad unit can accept both 300x250 and 300x600. A bidder bid $6.00 for the 300x600 size and has the highest price. -* The $6.00 line item got picked by the line item. +* The $6.00 line item got picked by the line item. * The best your ad server can do is to RANDOMLY choose a creative. If the 300x250 one is chosen, the ad will be cut in half. #### How Prebid.js solves this problem: Prebid.js can dynamically resize the returned creative to the right size. Here's the setup: -* Submit a few creatives of size 1x1 and make them override the line items' sizes when you [attach creatives to the line item]({{ site.github.url }}/adops/step-by-step.html#step-3-attach-the-creative-to-the-line-item). -* Your ad unit can accept both 300x250 and 300x600. A bidder bid $6.00 for the 300x600 size and has the highest price. Prebid.js passed the bid in, as well as a generated bid ID. -* The $6.00 line item got picked by the line item. +* Submit a few creatives of size 1x1 and make them override the line items' sizes when you [attach creatives to the line item](/adops/step-by-step.html#step-3-attach-the-creative-to-the-line-item). +* Your ad unit can accept both 300x250 and 300x600. A bidder bid $6.00 for the 300x600 size and has the highest price. Prebid.js passed the bid in, as well as a generated bid ID. +* The $6.00 line item got picked by the line item. * Your ad server randomly choose a 1x1 creative. However, because all creatives have the same content, it does not make a difference. -* The creative content has the bid ID. Prebid.js reads this bid ID, which is mapped to size 300x600. +* The creative content has the bid ID. Prebid.js reads this bid ID, which is mapped to size 300x600. * Prebid.js resize the returned creative to size 300x600 and injects the bid's cretive payload. There you go! @@ -77,7 +77,7 @@ There're a few reasons why previously you'd need different set of line items for 1. Bidders did not design their implementation guide with other bidders in mind. 2. Bidders all have different targeting parameters. -3. You need to run reports to learn fill rates and CPM from different bidders. +3. You need to run reports to learn fill rates and CPM from different bidders. Assume we have 1 set of line items for ALL bidders. Consider the below key-value pairs came in: (AppNexus bid $1.60, Rubicon bid $1.20. Ad IDs are used for rendering the right creative): @@ -98,7 +98,7 @@ Prebid.js only picks the highest price bid and sends its key-value pairs to the * `hb_adId`: 65432 * `hb_bidder`: appnexus -This simplifies the setup and the right creative (with adId 65432) will get displayed. +This simplifies the setup and the right creative (with adId 65432) will get displayed. #### How about reporting? @@ -107,10 +107,8 @@ It's important to understand the fill rates and CPM from different bidders. Preb * For bidder X, at what CPM does it fill? * For bidder X, what's the fill rate out of all the winning header bidding bids? -Note that because Prebid.js only sends in the highest price bid, Google Ad Manager does not see the rest of the lost bids. However, from working with publishers, we conclude that the rest of the bids do NOT matter that much. Let's say one bidder always fills at 1 penny and bids 100% of the time. Is that information helpful? Not really, only the winning bids count. We belive the above 2 queries well serve the reporting and analytics needs. +Note that because Prebid.js only sends in the highest price bid, Google Ad Manager does not see the rest of the lost bids. However, from working with publishers, we conclude that the rest of the bids do NOT matter that much. Let's say one bidder always fills at 1 penny and bids 100% of the time. Is that information helpful? Not really, only the winning bids count. We belive the above 2 queries well serve the reporting and analytics needs. ### Conclusion Enjoy the much more simplified line items, creatives, and targeting setup! - - diff --git a/overview/intro.md b/overview/intro.md index 5f623d4ff8..23342c615b 100644 --- a/overview/intro.md +++ b/overview/intro.md @@ -13,42 +13,43 @@ sidebarType: 0 ## Overview {: .alert.alert-info :} -If you're looking for a more high-level overview of Prebid.org, including product features, membership, events, and so on, visit [Prebid.org](https://prebid.org/). +If you're looking for a marketing-level overview of the Prebid software and organization, including product features, membership, events, and so on, visit [Prebid.org](https://prebid.org/). Prebid is more than a product; it's a product suite, a community, and an organization. -- **Product Suite:** A free and open source suite of software products designed to enable publishers to implement header bidding on their websites and from within their apps. Our product line includes: - - **Prebid.js:** The core of our codebase. Prebid.js provides a simple and easy-to-implement code set to improve header bidding for display and video ads on a publisher's website and within OTT applications. +- **Product Suite:** A free and open source suite of software products that enables publishers to implement header bidding on websites and mobile apps. Our product line includes: + - **Prebid.js:** Prebid.js provides a powerful and easy-to-implement code set to improve header bidding for display and video ads on a publisher's website and within OTT applications. - **Prebid Server:** Provides a hosted or custom server-side solution for header bidding. Utilizing Prebid Server can reduce latency between bid request and ad selection, and speed the presentation of your site and ads. - **Prebid Mobile:** Our native iOS and Android solutions to enable header bidding within a mobile app. - **Community:** The developers that maintain and improve our products. -- **Organization:** A collection of leaders within the ad tech industry that promotes our products, works with the ad tech community to expand the solutions our products can provide, and encourages the development of the platform. For more about the organization, see the [Prebid.org](https://prebid.org/) website. +- **Organization:** An active membership of leaders within the ad tech industry promotes Prebid products and works with the ad tech community to define and implement enhanced solutions. For more about the organization, see the [Prebid.org](https://prebid.org/) website. -{% include alerts/alert_note.html content="Our flagship product, Prebid.js, is sometimes referred to as simply *Prebid*, but please be aware that the Prebid product line supports header bidding for web, AMP, and mobile apps, using both client- and server-side project components." %} +{: .alert.alert-info :} +Our flagship product, Prebid.js, is sometimes referred to as simply *Prebid*, but please be aware that the Prebid product line supports header bidding for web, AMP, and mobile apps, using both client- and server-side components. ## Header Bidding -### What is header bidding? +### What is Header Bidding? -Header bidding is a response to a fragmented and highly inefficient process for digital ad display. It is an alternative to the "waterfall" method, the process of offering impressions in one sales channel and if that does not succeed moving to less valuable channels. Header bidding is sometimes referred to as advance bidding or pre-bidding. -When the page loads, header bidding enables publishers to have simultaneous auctions with all SSPs and ad exchanges. Publishers can receive bids on their inventory that may be unavailable through their primary ad server and exchange. +Header bidding is a response to a fragmented and inefficient process for digital ad display. It is an alternative to the "waterfall" method, in which impressions are offered to one sales channel at a time, moving down an inflexible stack of sources. +With header bidding, the publisher creates a short delay in their ad serving to obtain bids from many SSPs and ad exchanges. In this way, publishers can receive high value bids on their inventory that may be unavailable through their primary ad server and exchange. The returned bids are then passed into the ad server so they can compete with direct demand and the primary ad server's exchange on a level playing field. -### A brief history of header bidding +### A Brief History of Header Bidding -The early days of header bidding were dominated by bad practices, closed proprietary tech, poor standards, and little to no cooperation between competing companies. Publishers were presented with the confusing and time-consuming process of having to manually patch together various solutions from different companies and processes. +The early days of header bidding were dominated by bad practices, proprietary tech, poor standards, and little to no cooperation between competing companies. Publishers were presented with the confusing and time-consuming process of having to manually patch together various solutions from different companies and processes. Prebid.js launched in 2015 to make header bidding easy for publishers by bringing conformity and simplicity to the header bidding process. By creating a simple, open tech layer upon which companies could add their code to a standard but optimized foundation, Prebid.js made it easier to implement header bidding, and offered the largest repository of working adapters. -Today, Prebid.js is the most widely used header bidding "container" or "wrapper" on the web. The ecosystem supports more than 150 demand partners, over fifteen analytics providers, and numerous publishers. +Today, Prebid.js is the most widely used header bidding "container" or "wrapper" on the web. The ecosystem supports more than 300 demand partners, about 50 analytics providers, and thousands of websites. ## Benefits of Prebid Products The Prebid product suite offers publishers multiple benefits designed to foster a better header bidding experience, including: -- A free and open source solution, enabling anyone to contribute or review code. +- A free and open source set of solutions, enabling anyone to contribute or review code. - The largest repository of working header bidding adapters. - Asynchronous and single time-out to provide a better user experience. - Prebid Server, to run faster auctions with more partners. -- Tools and analytics to optimize your setup. +- Modules, tools, and analytics support to optimize publisher setup. - Multiple options on formats (display, video, native) and channels (mobile, web). - A well established and helpful community that can advise on best practices and, if needed, provide professional setup and services. @@ -56,18 +57,18 @@ The Prebid product suite offers publishers multiple benefits designed to foster ### Prebid.js -Prebid.js is the core product of the Prebid suite. Implemented on multiple formats to include display, video, and native, it provides a simple process for header bidding that can be ramped up to fit the complexity of your needs. +Prebid.js is the core product of the Prebid suite. It supports multiple formats include display, video, and native, and provides a simple process for header bidding that can be ramped up to fit the complexity of your needs. **Reducing Latency** -One of the main problems publishers have experienced with other header bidding solutions is the delay between the bid requests being sent and the responses being returned. Many solutions use synchronous calls, meaning each SSP or ad exchange has to receive the request and return a response before the next SSP is called. This can lead to a long delay between when the web page is called and when it is actually loaded. -Prebid resolves this issue by concurrently calling the selected SSPs and ad exchanges within the set timeout. That setting is respected by Prebid.js, and any bidder not returning a result within the timeout duration is excluded from the auction. This dramatically decreases the page load time, providing a better user experience. +One of the main problems publishers have experienced with other header bidding solutions is the delay between the bid requests being sent and the responses being returned. Some solutions use synchronous calls, meaning each bidder has to receive the request and return a response before the next bidder is called. This can lead to a long delay between when the web page is called and when it is actually loaded. +Prebid resolves this issue by concurrently calling the selected bidders within the set timeout. That setting is respected by Prebid.js, and any bidder not returning a result within the timeout duration is excluded from the auction. This dramatically decreases the page load time, providing a better user experience. **Prebid.js process** A simple Prebid.js process follows these steps: -1. The ad server's tag is paused by a timer while Prebid.js sends out bid requests to selected SSPs and ad exchanges. -2. Creatives and bids are returned from the SSPs and ad exchanges. +1. The ad server's tag is paused by a timer while Prebid.js sends out bid requests to selected bidders. +2. Creatives and bids are returned from the bidders. 3. From the bid responses, Prebid.js finds a winner (if applicable) and caches the creatives. 4. Prebid passes the winning bid parameters to the ad server as key-values. 5. The ad server takes those key-values and finds a matching line item and compares to other line items that bid on this impression. @@ -78,9 +79,16 @@ A simple Prebid.js process follows these steps: ### Prebid Server Prebid Server provides a server-side solution to header bidding. Built on the same core principles as Prebid.js, our server solution can reduce latency and improve page load time. -Several Prebid.org members provide hosted solutions, enabling publishers to receive the benefits of server-side header bidding without the need to implement and manage the process themselves. -If a publisher would prefer to implement their own solution, [source code](https://github.com/prebid/prebid-server) is available from our Github page and detailed instructions for configuring, deploying and testing your implementation can be found in the [Prebid Server section](/prebid-server/overview/prebid-server-overview.html) of this site. +When a pub chooses to push auctions to the server-side, they're doing it to +lighten the load that header bidding has on the browser. For instance, if 5 +bidders are moved from the client-side to the server-side, the browser just makes +one request to PBS, which fans out the actual 5 auctions across server-to-server +connections. + +Several Prebid.org members provide [hosted solutions](https://prebid.org/product-suite/managed-services/), enabling publishers to receive the benefits of server-side header bidding without the need to implement and manage the process themselves. + +If a publisher would prefer to implement their own solution, source code in [Go](https://github.com/prebid/prebid-server) or [Java](https://github.com/prebid/prebid-server-java) is available from our Github page and detailed instructions for configuring, deploying and testing your implementation can be found in the [Prebid Server section](/prebid-server/overview/prebid-server-overview.html) of this site. **Prebid Server process** @@ -88,17 +96,19 @@ Prebid Server (PBS) provides multiple endpoints for auctions as well as data ret 1. An OpenRTB request is sent to Prebid Server. 2. Prebid Server conducts the auction with selected SSPs and ad exchanges. -3. PBS collects the bids and creatives and stores them in Prebid cache. -4. PBS passes the winning bid parameters to the ad server. -5. The ad server takes the passed in key-values and finds a matching line item and then compares to other line items that bid on this impression. -6. If the ad server determines Prebid wins the auction it returns a reference to the winning creative to Prebid. -7. Prebid retrieves the winning creative and displays it in the correct ad slot. +3. PBS collects the bids and creatives. +4. PBS passes the winning bid parameters to Prebid.js the ad server. +5. The ad server takes the passed in key-values and finds a matching line item and then compares to other line items that bid on this impression. +6. If the ad server determines Prebid wins the auction it returns the Prebid Universal Creative +7. The Prebid Universal Creative displays the winning ad.  +See the [Prebid Server documentation](/prebid-server/overview/prebid-server-overview.html) for more use cases including [AMP](/prebid-server/use-cases/pbs-amp.html) and [Mobile App](/prebid-server/use-cases/pbs-sdk.html). + ### Prebid Mobile -For mobile apps, Prebid provides Prebid Mobile (PBM), an end-to-end header bidding solution for both iOS and Android. Working in conjunction with Prebid Server, PBM reduces latency and enables access to more mobile buyers, provides options for banner and interstitial ad formats, and enables user to set global targeting values for the bid request. +For mobile apps, Prebid provides Prebid Mobile (PBM) SDK: an end-to-end header bidding solution for both iOS and Android. Working in conjunction with Prebid Server, PBM reduces latency and enables access to more mobile buyers, provides options for banner and interstitial ad formats, and enables user to set global targeting values for the bid request. **Prebid Mobile process** @@ -109,8 +119,8 @@ The PBM header bidding process follows these steps: 3. Each demand partner returns a bid response to Prebid Server. The bid response includes the bid price and the creative content. 4. Prebid Server sends the bid responses to Prebid Mobile. 5. Prebid Mobile sets key-value targeting for each ad slot through the primary ad server mobile SDK. This targeting will activate one or more of Prebid line items that were previously configured in the primary ad server. -6. If the line item associated with the Prebid Mobile bid wins, the primary ad server returns the Prebid Mobile creative JavaScript to the ad server’s SDK. -7. The Prebid Mobile creative JavaScript will fetch and render the corresponding creative content from the winning Prebid Server demand partner. +6. If the line item associated with the Prebid Mobile bid wins, the primary ad server returns the Prebid Universal Creative JavaScript to the ad server’s SDK. +7. The Prebid Universal Creative JavaScript will fetch and render the corresponding creative content from the winning Prebid Server demand partner.  diff --git a/overview/what-is-post-bid.md b/overview/what-is-post-bid.md index 0c7883dc61..0bbd22b652 100644 --- a/overview/what-is-post-bid.md +++ b/overview/what-is-post-bid.md @@ -11,7 +11,7 @@ sidebarType: 1 > Post-bid allows a publisher’s demand sources to compete in one auction based on price after the ad server has declined to choose a direct-sold or exchange-based line item. `Post-bid` is the configuration scenario where a publisher loads and runs Prebid.js -in a winning line item's creative. In a post-bid setup, +in a winning line item's creative. In a post-bid setup, demand sources compete _after_ the ad server has chosen the post-bid line item. Compare this to: - header bidding, where demand sources compete _before_ the ad server has seen @@ -21,7 +21,7 @@ they all compete in one single line item based on price. This diagram summarizes the post-bid scenario: -{: .pb-lg-img :} +{: .pb-lg-img :} Steps: @@ -62,7 +62,7 @@ already loaded. #### 3. Reporting is harder. -In the ad server's post-bid line item report, you’d only get an aggregated report of all demand sources. You may need to rely on a 3rd party reporting service to record which demand partner wins how much inventory. +In the ad server's post-bid line item report, you’d only get an aggregated report of all demand sources. You may need to rely on a 3rd party reporting service to record which demand partner wins how much inventory. ### Comparison of Monetization Solutions @@ -85,10 +85,9 @@ Yes. Check out the [example](/dev-docs/examples/postbid.html). #### 2. Can post-bid be used for mobile apps? -Yes, it works the same as for browsers. When utilizing a server-to-server architecture, the [app](/dev-docs/publisher-api-reference.html#setConfig-app) config option can be used to forward the mobile app details. +Yes, it works the same as for browsers. When utilizing a server-to-server architecture, the [app](/dev-docs/publisher-api-reference/setConfig.html#setConfig-app) config option can be used to forward the mobile app details. ## Getting Started Please refer to the [example](/dev-docs/examples/postbid.html). - diff --git a/overview/what-is-prebid-org.md b/overview/what-is-prebid-org.md index f3577affc8..46ede93b71 100644 --- a/overview/what-is-prebid-org.md +++ b/overview/what-is-prebid-org.md @@ -27,7 +27,7 @@ We focus on providing value-add to publishers and encourage the industry to depl Prebid takes two approaches to accomplish this: ### Wrapper Code of Conduct -Prebid members must agree to support the [Wrapper Code of Conduct](http://prebid.org/wrapper_code_of_conduct.html +Prebid members must agree to support the [Wrapper Code of Conduct](/wrapper_code_of_conduct.html ). This ensures that all wrapper providers are operating within the same principles. ### Trademark diff --git a/package.json b/package.json index 27b2226477..320ee697a4 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test": "echo \"Error: no test specified\" && exit 1", "dev": "npm run development", "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", - "watch": "npm run development -- --watch", + "watch": "bundle exec jekyll serve", "prod": "npm run production", "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --nide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, diff --git a/prebid-mobile/adops-price-granularity.md b/prebid-mobile/adops-price-granularity.md index 4d883ba8ff..65d4d04e87 100644 --- a/prebid-mobile/adops-price-granularity.md +++ b/prebid-mobile/adops-price-granularity.md @@ -62,4 +62,4 @@ Please contact your Prebid Mobile host company for details about how to implemen ## Further Reading -- [Prebid.js MediaTypePriceGranularity](/dev-docs/publisher-api-reference.html#setConfig-MediaType-Price-Granularity) +- [Prebid.js MediaTypePriceGranularity](/dev-docs/publisher-api-reference/setConfig.html#setConfig-MediaType-Price-Granularity) diff --git a/prebid-mobile/pbm-api/android/pbm-adunit-android.md b/prebid-mobile/pbm-api/android/pbm-adunit-android.md index 5bdddecf88..121b7e7761 100755 --- a/prebid-mobile/pbm-api/android/pbm-adunit-android.md +++ b/prebid-mobile/pbm-api/android/pbm-adunit-android.md @@ -37,7 +37,7 @@ The `AdUnit` object is an abstract object that cannot be instantiated. Use the [ PB Ad Slot is an identifier tied to the placement the ad will be delivered in. The use case for PB Ad Slot is to pass to exchange an ID they can use to tie to reporting systems or use for data science driven model building to match with impressions sourced from alternate integrations. A common ID to pass is the ad server slot name. -`adUnit.pbAdSlot = "/1111111/homepage/med-rect-2"` +`adUnit.ortb2Imp.ext.data.pbadslot = "/1111111/homepage/med-rect-2"` --- diff --git a/prebid-mobile/pbm-api/android/pbm-targeting-params-android.md b/prebid-mobile/pbm-api/android/pbm-targeting-params-android.md index f299f4ad67..01cce946bc 100755 --- a/prebid-mobile/pbm-api/android/pbm-targeting-params-android.md +++ b/prebid-mobile/pbm-api/android/pbm-targeting-params-android.md @@ -114,9 +114,9 @@ TargetingParams.setStoreUrl(storeUrl); ``` -### Open Measurment SDK (OMSDK) +### Open Measurement SDK (OMSDK) -OMSDK is designed to facilitate 3rd party viewability and verification measurement for ads served in mobile app enviroments. Prebid SDK will provide the signaling component to Bid Adapters, by way of Prebid Server, indicating the impression is elligible for OMSDK support. Prebid SDK does not currently integrate with OMSDK itself, instead it will rely on a publisher ad server to render viewability and verification measurement code. +OMSDK is designed to facilitate 3rd party viewability and verification measurement for ads served in mobile app enviroments. Prebid SDK will provide the signaling component to Bid Adapters, by way of Prebid Server, indicating the impression is eligible for OMSDK support. Prebid SDK does not currently integrate with OMSDK itself, instead it will rely on a publisher ad server to render viewability and verification measurement code. There three components to signaling support for OMSDK: * Partner Name @@ -369,6 +369,151 @@ TargetingParams.setSubjectToCOPPA(true); ``` +## User Identity + +Prebid SDK supports two interfaces to pass / maintain User IDs and ID vendor details: +* Real-time in Prebid SDK's API field setExternalUserIds +* Store User Id(s) in local storage + +Any identity vendor's details in local storage will be sent over to Prebid Server as is, unadulterated. If data is sent in the API and entered into local storage, the API detail will prevail. + +### Prebid SDK API Access + +Prebid SDK supports passing an array of UserID(s) at auction time in the field setExternalUserIds, that is globably scopped. It is sufficient enough to set the externalUserIdArray object once per user session, as these values would be used in all consecutive ad auctions in the same session. + + +```java +/** +* List containing objects that hold External UserId parameters for the current application user. * @param externalUserIds +*/ +public static void setExternalUserIds(ListexternalUserIds){ + PrebidMobile.externalUserIds = externalUserIds; +} +/** +* Returns the List that hold External UserId parameters for the current application user * @@return externalUserIds as Array. +*/ +public static List getExternalUserIds() { + return PrebidMobile.externalUserIds; +``` + + +*Exmaple*: + +Java +```java +// User Id from External Third Party Sources +ArrayList externalUserIdArray = new ArrayList<>(); +externalUserIdArray.add(new ExternalUserId("adserver.org", "111111111111", null, new HashMap() { + { + put ("rtiPartner", "TDID"); + } + +})); +externalUserIdArray.add(new ExternalUserId("netid.de", "999888777", null, null)); +externalUserIdArray.add(new ExternalUserId("criteo.com", "_fl7bV96WjZsbiUyQnJlQ3g4ckh5a1N", null, null)); +externalUserIdArray.add(new ExternalUserId("liveramp.com", "AjfowMv4ZHZQJFM8TpiUnYEyA81Vdgg", null, null)); +externalUserIdArray.add(new ExternalUserId("sharedid.org", "111111111111", 1, new HashMap() { + { + put("third", "01ERJWE5FS4RAZKG6SKQ3ZYSKV"); + } + +})); +//Set External User ID +PrebidMobile.setExternalUserIds(externalUserIdArray); +``` + + +### Local Storage + +Prebid SDK provides a local storage interface to set, retrieve or update an array of user IDs with associated identity vendor details. Prebid SDK will retrieve and pass User IDs and ID vendor details to PBS if values are present in local storage. The main difference between the Prebid API interface and the local storage interface is the persistence of storage of data. Local Storage data will persist across user sessions whereas the Prebid API interface (setExternalUserIds) persists only for the user session. If a vendor's details are passed both in local storage and the Prebid API at the same time, the Prebid API data (setExternalUserIds) will prevail. + +Prebid SDK Provides five functions to handle User ID details: +* storeExternalUserId +* fetchStoredExternalUserId +* fetchStoredExternalUserIds +* removeStoredExternalUserId +* removeStoredExternalUserIds + + +```java +/** +* Use this API for storing the externalUserId in the SharedPreference +* @param externalUserId the externalUserId instance to be stored in the SharedPreference +* */ +public static void storeExternalUserId(ExternalUserId externalUserId) { + if (externalUserId != null) { + StorageUtils.storeExternalUserId(externalUserId); + } + + else { + LogUtil.e("Targeting", "External User ID can't be set as null"); + } + +} + +/** +* Returns the stored (in the SharedPreference) ExternalUserId instance for a given source +* @param source +* */ +public static ExternalUserId fetchStoredExternalUserId(@NonNull String source) { + if (!TextUtils.isEmpty(source)) { + return StorageUtils.fetchStoredExternalUserId(source); + } + + return null; +} + +/** +* Returns the stored (in the SharedPreferences) External User Id list +* */ +public static List fetchStoredExternalUserIds() { + return StorageUtils.fetchStoredExternalUserIds(); +} + +/** +* Removes the stored (in the SharedPreference) ExternalUserId instance for a given source +* @param source +* */ +public static void removeStoredExternalUserId(@NonNull String source) { + if (!TextUtils.isEmpty(source)) { + StorageUtils.removeStoredExternalUserId(source); + } + +} + +/** +* Clear the Stored ExternalUserId list from the SharedPreference +* */ +public static void removeStoredExternalUserIds() { + StorageUtils.removeStoredExternalUserIds(); +} + +``` + +*Examples* + +```java +//Set External User ID +TargetingParams.storeExternalUserId(new ExternalUserId("sharedid.org", "111111111111", 1, new HashMap() { + { + put ("third", "01ERJWE5FS4RAZKG6SKQ3ZYSKV"); + } + +})); + +//Get External User ID +ExternalUserId externalUserId = TargetingParams.fetchStoredExternalUserId("sharedid.org"); + +//Get All External User IDs +List externalUserIdList = TargetingParams.fetchStoredExternalUserIds(); + +//Remove External UserID +TargetingParams.removeStoredExternalUserId("adserver.org"); + +//Remove All External UserID +TargetingParams.removeStoredExternalUserIds(); +``` + ## Further Reading - [Prebid Mobile API - Android]({{site.baseurl}}/prebid-mobile/pbm-api/android/pbm-api-android.html) diff --git a/prebid-mobile/pbm-api/ios/pbm-adunit-ios.md b/prebid-mobile/pbm-api/ios/pbm-adunit-ios.md index 91c656bb60..3c688d4fb5 100755 --- a/prebid-mobile/pbm-api/ios/pbm-adunit-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-adunit-ios.md @@ -42,7 +42,7 @@ Create a new Banner Ad Unit or Interstitial Ad Unit with a Prebid Server configu PB Ad Slot is an identifier tied to the placement the ad will be delivered in. The use case for PB Ad Slot is to pass to exchange an ID they can use to tie to reporting systems or use for data science driven model building to match with impressions sourced from alternate integrations. A common ID to pass is the ad server slot name. -`adUnit.pbAdSlot = "/1111111/homepage/med-rect-2"` +`adUnit.ortb2Imp.ext.data.pbadslot = "/1111111/homepage/med-rect-2"` --- @@ -259,7 +259,7 @@ func clearContextData() func loadDFPBanner(bannerUnit : AdUnit){ let bannerUnit = BannerAdUnit(configId: "6ace8c7d-88c0-4623-8117-75bc3f0a2e45", size: CGSize(width: 300, height: 250)) - bannerUnit.pbAdSlot = "/1111111/homepage/med-rect-2"` + bannerUnit.ortb2Imp.ext.data.pbadslot = "/1111111/homepage/med-rect-2"` let dfpBanner = DFPBannerView(adSize: kGADAdSizeMediumRectangle) dfpBanner.adUnitID = "/19968336/PriceCheck_300x250" diff --git a/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md b/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md index 334587b370..a118da3145 100644 --- a/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md @@ -151,9 +151,9 @@ Targeting.shared.itunesID Targeting.shared.itunesID = itunesID ``` -### Open Measurment SDK (OMSDK) +### Open Measurement SDK (OMSDK) -OMSDK is designed to facilitate 3rd party viewability and verification measurement for ads served in mobile app enviroments. Prebid SDK will provide the signaling component to Bid Adapters, by way of Prebid Server, indicating the impression is elligible for OMSDK support. Prebid SDK does not currently integrate with OMSDK itself, instead it will rely on a publisher ad server to render viewability and verification measurement code. +OMSDK is designed to facilitate 3rd party viewability and verification measurement for ads served in mobile app enviroments. Prebid SDK will provide the signaling component to Bid Adapters, by way of Prebid Server, indicating the impression is eligible for OMSDK support. Prebid SDK does not currently integrate with OMSDK itself, instead it will rely on a publisher ad server to render viewability and verification measurement code. There three components to signaling support for OMSDK: * Partner Name @@ -493,6 +493,149 @@ Objective C Targeting.shared.subjectToCOPPA = true; ``` +## User Identity + +Prebid SDK supports two interfaces to pass / maintain User IDs and ID vendor details: +* Real-time in Prebid SDK's API field externalUserIdArray +* Store User Id(s) in local storage + +Any identity vendor's details in local storage will be sent over to Prebid Server as is, unadulterated. If data is sent in the API and entered into local storage, the API detail will prevail. + +### Prebid SDK API Access + +Prebid SDK supports passing an array of UserID(s) at auction time in the field externalUserIdArray, that is globably scopped. It is sufficient enough to set the externalUserIdArray object once per user session, as these values would be used in all consecutive ad auctions in the same session. + + +```swift +public var externalUserIdArray = [ExternalUserId]() +``` + + +**Exmaples** + +SWIFT +```swift +// User Id from External Third Party Sources +var externalUserIdArray = [ExternalUserId]() +externalUserIdArray.append(ExternalUserId(source: "adserver.org", identifier: "111111111111", ext: ["rtiPartner" : "TDID"])) +externalUserIdArray.append(ExternalUserId(source: "netid.de", identifier: "999888777")) +externalUserIdArray.append(ExternalUserId(source: "criteo.com", identifier: "_fl7bV96WjZsbiUyQnJlQ3g4ckh5a1N")) +externalUserIdArray.append(ExternalUserId(source: "liveramp.com", identifier: "AjfowMv4ZHZQJFM8TpiUnYEyA81Vdgg")) +externalUserIdArray.append(ExternalUserId(source: "sharedid.org", identifier: "111111111111", atype: 1, ext: ["third" : "01ERJWE5FS4RAZKG6SKQ3ZYSKV"])) +Prebid.shared.externalUserIdArray = externalUserIdArray +``` + + +Objective-C +```objective_c +// User Id from External Third Party Sources +NSMutableArray *externalUserIdArray = [[NSMutableArray alloc] init]; +[externalUserIdArray addObject:[[ExternalUserId alloc]initWithSource:@"adserver.org" identifier:@"111111111111" atype:nil ext:@{@"rtiPartner" : @"TDID"}]]; +[externalUserIdArray addObject:[[ExternalUserId alloc]initWithSource:@"netid.de" identifier:@"999888777" atype: nil ext:nil]]; +[externalUserIdArray addObject:[[ExternalUserId alloc]initWithSource:@"criteo.com" identifier:@" _fl7bV96WjZsbiUyQnJlQ3g4ckh5a1N" atype:nil ext:nil]]; +[externalUserIdArray addObject:[[ExternalUserId alloc]initWithSource:@"liveramp.com" identifier:@" AjfowMv4ZHZQJFM8TpiUnYEyA81Vdgg" atype:nil ext:nil]]; +[externalUserIdArray addObject:[[ExternalUserId alloc]initWithSource:@"sharedid.org" identifier:@"111111111111" atype:[NSNumber numberWithInt:1] ext:@{@"third" : @"01ERJWE5FS4RAZKG6SKQ3ZYSKV"}]]; +Prebid.shared.externalUserIdArray = externalUserIdArray; +``` + +### Local Storage + +Prebid SDK provides a local storage interface to set, retrieve or update an array of user IDs with associated identity vendor details. Prebid SDK will retrieve and pass User IDs and ID vendor details to PBS if values are present in local storage. The main difference between the Prebid API interface and the local storage interface is the persistence of storage of data. Local Storage data will persist across user sessions whereas the Prebid API interface (externalUserIdArray) persists only for the user session. If a vendor's details are passed both in local storage and the Prebid API at the same time, the Prebid API data (externalUserIdArray) will prevail. + +Prebid SDK Provides five functions to handle User ID details: +* storeExternalUserId +* fetchStoredExternalUserIds +* fetchStoredExternalUserId +* removeStoredExternalUserId +* removeStoredExternalUserIds + + +```swift +/** +* This method allows to save External User Id in the User Defaults +*/ +public func storeExternalUserId(_ externalUserId: ExternalUserId) { + if let index = externalUserIds.firstIndex(where: { + $0.source == externalUserId.source + }) + + { + externalUserIds[index] = externalUserId + } + + else{ + externalUserIds.append(externalUserId) + } + + StorageUtils.setExternalUserIds(value: externalUserIds) +} +/** +* This method allows to get All External User Ids from User Defaults +*/ +public func fetchStoredExternalUserIds()->[ExternalUserId]? { + return StorageUtils.getExternalUserIds() +} +/** +* This method allows to get External User Id from User Defaults by passing respective 'source' string as +param */ +public func fetchStoredExternalUserId(_ source : String)->ExternalUserId? { + guard let array = StorageUtils.getExternalUserIds(), let externalUserId = array.first(where: { + $0.source + == source + }) + + else{ + return nil + } + + return externalUserId +} +/** +* This method allows to remove specific External User Id from User Defaults by passing respective 'source' +string as param +*/ +public func removeStoredExternalUserId(_ source : String) { + if let index = externalUserIds.firstIndex(where: { + $0.source == source + }) + + { + externalUserIds.remove(at: index) + StorageUtils.setExternalUserIds(value: externalUserIds) + } + +} +/** +* This method allows to remove all the External User Ids from User Defaults +*/ +public func removeStoredExternalUserIds() { + if var arrayExternalUserIds = StorageUtils.getExternalUserIds(){ + arrayExternalUserIds.removeAll() StorageUtils.setExternalUserIds(value: arrayExternalUserIds) + } + +} +``` + +**Examples** + +```swift +//Set External User ID +Targeting.shared.storeExternalUserId(ExternalUserId(source: "sharedid.org", identifier: "111111111111", atype: 1, ext: ["third" : "01ERJWE5FS4RAZKG6SKQ3ZYSKV"])) + +//Get External User ID +let externalUserIdSharedId = Targeting.shared.fetchStoredExternalUserId("sharedid.org") + +//Get All External User IDs +let externalUserIdsArray = Targeting.shared.fetchStoredExternalUserIds() + +//Remove External UserID +Targeting.shared.removeStoredExternalUserId("sharedid.org") + +//Remove All External UserID +Targeting.shared.removeStoredExternalUserIds() +``` + + ## Further Reading - [Prebid Mobile API - iOS](/prebid-mobile/pbm-api/ios/pbm-api-ios.html) diff --git a/prebid-mobile/pbm-api/ios/pbm-video-rewarded-adunit-ios.md b/prebid-mobile/pbm-api/ios/pbm-video-rewarded-adunit-ios.md index d1be426cc1..2befade496 100755 --- a/prebid-mobile/pbm-api/ios/pbm-video-rewarded-adunit-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-video-rewarded-adunit-ios.md @@ -21,7 +21,7 @@ Create a new Video Rewarded Ad Unit associated with a Prebid Server configuratio -# Paramaters +# Parameters Parameters is a sub class of RewardedVideoAdUnit.Create new Parameters class to define the parameters of the video ad unit. Parameters contain the OpenRTB video attributes. diff --git a/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md b/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md index 385bac77d3..7d54ba038a 100755 --- a/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md @@ -20,7 +20,7 @@ Video Insterstital is only supported with Google Ad Manager. `configId(String)`: Prebid Server configuration ID. -# Paramaters +# Parameters Parameters is a sub class of VideoInterstitialAdUnit.Create new Parameters class to define the parameters of the video ad unit. Parameters contain the OpenRTB video attributes. diff --git a/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md b/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md index f5379e6be3..93c063b712 100755 --- a/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md @@ -61,7 +61,7 @@ OpenRTB Placement Type represented as an enumeration of values: * inFeed is transformed into OpenRTB value 4 to bid adapters -### Paramaters +### Parameters Parameters is a sub class of videoAdUnit. Create new Parameters class to define the parameters of the video ad unit. Parameters contain the OpenRTB video attributes. diff --git a/prebid-mobile/privacy-regulation.md b/prebid-mobile/privacy-regulation.md index c98333cf3c..cf672cf34a 100644 --- a/prebid-mobile/privacy-regulation.md +++ b/prebid-mobile/privacy-regulation.md @@ -146,7 +146,7 @@ To ensure proper monetization and relevant targeting, the SDK should be enabled {% capture ccpaNote %} In order for publishers to meet their notice and opt out obligations under the CCPA, -Prebid Mobile supports the IAB US Privacy signal as defined in the in-app section of the [IAB US Privacy signal for CCPA](https://iabtechlab.com/wp-content/uploads/2019/11/US-Privacy-USER-SIGNAL-API-SPEC-v1.0.pdf). +Prebid Mobile supports the IAB US Privacy signal as defined in the in-app section of the [IAB US Privacy signal for CCPA](https://iabtechlab.com/standards/ccpa/). This is a reference for mobile app publishers using Prebid Mobile to surface notice, transparency and choice to end users located in California, United States, passing notice and opt out signals where necessary, to demand sources and their vendors. @@ -156,9 +156,9 @@ Prebid Mobile supports the IAB US Privacy signal as defined in the in-app sectio ### Notice and Opt out signal -Prebid mobile supports the [IAB US Privacy signal](https://iabtechlab.com/wp-content/uploads/2019/11/US-Privacy-USER-SIGNAL-API-SPEC-v1.0.pdf) implementation for CCPA. Publishers will be required perform the following actions: +Prebid mobile supports the [IAB US Privacy signal](https://iabtechlab.com/standards/ccpa/) implementation for CCPA. Publishers will be required perform the following actions: - Collect notice and opt out signals from eligible CCPA users -- Translate notice and opt-out signals into [IAB US Privacy String format](https://iabtechlab.com/wp-content/uploads/2019/11/U.S.-Privacy-String-v1.0-IAB-Tech-Lab.pdf) +- Translate notice and opt-out signals into [IAB US Privacy String format](https://iabtechlab.com/standards/ccpa/) - Store IAB US Privacy signal in NSUserDefaults for iOS or SharedPreferences for Android for persistent storage allowing access for vendors per IAB recommendations The job of the Prebid SDK will: diff --git a/prebid-server/developers/add-new-bidder-go.md b/prebid-server/developers/add-new-bidder-go.md index 76b49ecae8..83e4e47a06 100644 --- a/prebid-server/developers/add-new-bidder-go.md +++ b/prebid-server/developers/add-new-bidder-go.md @@ -13,7 +13,7 @@ Thank you for contributing a bid adapter to the open source Prebid Server projec This document guides you through the process of developing a new bid adapter for your bidding server. We encourage you to look at [existing bid adapters](https://github.com/prebid/prebid-server/tree/master/adapters) for working examples and practical guidance. You can also ask us questions by [submitting a GitHub issue](https://github.com/prebid/prebid-server/issues/new). {: .alert.alert-info :} -**NOTE:** There are two implementations of Prebid Server, [PBS-Go](https://github.com/prebid/prebid-server) and [PBS-Java](https://github.com/prebid/prebid-server-java). We recommend you build new adapters for PBS-Go and allow us to port it to PBS-Java within a couple of months. If you'd like to build both yourself, please also follow these [instructions for building an adapter in PBS-Java](/prebid-server/developers/add-new-bidder-java.html). +There are two implementations of Prebid Server, [PBS-Go](https://github.com/prebid/prebid-server) and [PBS-Java](https://github.com/prebid/prebid-server-java). We recommend you build new adapters for PBS-Go and allow us to port it to PBS-Java within a couple of months. If you'd like to build both yourself, please also follow these [instructions for building an adapter in PBS-Java](/prebid-server/developers/add-new-bidder-java.html). * TOC @@ -29,9 +29,9 @@ An OpenRTB 2.5 Bid Request contains one or more Impressions, each representing a ### Choose A Name -You will need to choose a unique name for your bid adapter. Names should be written in lower case and may not contain special characters or emoji. If you already have a Prebid.js bid adapter, we encourage you to use the same name with the same bidder parameters. You may not name your adapter `all`, `context`, `general`, `prebid`, or `skadn` as those have special meaning in various contexts. Existing bid adapter names are [maintained here](https://github.com/prebid/prebid-server/blob/master/openrtb_ext/bidders.go#L37). +You will need to choose a unique name for your bid adapter. Names should be written in lower case and may not contain special characters or emoji. If you already have a Prebid.js bid adapter, we encourage you to use the same name with the same bidder parameters. You may not name your adapter `all`, `context`, `data`, `general`, `prebid`, or `skadn` as those have special meaning in various contexts. Existing bid adapter names are [maintained here](https://github.com/prebid/prebid-server/blob/master/openrtb_ext/bidders.go#L37). -We ask that the first 6 letters of the name you choose be unique among the existing bid adapters. This consideration helps with generating targeting keys for use by some ad exchanges, such as Google Ad Manager. There's no need to manually check, as this constraint is enforced by the [`TestBidderUniquenessGatekeeping`](https://github.com/prebid/prebid-server/blob/master/openrtb_ext/bidders_test.go#L61) test. +We ask that the first 6 letters of the name you choose be unique among the existing bid adapters. This consideration helps with generating targeting keys for use by some ad exchanges, such as Google Ad Manager. There's no need to manually check, as this constraint is enforced by the [`TestBidderUniquenessGatekeeping`](https://github.com/prebid/prebid-server/blob/master/openrtb_ext/bidders_validate_test.go#L45) test. Throughout the rest of this document, substitute `{bidder}` with the name you've chosen. @@ -48,9 +48,9 @@ We are proud to run the Prebid Server project as a transparent and trustworthy h - Adapters must annotate the bid response with the proper media type, ideally based on the response from the bidding server. {: .alert.alert-warning :} -Failure to follow the rules will lead to delays in approving your adapter for inclusion in Prebid Server. If you'd like to discuss an exception to a rule, please make your request by [submitting a GitHub issue](https://github.com/prebid/prebid-server/issues/new). +Failure to follow the rules will lead to delays in approving your adapter. If you'd like to discuss an exception to a rule, please make your request by [submitting a GitHub issue](https://github.com/prebid/prebid-server/issues/new). -### Ongoing Support and Maintenance +### Support and Maintenance You are expected to provide support and maintenance for the code you contribute to Prebid Server as part of your bid adapter. We ask that you proactively update your adapter when your bidding server introduces new features or breaking changes. @@ -60,18 +60,18 @@ Please be attentive in reading and responding to emails and [GitHub issues](http ## Create Your Adapter -Prebid Server bid adapters consist of several components: bidder info, bidder parameters, adapter code, user sync code, registration with the core framework, and default configuration values. This chapter will guide you though each component. +Prebid Server bid adapters consist of several components: bidder info, bidder parameters, adapter code, registration with the core framework, and default configuration values. This document will guide you though each component. -Please refer to [existing bid adapters](https://github.com/prebid/prebid-server/tree/master/adapters) for working examples and practical guidance, but understand that our adapter interfaces and coding style evolve over time. Please prefer the examples in this document over differences you may find in code. +Please refer to [existing bid adapters](https://github.com/prebid/prebid-server/tree/master/adapters) for working examples and practical guidance, but understand that our adapter interfaces and coding style evolve over time. The examples in this document have precedence over differences you may find in an existing bid adapter. Our project is written in the [Go programming language](https://golang.org/). We understand not everyone has prior experience writing Go code. Please try your best and we'll respectfully steer you in the right direction during the review process. {: .alert.alert-info :} -Please do not ignore errors from method calls made in your bid adapter code. Even if it's seemingly impossible for an error to occur, such as from `json.Marshal`, it's still possible under the high throughput multi-threaded nature of Prebid Server. +**Please do not ignore errors from method calls made in your bid adapter code.** Even if it's seemingly impossible for an error to occur, such as from `json.Marshal`, it's still possible under the high throughput multi-threaded nature of Prebid Server. ### Bidder Info -Let's begin with your adapter's bidder information YAML file. This file is required and contains your maintainer email address, your [GDPR Global Vendor List (GVL) id](https://iabeurope.eu/vendor-list-tcf-v2-0/), specifies the ad formats your adapter will accept, and allows you to opt-out of video impression tracking. +Let's begin with your adapter's bidder information YAML file. This file is required and contains your bid adapter's maintainer email address, [GDPR Global Vendor List (GVL) ID](https://iabeurope.eu/vendor-list-tcf-v2-0/), supported ad formats, user sync endpoints, and allows you to opt-out of video impression tracking. Create a file with the path `static/bidder-info/{bidder}.yaml` and begin with the following template: @@ -93,6 +93,10 @@ capabilities: - video - audio - native +userSync: + redirect: + url: https://foo.com/sync?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: $UID ``` Modify this template for your bid adapter: @@ -100,6 +104,7 @@ Modify this template for your bid adapter: - Change the `gvlVendorID` from the sample value of `42` to the id of your bidding server as registered with the [GDPR Global Vendor List (GVL)](https://iabeurope.eu/vendor-list-tcf-v2-0/), or remove this line entirely if your bidding server is not registered with IAB Europe. - Change the `modifyingVastXmlAllowed` value to `false` if you'd like to opt-out of [video impression tracking](https://github.com/prebid/prebid-server/issues/1015), or remove this line entirely if your adapter doesn't support VAST video ads. - Remove the `capabilities` (app/site) and `mediaTypes` (banner/video/audio/native) combinations which your adapter does not support. +- Follow the [User Sync Configuration](#user-sync-configuration) documentation below to configure the endpoints for your bid adapter, or remove the `userSync` section if not supported. @@ -125,6 +134,10 @@ capabilities: site: mediaTypes: - banner +userSync: + redirect: + url: https://foo.com/sync?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: $UID ``` @@ -145,22 +158,72 @@ capabilities: mediaTypes: - banner - video +userSync: + redirect: + url: https://foo.com/sync?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: $UID ``` +#### User Sync Configuration + +Prebid Server offers a federated [user sync](https://docs.prebid.org/prebid-server/developers/pbs-cookie-sync.html) process to store user ids from multiple bidders in a single cookie under the host's domain. You may add support for your bid adapter by configuring iframe and/or redirect endpoints. + +The Bidder Info template above demonstrates configuration of a `redirect` user sync. The `url` points to an endpoint on your bidding server which will honor the privacy policies, replace the `userMacro` in the redirect url with the user's tracking id, and respond with an HTTP 302 redirect to that url. You may also specify an `iframe` endpoint which will return an HTML document to be rendered in an `iframe` on the user's device and use JavaScript to perform the redirect. You may omit the `{%raw%}{{.GDPR}}{%endraw%}`, `{%raw%}{{.GDPRConsent}}{%endraw%}`, and/or `{%raw%}{{.USPrivacy}}{%endraw%}` macros if they are not applicable to your legal situation. + +If both `iframe` and `redirect` endpoints are provided, you must specify a `default` field with a value of either `iframe` or `redirect`, based on your preference. + +```yaml +userSync: + default: iframe + iframe: + url: https://foo.com/iframe/sync?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: $UID + redirect: + url: https://foo.com/redirect/sync?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: $UID +``` + +If your bid adapter supports user sync and doesn't have a good default, you may optionally specify a `supports` array with the items `iframe` and/or `redirect` to inform Prebid Server hosts. Hosts will receive a warning on startup if a bid adapter supports user sync and isn't configured. Expect hosts to contact you at the maintainer email address in this file for instructions. + +```yaml +userSync: + # foo supports user syncing, but requires configuration by the host. contact this + # bidder directly at the email address in this file to ask about enabling user sync. + supports: + - iframe + - redirect +``` + +Each user sync is assigned a case-sensitive `key`, defaulting to your bidder name. You may use a different `key` value, but we discourage doing so except for when multiple bidders share the same bidding server. You might encounter this use case for built-in aliases or for multiple bidders implementing different protocols for the same bidding server. Only one bid adapter may specify endpoints when using a shared key, or Prebid Server will fail to startup due to the ambiguity. + +```yaml +foo.yaml +-------- +userSync: + redirect: + url: https://foo.com/sync?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: $UID + +bar.yaml +-------- +userSync: + key: foo +``` + ### Bidder Parameters -Your bid adapter might require extra information from the publisher to form a request to your bidding server. The bidder parameters JSON Schema codifies this information to allow Prebid Server to verify requests and to provide an API for third party configuration systems. +Your bid adapter might require extra information from the publisher to form a request to your bidding server. The bidder parameters JSON Schema codifies this information to allow Prebid Server to verify requests and to provide an API for configuration systems. Publishers will provide extra information using an OpenRTB 2.5 Bid Request Extension, preferably at `request.imp[].ext.prebid.bidder.{bidder}` but also supported at `request.imp[].ext.{bidder}`. Prebid Server will validate the publisher information based on your schema and relocate the data to `request.imp[].ext.bidder`, regardless of your bidder name or the publisher's chosen location. -We request that you do not duplicate information that is already present in the [OpenRTB 2.5 Bid Request specification](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf#page=13) or is already part of an established Prebid convention. For example, your bidder parameters should not include first party data, bid floors, schain, video parameters, referrer information, or privacy consent including COPPA, CCPA, and GDPR TCF. For video parameters in particular, you must prefer the OpenRTB 2.5 Bid Request standard of `request.imp[].video`. +We request you do not duplicate information already present in the [OpenRTB 2.5 Bid Request specification](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf#page=13) or already part of an established Prebid convention. For example, your bidder parameters should not include first party data, bid floors, schain, video parameters, referrer information, or privacy consent including COPPA, CCPA, and GDPR TCF. For video parameters in particular, you must prefer the OpenRTB 2.5 Bid Request standard of `request.imp[].video`. {: .alert.alert-warning :} -**ENDPOINT NOTE:** You may not use an endpoint domain as a bidder parameter. Prebid Server is not an open proxy. If absolutely necessary, you may specify a portion of the domain as a parameter to support geo regions or account specific servers. However, this is discouraged and may degrade the performance of your adapter since the server needs to maintain more outgoing connections. Host companies may choose to disable your adapter if it uses a dynamically configured domain. +You may not use an endpoint domain as a bidder parameter. Prebid Server is not an open proxy. If absolutely necessary, you may specify a portion of the domain as a parameter to support geo regions or account specific servers. However, this is discouraged and may degrade the performance of your adapter since the server needs to maintain more outgoing connections. Host companies may choose to disable your adapter if it uses a dynamically configured domain. -Create a file with the path `static/bidder-params/{bidder}.json` using [JSON Schema](https://spacetelescope.github.io/understanding-json-schema/) to define your bidder parameters. Prebid Server requires this file for every adapter, even if yours doesn't require bidder parameters (see the 'no parameters' example at the end of this section). +Create a file with the path `static/bidder-params/{bidder}.json` and use [JSON Schema](https://spacetelescope.github.io/understanding-json-schema/) to define your bidder parameters. Prebid Server requires this file for every adapter, even if yours doesn't require bidder parameters (see the 'no parameters' example at the end of this section). Let's start with this example which defines one required `placementId` string parameter: @@ -183,7 +246,9 @@ Let's start with this example which defines one required `placementId` string pa ``` We encourage you to utilize the full features of [JSON Schema](https://spacetelescope.github.io/understanding-json-schema/) to narrowly define your bidder parameter data types. If you copy and paste these examples, please remember to change the `title` and `description` to refer to your bidder name instead of our fictional Foo example. -When choosing your parameter names, please consider aligning with the OpenRTB 2.5 standard by using lower case letters without camel casing or special characters. +When choosing your parameter names, please consider aligning with the OpenRTB 2.5 standard by using lower case letters without camel casing or special characters. + +Properties in [JSON Schema](https://spacetelescope.github.io/understanding-json-schema/) are case sensitive. If you choose to specify multiple properties differing only by case for compatibility, we ask that you include the word 'preferred' in one of the descriptions to give a hint to third party configuration systems. In addition to the examples listed below, please refer to [existing bidder parameter files](https://github.com/prebid/prebid-server/tree/master/static/bidder-params) for guidance. @@ -234,7 +299,7 @@ In addition to the examples listed below, please refer to [existing bidder param "title": "Foo Adapter Params", "description": "A schema which validates params accepted by the Foo adapter", "type": "object", - + "properties": { "token": { "type": "string", @@ -280,18 +345,47 @@ In addition to the examples listed below, please refer to [existing bidder param } ``` + +Example: Website with banner ads only.
@@ -112,6 +117,10 @@ capabilities: site: mediaTypes: - banner +userSync: + redirect: + url: https://foo.com/sync?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: $UID ```+### Bidder Parameters Code {: .alert.alert-info :} -You can skip this step if your adapter has no bidder parameters. +You can skip this section if your adapter has no bidder parameters. -If you've defined bidder parameters for your adapter, you also need to represent your bidder parameters in code. The core framework uses the JSON Schema file for validation, but your adapter code needs a data structure to support JSON unmarshalling / deserialization. These data structures are organized in a shared path using a standard naming convention, which also serves as documentation of all adapter parameters. +If you defined bidder parameters for your adapter, you also need to represent your bidder parameters in code. The core framework uses the JSON Schema file for validation, but your adapter code needs a data structure to support JSON unmarshalling / deserialization. These data structures are organized in a shared path using a standard naming convention, which also serves as documentation of all adapter parameters. Create a file with the path `openrtb_ext/imp_{bidder}.go` containing an exported (must start with an upper case letter) data structure named `ImpExt{Bidder}`. All required and optional bidder parameters from the JSON Schema should be represented as fields. -For example, this is what the bidder parameter code looks like for the example we used in the previous section: +For example, this is what the bidder parameter code looks like for the Foo example we used in the previous section: ```go package openrtb_ext @@ -301,7 +395,7 @@ type ImpExtFoo struct { } ``` -Please follow [Go's standard naming convention](https://golang.org/doc/effective_go.html) for the field names (particularly for acronyms) and use `` `json:...` `` attributes to specify the JSON name, matching exactly what you defined in the bidder parameters JSON Schema. Please keep in mind that JSON is case sensitive. +Please follow [Go's standard naming convention](https://golang.org/doc/effective_go.html) for the field names (particularly for acronyms) and use `` `json:...` `` attributes to specify the JSON name, matching exactly what you defined in the bidder parameters JSON Schema. ### Adapter Code @@ -326,7 +420,7 @@ import ( "fmt" "net/http" - "github.com/mxmCherry/openrtb" + "github.com/mxmCherry/openrtb/v15/openrtb2" "github.com/prebid/prebid-server/adapters" "github.com/prebid/prebid-server/config" "github.com/prebid/prebid-server/errortypes" @@ -345,7 +439,7 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters return bidder, nil } -func (a *adapter) MakeRequests(request *openrtb.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { requestJSON, err := json.Marshal(request) if err != nil { return nil, []error{err} @@ -356,15 +450,15 @@ func (a *adapter) MakeRequests(request *openrtb.BidRequest, requestInfo *adapter Uri: a.endpoint, Body: requestJSON, } - + return []*adapters.RequestData{requestData}, nil } -func (a *adapter) MakeBids(request *openrtb.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { if responseData.StatusCode == http.StatusNoContent { return nil, nil } - + if responseData.StatusCode == http.StatusBadRequest { err := &errortypes.BadInput{ Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", @@ -379,18 +473,17 @@ func (a *adapter) MakeBids(request *openrtb.BidRequest, requestData *adapters.Re return nil, []error{err} } - var response openrtb.BidResponse + var response openrtb2.BidResponse if err := json.Unmarshal(responseData.Body, &response); err != nil { return nil, []error{err} } - + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) bidResponse.Currency = response.Cur for _, seatBid := range response.SeatBid { - for _, bid := range seatBid.Bid { - bid := bid // pin https://github.com/kyoh86/scopelint#whats-this + for i, bid := range seatBid.Bid { b := &adapters.TypedBid{ - Bid: &bid, + Bid: &seatBid.Bid[i], BidType: getMediaTypeForBid(bid), } bidResponse.Bids = append(bidResponse.Bids, b) @@ -409,16 +502,16 @@ The first argument, `bidderName`, is the name of the bidder being built. This ma The second argument, `config`, is all the configuration values set for your adapter. However, not all of this information is intended for use by the `Builder` method. The only two fields relevant here are `config.Endpoint` and `config.ExtraAdapterInfo`: - `config.Endpoint` is the base url of your bidding server and may be interpreted as either a literal address or as a templated macro to support dynamic domains or dynamic paths. -- `config.ExtraAdapterInfo` may be used for any other values your adapter may need, such as an application token or publisher allow/deny list. You may interpret this string however you like, although JSON is a common choice. +- `config.ExtraAdapterInfo` is an optional setting may be used for any other values your adapter may need, such as an application token or publisher allow/deny list. You may interpret this string however you like, although JSON is a common choice. -The `Builder` method is expected to return an error if either the `config.Endpoint` or the `config.ExtraAdapterInfo` values are invalid or cannot be parsed. Errors will be surfaced to the host during application startup as a fatal error. +The `Builder` method is expected to return an error if either the `config.Endpoint` or the `config.ExtraAdapterInfo` values are invalid or cannot be parsed. Errors will be surfaced to the host during application startup as a fatal error.Example: Multiple properties differing only by case.
+ +```json +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Foo Adapter Params", + "description": "A schema which validates params accepted by the Foo adapter", + "type": "object", + + "properties": { + "partnerid": { + "type": "string", + "description": "Partner ID, preferred." + }, + "partnerID": { + "secret": "string", + "description": "Partner ID" + } + }, + + "oneOf": [ + { "required": ["partnerid"] }, + { "required": ["partnerID"] } + ] +} +``` +Example: Builder using endpoint macros.
```go type adapter struct { - endpointTemplate template.Template + endpointTemplate *template.Template } // Builder builds a new instance of the Foo adapter for the given bidder with the given config. @@ -427,9 +520,9 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters if err != nil { return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } - + bidder := &adapter{ - endpointTemplate: *template, + endpointTemplate: template, } return bidder, nil } @@ -450,7 +543,7 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters if err != nil { return nil, err } - + bidder := &adapter{ endpoint: config.Endpoint, token: info.token, @@ -484,9 +577,9 @@ func buildDefaultExtraInfo() extraInfo { The `MakeRequests` method is responsible for returning none, one, or many HTTP requests to be sent to your bidding server. Bid adapters are forbidden from directly initiating any form of network communication and must entirely rely upon the core framework. This allows the core framework to optimize outgoing connections using a managed pool and record networking metrics. The return type `adapters.RequestData` allows your adapter to specify the HTTP method, url, body, and headers. -This method is called once by the core framework for bid requests which have at least one valid Impression for your adapter. Impressions not configured for your adapter will be removed and are not accessible. +This method is called once by the core framework for bid requests which have at least one valid Impression for your adapter. Impressions not configured for your adapter are not accessible. -The first argument, `request`, is the OpenRTB 2.5 Bid Request object. Extension information is stored as `json.RawMessage` byte arrays and must be unmarshalled and/or marshalled to be read and/or mutated. It is *critical* to understand that the `request` object contains pointers to shared memory. If your adapter needs to alter any data referenced by a pointer then you *must* first make a shallow copy. The only exception is for `request.Imp` and its elements, as these are already shallow copies. The exact same instance of the `request` object is also passed to the `MakeBids` method, so please be careful when mutating. It's safe to assume that `request.Imp[]` always contains at least one element and that the `request.Imp[].ext.bidder` was successfully validated by your bidder parameter JSON Schema. +The first argument, `request`, is the OpenRTB 2.5 Bid Request object. Extension information is stored as `json.RawMessage` byte arrays and must be unmarshalled and/or marshalled to be read and/or mutated. It is *critical* to understand that the `request` object contains pointers to shared memory. If your adapter needs to alter any data referenced by a pointer then you *must* first make a shallow copy. The only exception is for `request.Imp` and its elements, as these are already shallow copies. The exact same instance of the `request` object is also passed to the `MakeBids` method, so please be careful when mutating. It's safe to assume that `request.Imp[]` always contains at least one element and that the `request.Imp[].ext.bidder` was successfully validated per your bidder parameter JSON Schema.-The second argument, `requestInfo`, is for extra information and helper methods provided by the core framework. For now, this just includes `requestInfo.PbsEntryPoint` which is commonly used to determine if the request is for AMP or Long Form Video Ad Pods. This object will be expanded in the future to also include currency conversion and extension unmarshalling helper methods. +The second argument, `requestInfo`, is for extra information and helper methods provided by the core framework. This includes: + +- `requestInfo.PbsEntryPoint` to access the entry point of the bid request, commonly used to determine if the request is for AMP or for a [Long Form Video Ad Pod](/dev-docs/modules/adpod.html). +- `requestInfo.GlobalPrivacyControlHeader` to read the value of the `Sec-GPC` Global Privacy Control (GPC) header of the bid request. +- `requestInfo.ConvertCurrency` a method to perform currency conversions. -The `MakeRequests` method is expected to return a slice (similar to a C# `List` or a Java `ArrayList`) of `adapters.RequestData` objects representing the HTTP calls to be sent to your bidding server and a slice of type `error` for any issues encountered creating them. If there are no HTTP calls or if there are no errors, please return `nil` for both return values. Neither slices may contain `nil` elements. + +The `MakeRequests` method is expected to return a slice (similar to a C# `List` or a Java `ArrayList`) of `adapters.RequestData` objects representing the HTTP calls to be sent to your bidding server and a slice of type `error` for any issues encountered creating them. If there are no HTTP calls or if there are no errors, please return `nil` for both return values. Please do not add `nil` items in the slices. {: .alert.alert-info :} HTTP calls to your bidding server will automatically prefer GZIP compression. You should not specify it yourself using headers. You don't have to worry about decompressing the response in `MakeBids` either, as that will be taken care of automatically. -An Impression may define multiple sizes and/or multiple ad formats. If your bidding server limits requests to a single ad placement, size, or format, then your adapter will need to split the Impression into multiple calls and merge the responses. +##### Impression Splitting -Example: Mutating banner shared memory (make a copy).
@@ -504,33 +597,37 @@ if request.Imp[i].W == nil && request.Imp[i].H == nil && len(request.Imp[i].Form--### Create A User Syncer (Optional) - -Prebid Server offers a federated [user sync solution](https://docs.prebid.org/prebid-server/developers/pbs-cookie-sync.html) to store user ids in a single cookie under the host's domain. You may add support with a relatively small amount of code if your bidding server supports this protocol. - -Create a file with the path `adatpers/{bidder}/usersync.go` using the following template: - -```go -package {bidder} - -import ( - "text/template" - - "github.com/prebid/prebid-server/adapters" - "github.com/prebid/prebid-server/usersync" -) - -func NewSyncer(template *template.Template) usersync.Usersyncer { - return adapters.NewSyncer("{bidder}", template, adapters.SyncTypeRedirect) -} -``` - -The heavy lifting is handled by the `adapters.NewSyncer` method. You just need to provide a few arguments: - -{: .table .table-bordered .table-striped } -| Argument | Description -| - | - -| `familyName` | Name used for storing your user sync id within the federated cookie. Please keep this the same as your bidder name. -| `urlTemplate` | Pass through the `template` argument. -| `syncType` | Type of user sync supported by your bidding server. The valid options are `SyncTypeRedirect` and `SyncTypeIframe`. - ### Register With The Core -Prebid Server does not use reflection or any other automagic technology to recognize your new bid adapter. You must manually register it with the core framework. +Prebid Server does not use reflection or any other automated technology to recognize your new bid adapter. You must manually register it with the core framework. {: .alert.alert-info :} You will need to add an `import` statement for your bid adapter package in these files. Modern code editors such as Visual Studio Code and JetBrain's GoLand will automatically do that for you. @@ -743,7 +854,7 @@ const ( func CoreBidderNames() []BidderName { return []BidderName{ ... - Bidder{Bidder}, + Bidder{Bidder}, ... } } @@ -761,20 +872,9 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { } ``` -If you have a user syncer, edit the file `usersync/usersyncers/syncer.go` to include it in the syncer map. - -```go -func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync.Usersyncer { - syncers := make(map[openrtb_ext.BidderName]usersync.Usersyncer, len(cfg.Adapters)) - ... - insertIntoMap(cfg, syncers, openrtb_ext.Bidder{Bidder}, {bidder}.NewSyncer) - ... -} -``` - ### Set Adapter Defaults -Lastly, you need to provide default settings for your bid adapter. You can decide if you'd like your bid adapter to be enabled out of the box, and if so, you'll need to provide a default endpoint and default extra adapter info if applicable. If your bid adapter requires host specific information to function properly, such as a security token or host account, then it's best to leave the adapter disabled. +You need to provide default settings for your bid adapter. You can decide if you'd like your bid adapter to be enabled out of the box, and if so, you'll need to provide a default endpoint and default extra adapter info (if applicable). If your bid adapter requires host specific information to function properly, such as a security token or host account, then it's best to leave the adapter disabled. {: .alert.alert-warning :} **HOST SPECIFIC INFO:** The default endpoint must not be specific to any particular host, such as Xandr/AppNexus. We may ask you about suspicious looking ids during the review process. Please reach out to individual hosts if you need to set specialized configuration. @@ -787,7 +887,7 @@ Edit the file `config/config.go` to register your default endpoint within the `S func SetupViper(v *viper.Viper, filename string) { ... v.SetDefault("adapters.{bidder}.endpoint", "https://your.url/any/path") - v.SetDefault("adapters.{bidder}.extra_info", `{"your": "extra info"}`) + v.SetDefault("adapters.{bidder}.extra_info", `{"your": "extra info"}`) ... } ``` @@ -804,76 +904,9 @@ func SetupViper(v *viper.Viper, filename string) { } ``` -### Set User Syncer Defaults - -If you implemented a user syncer, you'll need to provide a default endpoint. Edit the file `config/config.go` to alphabetically register your user syncer in the `setDerivedDefaults` method: - -```go -func (cfg *Configuration) setDerivedDefaults() { - ... - setDefaultUsersync(cfg.Adapters, openrtb_ext.Bidder{Bidder}, "https://your.url/sync?r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3D{bidder}%26gdpr%3D{%raw%}{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}{%endraw%}%26uid%3D%5BUUID%5D") - ... -} -``` - -If you don't have a good default, please add a comment instead. - -```go -func (cfg *Configuration) setDerivedDefaults() { - ... - // openrtb_ext.Bidder{Bidder} doesn't have a good default. - ... -} -``` - - -Yes, you're right. That url value is quite complicated. You can find further details in our [user sync documentation](https://docs.prebid.org/prebid-server/developers/pbs-cookie-sync.html). - -The user sync endpoint is composed of two main parts, the url of your user syncer and a redirect back to Prebid Server. The url of your user syncer is responsible for reading the user id from the client's cookie and redirecting to Prebid Server with a user id macro resolved. - -The url of your user syncer can make use of the following privacy policy macros which will be resolved by Prebid Server before sending the url to your server: -- `{%raw%}{{.USPrivacy}}{%endraw%}`: Client's CCPA consent string. -- `{%raw%}{{.GDPR}}{%endraw%}`: Client's GDPR TCF enforcement flag. -- `{%raw%}{{.GDPRConsent}}{%endraw%}`: Client's GDPR TCF consent string. - -Example: Impression splitting.
+An Impression may define multiple sizes and/or multiple ad formats. If your bidding server limits requests to a single ad placement, size, or format, then your adapter will need to split the Impression into multiple calls and merge the responses. ```go -func (a *adapter) MakeRequests(request *openrtb.BidRequest, requestInfo *adapters.ExtraRequestInfo) (*adapters.RequestData, []error) { +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) (*adapters.RequestData, []error) { var requests []*adapters.RequestData var errors []error - + requestCopy := *request for _, imp := range request.Imp { - requestCopy.Imp = []openrtb.Imp{imp} + requestCopy.Imp = []openrtb2.Imp{imp} requestJSON, err := json.Marshal(request) if err != nil { errors = append(errors, err) continue } - + requestData := &adapters.RequestData{ Method: "POST", Uri: a.endpoint, @@ -541,12 +638,56 @@ func (a *adapter) MakeRequests(request *openrtb.BidRequest, requestInfo *adapter return requests, errors } ``` + +##### Currency + +If your bidding server supports multiple currencies, please pass through the `request.cur` field. If your bidding server only bids in a single currency, such as USD or EUR, that's fine. Prebid Server will convert your bid to the request currency if you include it in the bid response, otherwise we assume USD and conversion will not occur. + +Please ensure you forward the bid floor (`request.imp[].bidfloor`) and bid floor currency (`request.imp[].bidfloorcur`) values to your bidding server for enforcement. You can use of the `requestInfo.ConvertCurrency` helper method for currency conversions if your endpoint only supports floors in a specific currency. + +Please ensure you forward the bid floor (`request.imp[].bidfloor`) and bid floor currency (`request.imp[].bidfloorcur`) values to your bidding server for enforcement. You have access to the currency conversion helper method `ConvertCurrency` in case your endpoint only supports floors in a single currency. + ++-If your bidding server supports multiple currencies, please be sure to pass through the `request.cur` field. If your bidding server only bids in a single currency, such as USD or EUR, that's fine. Prebid Server will convert your bid to the request currency if you include it in the bid response, otherwise we assume USD and conversion will not occur. - -Please ensure you forward the bid floor (`request.imp[].bidfloor`) and bid floor currency (`request.imp[].bidfloorcur`) values to your bidding server for enforcement. You'll soon have access to currency conversion helper methods if your endpoint only supports floors in a single currency. +##### Common Data There are a several values of a bid that publishers expect to be populated. Some are defined by the OpenRTB 2.5 specification and some are defined by Prebid conventions. @@ -557,9 +698,10 @@ There are a several values of a bid that publishers expect to be populated. Some | COPPA | OpenRTB | `request.regs.ext.us_privacy`Example: Currency conversion needed for bid floor values in impressions.
+ +```go +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) (*adapters.RequestData, []error) { + + for _, imp := range request.Imp { + // Check if imp comes with bid floor amount defined in a foreign currency + if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" { + + // Convert to US dollars + convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") + if err != nil { + return nil, []error{err} + } + + // Update after conversion. All imp elements inside request.Imp are shallow copies + // therefore, their non-pointer values are not shared memory and are safe to modify. + imp.BidFloorCur = "USD" + imp.BidFloor = convertedValue + } + } + + requestJSON, err := json.Marshal(request) + if err != nil { + return nil, []error{err} + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: requestJSON, + } + + return []*adapters.RequestData{requestData}, nil +} +```
The publisher is specifying the Children's Online Privacy Protection flag. | Currency | OpenRTB |`request.cur`
The publisher is specifying the desired bid currency. The Prebid Server default is USD. | [Debug](https://github.com/prebid/prebid-server/issues/745) | Prebid | `request.ext.prebid.debug`
The publisher is requesting verbose debugging information from Prebid Server. +| [Request-Defined currency conversion rates](https://docs.prebid.org/prebid-server/features/pbs-currency.html) | Prebid | `request.ext.prebid.currency`
The publisher decides to prioritize its own custom currency conversion rates over Prebid Server's currency conversion rates. If a currency rate is not found in `request.ext.prebid.currency`, Prebid Server's rates will be used unless `usepbsrates` is set to `false`. If missing, `usepbsrates` defaults to true. | [First Party Data (FPD)](https://docs.prebid.org/prebid-server/features/pbs-fpd.html)| Prebid | `request.imp[].ext.context.data.*`, `request.app.ext.data.*`, `request.site.ext.data.*`, `request.user.ext.data.*`
The publisher may provide first party data (e.g. keywords). | GDPR | OpenRTB | `request.regs.ext.gdpr`, `request.user.ext.consent`
The publisher is specifying the European General Data Protection Regulation flag and TCF consent string. -| Site or App | OpenRTB | `request.site`, `request.app`
The publisher will provide either the site or app, but not both, representing the client's device. +| Site or App | OpenRTB | `request.site`, `request.app`
The publisher will provide either the site or app, but not both, representing the client's device. | Supply Chain | OpenRTB | `request.source.ext.schain`
The publisher's declaration of all parties who are selling or reselling the bid request. | Test | OpenRTB | `request.test`
The publisher is sending non-production traffic which also enables verbose debugging information from Prebid Server. | Video | OpenRTB | `request.imp[].video`
The publisher is specifying video ad requirements or preferences. @@ -571,18 +713,20 @@ For simplicity, adapters are expected to make net-price bids (e.g. "If this ad w The `MakeBids` method is responsible for parsing the bidding server's response and mapping it to the [OpenRTB 2.5 Bid Response object model](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf#page=32). -This method is called for each response received from your bidding server within the bidding window (`request.tmax`). If there are no requests or if all requests time out, the `MakeBids` method will not be called. +This method is called for each response received from your bidding server within the bidding time window (`request.tmax`). If there are no requests or if all requests time out, the `MakeBids` method will not be called. -{: .alert.alert-info :} +{: .alert.alert-warning :} It's *imperative* to include all required information in the response for your bid to be accepted. Please avoid common mistakes, such as not specifying the bid currency and not properly detecting the media type from the bidding server response. The first argument, `request`, is the exact same OpenRTB 2.5 Bid Request object provided to (and potentially mutated by) the `MakeRequests` method. The information in the `request` may be useful when detecting the media type. The second argument, `requestData`, is the exact same `adapters.RequestData` object returned by the `MakeRequests` method. It's rare for adapters to make use of this information, but it's provided for potential edge cases. -The third argument, `responseData`, is the HTTP response received from your bidding server and contains the status code, body, and headers. If your bidding server replies with a GZIP encoded body, it will be automatically decompressed. +The third argument, `responseData`, is the HTTP response received from your bidding server and contains the status code, body, and headers. If your bidding server replies with a GZIP encoded body, it will be automatically decompressed. -The `MakeBids` method is expected to return an `adapters.BidderResponse` object with one or more bids mapped from your bidding server's response. This may be as simple as decorating an OpenRTB 2.5 Bid Response with a some Prebid Server metadata (such as the media type) or more complicated mapping logic depending on your server's response format. +The `MakeBids` method is expected to return an `adapters.BidderResponse` object with one or more bids mapped from your bidding server's response. This may be as simple as decorating an OpenRTB 2.5 Bid Response with some Prebid Server metadata (such as the media type) or more complicated mapping logic depending on your server's response format. + +##### Object Model Please review the entire [OpenRTB 2.5 Bid Response](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf#page=32) documentation to fully understand the response object model and expectations. We've summarized some common fields below. Data which is listed as required is enforced by the core framework and cannot be omitted. @@ -591,33 +735,38 @@ Please review the entire [OpenRTB 2.5 Bid Response](https://www.iab.com/wp-conte | - | - | - | `.Currency` | Required | [3-letter ISO 4217 code](https://www.iso.org/iso-4217-currency-codes.html) defining the currency of the bid. The Prebid Server default is USD. | `.Bids[].BidType` | Required | Prebid Server defined value identifying the media type as `banner`, `video`, `audio`, or `native`. Should be mapped from the bidding server response. -| `.Bids[].Bid.ADomain` | Optional | Advertiser domain for block list checking. -| `.Bids[].Bid.AdM` | Optional | Ad markup to serve the creative if the bid wins. May be HTML, Native, or VAST/VMAP formats. | `.Bids[].Bid.CrID` | Required | Unique id of the creative. | `.Bids[].Bid.ID` | Required | Bidder generated id to assist with logging and tracking. | `.Bids[].Bid.ImpID` | Required | ID of the corresponding bid request Impression. Prebid Server validates the id is actually found in the bid request. | `.Bids[].Bid.Price` | Required | Net price CPM of the bid, not gross price. Publishers can correct for gross price bids by setting Bid Adjustments to account for fees. We recommend the most granular price a bidder can provide. +| `.Bids[].Bid.ADomain` | Optional | Advertiser domain for block list checking. +| `.Bids[].Bid.AdM` | Optional | Ad markup to serve if the bid wins. May be HTML, Native, or VAST/VMAP formats. You should resolve any AUCTION_PRICE macros. | `.Bids[].Bid.W` | Optional | Width of the creative in pixels. | `.Bids[].Bid.H` | Optional | Height of the creative in pixels. | `.Bids[].Bid.Ext` | Optional | Embedded JSON containing Prebid metadata (see below) or custom information. -If you'd like to support Long Form Video Ad Pods, then you'll need to provide the followings information: +{: .alert.alert-info :} +We recommend resolving creative OpenRTB macros in your adapter. Otherwise, AUCTION_PRICE will eventually get resolved by the [Prebid Universal Creative](https://github.com/prebid/prebid-universal-creative), but by then the bid price will be in the ad server currency and quantized by the price granularity. + +If you'd like to support [Long Form Video Ad Pods](/dev-docs/modules/adpod.html)s, then you'll need to provide the followings information: {: .table .table-bordered .table-striped } | BidderResponse Path | Description | - | - -| `.Bids[].BidVideo.PrimaryCategory` | Category for the bid. Should be able to be translated to the primary ad server format. -| `.Bids[].Bid.Cat` | Category for the bid. Should be able to be translated to the primary ad server format. +| `.Bids[].BidVideo.PrimaryCategory` | Category for the bid in the taxonomy used by the ad server. Will be passed through without translation. +| `.Bids[].Bid.Cat` | IAB category for the bid which may be translated to the taxonomy used by the ad server. | `.Bids[].BidVideo.Duration` | Length of the video in integer seconds. | `.Bids[].DealPriority` | Deal tier integer value. Defaults to 0. {: .alert.alert-info :} Either `.Bids[].BidVideo.PrimaryCategory` or `.Bids[].Bid.Cat` should be provided. -Prebid has historically struggled with sharing granular bid response data with publishers, analytics, and reporting systems. To address this, we've introduced a standard object model. We encourage adapters to provide as much information as possible in the bid response. +##### Metadata + +Prebid has introduced a standard object model for sharing granular bid response data with publishers, analytics, and reporting systems. We encourage adapters to provide as much information as possible in the bid response. {: .alert.alert-danger :} -Bid metadata will be *required* in Prebid.js 5.X+ release, specifically for AdvertiserDomains and MediaType. We recommend making sure your adapter sets these values or Prebid.js may throw out the bid. +Bid metadata will be *required* in Prebid.js 5.X+ release, specifically for bid.ADomain and MediaType. We recommend making sure your adapter sets these values or Prebid.js may throw out the bid. {: .table .table-bordered .table-striped } | Path | Description @@ -628,13 +777,12 @@ Bid metadata will be *required* in Prebid.js 5.X+ release, specifically for Adve | `.AgencyName` | Bidder-specific agency name. | `.AdvertiserID` | Bidder-specific advertiser id. | `.AdvertiserName` | Bidder-specific advertiser name. -| `.AdvertiserDomains` | Advertiser domains for the landing page(s). Should match `.Bids[].Bid.ADomain`. | `.BrandID` | Bidder-specific brand id for advertisers with multiple brands. | `.BrandName` | Bidder-specific brand name. -| `.dchain` | Demand Chain Object. +| `.DChain` | Demand chain object. | `.PrimaryCategoryID` | Primary IAB category id. | `.SecondaryCategoryIDs` | Secondary IAB category ids. -| `.MediaType` | Either `banner`, `audio`, `video`, or `native`. Should match `.Bids[].BidType`. +| `.MediaType` | Either `banner`, `audio`, `video`, or `native`. This is used in the scenario where a bidder responds with a mediatype different than the stated type. e.g. native when the impression is for a banner. One use case is to help publishers determine whether the creative should be wrapped in a safeframe. @@ -642,83 +790,46 @@ Bid metadata will be *required* in Prebid.js 5.X+ release, specifically for AdveExample: Setting metadata.
```go -func (a *adapter) MakeBids(request *openrtb.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { ... for _, seatBid := range response.SeatBid { - for _, bid := range seatBid.Bid { - bid := bid // pin https://github.com/kyoh86/scopelint#whats-this + for i, bid := range seatBid.Bid { b := &adapters.TypedBid{ - Bid: &bid, + Bid: &seatBid.Bid[i], BidType: getMediaTypeForBid(bid), - } - - if meta, err := buildMeta(b); err != nil { - errs = append(errs, metaErr) - } else { - b.Bid.Ext = meta - bidResponse.Bids = append(bidResponse.Bids, b) + BidMeta: getBidMeta(bid), } } ... } -func buildMeta(bid *adapters.TypedBid) (json.RawMessage, error) { - metaExt := openrtb_ext.ExtBidPrebid { - Meta: &openrtb_ext.ExtBidPrebidMeta { - NetworkID: 1, - NetworkName: "Some Network Name", - AgencyID: 2, - AgencyName: "Some Agency Name", - AdvertiserID: 3, - AdvertiserName: "Some Advertiser Name", - AdvertiserDomains: bid.ADomain, - dchain: bid.ext.dchain, - BrandID: 4, - BrandName: "Some Brand Name", - PrimaryCategoryID: "IAB-1", - SecondaryCategoryIDs: []string{"IAB-2", "IAB-3"}, - MediaType: b.BidType, - } +func getBidMeta(bid *adapters.TypedBid) *openrtb_ext.ExtBidPrebidMeta { + // Not all fields are required. This example includes all fields for + // demonstration purposes. + return &openrtb_ext.ExtBidPrebidMeta { + NetworkID: 1, + NetworkName: "Some Network Name", + AgencyID: 2, + AgencyName: "Some Agency Name", + AdvertiserID: 3, + AdvertiserName: "Some Advertiser Name", + AdvertiserDomains: []string{"Some Domain"}, + DemandSource: "Some Demand Source", + DChain: json.RawMessage(`{Some Demand Chain JSON}`), + BrandID: 4, + BrandName: "Some Brand Name", + PrimaryCategoryID: "IAB-1", + SecondaryCategoryIDs: []string{"IAB-2", "IAB-3"}, + MediaType: "banner", } - return json.Marshal(meta) } ```-- -Example: Bidding server url with no macros.
- -```go -"https://your.url/sync?r=" -``` --- - -The redirect url for Prebid Server must follow this format: -``` -{host}/setuid?bidder={bidder}&gdpr={%raw%}{{.GDPR}}&gdpr_consent={{.GDPRConsent}}{%endraw%}&uid=[UUID] -``` - -{: .table .table-bordered .table-striped } -| Token | Description -| - | - -| `{host}` | Placeholder for the Prebid Server host url. In code, you would substitute it with `url.QueryEscape(externalURL)`. -| `{bidder}` | Placeholder for the name of your bid adapter. -| `[UUID]` | Macro defined by your user sync server which will be replaced with the user's id. - -The final value of the redirect url is encoded for safe use within a query string: - -``` -{host}%2Fsetuid%3Fbidder%3D{bidder}%26gdpr%3D{%raw%}{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}{%endraw%}%26uid%3D%5BUUID%5D -``` - ## Test Your Adapter -This chapter will guide you through the creation of automated unit tests to cover your bid adapter code, bidder parameters JSON Schema, and user sync code. We use GitHub Action Workflows to ensure the code you submit passes validation. You can run the same validation locally with this command: +This section will guide you through the creation of automated unit tests to cover your bid adapter code and bidder parameters JSON Schema. We use GitHub Action Workflows to ensure the code you submit passes validation. You can run the same validation locally with this command: ```bash ./validate.sh --nofmt --cov --race 10 @@ -881,7 +914,7 @@ This chapter will guide you through the creation of automated unit tests to cove ### Adapter Code Tests -Bid requests and server responses can be quite verbose. To avoid large blobs of text embedded within test code, we've created a framework for bid adapters which use a JSON body and/or a url. If your bidding server uses another payload format, such as XML, you're on your own. +Bid requests and server responses can be quite verbose. To avoid large blobs of text embedded within test code, we've created a framework for bid adapters which use a JSON body and/or a url to send a bid request. We require the use of our test framework as it includes checks to ensure no changes are made to shared memory. We strive for as much test coverage as possible, but recognize that some code paths are impractical to simulate and rarely occur. You do not need to test the error conditions for `json.Marshal` calls, for template parse errors within `MakeRequests` or `MakeBids`, or for `url.Parse` calls. Following this guidance usually results in a coverage rate of around 90% - 95%, although we don't enforce a specific threshold. @@ -892,7 +925,7 @@ package {bidder} import ( "testing" - + "github.com/prebid/prebid-server/adapters/adapterstest" "github.com/prebid/prebid-server/config" "github.com/prebid/prebid-server/openrtb_ext" @@ -901,11 +934,11 @@ import ( func TestJsonSamples(t *testing.T) { bidder, buildErr := Builder(openrtb_ext.Bidder{Bidder}, config.Adapter{ Endpoint: "http://whatever.url"}) - + if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) } - + adapterstest.RunJSONBidderTest(t, "{bidder}test", bidder) } ``` @@ -960,7 +993,7 @@ The format of a JSON test is as follows: The `mockBidRequest`, `httpCalls`, and `expectedBidResponses` fields are required. The `expectedMakeRequestsErrors` and `expectedMakeBidsErrors` may be omitted if there are no expected errors. We provide a `literal` and `regex` mode for testing error values. We often use the `regex` mode to handle error messages produced by the core Go framework which changed between recent releases. -To make everyone's life easier, please use a JSON 'prettifier' to apply standard formatting to your test files. We recommend the use of Visual Studio Code's [Beautify](https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify) extension. +Please use a JSON 'prettifier' to apply standard formatting to your test files. We recommend the use of Visual Studio Code's [Beautify](https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify) extension. ### Builder Tests @@ -972,7 +1005,7 @@ If your adapter supports template parsing, we recommend adding this failure test func TestEndpointTemplateMalformed(t *testing.T) { _, buildErr := Builder(openrtb_ext.Bidder{Bidder}, config.Adapter{ Endpoint: "{%raw%}{{Malformed}}{%endraw%}"}) - + assert.Error(t, buildErr) } ``` @@ -985,7 +1018,7 @@ func TestBadConfig(t *testing.T) { Endpoint: `http://it.doesnt.matter/bid`, ExtraAdapterInfo: `{foo:42}`, }) - + assert.Error(t, buildErr) } @@ -994,27 +1027,14 @@ func TestEmptyConfig(t *testing.T) { Endpoint: `http://it.doesnt.matter/bid`, ExtraAdapterInfo: ``, }) - + bidder{Bidder} := bidder.(*adapter) - + assert.NoError(t, buildErr) assert.Empty(t, bidder{Bidder}.extraInfo.SomeInfo) } ``` -### Adapter Race Condition Tests - -You must define race condition tests for each media type supported by your bid adapter. We don't expect bid adapters to run concurrent code. Rather, these tests attempt to verify your bid adapter doesn't modify shared memory. We use Go's [race detector](https://golang.org/doc/articles/race_detector.html) which is a great line of defense, but it may produce false negatives. It will not produce false positives, so please investigate further if these tests ever fail. - -Create a file with the path `adapters/{bidder}/{bidder}test/params/race/{mediaType}.json` for each `banner`, `video`, `audio`, and `native` media type supported by your adapter. Include all required and optional bidder parameters defined by your JSON Schema. - -Here's an example file using the same example JSON Schema from other chapters: -```json -{ - "placementId": "Some Placement" -} -``` - ### Bidder Parameter Tests The bidder parameter JSON Schema files are considered a form of code and must be tested. Create a file with the path `adapters/{bidder}/params_test.go` using the following template: @@ -1025,7 +1045,7 @@ package {bidder} import ( "encoding/json" "testing" - + "github.com/prebid/prebid-server/openrtb_ext" ) @@ -1034,7 +1054,7 @@ func TestValidParams(t *testing.T) { if err != nil { t.Fatalf("Failed to fetch the json schema. %v", err) } - + for _, p := range validParams { if err := validator.Validate(openrtb_ext.Bidder{Bidder}, json.RawMessage(p)); err != nil { t.Errorf("Schema rejected valid params: %s", p) @@ -1047,7 +1067,7 @@ func TestInvalidParams(t *testing.T) { if err != nil { t.Fatalf("Failed to fetch the json schema. %v", err) } - + for _, p := range invalidParams { if err := validator.Validate(openrtb_ext.Bidder{Bidder}, json.RawMessage(p)); err == nil { t.Errorf("Schema allowed invalid params: %s", p) @@ -1066,66 +1086,11 @@ var invalidParams = []string{ ``` Please include tests for required fields, optional fields, conditional fields such as `oneOf`, regex filters, and data type mismatches. For example, if the field is defined as a string please include one invalid case for the wrong data type such as an integer in this example. -You don't have to go crazy with combinatorials. We're looking for just enough test cases to build confidence. - -### User Syncer Tests - -{: .alert.alert-info :} -Please skip to the end of this section if your adapter doesn't define a user syncer. - -We ask that you include a user syncer test to verify the basic mechanics of macro substitution. The `syncURL` should be the same value used in the `setDefaultUsersync` call with the `url.QueryEscape(externalURL)` code replaced with a simple hardcoded value such as `"host"`. Please keep the privacy policy values simple, as we're only testing substitution. - -Create a file with the path `adapters/{bidder}/usersync_test.go` using the following template: - -```go -package {bidder} - -import ( - "testing" - "text/template" - - "github.com/prebid/prebid-server/privacy" - "github.com/prebid/prebid-server/privacy/ccpa" - "github.com/prebid/prebid-server/privacy/gdpr" - "github.com/stretchr/testify/assert" -) - -func TestSyncer(t *testing.T) { - syncURL := "Example: Bidding server url with CCPA privacy consent.
- -```go -"https://your.url/sync?usp={%raw%}{{.USPrivacy}}{%endraw%}&r=" -``` -" - syncURLTemplate := template.Must( - template.New("sync-template").Parse(syncURL), - ) - - syncer := NewSyncer(syncURLTemplate) - syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{ - GDPR: gdpr.Policy{ - Signal: "A", - Consent: "B", - }, - CCPA: ccpa.Policy{ - Consent: "C", - }, - }) - - assert.NoError(t, err) - assert.Equal(t, " ", syncInfo.URL) - assert.Equal(t, "redirect", syncInfo.Type) -} -``` - -If you *DON'T* have a user syncer, edit the file `usersync/usersyncers/syncer_test.go` to exclude your bid adapter from user sync tests: - -```go -adaptersWithoutSyncers := map[openrtb_ext.BidderName]bool{ - ... - openrtb_ext.Bidder{Bidder}: true, - ... -} -``` +There is no need to provide a combinatorial for every edge case possibility. We're looking for just enough test cases to build confidence. ### Manual End To End Tests -We'll verify your adapter works correctly on a technical level during the code review, but you'll need to perform separate end-to-end testing: +We'll verify your adapter works correctly on a technical level during the code review, but you'll need to perform manual end-to-end testing: 1. Build the project and start your server: ```bash @@ -1169,13 +1134,15 @@ We'll verify your adapter works correctly on a technical level during the code r }' ``` -If your bid adapters defines a user syncer, please perform end-to-end testing of the user sync process: +### User Sync Testing + +If your bid adapter defines one or more user sync endpoints, you'll need to perform manual end-to-end testing of each endpoint using the following process: -1. [Save a User ID](https://docs.prebid.org/prebid-server/endpoints/pbs-endpoint-setuid.html) using the `familyName` of your user syncer. This is likely the same as your bidder name. +1. [Save a User ID](https://docs.prebid.org/prebid-server/endpoints/pbs-endpoint-setuid.html) using the `key` of your user sync endpoint. This should default to your bidder name and is case sensitive. 1. Run a test auction (see the curl example above) and verify in the debug response that the outgoing `request.ext.debug.httpcalls` calls includes the User ID you saved in step 1. -It may be a bit tricky to track down the root cause of user sync errors. If you get stuck, please [submit a GitHub issue](https://github.com/prebid/prebid-server/issues/new) and we'll provide guidance. +If you are having issues finding the root cause of user sync errors, please [submit a GitHub issue](https://github.com/prebid/prebid-server/issues/new) and we'll provide guidance. ## User Documentation @@ -1199,7 +1166,9 @@ dchain_supported: true/false userId: media_types: banner, video, audio, native safeframes_ok: true/false -bidder_supports_deals: true/false +deals_supported: true/false +floors_supported: true/false +fpd_supported: true/false pbjs: true/false pbs: true/false pbs_app_supported: true/false @@ -1229,7 +1198,9 @@ Notes on the metadata fields: - If you support adding a demand chain on the bid response, add `dchain_supported: true`. Default is false. - If your bidder doesn't work well with safeframed creatives, add `safeframes_ok: false`. This will alert publishers to not use safeframed creatives when creating the ad server entries for your bidder. No default. - If your bidder supports mobile apps, set `pbs_app_supported: true`. No default value. -- If your bidder supports deals, set `bidder_supports_deals: true`. No default value. +- If your bidder supports deals, set `deals_supported: true`. No default value. +- If your bidder supports floors, set `floors_supported: true`. No default value. +- If your bidder supports first party data, set `fpd_supported: true`. No default value. - If you're a member of Prebid.org, add `prebid_member: true`. Default is false. @@ -1246,13 +1217,6 @@ Notes on the metadata fields: - `adapters/{bidder}/{bidder}_test.go` - `adapters/{bidder}/{bidder}test/exemplary/*.json` - `adapters/{bidder}/{bidder}test/supplemental/*.json` - - `adapters/{bidder}/{bidder}test/params/race/{mediaType}.json` -- User Syncer - If You Have One - - `adapters/{bidder}/usersync.go` - - `adapters/{bidder}/usersync_test.go` - - `usersync/usersyncers/syncer.go` -- User Syncer - If You Don't - - `usersync/usersyncers/syncer_test.go` - Register With The Core - `openrtb_ext/bidders.go` - `exchange/adapter_builders.go` @@ -1261,7 +1225,7 @@ Notes on the metadata fields: ## Contribute -Whew! You're almost done. Thank you for taking the time to develop a Prebid Server bid adapter. When you're ready, [contribute](https://github.com/prebid/prebid-server/blob/master/docs/developers/contributing.md) your new bid adapter by opening a PR to the [PBS-Go GitHub repository](https://github.com/prebid/prebid-server) with the name "New Adapter: {Bidder}". +Thank you for taking the time to develop a Prebid Server bid adapter. When you're ready, [contribute](https://github.com/prebid/prebid-server/blob/master/docs/developers/contributing.md) your new bid adapter by opening a PR to the [PBS-Go GitHub repository](https://github.com/prebid/prebid-server) with the name "New Adapter: {Bidder}". {: .alert.alert-warning :} You don't need to ask permission or open a GitHub issue before submitting an adapter. diff --git a/prebid-server/developers/add-new-bidder-java.md b/prebid-server/developers/add-new-bidder-java.md index d13385986f..61471a929d 100644 --- a/prebid-server/developers/add-new-bidder-java.md +++ b/prebid-server/developers/add-new-bidder-java.md @@ -77,14 +77,8 @@ Create a file with the path `static/bidder-info/{bidder}.yaml` and begin with th ```yaml adapters: - {bidder}: - enabled: false + yourBidderCode: endpoint: http://possible.endpoint - pbs-enforces-gdpr: true - pbs-enforces-ccpa: true - modifying-vast-xml-allowed: true - deprecated-names: - aliases: meta-info: maintainer-email: maintainer@email.com app-media-types: @@ -101,16 +95,16 @@ adapters: vendor-id: your_vendor_id usersync: url: your_bid_adapter_usersync_url - redirect-url: /setuid?bidder={bidder}&gdpr={%raw%}{{gdpr}}{%endraw%}&gdpr_consent={%raw%}{{gdpr_consent}}{%endraw%}&us_privacy={%raw%}{{us_privacy}}{%endraw%} - cookie-family-name: {bidder} + redirect-url: /setuid?bidder=yourBidderCode&gdpr={%raw%}{{gdpr}}{%endraw%}&gdpr_consent={%raw%}{{gdpr_consent}}{%endraw%}&us_privacy={%raw%}{{us_privacy}}{%endraw%} + cookie-family-name: yourBidderCode type: redirect support-cors: false ``` Modify this template for your bid adapter: - Change the maintainer email address to a group distribution list on your ad server's domain. A distribution list is preferred over an individual mailbox to allow for robustness, as roles and team members naturally change. -- Change the `modifyingVastXmlAllowed` value to `true` if you'd like to opt-in for video impression tracking. -- Change the `enabled` value to `true` if you'd like to make your bid adapter enabled. +- Change the `modifying-vast-xml-allowed` value to `false` if you'd like to opt out of video impression tracking. It defaults to `true`. +- Change the `pbs-enforces-ccpa` to `false` if you'd like to disable ccpa enforcement. Defaults to `true`. - Change the `vendor-id` value to id of your bidding server as registered with the [GDPR Global Vendor List (GVL)](https://iabeurope.eu/vendor-list-tcf-v2-0/). Leave this as `0` if you are not registered with IAB Europe. - Remove the `capabilities` (app/site) and `mediaTypes` (banner/video/audio/native) combinations which your adapter does not support. - Change the `cookie-family-name` to the name which will be used for storing your user sync id within the federated cookie. Please keep this the same as your bidder name. @@ -124,6 +118,57 @@ The url of your user syncer can make use of the following privacy policy macros - Change the `usersync:type` value to `redirect` or `iframe` specific to your bidder. +### Default bidder configuration + +Prebid Server has default configuration for common bidder properties, which can be overriden by bidders in their +configurations. + +Default configuration: + +```yaml +adapter-defaults: + enabled: false + pbs-enforces-ccpa: true + modifying-vast-xml-allowed: true +``` + +There are also some default properties which can't be overridden in adapter-defaults, but rather in particular adapter's config: +- `aliases`: Defaults to empty +- `deprecated-names`: Defaults to empty +- `extra-info`: Defaults to empty + +### Create bidder alias +If you want to add bidder that is an alias of existing bidder, you need just to update configuration of parent bidder: + +Example of adding bidder alias: +```yaml +adapters: + yourBidderCode: + ... + aliases: + yourBidderAlias: + endpoint: http://possible.alias/endpoint + app-media-types: + - banner + - video + site-media-types: + - banner + - video + usersync: + cookie-family-name: yourBidderCode +``` + +Aliases are configured by adding child configuration object at `adapters.yourBidderCode.aliases.yourBidderAlias` + +Aliases support the same configuration options that their bidder counterparts support except `aliases` (i.e. it's not possible +to declare alias of an alias). + +{: .alert.alert-warning :} +**Aliases cannot declare support for media types not supported by their parent bidders**
+However aliases could narrow down media types they support.
+For example: if the bidder is written to not support native site requests, then an alias cannot magically decide to change that; +However, if a bidder supports native site requests, and the alias does not want to for some reason, it has the ability to remove that support. + ### Bidder Parameters Your bid adapter might require extra information from the publisher to form a request to your bidding server. The bidder parameters JSON Schema codifies this information to allow Prebid Server to verify requests and to provide an API for third party configuration systems. @@ -499,14 +544,17 @@ Please review the entire [OpenRTB 2.5 Bid Response](https://www.iab.com/wp-conte | `.Currency` | Required | [3-letter ISO 4217 code](https://www.iso.org/iso-4217-currency-codes.html) defining the currency of the bid. The Prebid Server default is USD. | `.Bids[].BidType` | Required | Prebid Server defined value identifying the media type as `banner`, `video`, `audio`, or `native`. Should be mapped from the bidding server response. | `.Bids[].Bid.ADomain` | Optional | Advertiser domain for block list checking. -| `.Bids[].Bid.AdM` | Optional | Ad markup to serve the creative if the bid wins. May be HTML, Native, or VAST/VMAP formats. +| `.Bids[].Bid.AdM` | Optional | Ad markup to serve if the bid wins. May be HTML, Native, or VAST/VMAP formats. You should resolve any AUCTION_PRICE macros. | `.Bids[].Bid.CrID` | Required | Unique id of the creative. | `.Bids[].Bid.ID` | Required | Bidder generated id to assist with logging and tracking. | `.Bids[].Bid.ImpID` | Required | ID of the corresponding bid request Impression. Prebid Server validates the id is actually found in the bid request. | `.Bids[].Bid.Price` | Required | Net price CPM of the bid, not gross price. Publishers can correct for gross price bids by setting Bid Adjustments to account for fees. We recommend the most granular price a bidder can provide. | `.Bids[].Bid.W` | Optional | Width of the creative in pixels. | `.Bids[].Bid.H` | Optional | Height of the creative in pixels. -| `.Bids[].Bid.Ext` | Optional | Embedded JSON containing Prebid metadata (see below) or custom information. +| `.Bids[].Bid.Ext.Prebid.Meta` | Optional | Embedded JSON containing Prebid metadata (see below) or custom information. + +{: .alert.alert-info :} +We recommend resolving creative OpenRTB macros in your adapter. Otherwise, AUCTION_PRICE will eventually get resolved by the [Prebid Universal Creative](https://github.com/prebid/prebid-universal-creative), but by then the bid price will be in the ad server currency and quantized by the price granularity. If you'd like to support Long Form Video Ad Pods, then you'll need to provide the followings information: @@ -524,7 +572,7 @@ Either `.Bids[].BidVideo.PrimaryCategory` or `.Bids[].Bid.Cat` should be provide Prebid has historically struggled with sharing granular bid response data with publishers, analytics, and reporting systems. To address this, we've introduced a standard object model. We encourage adapters to provide as much information as possible in the bid response. {: .alert.alert-danger :} -Bid metadata will be *required* in Prebid.js 5.x+ release, specifically for AdvertiserDomains and MediaType. We recommend making sure your adapter sets these values or Prebid.js may throw out the bid. +Bid metadata will be *required* in Prebid.js 5.X+ release, specifically for bid.ADomain and MediaType. We recommend making sure your adapter sets these values or Prebid.js may throw out the bid. {: .table .table-bordered .table-striped } | Path | Description | @@ -535,13 +583,12 @@ Bid metadata will be *required* in Prebid.js 5.x+ release, specifically for Adve | `.AgencyName` | Bidder-specific agency name | | `.AdvertiserID` | Bidder-specific advertiser id | | `.AdvertiserName` | Bidder-specific advertiser name | -| `.AdvertiserDomains` | Advertiser domains for the landing page(s). Should match `.Bids[].Bid.ADomain` | | `.BrandID` | Bidder-specific brand id for advertisers with multiple brands | | `.BrandName` | Bidder-specific brand name | | `.dchain` | Demand Chain Object | `.PrimaryCategoryID` | Primary IAB category id | | `.SecondaryCategoryIDs` | Secondary IAB category ids | -| `.MediaType` | Either `banner`, `audio`, `video`, or `native`. Should match `.Bids[].BidType` | +| `.MediaType` | Either `banner`, `audio`, `video`, or `native`. This is used in the scenario where a bidder responds with a mediatype different than the stated type. e.g. native when the impression is for a banner. One use case is to help publishers determine whether the creative should be wrapped in a safeframe. | @@ -748,7 +795,6 @@ Go to `test-application.properties` file and add folowing properties ```yaml adapters.{bidder}.enabled=true adapters.{bidder}.endpoint=http://localhost:8090/{bidder}-exchange -adapters.{bidder}.pbs-enforces-gdpr=true adapters.{bidder}.usersync.url=//{bidder}-usersync ``` @@ -1122,7 +1168,9 @@ dchain_supported: true/false userId:media_types: banner, video, audio, native safeframes_ok: true/false -bidder_supports_deals: true/false +deals_supported: true/false +floors_supported: true/false +fpd_supported: true/false pbjs: true/false pbs: true/false pbs_app_supported: true/false @@ -1152,7 +1200,9 @@ Notes on the metadata fields: - If you support adding a demand chain on the bid response, add `dchain_supported: true`. Default is false. - If your bidder doesn't work well with safeframed creatives, add `safeframes_ok: false`. This will alert publishers to not use safeframed creatives when creating the ad server entries for your bidder. No default. - If your bidder supports mobile apps, set `pbs_app_supported`: true. No default value. -- If your bidder supports deals, set `bidder_supports_deals: true`. No default value. +- If your bidder supports deals, set `deals_supported: true`. No default value. +- If your bidder supports floors, set `floors_supported: true`. No default value. +- If your bidder supports first party data, set `fpd_supported: true`. No default value. - If you're a member of Prebid.org, add `prebid_member: true`. Default is false. diff --git a/prebid-server/developers/code-reviews.md b/prebid-server/developers/code-reviews.md index 737779afbe..1c8dfa2d70 100644 --- a/prebid-server/developers/code-reviews.md +++ b/prebid-server/developers/code-reviews.md @@ -44,7 +44,7 @@ Code reviews should focus on things which cannot be validated by machines. Some examples include: - Can we improve the user's experience in any way? -- Have the relevant [docs](..) been added or updated? If not, add the `needs docs` label. +- Have the relevant docs been added or updated? If not, add the `needs docs` label. - Do you believe that the code works by looking at the unit tests? If not, suggest more tests until you do! - Is the motivation behind these changes clear? If not, there must be [an issue](https://github.com/prebid/prebid-server/issues) explaining it. Are there better ways to achieve those goals? - Does the code use any global, mutable state? [Inject dependencies](https://en.wikipedia.org/wiki/Dependency_injection) instead! diff --git a/prebid-server/developers/installing-go.md b/prebid-server/developers/installing-go.md index 9531c00b72..c94df13c66 100644 --- a/prebid-server/developers/installing-go.md +++ b/prebid-server/developers/installing-go.md @@ -59,7 +59,7 @@ The server can be reached at `http://localhost:8000`. ## Contributing -Want to [add a bidding adapter](https://github.com/prebid/prebid-server/blob/master/docs/developers/add-new-bidder.md)? +Want to [add a bidding adapter](/prebid-server/developers/add-new-bidder-go.html)? Report bugs, request features, and suggest improvements [on Github](https://github.com/prebid/prebid-server/issues). diff --git a/prebid-server/developers/pbs-cookie-sync.md b/prebid-server/developers/pbs-cookie-sync.md index cd6c6878c3..dc739375db 100644 --- a/prebid-server/developers/pbs-cookie-sync.md +++ b/prebid-server/developers/pbs-cookie-sync.md @@ -27,14 +27,14 @@ Prebid Server stores bidder IDs in the `uids` cookie in the host domain. For exa ## Setting the uids Cookie -### Setting the uids cookie from Prebid.js +### Setting the uids cookie from Prebid.js Here's how these IDs get placed in the cookie from Prebid.js: {:class="pb-lg-img"} -1) Prebid.js starts by calling the Prebid Server [`/cookie_sync`](/prebid-server/endpoints/pbs-endpoint-cookieSync.html), letting it know which server-side bidders will be participating in the header bidding auction. +1) Prebid.js starts by calling the Prebid Server [`/cookie_sync`](/prebid-server/endpoints/pbs-endpoint-cookieSync.html), letting it know which server-side bidders will be participating in the header bidding auction. ``` POST https://prebid-server.example.com/cookie_sync @@ -50,9 +50,9 @@ POST https://prebid-server.example.com/cookie_sync 3) When it receives the response, Prebid.js loops through each element of `bidder_status[]`, dropping a pixel for each `bidder_status[].usersync.url`. -4) The bidder-specific endpoints read the users's cookie for the bidder's domain and respond with a redirect back to Prebid Server's [`/setuid` endpoint](/prebid-server/endpoints/pbs-endpoint-setuid.html) +4) The bidder-specific endpoints read the users' cookie for the bidder's domain and respond with a redirect back to Prebid Server's [`/setuid` endpoint](/prebid-server/endpoints/pbs-endpoint-setuid.html) -5) When the browser receives this redirect, it contacts Prebid Server, which will once again check the privacy settings and will update the `uids` cookie if allowed. +5) When the browser receives this redirect, it contacts Prebid Server, which will once again check the privacy settings and if allowed, update the `uids` cookie. ### Setting the uids cookie from AMP @@ -60,7 +60,8 @@ Cookie sync for AMP works in a way quite similar to Prebid.js. 1) The Prebid Server hosting company places a modified version of the `load-cookie` script onto a CDN. This script is part of the [Prebid Universal Creative](https://github.com/prebid/prebid-universal-creative/blob/master/src/cookieSync.js) repo. -Note that the only two values currently valid for 'endpoint' are 'appnexus' and 'rubicon' -- other host companies should update their copy to include their endpoint. +{: .alert.alert-warning :} +The only two values currently valid for 'endpoint' are 'appnexus' and 'rubicon' -- other host companies should update their copy to include their endpoint. See [the AMP implementation guide](/dev-docs/show-prebid-ads-on-amp-pages.html#user-sync) for more information. @@ -76,44 +77,58 @@ See [the AMP implementation guide](/dev-docs/show-prebid-ads-on-amp-pages.html#u ``` -Note: if the publisher has an AMP Consent Management Platform, they should use `load-cookie-with-consent.html`. +{: .alert.alert-info :} +If the publisher has an AMP Consent Management Platform, they should use `load-cookie-with-consent.html`. 3) At runtime, the `load-cookie` script just calls the Prebid Server /cookie_sync endpoint. The rest works the same as described for Prebid.js above. ## Bidder Instructions for Building a Sync Endpoint -Bidders must implement an endpoint under their domain which accepts an encoded URI for redirects. -This URL should be able to accept privacy parameters: +Building a sync endpoint is optional -- there is no benefit from ID syncing for mobile-only bidders. For browser-based bidding, ID syncing can help improve buyer bid rate. There are two main options a bidder can choose to support: + +- redirect: the client will drop an IMG tag into the page, then call the bidder's URL which needs to redirect to the Prebid Server /setuid endpoint. +- iframe: the client will drop an IFRAME tag into the page, then call the bidder's URL which responds with HTML and Javascript that calls the Prebid Server /setuid endpoint at some point. + +Bidders must implement an endpoint under their domain which accepts an encoded URI for redirects. This URL should be able to accept privacy parameters: - gdpr: if 0, declares this request isn't in GDPR scope. If 1, declares it is in scope. Otherwise indeterminate. - gdpr_consent: the TCF1 or TCF2 consent string. This is unpadded base64-URL encoded. - us_privacy: the IAB US Privacy string -These values will be passed to your usersync endpoint. For example: +The specific attributes can differ for your endpoint. For instance, you could choose to receive gdprConsent rather than gdpr_consent. -Here's an example that shows the privacy macros used by PBS-Go: +Here's an example that shows the privacy macros as configured in PBS-Go: ``` -GET some-bidder-domain.com/usersync-url?gdpr={%raw%}{{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}{%endraw%}&redirectUri=prebid-server.example.com%2Fsetuid%3Fbidder%3Dsomebidder%26uid%3D%24UID +userSync: + redirect: + url: https://some-bidder-domain.com/usersync-url?gdpr={%raw%}{{.GDPR}}{%endraw%}&consent={%raw%}{{.GDPRConsent}}{%endraw%}&us_privacy={%raw%}{{.USPrivacy}}{%endraw%}&redirect={%raw%}{{.RedirectURL}}{%endraw%} + userMacro: YOURMACRO ``` -PBS-Java uses slightly different macros: + +PBS-Java uses slightly different macros in the bidder config: ``` -GET some-bidder-domain.com/usersync-url?gdpr={%raw%}{{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}{%endraw%}&redirectUri=prebid-server.example.com%2Fsetuid%3Fbidder%3Dsomebidder%26uid%3D%24UID +usersync: + url: https://some-bidder-domain.com/usersync-url?gdpr={%raw%}{{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}{%endraw%}&redirectUri= + redirect-url: /setuid?bidder=acuityads&gdpr={%raw%}{{gdpr}}{%endraw%}&gdpr_consent={%raw%}{{gdpr_consent}}{%endraw%}&us_privacy={%raw%}{{us_privacy}}{%endraw%}&uid=YOURMACRO ``` -In either case, you can receive the values on whatever query string parameters you'd like -- these are -the macros you can use to define the values. +In either case, the {%raw%}{{...}}{%endraw%} macros are resolved by PBS. + +{: .alert.alert-warning :} +The "YOURMACRO" string here needs to be whatever your sync endpoint will recognize and resolve to the user's ID from your domain. Some examples of macros that bidders use: $UID, ${UID}, $$visitor_cookie$$, ${DI_USER_ID}, etc. Every bidder has their own value here. -This example endpoint would URL-decode the `redirectUri` param to get `prebid-server.example.com/setuid?bidder=somebidder&uid=$UID`. -It would then replace the `$UID` macro with the user's ID from their cookie. Supposing this user's ID was "132", -it would then return a redirect to `prebid-server.example.com/setuid?bidder=somebidder&uid=132`. +Here's how this all comes together: -Prebid Server would then save this ID mapping of `somebidder: 132` under the cookie at `prebid-domain.com`. +1. Prebid.js calls Prebid Server's cookie_sync endpoint +2. PBS responds with an array of user sync URLs, which may include your bidder's sync url +3. Prebid.js drops an img or iframe into the page, causing the browser to connect to the your usersync endpoint. +4. Your usersync endpoint will return with either a redirect to Prebid Server's /setuid endpoint or iframe HTML that eventually calls Prebid Server's /setuid endpoint. +5. Prebid Server then saves this ID mapping of `mybidder: 132` under the cookie at `prebid-domain.com`. -When the client then calls `www.prebid-domain.com/openrtb2/auction`, the ID for `somebidder` will be available in the Cookie. -Prebid Server will then stick this into `request.user.buyeruid` in the OpenRTB request it sends to `somebidder`'s Bidder. +Then the next time the client then calls `www.prebid-domain.com/openrtb2/auction`, the ID for `mybidder` will be available in the Cookie. Prebid Server will then stick this value into `request.user.buyeruid` in the OpenRTB request it sends to `mybidder`'s bid adapter. ## Further Reading - [Prebid Server Overview](/prebid-server/overview/prebid-server-overview.html) -- [Prebid.js s2sConfig](/dev-docs/publisher-api-reference.html#setConfig-Server-to-Server) +- [Prebid.js s2sConfig](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Server-to-Server) - [Prebid AMP Implementation Guide](/dev-docs/show-prebid-ads-on-amp-pages.html) diff --git a/prebid-server/endpoints/info/pbs-endpoint-info.md b/prebid-server/endpoints/info/pbs-endpoint-info.md index 0b98700936..6c85c84dec 100644 --- a/prebid-server/endpoints/info/pbs-endpoint-info.md +++ b/prebid-server/endpoints/info/pbs-endpoint-info.md @@ -17,7 +17,7 @@ This endpoint returns a list of Bidders supported by Prebid Server. These are the core values allowed to be used as `request.imp[i].ext.{bidder}` keys in [Auction](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html) requests. -For detailed info about a specific Bidder, use [`/info/bidders/{bidderName}`](./bidders/bidderName.html) +For detailed info about a specific Bidder, use [`/info/bidders/{bidderName}`](#get-infobiddersbiddername). ### Sample Response {:.no_toc} @@ -37,7 +37,7 @@ This endpoint returns JSON like: ## GET /info/bidders/{bidderName} This endpoint returns some metadata about the Bidder whose name is `{bidderName}`. -Legal values for `{bidderName}` can be retrieved from the [/info/bidders](../bidders.html) endpoint. +Legal values for `{bidderName}` can be retrieved from the [`/info/bidders`](#get-infobidders) endpoint. ### Sample Response {:.no_toc} diff --git a/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md b/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md index 6dd89dfe28..c984822090 100644 --- a/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md +++ b/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md @@ -6,10 +6,14 @@ title: Prebid Server | Endpoints | OpenRTB2 | AMP --- # Prebid Server | Endpoints | /openrtb2/amp +{:.no_toc} + +* TOC +{:toc} This document describes the behavior of the Prebid Server AMP endpoint in detail. For a more general reference, see the [Prebid AMP Implementation Guide -]({{site.baseurl}}/dev-docs/show-prebid-ads-on-amp-pages.html). +](/dev-docs/show-prebid-ads-on-amp-pages.html). ## GET /openrtb2/amp @@ -18,25 +22,29 @@ For a more general reference, see the [Prebid AMP Implementation Guide {: .table .table-bordered .table-striped } | Param | Scope | Type | Description | | --- | --- | --- | --- | -| tag_id | Required | `String` | The `tag_id` ID must reference a [Stored BidRequest]({{site.baseurl}}/prebid-server/features/pbs-storedreqs.html). For a thorough description of bid request JSON, see the [/openrtb2/auction](./auction.html) docs. | -| w | recommended | `String` | Comes from the amp-ad.width attribute. The stored request may contain width already, but this parameter reflects what's actually in the page. It replaces imp.banner.format[0].w | -| h | recommended | `String` | Comes from the amp-ad.height attribute. The stored request may contain height already, but this parameter reflects what's actually in the page. It replaces imp.banner.format[0].h | +| tag_id | Required | `String` | The `tag_id` ID must reference a [Stored BidRequest]({{site.baseurl}}/prebid-server/features/pbs-storedreqs.html). For a thorough description of bid request JSON, see the [/openrtb2/auction](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html) docs. | +| w | recommended | `String` | Comes from the amp-ad.width attribute. The stored request may contain width already, but this parameter reflects what's actually in the page. It's used to help determine imp.banner.format[0].w. See [resolving sizes](#resolving-sizes). | +| h | recommended | `String` | Comes from the amp-ad.height attribute. The stored request may contain height already, but this parameter reflects what's actually in the page. It's used to help determine imp.banner.format[0].h. See [resolving sizes](#resolving-sizes). | | ms | optional | `String` | Comes from the amp-ad.data-multi-size attribute. e.g. "970x90, 728x90". Sizes are parsed and added to imp.banner.format | -| oh | optional | `String` | Comes from the amp-ad.data-override-height attribute. See below for details on size calculation. | -| ow | optional | `String` | Comes from the amp-ad.data-override-width attribute. See below for details on size calculation. | +| oh | optional | `String` | Comes from the amp-ad.data-override-height attribute. See [resolving sizes](#resolving-sizes). | +| ow | optional | `String` | Comes from the amp-ad.data-override-width attribute. See [resolving sizes](#resolving-sizes). | | curl | optional | `String` | Added to OpenRTB request as site.page | | slot | optional | `String` | Added to OpenRTB request as imp[0].tagid | | timeout | optional | `String` | Added to OpenRTB request as tmax | -| targeting | optional | `String` | First Party Data (PBS-Java only) | +| targeting | optional | `String` | First Party Data | | gdpr_consent | optional | `String` | Consent string passed from CMP. Note this is used for both GDPR and CCPA. | +| consent_type | optional | `String` | If "1", request is TCFv1 and GDPR fields are ignored. If "2", the 'gdpr_consent' field is interpreted as TCFv2. If "3", the 'gdpr_consent' field is interpreted as us_privacy. | +| gdpr_applies | optional | `String` | Takes the values "true", "false" or empty. This is used as the value of regs.ext.gdpr. If "true", regs.ext.gdpr:1, if "false", regs.ext.gdpr:0. | +| addtl_consent | optional | `String` | GAM "additional consent". If present, this value is copied to user.ext.ConsentedProvidersSettings.consented_providers | | account | optional | `String` | Can be used to pass the Prebid-Server specific account ID. This is useful if `tag_id` parameters aren't unique across accounts. | -| debug | optional | `integer` | If 1, returns additional debug info. | +| debug | optional | `integer` | If 1, sets ext.prebid.debug to true to obtain additional debug info. | To be compatible with AMP, this endpoint behaves different from normal `/openrtb2/auction` requests. -1. The Stored `request.imp` data must have exactly one element. -2. `request.imp[0].secure` will be always be set to `1`, because AMP requires all content to be `https`. -3. AMP query params will overwrite parts of your Stored Request. For details, see the [Query Parameters](#query_params) section. +1. The 'tag_id' parameter points to a stored request. +2. The stored request must have exactly one `imp` element. +3. The request `imp[0].secure` will be always be set to `1`, because AMP requires all content to be `https`. +4. AMP query params will overwrite parts of your Stored Request. See the table above. ### Request @@ -63,98 +71,67 @@ An example Stored Request is given below: } } }, - "imp": [ - { - "id": "some-impression-id", - "banner": {}, // The sizes are defined by your AMP tag query params settings - "ext": { - "appnexus": { + "imp": [{ + "id": "some-impression-id", + "banner": {}, // The sizes are defined by your AMP tag query params settings + "ext": { + "prebid": { + "bidder": { + "bidderA": { // Insert parameters here }, - "rubicon": { + "bidderB": { // Insert parameters here } } - } - ] + } + } + }] } ``` +Note that other ext.prebid extensions can be specified in the stored request such as: +- [ext.prebid.currency](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#currency-support) +- [ext.prebid.aliases](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bidder-aliases) +- [ext.prebid.multibid](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#multibid-pbs-java-only) +- etc. + #### First Party Data (Currently only supported in PBS-Java) -You can send first party data into an AMP request by encoding a JSON -targeting block like this: +The nature of AMP is that user-level FPD is difficult or impossible. All of the pages are cached on a CDN and page javascript that can modify RTC calls is severely limited. -``` -GET /openrtb2/amp?tag_id=7470-Eater_AMP_ROS_ATF&w=300&h=250&ow=&oh=&ms=&slot=%2F172968584%2Feater%2Fgoogle%2Famp_med_rec_02&targeting=%7B%22site%22%3A%7B%22keywords%22%3A%22article%2C%20las%20vegas%22%2C%22cat%22%3A%7B%22blah%22%3A%221%22%7D%2C%22other-attribute%22%3A%22other-value%22%2C%22ext%22%3A%7B%22data%22%3A%7B%22entry_group%22%3A%5B%22front-page%22%2C%22featured-stories%22%5D%2C%22page_type%22%3A%22AMP%22%7D%7D%7D%2C%22user%22%3A%7B%22gender%22%3A%22m%22%7D%2C%22bidders%22%3A%5B%22rubicon%22%2C%22appnexus%22%5D%2C%22keywords%22%3A%22las%20vegas%20hospitality%20employees%22%2C%22foo%22%3A%7B%22bar%22%3A%22baz%22%7D%7D... -``` +Contextual First Party Data must be defined in the stored request entries. -Prebid Server will expand the targeting value and merge the data into -the resulting OpenRTB JSON for the appropriate bidders. +The only field that PBS supports in the AMP call that can be considered FPD is the 'targeting' block. These are key-value pairs that are sent to the ad server. They are also copied to the ORTB JSON in imp[].ext.data. -For example, if this AMP targeting is provided: +For example, if the AMP JSON targeting provided is: ``` -{ - "site": { - "keywords": "article, las vegas", // (1) - "cat": { "blah": "1" }, // invalid data type, will be dropped - "other-attribute": "other-value", // not openrtb2, remove - "ext": { - "data": { - "entry_group": ["front-page","featured-stories"], // (4) - "page_type": "AMP" // (5) - } - } - }, - "user": { - "gender": "m", // (2) - }, - "bidders": ["rubicon","appnexus"], // (3) - "keywords": "las vegas hospitality employees", // (6) - "foo": { // (7) - "bar": "baz" - } -} +
+ ``` -The numbered elements from the raw targeting data above are merged into the resulting OpenRTB like this: +The AMP URL would be something like this: +``` +GET /openrtb2/amp?tag_id=1001-my-test&w=300&h=250&ow=&oh=&ms=&slot=%2F1111%2Famp_test&targeting=%7B%22attr1%22%3A%22val1%22%2C%22attr2%22%3A%22val2%22%7D&... +``` +And the resulting OpenRTB would merge these targeting values as FPD on imp.ext.data: ``` { - "imp": [...], - "site": { - "publisher": { … }, - "keywords": "article, las vegas" // (1) - "ext":{ - "data": { - "entry_group": ["front-page","featured-stories"], // (4) - "page_type": "AMP" // (5) - } - } - }, - "user": { - "gender": "m" // (2) - }, - "ext": { - "prebid": { - "data": { - "bidders": ["rubicon",appnexus"], // (3) - } - } - }, - "imp": [ + "imp": [{ ... "ext": { - "context": { - "data": { - "keywords": "las vegas hospitality employees", // (6) - "foo": { // (7) - "bar": "baz" - } - } - } + "data": { + "attr1": "val1", + "attr2": "val2" + } } - ] + }], + ... } ``` @@ -222,41 +199,7 @@ The following errors can occur when loading a stored OpenRTB request for an inco | Checking stored request for match against tag_id. | 999 | No AMP config found for tag_id `%s`. | Error is returned. | | Checking if imp exists. | 999 | Data for tag_id=`'%s'` does not define the required imp array. | Error is returned. | | Checking if imp count is greater than one. | 999 | Data for tag_id `'%s'` includes `%d` imp elements. Only one is allowed. | Error is returned. | -| Checking if request.app exists. | 999 | `request.app` must not exist in AMP stored requests. | Error is returned. | - - - -### Query Parameter Details - - - A configuration option `amp_timeout_adjustment_ms` may be set to account for estimated latency so that Prebid Server can handle timeouts from adapters and respond to the AMP RTC request before it times out. - -Ensure that the amp-ad component was imported in the header. - -```html - - ``` - -This script provides code libraries that will convert the `` properties to the endpoint query parameters. In the most basic usage pass `width` and `height` as well as `type` and a `rtc-config`. The `type` value is the ad network you will be using. The `rtc-config` is used to pass JSON configuration to the Prebid Server, which handles the communication with [AMP RTC](https://medium.com/ampfuel/better-than-header-bidding-amp-rtc-fc54e80f3999). Vendors is an object that defines any vendors that will be receiving the RTC callout. In this example, the required parameter `tag_id` will receive the `PLACEMENT_ID` (or `REQUEST_ID`) value. - -```html - ``` -{: .alert.alert-info :} -First party data may be passed in on the "targeting" field. See the [`/openrtb2/amp` endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) documentation for more details. - ### Prebid Server Receives the AMP Request Prebid Server's first job on the [/openrtb2/amp endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) is to create an OpenRTB block to pass to the adapters. @@ -76,15 +73,8 @@ Prebid Server's first job on the [/openrtb2/amp endpoint](/prebid-server/endpoin The `tag_id` in the AMP URL is used to look up the bulk of the request. If the lookup fails, the request can't proceed. If it's successful, the next step is to parse the AMP query string parameters and place them -in the appropriate OpenRTB locations: - -- w added into the openrtb packet at imp.banner.format[0].w -- h added into the openrtb packet at imp.banner.format[0].h -- ms (multiple-sizes) - takes values like "970x90, 728x90". Parse sizes and add to imp.banner.format array -- ow, oh - override width, override height -- curl added as site.page -- slot added as imp.tagid -- timeout added as tmax +in the appropriate OpenRTB locations. See the [AMP endpoint documentation](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) +for details. So for the /openrtb2/amp URL above, the resulting OpenRTB might be: ``` @@ -116,17 +106,7 @@ So for the /openrtb2/amp URL above, the resulting OpenRTB might be: "id": "0000" }, "ext": { - "amp": 1, - "data": { - "key1": "val1" - } - } - }, - "user": { - "ext": { - "data": { - "key2": "val2" - } + "amp": 1 } }, "device": { @@ -168,8 +148,8 @@ Only a few dynamic parameters on the query string are integrated into the result #### First Party Data Support -Any targeting data passed in through the [`/openrtb2/amp`](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) endpoint is merged -into the OpenRTB JSON and permissions, if defined, are applied to each bidder. +Ad Server targeting data passed in through the [`/openrtb2/amp`](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) endpoint is merged +into the OpenRTB JSON in imp[].ext.data. #### Auction and Response @@ -180,7 +160,6 @@ From here, the header bidding auction is mostly the same as it is for Prebid.js: 1. Collect responses 1. Prepare the response - ### AMP Gets the Response AMP RTC endpoints can only respond with targeting, not OpenRTB. The @@ -216,4 +195,5 @@ into an iframe for display. ## Further Reading -- [AMP Support](/formats/amp.html) +- [Prebid AMP Support](/formats/amp.html) +- [PBS AMP endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) diff --git a/prebid-server/use-cases/pbs-pbjs.md b/prebid-server/use-cases/pbs-pbjs.md index 472ff3c43a..c736eb01c5 100644 --- a/prebid-server/use-cases/pbs-pbjs.md +++ b/prebid-server/use-cases/pbs-pbjs.md @@ -11,7 +11,7 @@ title: Prebid Server | Use Cases | Prebid.js * TOC {:toc} -When publishers specify bidders in [Prebid.js `s2sConfig`](/dev-docs/publisher-api-reference.html#setConfig-Server-to-Server), the browser connects to Prebid Server to coordinate the header bidding auction for those bidders. +When publishers specify bidders in [Prebid.js `s2sConfig`](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Server-to-Server), the browser connects to Prebid Server to coordinate the header bidding auction for those bidders. ## Workflow @@ -25,7 +25,7 @@ Here are workflows diagramming how this works. 1. Prebid Server parses the request and holds the auction. 1. The response, including the body of the winning creative(s), is sent back to the browser. 1. Prebid.js passes ad server targeting variables to the page, which forwards it to the ad server. -1. When a header bidding ad wins, the ad server responds to the page with the [Prebid Universal Creative](overview/prebid-universal-creative.html). +1. When a header bidding ad wins, the ad server responds to the page with the [Prebid Universal Creative](https://github.com/prebid/prebid-universal-creative). 1. Which calls the render function in Prebid.js to display the creative. ### Video @@ -49,7 +49,7 @@ The following sections give additional details of the steps provided in the work ### Prebid.js s2sConfig is Placed in the Page -Here's a page example assuming that you're running your own Prebid Server. See [Prebid.js `s2sConfig`](/dev-docs/publisher-api-reference.html#setConfig-Server-to-Server) for more information. Note that this config would handle both banner and video auctions server-side for bidderA and bidderB. +Here's a page example assuming that you're running your own Prebid Server. See [Prebid.js `s2sConfig`](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Server-to-Server) for more information. Note that this config would handle both banner and video auctions server-side for bidderA and bidderB. ``` pbjs.setConfig({ diff --git a/prebid-server/versions/pbs-versions-go.md b/prebid-server/versions/pbs-versions-go.md index 9f6a45ea99..d2de934923 100644 --- a/prebid-server/versions/pbs-versions-go.md +++ b/prebid-server/versions/pbs-versions-go.md @@ -28,7 +28,7 @@ The Go version of Prebid Server is for those who: ## Features -PBS-Go has all the core PBS features, but does have a backlog of newer [features](/prebid-server/features/pbs-feature-idx.html), so you'll want to look over the list to be familiar with the differences. +We recommend you review the [feature comparison list](/prebid-server/features/pbs-feature-idx.html) to familiarize yourself with the differences between this and PBS-Java in deciding which version is right for you. ## Code Repositories diff --git a/prebid-server/versions/pbs-versions-java.md b/prebid-server/versions/pbs-versions-java.md index d024930727..7f68600244 100644 --- a/prebid-server/versions/pbs-versions-java.md +++ b/prebid-server/versions/pbs-versions-java.md @@ -27,7 +27,7 @@ The Java version of Prebid Server is for those who: ## Features -PBS-Java look over the [feature list](/prebid-server/features/pbs-feature-idx.html) to be familiar with the differences. +We recommend you review the [feature comparison list](/prebid-server/features/pbs-feature-idx.html) to familiarize yourself with the differences between this and PBS-Go in deciding which version is right for you. ## Code Repositories diff --git a/prebid-video/video-getting-started.md b/prebid-video/video-getting-started.md index e9a76e3d99..fbc05431c3 100644 --- a/prebid-video/video-getting-started.md +++ b/prebid-video/video-getting-started.md @@ -58,7 +58,7 @@ If you already have a Prebid integration for banner, you don’t need to do anyt Your first step to implementing header bidding for video is to [download Prebid.js]({{site.github.url}}/download.html). Before downloading, select the adapters you want to include. (You can add more adapters later.) - Include at least one video adapter. Find a list of available video adapters [here]({{site.github.url}}/dev-docs/bidders.html#bidder-video-native). -- If Google Ad Manager is your ad server, you must include the [Google Ad Manager Video module]({{site.github.url}}/dev-docs/publisher-api-reference.html#module_pbjs.adServers.dfp.buildVideoUrl). +- If Google Ad Manager is your ad server, you must include the [Google Ad Manager Video module](/dev-docs/publisher-api-reference/adServers.dfp.buildVideoUrl.html). - If you’ll be integrating with Prebid Server, be sure to include “Prebid Server” in the list of adapters. ### Define Prebid Ad Units @@ -71,7 +71,11 @@ Setting up Prebid ad units is almost the same whether you’re working with inst mediaTypes: { video: { context: 'instream', //or 'outstream' - playerSize: [640, 480] + playerSize: [640, 480], + mimes: ['video/mp4'], // required for Prebid Server + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1 } ``` @@ -80,17 +84,6 @@ The mediaTypes.video.playerSize field is where you define the player size that w-``` -Here's a simplified URL: - -``` -/openrtb2/amp?tag_id='ef8299d0-cc32-46cf-abcd-41cebe8b4b85'&w=300&h=250&timeout=500 -``` - -Some endpoint parameters will override parts of the Stored Request. - -1. `ow`, `oh`, `w`, `h`, and/or `ms` will be used to set `request.imp[0].banner.format` if `request.imp[0].banner` is present. -2. `curl` will be used to set `request.site.page` -3. `timeout` will generally be used to set `request.tmax`. However, the Prebid Server host can [configure](https://github.com/prebid/prebid-server/blob/master/docs/developers/configuration.md) their deploy to reduce this timeout for technical reasons. -4. `debug` will be used to set `request.test`, causing the `response.debug` to have extra debugging info in it. +| Checking if app exists. | 999 | The `app` object must not exist in AMP stored requests. | Error is returned. | ### Resolving Sizes @@ -265,15 +208,23 @@ track the logic used by `doubleclick` when resolving sizes used to fetch ads fro Specifically: -1. If `ow` and `oh` exist, `request.imp[0].banner.format` will be a single element with `w: ow` and `h: oh` -2. If `ow` and `h` exist, `request.imp[0].banner.format` will be a single element with `w: ow` and `h: h` -3. If `oh` and `w` exist, `request.imp[0].banner.format` will be a single element with `w: w` and `h: oh` -4. If `ms` exists, `request.imp[0].banner.format` will contain an element for every size it uses. -5. If `w` and `h` exist, `request.imp[0].banner.format` will be a single element with `w: w` and `h: h` -6. If `w` _or_ `h` exist, it will be used to override _one_ of the dimensions inside each element of `request.imp[0].banner.format` -7. If none of these exist then the Stored Request values for `request.imp[0].banner.format` will be used without modification. +1. If `ow` and `oh` exist, `imp[0].banner.format` will be a single element with `w: ow` and `h: oh` +2. If `ow` and `h` exist, `imp[0].banner.format` will be a single element with `w: ow` and `h: h` +3. If `oh` and `w` exist, `imp[0].banner.format` will be a single element with `w: w` and `h: oh` +4. If `ms` exists, `imp[0].banner.format` will contain an element for every size it uses. +5. If `w` and `h` exist, `imp[0].banner.format` will be a single element with `w: w` and `h: h` +6. If `w` _or_ `h` exist, it will be used to override _one_ of the dimensions inside each element of `imp[0].banner.format` +7. If none of these exist then the Stored Request values for `imp[0].banner.format` will be used without modification. + +## Configuration Options + +- settings.generate-storedrequest-bidrequest-id: replace the stored request `id` with a UUID (PBS-Java only) +- amp.default-timeout-ms: default operation timeout for AMP requests +- amp.timeout-adjustment-ms: reduces timeout value passed in AMP request. Can be used to account for estimated latency so that Prebid Server can respond to the AMP RTC request before it times out. +- amp.max-timeout-ms: maximum operation timeout for AMP requests ## Further Reading - [Prebid and AMP](/formats/amp.html) - [Prebid Server AMP Use Case Overview](/prebid-server/use-cases/pbs-amp.html) - [Prebid Server First Party Data](/prebid-server/features/pbs-fpd.html) +- [Stored Requests](/prebid-server/features/pbs-storedreqs.html) diff --git a/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.md b/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.md index 2970c7e481..007d721f2b 100644 --- a/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.md +++ b/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.md @@ -113,7 +113,7 @@ Prebid Server recognizes several standard OpenRTB2.5 fields. #### Currency The `cur` field is read and the first element of the array is taken to be the -"Ad Server Currency" for purposes of [currency conversion](/prebid-server/features/pbs-currency.html). +"Ad Server Currency" for purposes of [currency conversion](/prebid-server/features/pbs-currency.html). #### Expiration @@ -144,40 +144,19 @@ How long an item is stored in Prebid Cache is determined by this hunt path: 4. account config: {banner,video}-cache-ttl 5. global config: cache.{banner,video}-ttl-seconds -#### Test - -This flag triggers Prebid Server to dump additional debug info into the OpenRTB response. e.g. - -``` - "ext": { - "debug": { - "httpcalls": { - "bidderA": [ - ... - ] - }, - "resolvedrequest": { - ... - }, - "responsetimemillis": { - ... - } - ... -``` - #### Privacy fields Prebid Server reads the OpenRTB privacy fields: - regs.coppa -- regs.ext.gdpr +- regs.ext.gdpr - regs.ext.us_privacy - user.ext.consent - device.lmt #### Other OpenRTB Fields -Prebid Server doesn't do any special processing on any other fields, but passes them +Prebid Server doesn't do any special processing on any other fields, but passes them all to the bid and analytics adapters. ### OpenRTB Extensions @@ -203,7 +182,9 @@ Exceptions are made for extensions with "standard" recommendations: - `request.site.ext.amp` -- To identify AMP as the request source - `request.app.ext.source` and `request.app.ext.version` -- To support identifying the displaymanager/SDK in mobile apps. If given, we expect these to be strings. -#### Bid Adjustments +#### OpenRTB Request Extensions + +##### Bid Adjustments Bidders are encouraged to make Net bids. However, there's no way for Prebid to enforce this. If you find that some bidders use Gross bids, publishers can adjust for it with `request.ext.prebid.bidadjustmentfactors`: @@ -213,8 +194,8 @@ If you find that some bidders use Gross bids, publishers can adjust for it with "ext": { "prebid": { "bidadjustmentfactors": { - "appnexus": 0.8, - "rubicon": 0.7 + "bidderA": 0.9, + "bidderB": 0.8 } } } @@ -223,7 +204,34 @@ If you find that some bidders use Gross bids, publishers can adjust for it with This may also be useful for publishers who want to account for different discrepancies with different bidders. -#### Targeting +It's also possible to define different bid adjustment factors by mediatype, which can be helpful to adjust discrepancies that differ across mediatypes (PBS-Java only): +``` +{ + "ext": { + "prebid": { + "bidadjustmentfactors": { + "bidderA": 0.9, + "bidderB": 0.8, + "mediatypes": { + "banner": { + "bidderA": 0.8 + }, + "video-outstream": { + "bidderC": 0.9 + }, + "video": { + "bidderB": 0.85 + } + } + } + } + } +} +``` + +Note that video-outstream is defined to be imp[].video requests where imp[].video.placement is greater than 1. + +##### Targeting Targeting refers to strings which are sent to the adserver to [make header bidding possible](/overview/intro.html#how-does-prebid-work). @@ -231,6 +239,24 @@ Targeting refers to strings which are sent to the adserver to `request.ext.prebid.targeting` is an optional property which causes Prebid Server to set these params on the response at `response.seatbid[i].bid[j].ext.prebid.targeting`. +{: .table .table-bordered .table-striped } +| Attribute | Required? | Description | Example | Type | +| --- | --- | --- | --- | --- | +| pricegranularity | no | Defines how PBS quantizes bid prices into buckets | (see below) | object | +| pricegranularity.precision | no | How many decimal places are there in price buckets | Defaults to 2 | integer | +| pricegranularity.ranges | no | Non-overlapping price bucket definitions | (see below) | array of objects | +| pricegranularity.ranges.max | no | Top end of this range of price buckets. The bottom end is 0 or the max of the previous bucket. Note: in order to prevent ranges with gaps, there's no 'min' attribute. | 5.55 | float | +| pricegranularity.ranges.increment | no | Size of the buckets in this range. | 1.50 | float | +| mediatypepricegranularity | no | Defines how PBS quantizes bid prices into buckets, allowing for different ranges by media type. | (see below) | object | +| mediatypepricegranularity.banner | no | Defines how PBS quantizes bid prices into buckets for banners. | (see below) | object | +| mediatypepricegranularity.video | no | Defines how PBS quantizes bid prices into buckets for video. | (see below) | object | +| mediatypepricegranularity.TYPE.precision | no | How many decimal places are there in price buckets. | Defaults to 2 | integer | +| mediatypepricegranularity.TYPE.ranges | no | Same as pricegranularity.ranges | (see below) | array of objects | +| includewinners | no | Whether to include targeting for the winning bids in response.seatbid[].bid[]. ext.prebid.targeting. Defaults to false. | true | boolean | +| includebidderkeys | no | Whether to include targeting for the best bid from each bidder in response.seatbid[].bid[]. ext.prebid.targeting. Defaults to false. | true | boolean | +| includeformat | no | Whether to include the "hb_format" targeting key. Defaults to false. | false | boolean | +| preferdeals | no | If targeting is returned and this is true, PBS will choose the highest value deal before choosing the highest value non-deal. Defaults to false. | true | boolean | + **Request format** (optional param `request.ext.prebid.targeting`) ``` @@ -242,12 +268,14 @@ to set these params on the response at `response.seatbid[i].bid[j].ext.prebid.ta "precision": 2, "ranges": [{ "max": 20.00, - "increment": 0.10 // This is equivalent to the deprecated "pricegranularity": "medium" + "increment": 0.10 // This is equivalent to the deprecated + // "pricegranularity": "medium" }] }, - "includewinners": false, // Optional param defaulting to true - "includebidderkeys": false // Optional param defaulting to true - "includeformat": false // Optional param defaulting to false + "includewinners": true, // Optional param defaulting to false + "includebidderkeys": false, // Optional param defaulting to false + "includeformat": false, // Optional param defaulting to false + "preferdeals": true // Optional param defaulting to false } } } @@ -257,11 +285,11 @@ The list of price granularity ranges must be given in order of increasing `max` For backwards compatibility the following strings will also be allowed as price granularity definitions. There is no guarantee that these will be honored in the future. "One of ['low', 'med', 'high', 'auto', 'dense']" See [price granularity definitions](/prebid-mobile/adops-price-granularity.html) -One of "includewinners" or "includebidderkeys" must be true (both default to true if unset). If both were false, then no targeting keys would be set, which is better configured by omitting targeting altogether. +One of "includewinners" or "includebidderkeys" must be true (both default to false if unset). If both are false, then no targeting keys will be set, which is better configured by omitting targeting altogether. The parameter "includeformat" indicates the type of the bid (banner, video, etc) for multiformat requests. It will add the key `hb_format` and/or `hb_format_{bidderName}` as per "includewinners" and "includebidderkeys" above. -MediaType PriceGranularity (PBS-Java only) - when a single OpenRTB request contains multiple impressions with different mediatypes, or a single impression supports multiple formats, the different mediatypes may need different price granularities. If `mediatypepricegranularity` is present, `pricegranularity` would only be used for any mediatypes not specified. +MediaType PriceGranularity (PBS-Java only) - when a single OpenRTB request contains multiple impressions with different mediatypes, or a single impression supports multiple formats, the different mediatypes may need different price granularities. If `mediatypepricegranularity` is present, `pricegranularity` would only be used for any mediatypes not specified. ``` { @@ -316,7 +344,7 @@ The winning bid for each `request.imp[i]` will also contain `hb_bidder`, `hb_siz **NOTE**: Targeting keys are limited to 20 characters. If {bidderName} is too long, the returned key will be truncated to only include the first 20 characters. -#### Cookie syncs +##### Buyer UID Each Bidder should receive their own ID in the `request.user.buyeruid` property. Prebid Server has three ways to populate this field. In order of priority: @@ -350,12 +378,12 @@ If you're using [Prebid.js](https://github.com/prebid/Prebid.js), this is happen If you're using another client, you can populate the Cookie of the Prebid Server host with User IDs for each Bidder by using the `/cookie_sync` endpoint, and calling the URLs that it returns in the response. -#### Native Request +##### Native Request For each native request, the `assets` object's `id` field is optional and if not defined, Prebid Server will set this automatically, using the index of the asset in the array as the ID. -#### Bidder Aliases +##### Bidder Aliases Requests can define Bidder aliases if they want to refer to a Bidder by a separate name. This can be used to request bids from the same Bidder with different params. For example: @@ -396,85 +424,34 @@ This prevents breaking API changes as new Bidders are added to the project. For example, if the Request defines an alias like this: ``` - "aliases": { - "appnexus": "rubicon" - } +"aliases": { + "appnexus": "rubicon" +} ``` then any `imp.ext.appnexus` params will actually go to the **rubicon** adapter. It will become impossible to fetch bids from AppNexus within that Request. -#### Bidder Alias GVL IDs (PBS-Java only) +##### Bidder Alias GVL IDs (PBS-Java only) For environments that have turned on [GDPR enforcement](/prebid-server/features/pbs-privacy.html#gdpr), it can be important to define the Global Vendor List (GVL) ID with an alias. To do this, just set `ext.prebid.aliasgvlids` alongside ext.prebid.aliases: ``` -"ext": +"ext": { "prebid": { - "aliases": { "newAlias": "originalBidderCode" }, - "aliasgvlids": { "newAlias": 11111 } - } - } -}); -``` - -#### Bidder Response Times - -`response.ext.responsetimemillis.{bidderName}` tells how long each bidder took to respond. -These can help quantify the performance impact of "the slowest bidder." - -#### Bidder Errors - -`response.ext.errors.{bidderName}` contains messages which describe why a request may be "suboptimal". -For example, suppose a `banner` and a `video` impression are offered to a bidder -which only supports `banner`. - -In cases like these, the bidder can ignore the `video` impression and bid on the `banner` one. -However, the publisher can improve performance by only offering impressions which the bidder supports. - -For example, a request may return this in `response.ext` - -``` -{ - "ext": { - "errors": { - "appnexus": [{ - "code": 2, - "message": "A hybrid Banner/Audio Imp was offered, but Appnexus doesn't support Audio." - }], - "rubicon": [{ - "code": 1, - "message": "The request exceeded the timeout allocated" - }] + "aliases": { + "newAlias": "originalBidderCode" + }, + "aliasgvlids": { + "newAlias": 11111 } } } ``` -The codes currently defined are: - -``` -0 NoErrorCode -1 TimeoutCode -2 BadInputCode -3 BadServerResponseCode -999 UnknownErrorCode -``` - -#### Debugging - -`response.ext.debug.httpcalls.{bidder}` will be populated **only if** `request.test` **was set to 1**. - -This contains info about every request and response sent by the bidder to its server. -It is only returned on `test` bids for performance reasons, but may be useful during debugging. - -`response.ext.debug.resolvedrequest` will be populated **only if** `request.test` **was set to 1**. - -This contains the request after the resolution of stored requests and implicit information (e.g. site domain, device user agent). - -#### Stored Requests +##### Stored Requests `request.imp[i].ext.prebid.storedrequest` incorporates a [Stored Request](/prebid-server/features/pbs-storedreqs.html) from the server. @@ -496,7 +473,7 @@ A typical `storedrequest` value looks like this: For more information, see the docs for [Stored Requests](/prebid-server/features/pbs-storedreqs.html). -#### Cache bids +##### Cache bids Bids can be temporarily cached on the server by sending instructions in `request.ext.prebid.cache`: @@ -532,7 +509,7 @@ If they exist, the values can be used to fetch the bid's VAST XML from Prebid Ca These options are mainly intended for certain limited Prebid Mobile setups, where bids cannot be cached client-side. -#### GDPR +##### GDPR Prebid Server supports the IAB's GDPR recommendations, which can be found [here](https://iabtechlab.com/wp-content/uploads/2018/02/OpenRTB_Advisory_GDPR_2018-02.pdf). @@ -543,7 +520,7 @@ This adds two optional properties: These fields will be forwarded to each Bidder, so they can decide how to process them. -#### Interstitial support +##### Interstitial support Additional support for interstitials is enabled through the addition of two fields to the request: device.ext.prebid.interstitial.minwidthperc and device.ext.interstial.minheightperc The values will be numbers that indicate the minimum allowed size for the ad, as a percentage of the base side. For example, a width of 600 and "minwidthperc": 60 would allow ads with widths from 360 to 600 pixels inclusive. @@ -553,12 +530,10 @@ Example: { "imp": [{ ... - "banner": { - ... - } + "banner": { ... }, "instl": 1, ... - }] + }], "device": { ... "h": 640, @@ -578,25 +553,25 @@ Example: PBS receiving a request for an interstitial imp and these parameters set, it will rewrite the format object within the interstitial imp. If the format array's first object is a size, PBS will take it as the max size for the interstitial. If that size is 1x1, it will look up the device's size and use that as the max size. If the format is not present, it will also use the device size as the max size. (1x1 support so that you don't have to omit the format object to use the device size) PBS with interstitial support will come preconfigured with a list of common ad sizes. Preferentially organized by weighing the larger and more common sizes first. But no guarantees to the ordering will be made. PBS will generate a new format list for the interstitial imp by traversing this list and picking the first 10 sizes that fall within the imp's max size and minimum percentage size. There will be no attempt to favor aspect ratios closer to the original size's aspect ratio. The limit of 10 is enforced to ensure we don't overload bidders with an overlong list. All the interstitial parameters will still be passed to the bidders, so they may recognize them and use their own size matching algorithms if they prefer. -#### Currency Support +##### Currency Support To set the desired 'ad server currency', use the standard OpenRTB `cur` attribute. Note that Prebid Server only looks at the first currency in the array. ``` - "cur": ["USD"] +"cur": ["USD"] ``` If you want or need to define currency conversion rates (e.g. for currencies that your Prebid Server doesn't support), -define ext.prebid.currency.rates. (Currently supported in PBS-Java only) +define ext.prebid.currency.rates. ``` "ext": { "prebid": { - "currency": { - "rates": { - "USD": { "UAH": 24.47, "ETB": 32.04 } - } - } + "currency": { + "rates": { + "USD": { "UAH": 24.47, "ETB": 32.04 } + } + } } } ``` @@ -604,62 +579,89 @@ define ext.prebid.currency.rates. (Currently supported in PBS-Java only) If it exists, a rate defined in ext.prebid.currency.rates has the highest priority. If a currency rate doesn't exist in the request, the external file will be used. -#### Supply Chain Support +##### Supply Chain Support Basic supply chains are passed to Prebid Server on `source.ext.schain` and passed through to bid adapters. Prebid Server does not currently offer the ability to add a node to the supply chain. -Bidder-specific schains (PBS-Java only): +Bidder-specific schains: ``` -ext.prebid.schains: [ - { bidders: ["bidderA"], schain: { SCHAIN OBJECT 1}}, - { bidders: ["*"], schain: { SCHAIN OBJECT 2}} +"ext.prebid.schains": [ + { "bidders": ["bidderA"], "schain": { SCHAIN OBJECT 1}}, + { "bidders": ["*"], "schain": { SCHAIN OBJECT 2}} ] ``` In this scenario, Prebid Server sends the first schain object to `bidderA` and the second schain object to everyone else. If there's already an source.ext.schain and a bidder is named in ext.prebid.schains (or covered by the wildcard condition), ext.prebid.schains takes precedent. -#### User IDs +##### User IDs -Prebid Server adapters can support the [Prebid.js User ID modules](http://prebid.org/dev-docs/modules/userId.html) by reading the following extensions and passing them through to their server endpoints: +Prebid Server adapters can support the [Prebid.js User ID modules](/dev-docs/modules/userId.html) by reading the following extensions and passing them through to their server endpoints: ``` { - "user": { - "ext": { - "eids": [{ - "source": "adserver.org", - "uids": [{ - "id": "111111111111", - "ext": { - "rtiPartner": "TDID" - } - }] - }, - { - "source": "pubcommon", - "id":"11111111" - } - ] - } + "user": { + "ext": { + "eids": [{ + "source": "adserver.org", + "uids": [{ + "id": "111111111111", + "ext": { + "rtiPartner": "TDID" + } + }] + }, + { + "source": "pubcid.org", + "id":"11111111" + }] + } + } +} +``` + +##### EID Permissions + +Publishers can constrain which bidders receive which user.ext.eids entries. See the [Prebid.js user ID permissions](/dev-docs/modules/userId.html#permissions) reference for background. + +``` +{ + "ext": { + "prebid": { + "data": { + "eidpermissions": [ // prebid server will use this to filter user.ext.eids + {"source": "sharedid.org", "bidders": ["*"]}, // * is the default + {"source": "neustar.biz", "bidders": ["bidderB"]}, + {"source": "id5-sync.com", "bidders": ["bidderA","bidderC"]} + ] + } } + } } ``` -#### Rewarded Video (PBS-Java only) +ext.prebid.data.eidpermissions is an array of objects that can contain these attributes: + +{: .table .table-bordered .table-striped } +| Attribute | Required? | Description | Example | Type | +| --- | --- | --- | --- | --- | +| source | Yes | Which user.ext.eids.source is receiving the permissions | "sharedid.org" | string | +| bidders | Yes | Which bidders are allowed to receive the named eid source | ["bidderA", "bidderC"] | array of strings | + +##### Rewarded Video (PBS-Java only) Rewarded video is a way to incentivize users to watch ads by giving them 'points' for viewing an ad. A Prebid Server client can declare a given adunit as eligible for rewards by declaring `imp.ext.prebid.is_rewarded_inventory:1`. -#### Debug Flag +##### Debug Flag The OpenRTB `test` flag has a special meaning that bidders may react to: they may not perform a normal auction, or may not pay for test requests. -You can turn on the extra Prebid Server debug log without the formal `test` behavior by instead setting `ext.prebid.debug:1`. +You can turn on the extra Prebid Server debug log without the formal `test` behavior by instead setting `ext.prebid.debug: true`. -#### Stored Responses (PBS-Java only) +##### Stored Responses (PBS-Java only) While testing SDK and video integrations, it's important, but often difficult, to get consistent responses back from bidders that cover a range of scenarios like different CPM values, deals, etc. Prebid Server supports a debugging workflow in two ways: @@ -677,24 +679,34 @@ When a storedauctionresponse ID is specified: This request: ``` { - "test":1, - "tmax":500, + "test": 1, + "tmax": 500, "id": "test-auction-id", "app": { ... }, "ext": { - "prebid": { - "targeting": {}, - "cache": { "bids": {} } - } + "prebid": { + "targeting": {}, + "cache": { + "bids": {} + } + } }, "imp": [ { "id": "a", - "ext": { "prebid": { "storedauctionresponse": { "id": "1111111111" } } } + "ext": { + "prebid": { + "storedauctionresponse": { "id": "1111111111" } + } + } }, { "id": "b", - "ext": { "prebid": { "storedauctionresponse": { "id": "22222222222" } } } + "ext": { + "prebid": { + "storedauctionresponse": { "id": "22222222222" } + } + } } ] } @@ -703,16 +715,16 @@ This request: Will result in this response, assuming that the ids exist in the appropriate DB table read by Prebid Server: ``` { - "id": "test-auction-id", - "seatbid": [ - { - // BidderA bids from storedauctionresponse=1111111111 - // BidderA bids from storedauctionresponse=22222222 - }, - { - // BidderB bids from storedauctionresponse=1111111111 - // BidderB bids from storedauctionresponse=22222222 - } + "id": "test-auction-id", + "seatbid": [ + { + // BidderA bids from storedauctionresponse=1111111111 + // BidderA bids from storedauctionresponse=22222222 + }, + { + // BidderB bids from storedauctionresponse=1111111111 + // BidderB bids from storedauctionresponse=22222222 + } ] } ``` @@ -723,37 +735,37 @@ In contrast to what's outlined above, this approach lets some real auctions take ``` { - "test":1, - "tmax":500, + "test": 1, + "tmax": 500, "id": "test-auction-id", "app": { ... }, "ext": { - "prebid": { - "targeting": {}, - "cache": { "bids": {} } - } + "prebid": { + "targeting": {}, + "cache": { "bids": {} } + } }, "imp": [ { "id": "a", "ext": { - "prebid": { - "storedbidresponse": [ - { "bidder": "BidderA", "id": "333333" }, - { "bidder": "BidderB", "id": "444444" }, - ] - } + "prebid": { + "storedbidresponse": [ + { "bidder": "BidderA", "id": "333333" }, + { "bidder": "BidderB", "id": "444444" }, + ] + } } }, { "id": "b", "ext": { - "prebid": { - "storedbidresponse": [ - { "bidder": "BidderA", "id": "5555555" }, - { "bidder": "BidderB", "id": "6666666" }, - ] - } + "prebid": { + "storedbidresponse": [ + { "bidder": "BidderA", "id": "5555555" }, + { "bidder": "BidderB", "id": "6666666" }, + ] + } } } ] @@ -763,18 +775,18 @@ Could result in this response: ``` { - "id": "test-auction-id", - "seatbid": [ - { - "bid": [ - // contents of storedbidresponse=3333333 as parsed by bidderA adapter - // contents of storedbidresponse=5555555 as parsed by bidderA adapter - ] - }, - { - // contents of storedbidresponse=4444444 as parsed by bidderB adapter - // contents of storedbidresponse=6666666 as parsed by bidderB adapter - } + "id": "test-auction-id", + "seatbid": [ + { + "bid": [ + // contents of storedbidresponse=3333333 as parsed by bidderA adapter + // contents of storedbidresponse=5555555 as parsed by bidderA adapter + ] + }, + { + // contents of storedbidresponse=4444444 as parsed by bidderB adapter + // contents of storedbidresponse=6666666 as parsed by bidderB adapter + } ] } ``` @@ -784,7 +796,7 @@ Setting up the storedresponse DB entries is the responsibility of each Prebid Se See Prebid.org troubleshooting pages for how to utilize this feature within the context of the browser. -#### First Party Data Support (PBS-Java only) +##### First Party Data Support (PBS-Java only) This is the Prebid Server version of the Prebid.js First Party Data feature. It's a standard way for the page (or app) to supply first party data and control which bidders have access to it. @@ -792,69 +804,89 @@ It specifies where in the OpenRTB request non-standard attributes should be pass ``` { + "ext": { + "prebid": { + "data": { "bidders": [ "rubicon", "appnexus" ] } // these are the bidders allowed to see protected data + } + }, + "site": { + "keywords": "", + "search": "", "ext": { - "prebid": { - "data": { "bidders": [ "rubicon", "appnexus" ] } // these are the bidders allowed to see protected data - } - }, - "site": { - "keywords": "", - "search": "", - "ext": { - data: { GLOBAL CONTEXT DATA } // only seen by bidders named in ext.prebid.data.bidders[] - } - }, - "user": { - "keywords": "", - "gender": "", - "yob": 1999, - "geo": {}, - "ext": { - data: { GLOBAL USER DATA } // only seen by bidders named in ext.prebid.data.bidders[] + "data": { GLOBAL SITE DATA } // only seen by bidders named in ext.prebid.data.bidders[] + } + }, + "user": { + "keywords": "", + "gender": "", + "yob": 1999, + "geo": {}, + "ext": { + "data": { GLOBAL USER DATA } // only seen by bidders named in ext.prebid.data.bidders[] + } + }, + "imp": [ + { + ... + "ext": { + "data": { + ADUNIT SPECFIC CONTEXT DATA // can be seen by all bidders } + } + } + ] +} +``` + +Bidder-specific data can be defined with ext.prebid.bidderconfig: +``` +"ext": { + "prebid": { + "bidderconfig": { + "bidders": ["bidderA", "bidderB"] }, - "imp": [ - "ext": { - "context": { - "keywords": "", - "search": "", - "data": { ADUNIT SPECFIC CONTEXT DATA } // can be seen by all bidders - } - } - ] + "config": { + "ortb2": { + "site": { ... }, + "user": { ... } + } + } + } +} ``` -Prebid Server enforces the data permissioning. So before passing the values to the bidder adapters, the PBS core will: +Prebid Server enforces data permissioning. So before passing values to the bidder adapters, the PBS core will: -1. check for ext.prebid.data.bidders -1. if it exists, store it locally, but remove it from the OpenRTB before being sent to the adapters +1. Check for ext.prebid.bidderconfig + 1. If it exists, merge config.ortb2 into the bidder-specific request 1. As the OpenRTB request is being sent to each adapter: - 1. if ext.prebid.data.bidders exists in the original request, and this bidder is on the list then copy site.ext.data, app.ext.data, and user.ext.data to their bidder request -- otherwise don't copy those blocks + 1. If ext.prebid.data.bidders exists in the original request and this bidder is on the list, then copy site.content.data, site.ext.data, app.ext.data, user.data, and user.ext.data to the bidder request -- otherwise don't copy those blocks. Remove ext.prebid.data.bidders from the bidder-specific request 1. copy other objects as normal -Each adapter must be coded to read the values from these locations and pass it to their endpoints appropriately. +Each adapter must be coded to read the values from the ortb and pass it to their endpoints appropriately. -#### Custom Targeting (PBS-Java only) +##### Custom Targeting (PBS-Java only) An OpenRTB extension, whether in the the original request or the [stored-request](/prebid-server/features/pbs-storedreqs.html), can customize the ad server targeting generated by PBS. The OpenRTB field is `ext.prebid.adservertargeting`. Here's an example: ``` - ext.prebid.adservertargeting: [{ - "key": "hb_amp_ow", // the targeting key - "source": "bidrequest", // pull the value from the path specified in the bid request object - "value": "ext.prebid.amp.data.ow" // path to value in the bidrequest - },{ - "key": "hb_static_thing", - "source": "static", // just use the 'value' provided - "value": "my-static-value" - },{ - "key": "{{BIDDER}}_custom1", // {{BIDDER}} is a macro to be resolved - "source": "bidresponse", // pull the value from the path specified in the bid response object - "value": "seatbid.bid.ext.custom1" - } - }] +"ext.prebid.adservertargeting": [ + { + "key": "hb_amp_ow", // the targeting key + "source": "bidrequest", // pull the value from the path specified in the bid request object + "value": "ext.prebid.amp.data.ow" // path to value in the bidrequest + },{ + "key": "hb_static_thing", + "source": "static", // just use the 'value' provided + "value": "my-static-value" + },{ + "key": "{% raw %}{{BIDDER}}{% endraw %}_custom1", // {% raw %}{{BIDDER}}{% endraw %} is a macro to be resolved + "source": "bidresponse", // pull the value from the path specified in the bid response object + "value": "seatbid.bid.ext.custom1" + } +] ``` `ext.prebid.adservertargeting` is an array objects. Each object has the following format: @@ -867,32 +899,305 @@ The OpenRTB field is `ext.prebid.adservertargeting`. Here's an example: In order to pull AMP parameters out into targeting, Prebid Server places AMP query string parameters in ext.prebid.amp.data. e.g. ``` +"ext": { + "prebid": { + "amp": { + "data": { + "adc": "GA1.2.662776284.1602172186", + "curl": "https://example.com/index.html", + "debug": "1", + "pvid": "", // page view ID + "ms": "", // multi-size + "ow": "", // override-width + "oh": "", // override-height + "w": "300", + "h": "50", + "gdpr_consent": "", + "purl": "https://example.com/index.html", + "slot": "/11111/amp_test", + "timeout": "1000", + "targeting": "{\"site\":{\"attr\":\"val\"}}", + "tag_id": "amp-AMP_Test-300x250", + "account": "22222" + } + } + } +} +``` + +##### EID Permissions (PBS-Go only) + +This feature allows publishers to specify ext.prebid.eidpermissions, defining which extended ID +in user.ext.eids is allowed to be passed to which bid adapter. For example: + +``` +{ + "ext": { + "prebid": { + "data": { + "eidpermissions": [ // prebid server will use this to filter user.ext.eids + {"source": "sharedid.org", "bidders": ["*"]}, // * is the default + {"source": "neustar.biz", "bidders": ["bidderB"]}, + {"source": "id5-sync.com", "bidders": ["bidderA","bidderC"]} + ] + } + } + } +} +``` + +##### MultiBid (PBS-Java only) + +Allows a single bidder to bid more than once into an auction and have extra bids passed +back to the client. + +See the [Prebid.js MultiBid Module](/dev-docs/modules/multibid.html) for background information and use cases. + +The Prebid extension to the OpenRTB protocol is `ext.prebid.multibid`. For example: + +``` +{ + "ext": { + "prebid": { + "multibid": [{ + "bidder": "bidderA", + "maxbids": 2, + "targetbiddercodeprefix": "bidA" + }, { + "bidder": "bidderB", + "maxbids": 3, + "targetbiddercodeprefix": "bidB" + }, { + "bidders": ["bidderC", "bidderD"], + "maxbids": 2 + }] + } + } +} +``` + +MultiBid parameter details: + +{: .table .table-bordered .table-striped } +| Attribute | Required? | Description | Example | Type | +| --- | --- | --- | --- | --- | +| bidder | Yes, unless bidders is specified | A biddercode | `'bidderA'` | string | +| bidders | Yes, unless bidder is specified | Multiple biddercodes | `['bidderB','bidderC']` | array of strings | +| maxBids | Yes | The number of bids the named bidder(s) can supply. Max of 9. | `2` | integer | +| targetBiddercodePrefix | No | An alternate (short) bidder code to send to the ad server. A number will be appended, starting from 2, e.g. hb_pb_PREFIX2. If not provided, the extra bids will not go to the ad server. | `'bidA'` | string | + +Prebid Server core does the following when it sees `ext.prebid.multibid`: + +1. Before sending the request to bid adapters, it removes all entries from the multibid array except the one for that particular bid adapter. This lets the bid adapters be aware of how many bids they're going to be allowed to submit into the auction. +2. Lets any additional bids through the OpenRTB response on `seatbid[].bid[]`. +3. Adds the additional specified targeting on `seatbid[].bid[].ext.prebid.targeting` and repeats the biddercode used for targeting on `seatbid[].bid[].ext.prebid.targetbiddercode`. + +Here's an example response: +``` +{ + "seatbid": [{ + "seat": "bidderA", + "bid": [{ + "id": "bid1", + "impid": "imp1", + "price": 1.04, + "ext": { + "prebid": { + "targeting": { + "hb_pb_bidderA": 1.00 + }, + "targetbiddercode": "bidderA" + } + } + ... + }, { + "id": "bid2", + "impid": "imp1", // same imp as above + "price": 0.8, + "ext": { + "prebid": { + "targeting": { + "hb_pb_bidA2": 0.50 + }, + "targetbiddercode": "bidA2" + } + } + ... + }] + }] +} +``` + +##### Echo StoredRequest Video Attributes (PBS-Java only) + +Several video specific fields can be set in the Stored Request that +the device player would not have context to at time of render. +The requester (e.g. Prebid SDK) can send this signal to Prebid Server, +which causes PBS-core to place the video-related attributes on the response. + +``` +{ + ... + "imp": [{ + "id": "123456789", + "video": { + ... + }, "ext": { - "prebid": { - "amp": { - "data": { - "adc": "GA1.2.662776284.1602172186", - "curl": "https://example.com/index.html", - "debug": "1", - "pvid": "", // page view ID - "ms": "", // multi-size - "ow": "", // override-width - "oh": "", // override-height - "w": "300", - "h": "50", - "gdpr_consent": "", - "purl": "https://example.com/index.html", - "slot": "/11111/amp_test", - "timeout": "1000", - "targeting": "{\"site\":{\"attr\":\"val\"}}", - "tag_id": "amp-AMP_Test-300x250", - "account": "22222" - } - } - } + "prebid": { + "storedrequest": { + "id": "xxx" + }, + "options": { + "echovideoattrs": true + } + } + }, + ... + }] + ... +} +``` +1. Prebid Server receives this request and expands the `storedrequest` value, merging it with the imp object. +2. Because `echovideoattrs` is true, video parameters in the storedrequest imp[].video are copied to seatbid.bid.ext.prebid.storedrequestattributes. + +``` +{ + "seatbid": [{ + "bid": [{ + ... + "ext": { + "prebid": { + "storedrequestattributes": { + "maxduration": 60, + "mimes": ["video/mp4"], + "minduration": 15, + "protocols": [1, 2], + "skipafter": 0, + "skipmin": 0, + "startdelay": 0, + "playbackmethod": [1] + } + } + } + }] + }], + ... +} +``` + +#### OpenRTB Response Extensions + +##### Bidder Response Times + +`response.ext.responsetimemillis.{bidderName}` tells how long each bidder took to respond. +These can help quantify the performance impact of "the slowest bidder." + +##### Bidder Errors + +`response.ext.errors.{bidderName}` contains messages which describe why a request may be "suboptimal". +For example, suppose a `banner` and a `video` impression are offered to a bidder +which only supports `banner`. + +In cases like these, the bidder can ignore the `video` impression and bid on the `banner` one. +However, the publisher can improve performance by only offering impressions which the bidder supports. + +For example, a request may return this in `response.ext` + +``` +{ + "ext": { + "errors": { + "appnexus": [{ + "code": 2, + "message": "A hybrid Banner/Audio Imp was offered, but Appnexus doesn't support Audio." + }], + "rubicon": [{ + "code": 1, + "message": "The request exceeded the timeout allocated" + }] } + } +} +``` + +The codes currently defined are: + +``` +0 NoErrorCode +1 TimeoutCode +2 BadInputCode +3 BadServerResponseCode +999 UnknownErrorCode +``` + +##### Ad Server Targeting + +Prebid Server will generate ad server targeting variables as defined by request parameters: + +1. If ext.prebid.targeting.includewinners is true, seatbid.bid.ext.prebid.targeting will be defined for the top bid in each imp object and will carry the following targeting values: hb_pb, hb_size, and hb_bidder. +1. If ext.prebid.targeting.includebidderkeys is true, seatbid.bid.ext.prebid.targeting will be defined for the top bid from each bidder in each imp object and will carry the following targeting values: hb_pb_BIDDER and hb_size_BIDDER. +1. If ext.prebid.cache.bids is specified, any targeting objects will also contain hb_cache_id, hb_cache_id_BIDDER, hb_cache_host, and hb_cache_path. +1. If ext.prebid.cache.vastxml is specified, any targeting objects will also contain hb_uuid, hb_uuid_BIDDER, hb_cache_host, and hb_cache_path. +1. If the bid response defines a deal, any targeting objects will also contain hb_deal or hb_deal_BIDDER +1. If ext.prebid.adservertargeting is defined, arbitrary targeting values may be specified. + +``` +{ + "seatbid": [{ + "seat": "bidderA", + "bid": [{ + "id": "bid1", + "impid": "imp1", + "price": 1.04, + "ext": { + "prebid": { + "targeting": { + "hb_pb": 1.00, // values without prefixes on the winning bids only + "hb_pb_bidderA": 1.00, // only if includebidderkeys is true + "hb_bidder": "bidderA", + "hb_size": "300x250", + "hb_size_bidderA": "300x250", + "hb_format": "video", // only if includeformat is specified + "hb_deal": "123" // only if bid response contains a deal + } + } + } + ... + }] + }] +} ``` +##### Debug Output + +`response.ext.debug.httpcalls.{bidder}` will be populated only if `test:1` or `ext.prebid.debug:true`. + +This contains info about every request and response sent by the bidder to its server. +It is only returned on `test` bids for performance reasons, but may be useful during debugging. + +`response.ext.debug.resolvedrequest` will be populated **only if** `request.test` **was set to 1**. + +This contains the request after the resolution of stored requests and implicit information (e.g. site domain, device user agent). + +``` +"ext": { + "debug": { + "httpcalls": { + "bidderA": [ ... ] + }, + "resolvedrequest": { ... }, + "responsetimemillis": { ... } + ... + } +} +``` + +##### Original Bid CPM (PBS-Java only) + +`response.seatbid[].bid[].ext.origbidcpm` and `response.seatbid[].bid[].ext.origbidcur` will contain the original bid price/currency from the bidder. +The value in seatbid[].bid[].price may be converted for currency and adjusted with a [bid adjustment factor](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bid-adjustments). + ### OpenRTB Ambiguities This section describes the ways in which Prebid Server **implements** OpenRTB spec ambiguous parts. @@ -900,7 +1205,6 @@ This section describes the ways in which Prebid Server **implements** OpenRTB sp - `request.cur`: If `request.cur` is not specified in the bid request, Prebid Server will consider it as being `USD` whereas OpenRTB spec doesn't mention any default currency for bid request. ```request.cur: ['USD'] // Default value if not set``` - ### OpenRTB Differences This section describes the ways in which Prebid Server **breaks** the OpenRTB spec. @@ -933,6 +1237,74 @@ In the OpenRTB spec, `request.imp[i].secure` says: In Prebid Server, an `https` request which does not define `secure` will be forwarded to Bidders with a `1`. Publishers who run `https` sites and want insecure ads can still set this to `0` explicitly. +### HTTP Headers + +In order to facilitate compatibility and analytics, Prebid Server will add the x-prebid HTTP header to outgoing requests. Some examples: + +``` +x-prebid: pbs-go/0.155 +x-prebid: pbjs/4.39,pbs-go/0.155 +x-prebid: prebid-mobile/1.2.3,pbs-java/1.64 +``` + +The PBJS version comes from ext.prebid.channel: `{name: "pbjs", version: "4.39"}` + +The Prebid SDK version comes from: +``` +"app.ext.prebid": { + "source": "prebid-mobile" + "version": "1.2.3" +} +``` + + +### Prebid Server ORTB2 Extension Summary + +{: .table .table-bordered .table-striped } +| Req/Resp | Extension | Description | Type | Example | Adapter Sees? | +| --- | --- | --- | --- | --- | --- | +| req | imp[].ext.prebid. bidder.BIDDER | bidder parameters | object | imp[].ext. prebid.bidder. biddera: { placement: 123 } | They see the object as imp[].ext.bidder | +| req | imp[].ext.BIDDER | DEPRECATED place to put bidder parameters | object | imp[].ext. prebid.bidder. biddera: { placement: 123 } | They see the object as imp[].ext.bidder | +| req | imp[].ext.prebid. storedrequest.id | look up the defined stored request and merge the DB contents with this imp | object | see [stored requests](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#stored-requests) | no | +| req | imp[].ext.prebid. storedauctionresponse | PBS-Core skips the auction and uses the response in the DB instead | object | see [stored responses](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#stored-responses-pbs-java-only) | no | +| req | imp[].ext.prebid. is_rewarded_inventory | passed through to bid adapters | integer | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#rewarded-video-pbs-java-only) | yes | +| req | imp[].ext.data.ATTR | Publisher-specific adunit-level first party data | any | "pmp_elig": true | yes | +| req | app.ext.source | defined by Prebid SDK | string | "prebid-mobile" | yes | +| req | app.ext.version | defined by Prebid SDK | string | "1.6" | yes | +| req | ext.prebid.bidadjustmentfactors | Adjust the CPM value of bidrequests | object | See [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bid-adjustments) | no | +| req | ext.prebid.targeting | defines the targeting values PBS-core places in seatbid.bid.ext.prebid.targeting | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#targeting) | no | +| req | ext.prebid.adservertargeting | advanced targeting value rules | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#custom-targeting-pbs-java-only) | no | +| req | ext.prebid.integration | host-dependent integration type passed through to events and analytics | string | "managed" | yes | +| req | ext.prebid.channel | Generally "pbjs", "amp", or "app". Passed through to events and analytics | object | {name: "pbjs", version: "4.39"} | yes | +| req | ext.prebid.aliases | defines alternate names for bidders | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bidder-aliases) | yes | +| req | ext.prebid.debug | provides debug output in response | boolean | true | yes | +| req | ext.prebid.cache | defines whether to put bid results in Prebid Cache | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#cache-bids) | no | +| req | ext.prebid.schains | bidder-specific supply chains | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#supply-chain-support) | no | +| req | ext.prebid.data.bidders | bidders in scope for bidder-specific first party data | array of strings | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#first-party-data-support-pbs-java-only) | no | +| req | ext.prebid.bidderconfig | bidder-specific first party data | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#first-party-data-support-pbs-java-only) | no | +| req | ext.prebid.currency | publisher-defined currency conversions | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#currency-support) | yes | +| req | ext.prebid.no-sale | turns off CCPA processing for the named bidder(s) | array of strings | ["bidderA"] | no | +| req | ext.prebid.interstitial | PBS-core will adjust the sizes on a request for interstitials | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#interstitial-support) | yes | +| req | ext.prebid.auctiontimestamp | timestamp for use in correlating PBJS and PBS events | long int | 123456789 | yes | +| req | ext.prebid.options. echovideoattrs | causes PBS-core to [echo video attributes](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#echo-storedrequest-video-attributes-pbs-java-only) on seatbid[].bid[].ext.prebid.storedrequestattributes so the player has access to them | boolean | true | yes | +| req | ext.prebid.multibid | allows bidders to respond with more than one bid | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#multibid-pbs-java-only) | yes, but only their value | +| req | ext.prebid.buyeruid | An alternate to [/cookie_sync](/prebid-server/endpoints/pbs-endpoint-cookieSync.html), the request can supply bidder ID values | object | See [doc](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#buyer-uid) | no | +| resp | seatbid[].bid[].ext. prebid.targeting | ad server targeting values. Related to req ext.prebid.targeting. | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#ad-server-targeting) | n/a | +| resp | seatbid[].bid[].ext.prebid. type | "banner", "video", "native" | string | "banner" | n/a | +| resp | seatbid[].bid[].ext.prebid. cache.bids.url | URL location of the bid or VAST | string | URL | n/a | +| resp | seatbid[].bid[].ext.prebid. cache.bids.cacheId | ID of the bid or VAST | string | "1234" | n/a | +| resp | seatbid[].bid[].ext.prebid. events.win | URL for registering a BIDS_WON event for this bid | string | URL | n/a | +| resp | seatbid[].bid[].ext.prebid. events.imp | URL for registering an impression event for this bid | string | URL | n/a | +| resp | seatbid[].bid[].ext.prebid. bidid | defines a Prebid-generated id for this bid in case the bidder's ID isn't unique | string | UUID | n/a | +| resp | seatbid[].bid[].ext.prebid. meta.ATTR | bidder-supplied metadata | object | see [docs](/prebid-server/developers/add-new-bidder-go.html) | n/a | +| resp | seatbid[].bid[].ext.prebid. storedrequestattributes | results of the ext.prebid.options.echovideoattrs option above. | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#echo-storedrequest-video-attributes-pbs-java-only) | n/a | +| resp | response.seatbid[].bid[].ext. origbidcpm | a copy of the unadjusted bid price | float | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#original-bid-cpm-pbs-java-only) | n/a | +| resp | response.seatbid[].bid[].ext. origbidcur | a copy of the original bid currency | string | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#original-bid-cpm-pbs-java-only) | n/a | +| resp | ext.responsetimemillis.BIDDER | debug mode: how long the named bidder took to respond with a bid | integer | 100 | n/a | +| resp | ext.debug.httpcalls.BIDDER | debug mode: the HTTP request/response from the named bidder | object | | n/a | +| resp | ext.errors.BIDDER | debug mode: errors from the named bidder | object | | n/a | +| resp | ext.debug | debug mode: useful output | object | see [docs](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#debug-output)| n/a | + ### Further Reading - [The OpenRTB 2.5 spec](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf) diff --git a/prebid-server/endpoints/openrtb2/pbs-endpoint-video.md b/prebid-server/endpoints/openrtb2/pbs-endpoint-video.md index 259056b01e..c8eb75a9cc 100644 --- a/prebid-server/endpoints/openrtb2/pbs-endpoint-video.md +++ b/prebid-server/endpoints/openrtb2/pbs-endpoint-video.md @@ -110,7 +110,7 @@ These key-values are returned to the SSAI server as part of the video response. | pricegranularity.ranges | Optional (recommended) | `Object[]` | See [price range](#price-range) for details. | | regs | Optional | `Object` | Container object for data related to various regulations. See the [Regulations](#price-range) section below for more details. | | regs.ext.gdpr | Optional | `Integer` | Enable the user to indicate whether GDPR is in effect. `0` for disabled, `1` for enabled. The default setting is disabled. See the [Regulations](#price-range) section below for more details. | -| regs.ext.us_privacy | Optional | `String` | Enables the user to apply California Consumer Protection Act (CCPA) settings per [IAB standards for U.S. Privacy](https://iabtechlab.com/wp-content/uploads/2019/11/OpenRTB-Extension-U.S.-Privacy-IAB-Tech-Lab.pdf). See the [Regulations](#price-range) section below for more details. | +| regs.ext.us_privacy | Optional | `String` | Enables the user to apply California Consumer Protection Act (CCPA) settings per [IAB standards for U.S. Privacy](https://iabtechlab.com/standards/ccpa/). See the [Regulations](#price-range) section below for more details. | ### Pod Duration Range @@ -243,7 +243,7 @@ Publishers can comply with CCPA regulations by setting `regs.ext.us.privacy` to ] }, "site": { - "page": "http://www.foobar.com/1234.html" + "page": "https://www.foobar.com/1234.html" }, "user": { "yob": 1982, diff --git a/prebid-server/endpoints/pbs-endpoint-admin.md b/prebid-server/endpoints/pbs-endpoint-admin.md index 15f77672ab..bca308651e 100644 --- a/prebid-server/endpoints/pbs-endpoint-admin.md +++ b/prebid-server/endpoints/pbs-endpoint-admin.md @@ -138,6 +138,7 @@ Query Params - statusCode - specifies that only interactions resulting in this response status code should be logged; valid values: >=200 and <=500 - account - specifies that only interactions involving this account should be logged - limit - number of interactions to log; there is an upper threshold for this value set in configuration +- bidder - name of the bidder whose adapter request will be logged ## /logging/changelevel diff --git a/prebid-server/endpoints/pbs-endpoint-event.md b/prebid-server/endpoints/pbs-endpoint-event.md index 320a4008fd..28a4f38b05 100644 --- a/prebid-server/endpoints/pbs-endpoint-event.md +++ b/prebid-server/endpoints/pbs-endpoint-event.md @@ -7,7 +7,7 @@ title: Prebid Server | Endpoints | Events # Prebid Server | Endpoints | Events (Java-only) -PBS-Java supports events as described in these GitHub issues: +Prebid Server supports events as described in these GitHub issues: - [Prebid Server Event Notification proposal](https://github.com/prebid/prebid-server/issues/800) - [Prebid Server Event Updates](https://github.com/prebid/prebid-server/issues/1202) @@ -33,7 +33,7 @@ This endpoint alerts Prebid Server to process the event. Most of the time this j ### Sample request ``` -GET http://prebid.site.com/event?t=win&b=1234567890&bidder=rubicon&f=i +GET https://prebid.site.com/event?t=win&b=1234567890&bidder=rubicon&f=i ``` ## `POST /vtrack` diff --git a/prebid-server/endpoints/pbs-endpoint-overview.md b/prebid-server/endpoints/pbs-endpoint-overview.md index 502dcfe7b1..e6f0e6c739 100644 --- a/prebid-server/endpoints/pbs-endpoint-overview.md +++ b/prebid-server/endpoints/pbs-endpoint-overview.md @@ -22,8 +22,8 @@ The API endpoints recognized by Prebid Server: | [GET /getuids](/prebid-server/endpoints/pbs-endpoint-getuids.html) | Parses the `uids` cookie and returns JSON. | | [GET /status](/prebid-server/endpoints/pbs-endpoint-status.html) | A health check. | | [GET /info](/prebid-server/endpoints/info/pbs-endpoint-info.html) | Returns various information about how the server is configured. | -| [GET /event](/prebid-server/endpoints/pbs-endpoint-event.html) | (PBS-Java only) Alerts Prebid Server to process an event. | -| [POST /vtrack](/prebid-server/endpoints/pbs-endpoint-event.html) | (PBS-Java only) Cache VAST XML after inserting tracking string. | +| [GET /event](/prebid-server/endpoints/pbs-endpoint-event.html) | Alerts Prebid Server to process an event. | +| [POST /vtrack](/prebid-server/endpoints/pbs-endpoint-event.html) | Cache VAST XML after inserting tracking string. | | [/currency/rates](/prebid-server/endpoints/pbs-endpoint-admin.html) | (Admin port only) Retrieves the server's current currency conversion rates. | ## Prebid Cache diff --git a/prebid-server/endpoints/pbs-endpoint-setuid.md b/prebid-server/endpoints/pbs-endpoint-setuid.md index eaf27a1bb8..eb47472dd5 100644 --- a/prebid-server/endpoints/pbs-endpoint-setuid.md +++ b/prebid-server/endpoints/pbs-endpoint-setuid.md @@ -16,10 +16,14 @@ This endpoint saves a UserID for a Bidder in the Cookie. Saved IDs will be recog ### Query Params -- `bidder`: The FamilyName of the Usersyncer (`../../usersync/usersync.go`) which is being synced. +- `bidder`: The key of the bidder which is being synced. This may not always match the bidder name,. - `uid`: The ID which the Bidder uses to recognize this user. If undefined, the UID for `bidder` will be deleted. - `gdpr`: This should be `1` if GDPR is in effect, `0` if not, and undefined if the caller isn't sure - `gdpr_consent`: This is required if `gdpr` is one, and optional (but encouraged) otherwise. If present, it should be an [unpadded base64-URL](https://tools.ietf.org/html/rfc4648#page-7) encoded [Vendor Consent String](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/Consent%20string%20and%20vendor%20list%20formats%20v1.1%20Final.md). +- `f`: The desired format of the response. + - If f=i (format=image), PBS will respond with a blank 1x1 PNG, set the Content-Length to the appropriate number of bytes, and set Content-Type to image/png + - If f=b (format=blank), PBS will response with empty HTML with Content-Length 0 and Content-Type to text/html + If the `gdpr` and `gdpr_consent` params are included, this endpoint will _not_ write a cookie unless: @@ -30,4 +34,13 @@ If in doubt, contact the company hosting Prebid Server and ask if they're GDPR-r ### Sample request -`GET http://prebid.site.com/setuid?bidder=adnxs&uid=12345&gdpr=1&gdpr_consent=BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw` +`GET https://prebid.site.com/setuid?bidder=adnxs&uid=12345&gdpr=1&gdpr_consent=BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw` + +### Return Values + +- HTTP 400 - The request is in GDPR scope and the consent string is missing or invalid. +- HTTP 451 - PBS does not have permission to set a cookie due to GDPR or another privacy rule. +- HTTP 200 + - Success with image response: if the f=i parameter is specified or if the named bidder prefers redirect cookie_syncs, then PBS responds with a blank 1x1 PNG, set the Content-Length to the appropriate number of bytes, and set Content-Type to image/png + - Success with empty response: if the f=b parameter is specified or if the named bidder prefers iframe cookie_syncs, then PBS responds with empty HTML, Content-Length 0 and Content-Type to text/html + diff --git a/prebid-server/features/pbs-currency.md b/prebid-server/features/pbs-currency.md index 8b6201fb5f..347abf63e6 100644 --- a/prebid-server/features/pbs-currency.md +++ b/prebid-server/features/pbs-currency.md @@ -80,17 +80,17 @@ Here are a couple examples showing the logic behind the currency converter: ## Request-Defined Conversion Rates -Using PBS-Java, rates can be passed in on the request: +Rates can be passed in on the request: ``` "ext": { - "prebid": { - "currency": { - "rates": { - "USD": { "UAH": 24.47, "ETB": 32.04, "EUR": 0.92, ... } - }, - "usepbsrates": false // defaults to true - } + "prebid": { + "currency": { + "rates": { + "USD": { "UAH": 24.47, "ETB": 32.04, "EUR": 0.92, ... } + }, + "usepbsrates": false // defaults to true + } } } ``` @@ -104,3 +104,9 @@ Note that the `usepbsrates` flag allows you to define which rates to use when PB A dedicated endpoint on the Admin port will allow you to see what's happening within the currency converter. See [currency rates endpoint](/prebid-server/endpoints/pbs-endpoint-admin.html) for more details. + +## Price Granularity + +When converting to a currency where the typical nominal CPMs are much different than USD such as JPY or INR, use a custom price granularity that reflects the typical range of CPMs in that currency. + +The predefined price granularities such as `medium` or `dense` will not be correctly scaled and thus almost every bid will end in the top bucket. Unlike Prebid.js, Prebid Server does not support `granularityMultiplier` to scale granularities so a custom price granularity needs to be used. \ No newline at end of file diff --git a/prebid-server/features/pbs-default-request.md b/prebid-server/features/pbs-default-request.md index 3badc95482..d11b01a092 100644 --- a/prebid-server/features/pbs-default-request.md +++ b/prebid-server/features/pbs-default-request.md @@ -21,7 +21,7 @@ default_request: alias_info: false ``` -The `file.name` option is the path/filename of a JSON file containing default request JSON. See the [stored request doc](/prebid-server/features/pbs-storedreqs.html) and the [openrtb2/auction endpoint doc](/prebid-server/endpoints/openrtb2/auction.html) for details about the syntax. +The `file.name` option is the path/filename of a JSON file containing default request JSON. See the [stored request doc](/prebid-server/features/pbs-storedreqs.html) and the [openrtb2/auction endpoint doc](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html) for details about the syntax. PBS-Java has a slightly different configuration in application.yaml: ``` diff --git a/prebid-server/features/pbs-feature-idx.md b/prebid-server/features/pbs-feature-idx.md index 37e4f71c87..c7bcf46a02 100644 --- a/prebid-server/features/pbs-feature-idx.md +++ b/prebid-server/features/pbs-feature-idx.md @@ -11,31 +11,37 @@ title: Prebid Server | Features | Feature Set | Feature | Description | PBS-Go | PBS-Java | |-------------+---------+-------------+--------+----------| | [Currency](/prebid-server/features/pbs-currency.html) | Core | Loads currency conversions from an outside source, allows non-supported currencies to come in on the OpenRTB2 request, converts bid currencies to the request's prefered currency. | ``` @@ -61,13 +61,10 @@ There are two basic ways of invoking AMP RTC: type="doubleclick" data-slot="/000/amp_test" data-multi-size-validation="false" - rtc-config='{"urls": ["https://prebid-server-qa.example.com/openrtb2/amp?tag_id=11111&w=300&h=50&slot=%2F000%2Famp_test&targeting=%7B%22site%22%3A%20%7B%22key1%22%3A%20%22val1%22%7D%2C%20%22user%22%3A%20%7B%22key2%22%3A%20%22val2%22%7D%7D%7D&purl=encoded_page_url&account=333&gdpr_consent=encoded_cmp_consent_string"] + rtc-config='{"urls": ["https://prebid-server-qa.example.com/openrtb2/amp?tag_id=11111&w=300&h=50&slot=%2F000%2Famp_test&purl=encoded_page_url&account=333&gdpr_consent=encoded_cmp_consent_string"]|
| -| [Currency](/prebid-server/features/pbs-currency.html) | Request-Defined Rates | Allows the request to define its own currency rates. | |
| -| Currency | pbsConvertCurrency method | Allows adapters to convert bid floors to a different currency if needed. | |
| +| [Currency](/prebid-server/features/pbs-currency.html) | Request-Defined Rates | Allows the request to define its own currency rates. |
|
| +| Currency | Convert Currency Method | Allows adapters to convert bid floors to a different currency if needed. |
|
| | [Deals](/prebid-server/features/pbs-deals.html) | Core | Basic deal support, creating hb_deal targeting when appropriate. |
|
| +| Deals | Deal prioritization | Supports the 'preferdeals' [targeting flag](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#targeting) to give deals the priority when PBS returns ad server targeting. |
|
| | [AMP](/prebid-server/use-cases/pbs-amp.html) | Core | Reads and responds to the /openrtb2/amp endpoint |
|
| | Targeting | Core | Request can specify `includewinners` and `includebidderkeys`. These cause PBS to emit seatbid[].bid[].ext.prebid.targeting values. |
|
| | Targeting | Format | Request can specify `includeformat`, which causes PBS to emit hb_format along with other targeting values like hb_pb, etc. |
|
| | Targeting | [Custom Targeting](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#custom-targeting-pbs-java-only) | Request can specify `ext.prebid.adservertargeting`, which causes PBS to emit custom targeting values. | |
| | [Price Granularity](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#targeting) | Core | Request can define quantization rules. Bids are quantized before being added to ad server targeting. |
|
| | Price Granularity | Mediatype pricegranularity | Request can define different quantization rules for different mediatypes. Bids are quantized before being added to ad server targeting. | |
| +| [Bid Adjustments](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bid-adjustments) | Core | Allows publishers to adjust bid prices to account for gross/net or consistent discrepancies. |
|
| +| [Bid Adjustments](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bid-adjustments) | By mediatype | Allows for different bid adjustments by mediatype banner, video, native. | |
| | [GDPR](/prebid-server/features/pbs-privacy.html) | TCF 1.1 core | Able to: read the TCF1.1 global vendor list, parse incoming TCF1.1 consent strings, and [take appropriate enforcement action](https://docs.google.com/document/d/1g0zAYc_EfqyilKD8N2qQ47uz0hdahY-t8vfb-vxZL5w/edit). |
|
| | GDPR | TCF 1.1 Account Config | Able to turn on and off TCF1 enforcement per account. |
|
| | GDPR | TCF 1.1 Geo-lookup | Can use a geographic lookup service to help determine whether the incoming request is in-scope for GDPR. | |
| | GDPR | TCF 1.1 GVL Fallback | Allow the host company to optionally add a default TCF1 GVL file. |
|
| | GDPR | TCF 2 core | Able to: read the TCF2 global vendor list, parse incoming TCF2 consent strings, and [take appropriate enforcement action](https://docs.google.com/document/d/1fBRaodKifv1pYsWY3ia-9K96VHUjd8kKvxZlOsozm8E/edit). |
|
| | GDPR | TCF 2 Account Config | Able to turn on and off TCF2 enforcement per account. |
|
| +| GDPR | Support for basicEnforcementVendors | Host companies can define bidders that don't require vendor consent but do require Purpose consent. |
|
| | GDPR | TCF 2 Geo-lookup | Can use a geographic lookup service to help determine whether the incoming request is in-scope for GDPR. | |
| | GDPR | TCF 2 Integration type exception | Can be configured to turn off GDPR checks for a specific account and a specific integration type. e.g. Account 123 has a different legal basis for AMP. | |
| | [US Privacy](/prebid-server/features/pbs-privacy.html) | USP core | Able to: read the US Privacy consent string (CCPA) and [take appropriate enforcement action](https://github.com/prebid/prebid-server/issues/1129). |
|
| | US Privacy | USP AMP support | Able to: read the US Privacy consent string from AMP requests and [take appropriate enforcement action](https://github.com/prebid/prebid-server/issues/1176). |
|
| | COPPA | Core | Able to read the COPPA flag and [take appropriate enforcement action](https://github.com/prebid/prebid-server/issues/929). |
|
| +| Global Privacy Control | Core | Passes the Sec-GPC header through to bidders. |
|
| | [Cache](/prebid-server/features/pbs-caching.html) | Bids core | Accepts the ext.prebid.cache.bids parameter, storing bid objects in PBC. |
|
| | Cache | VAST core | Accepts the ext.prebid.cache.vastxml parameter, storing VAST responses in PBC. |
|
| | Cache | Winning-only flag | Accepts a 'ext.prebid.cache.winningonly' parameter on the request. If true, instead of caching all bids and VAST, only the winning bid or VAST is stored. |
|
| | [Stored Requests](/prebid-server/features/pbs-storedreqs.html) | Core | Accepts a stored request ID in the OpenRTB, looks it up against a local data store, and merges with the OpenRTB request record. |
|
| | Stored Requests | Unique Per Account | If an account ID is provided, PBS can distinguish between otherwise identical SRIDs. | |
| +| Stored Requests | Unique BidRequest IDs | Supports the generate-storedrequest-bidrequest-id setting telling Prebid Server to override the static bidrequest.id in the stored request with a UUID. | |
| | Stored Responses | Stored Responses | Accepts a stored response ID in the OpenRTB, looks it up against a local data store, and merges with the OpenRTB response record. | |
| | First Party Data | Core | Accepts core first party data attributes and supports ext.prebid.data.bidders. | |
| | First Party Data | Bidder-specific data | Accepts bidder-specific first party data attributes. | |
| @@ -43,22 +49,27 @@ title: Prebid Server | Features | [Supply Chain](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#supply-chain-support) | Bidder-specific schains | Accepts bidder-specific schain |
|
| | Supply Chain | Host SChain | The host company can supply a global schain that's appended to the list of incoming nodes in source.ext.schain. | |
| | Publisher Accounts | Core | Ability to enforce that requests coming in have a valid account ID. |
|
| -| Publisher Accounts | AMP account parameter | Accept the account parameter on the AMP request. | |
| +| Publisher Accounts | AMP account parameter | Accept the account parameter on the AMP request. |
|
| | Publisher Accounts | Account-specific TTLs | Allow each account ID to have a custom PBC time-to-live for banner and video. | |
| | [Video](/formats/video.html) | Core | Support for basic instream and outstream video: passes video parameters to adapters, stores VAST responses when instructed. |
|
| | Video | Outstream renderers | Support for bidders specifying their own renderers for outstream video. | | | | Video | Long-form video | Support for the [long-form video endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-video.html). |
| | | Video | IAB advertiser category mapping | Able to map IAB advertiser categories to a supplied mapping table. |
| | -| Video | Echo video attributes | To support mobile video, copies stored request video attributes to the response. | |
| +| Video | [Echo video attributes](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#echo-storedrequest-video-attributes-pbs-java-only) | To support mobile video, copies stored request video attributes to the response. |
|
| | [Interstitials](/prebid-server/features/pbs-interstitials.html) | Core | Support device.ext.prebid.interstitial.minwidthperc and device.ext.prebid.interstitial.minheightperc parameters, [dynamically updating the impression format object](https://github.com/prebid/prebid-server/issues/755) from a configurable list of sizes filtered by these parameters. |
|
| | [Aliases](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bidder-aliases) | Core | Maps a biddercode on an incoming request to a specific server-side bid adapter named in the request or defined in config. |
|
| | Aliases | [GVL ID support](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#bidder-alias-gvl-ids-pbs-java-only) | Define the IAB GVL ID for an aliased biddercode. | |
| -| [User ID Sync](/prebid-server/developers/pbs-cookie-sync.html) | Core | Implements the /cookie_sync and /setuid endpoints. |
|
| -| User ID Sync | Cooperative sync | Does a pixel sync with more than just the bidders on the page. | |
| -| [Events](https://docs.google.com/document/d/1ry0X4C2EV-R0pMrm1IQk9BstxaT395UCl3KKqTGa5c8/edit#heading=h.7w5yevygp2gz) | Events | Ability to process the /event endpoint, place /event URLs in the OpenRTB response, and place /event URLs in VAST XML. | |
| -| Events | Events vasttrack endpoint | Ability to process the /vasttrack endpoint initated by Prebid.js, placing /event URLs in VAST XML. | |
| -| Events | Events BidID Generation | Some bidders don't generate unique enough BidIDs to join with auction events. This feature allows the host company to inject a PBS-generated BidID alongside the bidder-generated ID. | |
| -| Analytics | Analytics module support | Allows developers to plug in a [custom analytics adapter](https://github.com/prebid/prebid-server/blob/master/docs/developers/add-new-analytics-module.md). |
|
| +| [User ID Sync](/prebid-server/developers/pbs-cookie-sync.html) | Core | Implements the /cookie_sync and /setuid endpoints. Bidders may choose either redirect or iframe method. |
|
| +| User ID Sync | Multi-Method | Bidders can supply both pixel redirects as well as iframe syncs. |
|
| +| User ID Sync | Cooperative sync | Does a pixel sync with more than just the bidders on the page. |
|
| +| User ID Permissions | Extended ID Permissions | Allows publishers to determine which bidders are allowed to receive which extended ID. |
| | +| User ID Sync | Account override | Allows accounts to override the cooperative sync feature and bidder limits. | |
| +| User ID | [EID Permissions](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#eid-permissions) | The Publisher can define which bidders receive which extended user IDs. |
|
| +| [Events](https://docs.google.com/document/d/1ry0X4C2EV-R0pMrm1IQk9BstxaT395UCl3KKqTGa5c8/edit#heading=h.7w5yevygp2gz) | Events | Ability to process the /event endpoint, place /event URLs in the OpenRTB response, and place /event URLs in VAST XML. |
|
| +| Events | Events vasttrack endpoint | Ability to process the /vasttrack endpoint initated by Prebid.js, placing /event URLs in VAST XML. |
|
| +| Events | Events BidID Generation | Some bidders don't generate unique enough BidIDs to join with auction events. This feature allows the host company to inject a PBS-generated BidID alongside the bidder-generated ID. |
|
| +| Auction | [MultiBid](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#multibid-pbs-java-only) | Allow named bidders to supply more than one response. | |
| +| Analytics | Analytics module support | Allows developers to plug in a [custom analytics adapter](/prebid-server/developers/pbs-build-an-analytics-adapter.html). |
|
| | Bid Response Validation | Validate secure markup | PBS can configurably reject bid responses that don't supply a secure creative when in a secure context. | |
| | Bid Response Validation | Validate bid sizes | PBS can configurably reject bid responses with sizes that are bigger than the request dimensions. | |
| | [Bidder Info Endpoints](/prebid-server/endpoints/info/pbs-endpoint-info.html) | Core | Provides details on which bidders and parameters exist in this Prebid Server. |
|
| @@ -68,4 +79,6 @@ title: Prebid Server | Features | Operations | Circuit breaker | Protects system performance during fault scenarios by detecting problems with external and internal endpoints, turning them off temporarily when a problem occurs. | |
| | Operations | [Server default request](/prebid-server/features/pbs-default-request.html) | Support global defaults for incoming requests. |
|
| | Operations | IPv6 | Support taking IPv6 addresses and forwarding them to bidders. |
|
| +| [Programmatic Guaranteed](/prebid-server/features/pg/pbs-pg-idx.html) | Integration and Targeting | Ability to load, target, and report PG line items | |
| | Operations | [Request Logging Admin Endpoints](/troubleshooting/pbs-troubleshooting.html#request-logging) | Log a limited number of requests to understand the raw data clients are sending. | |
| +| Metadata | [x-prebid header](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#http-headers) | Put version information in outgoing HTTP headers. | |
| diff --git a/prebid-server/features/pbs-fpd.md b/prebid-server/features/pbs-fpd.md index 56a431f30a..082c28099e 100644 --- a/prebid-server/features/pbs-fpd.md +++ b/prebid-server/features/pbs-fpd.md @@ -25,24 +25,25 @@ Each of the three main sources of Prebid Server traffic will place First Party Data in the OpenRTB JSON in several places: {: .table .table-bordered .table-striped } -| OpenRTB Attribute | Description | PBJS Source | SDK Source | AMP Source | +| OpenRTB Attribute | Description | Prebid.js Source | SDK Source | AMP Source | | --- | --- | --- | --- | --- | -| site.ATTR | Only standard OpenRTB attributes should be here: name, domain, cat, sectioncat, pagecat, page, ref, search, keywords. | config ortb2.site.ATTR | n/a | site.ATTR | -| site.ext.data.ATTR | Any other site-related attributes should go here. | config ortb2.site.ext.data | n/a | site.ext.data.ATTR | +| site.ATTR | Only standard OpenRTB attributes should be here: name, domain, cat, sectioncat, pagecat, page, ref, search, keywords. | config ortb2.site.ATTR | n/a | Stored Request | +| site.ext.data.ATTR | Any other site-related attributes should go here. | config ortb2.site.ext.data | n/a | Stored Request | | app.ext.data.ATTR | Any app-related attributes should go here. | n/a | Targeting addContextData() | n/a | -| user.ATTR | Only standard OpenRTB attributes should be here: yob, gender, keywords. | config ortb2.user.ATTR | n/a | user.ATTR | -| user.ext.data.ATTR | Any other user-related attributes should go here. | config ortb2.user.ext.data.ATTR | Targeting addUserData() | user.ext.data.ATTR | -| imp[].ext.data.ATTR | AdUnit-specific attributes should go here. | AdUnit.ortb2.ext.data | AdUnit addContextData() | n/a | -| ext.prebid.data.bidders[] | If specified, only these bidders are allowed to see fields in {site/app/user}.ext.data. | n/a | addBidderToAccessControlList() | bidders | -| ext.prebid.bidderconfig | Bidder-specific config | [setBidderConfig()](/dev-docs/publisher-api-reference.html#module_pbjs.setBidderConfig) | n/a | n/a | +| user.ATTR | Only standard OpenRTB attributes should be here: yob, gender, keywords. | config ortb2.user.ATTR | n/a | n/a | +| user.ext.data.ATTR | Any other user-related attributes should go here. | config ortb2.user.ext.data.ATTR | Targeting addUserData() | n/a | +| imp[].ext.data.ATTR | AdUnit-specific attributes should go here. | AdUnit.ortb2.ext.data | AdUnit addContextData() | AMP targeting attribute or Stored Request | +| ext.prebid. data.bidders[] | If specified, only these bidders are allowed to see fields in {site/app/user}.ext.data. | n/a | addBidderTo AccessControlList() | Stored Request | +| ext.prebid. bidderconfig | Bidder-specific config | [setBidderConfig()](/dev-docs/publisher-api-reference/setBidderConfig.html) | n/a | Stored Request | This diagram summarizes how first party data flows into the OpenRTB JSON: {: .pb-lg-img :} {: .alert.alert-info :} -Note that Prebid.js supports the [`setBidderConfig`](/dev-docs/publisher-api-reference.html#module_pbjs.setBidderConfig) method of defining -bidder-specific first party data, while SDK and AMP only support the `ext.prebid.data.bidders[]` approach. +Note that Prebid.js directly supports the [`setBidderConfig`](/dev-docs/publisher-api-reference/setBidderConfig.html) method of defining +bidder-specific first party data, while SDK only supports the `ext.prebid.data.bidders[]` approach with an in-app call. +Both SDK and AMP can have the stored request define bidder FPD permissions. ## OpenRTB Examples diff --git a/prebid-server/features/pbs-privacy.md b/prebid-server/features/pbs-privacy.md index 373dc4a48b..bc83cc5a6c 100644 --- a/prebid-server/features/pbs-privacy.md +++ b/prebid-server/features/pbs-privacy.md @@ -33,16 +33,7 @@ The user must provide legal basis for the host company to read/write cookies or ### TCF 1.1 -If Prebid Server determines that the user is in GDPR scope and doesn't consent -to *all* of the vendor's 'purposes' as declared in the Global Vendor List, it 'anonymizes' -the request to the adapters: - -- Mask take off the last byte of the IPv4 address and anonymize IPv6 addresses -- Removes user.id and user.buyeruid -- Removes the request.device.ifa attribute -- Rounds the request.device.geo. {lat,lon} to two decimal places - -Full details are available [here](https://docs.google.com/document/d/1g0zAYc_EfqyilKD8N2qQ47uz0hdahY-t8vfb-vxZL5w/edit). +No longer supported by Prebid Server. ### TCF 2.0 @@ -61,16 +52,18 @@ for each 'Purpose' with different consequences for each: More details are available in the [Prebid Support for TCF2](https://docs.google.com/document/d/1fBRaodKifv1pYsWY3ia-9K96VHUjd8kKvxZlOsozm8E/edit#) reference and in the [Prebid Server GDPR Reference](https://docs.google.com/document/d/1g0zAYc_EfqyilKD8N2qQ47uz0hdahY-t8vfb-vxZL5w/edit#). -### GDPR Configuration +### Host Company GDPR Configuration -There are a number of configuration settings that PBS Host Companies need -to consider: +There are a number of GDPR configuration settings that PBS Host Companies must +consider: -- Host company GVL ID. Currently PBS requires the host company to have a GVL-ID or the setting of the `uids` cookie in GDPR scope will fail. -- The default expiration time of the uids cookie set in the host company domain should be defined to match what's in the TCF 2.1 `maxCookieAgeSeconds` GVL field. -- GDPR enforcement flags for each Purpose and Vendor +- **GDPR enabled** - Allows the host company to turn off GDPR support. Default setting is enabled=true. +- **Default GDPR applies** - How Prebid Server should respond if the incoming request doesn't have the `gdpr` flag. (Note: this config is currently called `gdpr.default_value` in PBS-Go and `gdpr.default-value` in PBS-Java.) +- **Host company GVL ID** - Currently PBS requires the host company to have a GVL-ID or the setting of the `uids` cookie in GDPR scope will fail. +- **GDPR enforcement flags** - for each Purpose +- **Host Cookie TTL** - The default expiration time of the `uids` cookie set in the host company domain should be defined to match what's in the TCF 2.1 `maxCookieAgeSeconds` GVL field. (This is the host-cookie.ttl-days setting in both Go and Java.) -The specific details vary slightly between PBS-Go and PBS-Java, so check the +The specific details vary between [PBS-Go](https://github.com/prebid/prebid-server/blob/master/config/config.go) and [PBS-Java](https://github.com/prebid/prebid-server-java/blob/master/docs/config-app.md), so check the version-specific documentation for more information. ## COPPA @@ -97,6 +90,11 @@ the following anonymization steps are taken: - Removes the request.device.ifa attribute - Rounds the request.device.geo. {lat,lon} to two decimal places +## Global Privacy Control + +In support of the [Global Privacy Control](https://globalprivacycontrol.org/), Prebid Server passes the `Sec-GPC` HTTP header through to bid adapters. It +does not currently take action on this header. + ## DNT Prebid Server does **not** recognize the Do-Not-Track header. The committee determined that it's obsolete in general and not supported on Safari specifically. We prefer not to implement, test, and document unsupported privacy flags. Prebid Server is not going to make a dent in the overall problems with DNT. diff --git a/prebid-server/features/pbs-storedreqs-go.md b/prebid-server/features/pbs-storedreqs-go.md index 7a8492a6f8..1b75183eaa 100644 --- a/prebid-server/features/pbs-storedreqs-go.md +++ b/prebid-server/features/pbs-storedreqs-go.md @@ -50,7 +50,7 @@ go build . ./prebid-server ``` -And then `POST` to [`/openrtb2/auction`](../endpoints/openrtb2/auction.md) with your chosen ID. +And then `POST` to [`/openrtb2/auction`](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html) with your chosen ID. ```json { diff --git a/prebid-server/features/pbs-storedreqs.md b/prebid-server/features/pbs-storedreqs.md index 966eace171..822b9b5237 100644 --- a/prebid-server/features/pbs-storedreqs.md +++ b/prebid-server/features/pbs-storedreqs.md @@ -8,27 +8,35 @@ title: Prebid Server | Features | Stored Requests # Prebid Server | Features | Stored Requests 'Stored Requests' are blocks of OpenRTB stored on the server-side that are merged into -OpenRTB requests in a couple of scenarios. +OpenRTB requests for Mobile App and AMP scenarios. The data source can be local files on Prebid Server, but more commonly it would be a relational database distributed across all the Prebid Servers in the host company's installation. ## Mobile App -Hardcoding bidders and parameters in a mobile app isn't ideal. Prebid Server allows Stored Request IDs to be -used in two ways: +We want to avoid hardcoding parameters into a mobile app like bidders and parameters. Because of this, Prebid Server allows host companies to store two types of JSON that are retrieved with a key called a 'Stored Request ID': -1. Define cross-adunit parameters like currency and price granularity -1. Define adunit-specific details: bidders and their parameters +- "top-level" requests, also called "wrapper-level" requests. This block is merged into the root level of the incoming ORTB request. It's not expected to have an imp object. +- "impression-level" requests are merged into a particular ORTB imp element. + +{: .pb-lg-img :} + +1. The SDK creates a 'skeleton' framework of the OpenRTB JSON that doesn't +contain the bidders or any other parameter that might be changed by AdOps. +2. Prebid Server merges all the stored requests into this template. +3. Creating the final OpenRTB JSON just like Prebid.js would have sent using the PBS Bid Adapter. See the [Mobile SDK Use Case reference](/prebid-server/use-cases/pbs-sdk.html) for specific examples. ## AMP The AMP protocol is converted to OpenRTB primarily using Stored Requests: the `tag_id` is used to look up -the base OpenRTB from the data source. After getting the bulk of the OpenRTB, AMP query string parameters +a single base OpenRTB from the data source. After getting the bulk of the OpenRTB, AMP query string parameters are used to inject and adjust parameters like size, url, etc. See the [AMP endpoint documentation](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) for more details. +{: .pb-lg-img :} + See the [AMP Use Case reference](/prebid-server/use-cases/pbs-amp.html) for specific examples. ## Creating Stored Requests diff --git a/prebid-server/features/pg/pbs-pg-bidder.md b/prebid-server/features/pg/pbs-pg-bidder.md new file mode 100644 index 0000000000..4d456606a6 --- /dev/null +++ b/prebid-server/features/pg/pbs-pg-bidder.md @@ -0,0 +1,141 @@ +--- +layout: page_v2 +sidebarType: 5 +title: Building a PG Bidder +--- + +# Building a Programmatic Guaranteed Bidder +{: .no_toc} + +* TOC +{:toc} + +## What is a PG Bidder? + +The architecture of Prebid Programmatic Guaranteed (PG) is inherently multi-vendor. A PG `Host Company` runs a global distributed cluster of Prebid Servers. These servers handle the 'real-time' requests... those that need to have millisecond response times. They also run a couple of backend servers that help manage the PG line items. One of them +is called the `General Planner`. The General Planner can connect out to multiple sources of PG Line Items, and that's where you come in -- as a PG Bidder, you can contribute PG Line Items into the auction ecosystem for the publishers who utilize the Host Company's installation. +Here's a diagram from the [white paper](https://files.prebid.org/pg/Prebid_Programmatic_Guaranteed_White_Paper.pdf). + +{: .pb-lg-img :} + +1. The PG Host Company runs clusters of Prebid Servers that receive requests from publishers. +2. Prebid Servers look up additional data for use in targeting. +3. The General Planner queries your PG Bidder endpoint and allocates your line items across the Prebid Server clusters. +4. The `Delivery Stats Service` is available for PG Bidders to obtain up-to-date reports on how line items are delivering. +5. The `Dimension Value API` should be used by bidders to create targeting values. +6. Each PG Bidder has it's own logic for pacing their line items in 1 or 5-minute increments called "plans". +7. The publisher or a service team enter the PG Line Items into the PG Bidder's user interface. + +Notes: +- It's possible that you could deliver PG Line Items through more than one PG Host Company. +- It it the responsibility of the PG Bidder to manage their own finance arrangements with each Publisher. +- It's possible that the Host Company may charge a fee to deliver PG Line Items through their infrastructure. + +## What's involved in building a PG Bidder? + +These are the high level steps for how to develop a PG Bidder and plug it into a Host Company's implementation. + +1. Contact a PG Host Company to make sure they're ready to incorporate a new PG Bidder. They may have additional requirements. +1. Obtain access to the Host Company's Dimension Value API and Delivery Stats server. You will receive a "biddercode" similar to the codes used in Prebid.js. e.g. "pgExample". +1. Develop a User Interface for the customer to enter PG info: date range, targeting details, price, and pacing details. The targeting information comes from the Host Company's Dimension Value API. +1. Develop a pacing algorithm that uses data from the Host Company's Delivery Stats server and your own data stores. +1. Develop a report that uses data from the Host Company's Delivery Stats server and your own data stores. +1. Develop an external API that can respond to requests from the Host Company's General Planner for line item data. +1. Develop a method for estimating inventory forecast and availability. The Host Company may have data available. +1. Contact the Host Company to begin integration testing. + +### Obtain targeting dimensions + +The Host Company will give PG Bidders access to their Dimension Value API which will let them know what attributes and values their Prebid Servers can target at runtime for particular clients. +The values used will differ between Host Companies and publishers. For example, there may be different geographic and device info services. Publisher AdSlot and First Party Data fields will also vary. + +Once granted authenticated access to the Dimension Value endpoint, you'll use the it to query it to get attribute names and values specific to the accounts you're working with. e.g. + +- GET /dim-val/api/v2/attr/names?account=1001 +- GET /dim-val/api/v2/attr/values?account=1001 + +There are various options for filtering data. See the [Dimension Value API documentation](https://github.com/prebid/pg-dim-val-api/blob/main/docs/server_endpoints.md) for more details. + +{: .alert.alert-info :} +In order to access client-specific targeting data, you'll need to know the account ID the Host Company uses for each publisher. + +See [PG Targeting Syntax](/prebid-server/features/pg/pbs-pg-targeting.html) for a list of targeting attributes you may be able +to get from the PG Host Company and how to format them as part of the [PG Plan](/prebid-server/features/pg/pbs-pg-plan.html). + +### Getting data from the Delivery Stats Service + +There are two reasons PG Bidders need data from the Host Company's PG Delivery Stats Service: + +1. **Line Item reporting**: detailed info is available about where in the delivery funnel each Line Item is getting attention or running into problems. See the [PG Glossary](/prebid-server/features/pg/pbs-pg-glossary.html#metrics) for which statistics you can expect. +1. **Inform the pacing algorithm**: in order to write a robust and responsive pacing algorithm, the PG Bidder is going to need fresh data. If the bidder's impression data stream is real-time, that may be enough. If not, the Host Company's Delivery Stats server can provide recent (5-minute) summaries of important metrics like tokens spend and bidsWon. See [PG Plans](/prebid-server/features/pg/pbs-pg-plan.html) for more details. + +Some example Delivery Stats queries: + +- GET /del-stats-summ/api/v1/report/line-item-summary?startTime=YYYY-MM-DDT00:00:00.000Z -- this returns an hourly aggregration for all of your line items since the specified time. See the [Line Item Summary Report endpoint documentation](https://github.com/prebid/pg-del-stats/blob/main/docs/line_item_summary_endpoint.md) for more info. +- GET /del-stats-pa/api/v2/report/delivery?bidderCode=pgExample&startTime=YYYY-MM-DDT00:00:00.000Z -- this returns 5-minute aggregations for all of your line items since the specified time. See the [Delivery Report endpoint documentation](https://github.com/prebid/pg-del-stats/blob/main/docs/delivery_report_endpoints.md) + + +### Answering General Planner requests + +When the PG Bidder is ready for integration with the Host Company, they'll provide an authenticated secure endpoint that will answer requests from the Host Company's General Planner. +The path of this endpoint can be anything you'd like. It will receive these query string parameters: + +{: .table .table-bordered .table-striped } +| Parameter | Format | Required? | Description | +| --- | --- | --- | --- | +| since | string | no | Timestamp in ISO-8601 format. For example, 2019-02-01T03:00:00.000Z. Service should respond with all meta data for active or nearly-active line items and schedules that got updated since this timestamp. Absence of this parameter signals request to return all active or nearly-active line items. | +| hours | string | no | Number of hours of plans desired i.e. provide the next 3 hours worth of plans | + +Here's an [example JSON response](https://github.com/prebid/pg-general-planner/blob/main/docs/samples/pa_rsp.json) that might come from your bidder planner. + +At this point, your endpoint needs to respond quickly with the most recently calculated set of PG line item pacing plans. A `plan` is a set +of instructions to Prebid Server that tells the system how often to serve +a line item in a given period. e.g. "serve LineA 50 times from noon-12:05, 55 times from 12:05-12:10, ..." + +The General Planner will be configured to call your endpoint every 1-10 minutes depending on the Host Company. + +See [PG Plan Definition](/prebid-server/features/pg/pbs-pg-plan.html) for more details. + +### General notes on writing a pacing algorithm + +At a high level, pacing a line item seems like it might be simple: + +``` +NumberOfImpressionsEach5MinPeriod=TotalImpressionsRemaining+3percentBuffer / NumberOf5MinPeriodsRemaining +``` + +But this approach wouldn't perform well: +- When the line falls behind, it won't take advantage of higher traffic periods to catch up. It will fall behind during normal low-traffic periods, saving all impressions for the last minute. +- As covered in the description of [tokens](/prebid-server/features/pg/pbs-pg-plan.html#tokens), a PG line item cannot assume that it'll be chosen every time it's offered to the ad server. Prebid PG paces based on tokens, not impressions, so the pacing algorithm needs to estimate how many times each line item needs to be offered to the ad server in order to land a final certified impression. + +Likewise, another naive approach is to try and immediately catch up to the "even delivery" line: +``` +ImpressionDeficit=TotalImpressions+3percentBuffer - TotalImpressionsShouldHaveByNow + +NumberOfImpressionsThis5MinPeriod=ImpressionDeficit * NoiseFactor +``` + +Potential problems with this algorithm: +- If it falls far behind, it could be overly aggressive in trying to catch up, affecting the delivery of other line items. +- If it gets ahead somehow, it will stop delivering entirely until time catches up to the delivery curve. + +Here are some examples of desirable delivery patterns: + +{: .pb-lg-img :} + +And these are examples of delivery patterns to avoid: + +{: .pb-lg-img :} + +For more information, see the "Plans" section of the [Intro to PG Whitepaper](https://files.prebid.org/pg/Prebid_Programmatic_Guaranteed_White_Paper.pdf). + +{: .alert.alert-warning :} +The PG Host Company may require periodic of testing with your pacing algorithm because undesirable +token management from on PG Bidder could affect line item delivery from other PG Bidders. + +## Related Topics + +- [PG Home Page](/prebid-server/features/pg/pbs-pg-idx.html) +- [PG Plans](/prebid-server/features/pg/pbs-pg-plan.html) +- [PG Glossary](/prebid-server/features/pg/pbs-pg-glossary.html) +- [PG Targeting](/prebid-server/features/pg/pbs-pg-targeting.html) diff --git a/prebid-server/features/pg/pbs-pg-glossary.md b/prebid-server/features/pg/pbs-pg-glossary.md new file mode 100644 index 0000000000..c4dd2df468 --- /dev/null +++ b/prebid-server/features/pg/pbs-pg-glossary.md @@ -0,0 +1,80 @@ +--- +layout: page_v2 +sidebarType: 5 +title: Programmatic Guaranteed Glossary +--- + +# Programmatic Guaranteed Glossary +{: .no_toc} + +* TOC +{:toc} + +## Basic terminology + +- **Programmatic Ad** - an ad request that flows through the multi-vendor ad tech ecosystem +- **Guaranteed** - A buyer and seller have entered into a contract: to deliver a certain amount of impressions to a particular target over a particular date range. If contract isn't met, there may be financial penalties or extra impressions. +- **PG Host Company** - the entity running the Prebid PG software: Prebid Servers, General Planner, Delivery Stats, and Dimension Value API. +- **Prebid Ad Slot** - the "hole in the page" that's requesting an ad (note: this is not currently standard Prebid.org terminology). +- **Prebid Ad Unit** - a package of bidding parameters that defines which bidders and bid parameters are to be used for a specific "hole in the page". +- **Client Requests** - OpenRTB-like network calls from a client to the Prebid Server requesting one or more auctions. +- **Auction Requests** - a single OpenRTB ad request may contain 1 or more 'imp' blocks that define different auction scenarios. Each of these blocks is an "auction". Auctions are sent to one or more bidders and are associated with auction parameters for each bidder. +- **PG Bidder** - the ad exchange, demand side platform, or other bid source that directly or indirectly connects the Auction Request to a bid. Example bidders include Magnite, Criteo, etc. +- **Bidder Parameters** - the specific parameters required by the bidder describing the auction to take place. The Rubicon account, site, and zone are example parameters. +- **PG Line Item** - the base unit of ad delivery has a goal, date range, target, creatives, deal ID, and pacing options. +- **AdServer Line Item** - corresponding to the PG Line Item, the AdServer has a similar line item which prioritizes the PG Line Item in relation to other direct-sold agreements. It may also have a goal and date range, but the targeting will be just to the deal ID, not the full PG target. The creative is the Prebid-standard creative instead of the actual creative. +- **Deal** - an agreement between a buyer and a seller. In the PG context, a Deal may be comprised of 1 or more line items for different media types, targets, date ranges, etc. Since most bidders won't understand "line items", a candidate Deal ID is likely to be what's passed to each bidder. +- **Line Item Type** - sponsorship, guaranteed, non-guaranteed, house. +- **Creative** - the actual ad that will be seen by an end user. May be an image, HTML, video, or native. +- **Target** - a description of the specific sites, user, device, and geographic characteristics a line item is aimed at. +- **Goal** - How many total impressions a campaign line needs to serve +- **Bonus** - Extra impressions assigned to a campaign line to make sure it delivers at least the total goal. This may be stated as a percentage or a number of impressions. Bonus is important to make sure that impression counting discrepancies don't cause the campaign to be perceived as missing its goal. +- **Goal Type** - which metric is used to meet the goal. (i.e. wins or views) +- **Start and End Datetime** - the date range for the campaign could include starting and ending mid-day. Each campaign may also be associated with a timezone. +- **Delivery Type** - defines the general shape of the desired delivery curve: + - even delivery - impressions are roughly equal each day of the campaign + - front-loaded delivery - there may be more impressions delivered in the early days of the campaign + - as-soon-as-possible - serve this thing whenever there's a chance +- **Historic Delivery** - Number of impressions a line delivered until the end of previous day. +- **Deficit** - The number of impressions a line is behind due to lack of overall inventory, existence of road-blocks, or other reason. +- **Late Deficit** - Number of impressions that a line is behind due to trafficking reasons, normally late creative. We may choose to catch up on a late deficit differently than other kinds of deficits because it's the fault of the advertiser, and it could affect other campaigns. +- **Priority** - a way of ranking competing line items against each other. +- **Oversold** - one or more guaranteed line items are struggling and are unlikely to reach their goals. In some cases it may be better to let some of the line items finish at the expense of others, while in other scenarios it's better to distribute what's available. +- **Underdelivery** - when a line item is not serving enough impressions to meet its goal. +- **Overdelivery** - when a line item is serving too many impressions, or has met its delivery goal too early. +- **Frequency Cap** - how often a given user is allowed to see the advertising message. +- **Discrepancy** - impressions are counted by multiple systems which often different from each other by a few percent. The buyer and seller agree on which numbers are billable. The ad system needs to deliver enough impressions that the goal is met in the system-of-record. +- **Ad Inventory** - the combined set of attributes supplied with an ad request, whether direct or indirect. e.g. page context, user info, device info, etc. Line Item 'Targets' inspect these inventory attributes for matching. +- **Forecast** - how much inventory of a particular type is expected to come in over a specified time period. e.g. "how many 300x250 ad requests from example.com will come from Windows machines next week?" +- **Commitment** - a guaranteed line item that the publisher has promised to deliver to an advertiser. +- **Availability** - starts with the Projection, but removes traffic that's already sold to other committed line items. +- **Availability Buffer** - a safety factor to recognize that projections are always an estimate, and only the most sophisticated delivery systems can properly support the juggling involved in tightly sold overlapping inventory. + +## Metrics + +The basic design of the metrics offered by the PG system is a funnel that allows us to see where a line item's chance to deliver may be struggling. Here are the metrics available: + +- **clientAuctions** - the total number of auction impression requests seen by the system across all accounts. A single HTTPS request to PBS may contain multiple auction requests – this number basically reflects all auctions taking place. +- **accountAuctions** - the number of auctions taking place for the specific Rubicon Project account ID +- **domainMatched** - the number of times the domain portion of this line item's target matched an impression request. e.g. "1000 auctions for example.com". If there is no domain targeting, this number should be the same as accountAuctions. +- **targetMatched** - the number of times the line item's entire target matched a request. +- **targetMatchedButFcapped** - the number of times the line item's entire target matched a request, but the user ad already reached their personal frequency cap limit for this line item. +- **targetMatchedButFcapLookupFailed** - the number of times the line item's entire target matched a request, but was removed from consideration because the lines item has a frequency cap and the lookup to the Frequency Capping system failed. +- **pacingDeferred** - Prebid has taken the line item out of consideration in order to make sure it's not delivering too often +- **sentToBidder** - only the top few matching line items or deals will be sent to each bidder. This metric indicates whether the line item was in the top few. +- **sentToBidderAsTopMatch** - if the line item was considered most ready to serve by Prebid Server before going to the bidder, this metric will be incremented. +- **receivedFromBidder** - this metric indicates whether the bidder chose this deal/line item from the candidates sent to it. Bidders may reject any suggested Deal ID or fail to respond. +- **receivedFromBidderInvalidated** - indicates the number of times this deal/line item was received from a bidder, but rejected by Prebid Server for any reason. Rejection reasons include: incorrect size for auction, target didn't match, ahead of pace and not ready to serve. +- **sentToClient** - indicates how many times this line item was sent as the bidder's top match to the client, and therefore the ad server. +- **sentToClientAsTopMatch** - indicates how many times this line item was sent to the client/ad server flagged by Prebid Server as the most eligible PG line item. +- **lostToLineItems** - this array provides a measure of which competing line items have been considered more eligible to serve than this line item +- **events** - how many times this line item received notification of the stated event type. For now only the only supported event type is "win", but eventually there may be other types like "click", "video 50% played", etc. + +Here's a graphical representation showing what point in the delivery funnel each of these metrics measures: + +{: .pb-xlg-img :} + +## Related Topics + +- [PG Home Page](/prebid-server/features/pg/pbs-pg-idx.html) +- [PG White Paper](https://files.prebid.org/pg/Prebid_Programmatic_Guaranteed_White_Paper.pdf) diff --git a/prebid-server/features/pg/pbs-pg-host.md b/prebid-server/features/pg/pbs-pg-host.md new file mode 100644 index 0000000000..3abf6b3d5e --- /dev/null +++ b/prebid-server/features/pg/pbs-pg-host.md @@ -0,0 +1,67 @@ +--- +layout: page_v2 +sidebarType: 5 +title: Becoming a PG Host Company +--- + +# Becoming a PG Host Company +{: .no_toc} + +* TOC +{:toc} + +## Overview + +Prebid PG is open source, so anyone can spin up the 4 different types of servers +needed to offer a PG service. + +1. Prebid Servers handle the real-time mix of open market and PG auctions. +1. The General Planner collects PG line items from one or more PG Bidders. +1. The Delivery Stats Service provides pacing and reporting information. +1. The Dimension Value API provides the user interface the details required to build targets. + +See [Adding a PG Bidder](/prebid-server/features/pg/pbs-pg-bidder.html) for the +high level view of the components. + +As a PG Host Company, you will have expenses in running and maintaining a global high-performance cluster of servers and databases. You'll need at least one PG Bidder, +which might be one you build on your own or partner with someone else. You're under +no obligation to support other PG Bidders, but your publishers may request it. + +## Installing the Servers + +For now, the only information about building and running the servers is in +the relevant GitHub repos: + +- [Prebid Server Java](https://github.com/prebid/prebid-server-java). Note that Prebid Server Go doesn't currently support Programmatic Guaranteed. +- [General Planner](https://github.com/prebid/pg-general-planner) +- [Delivery Stats Service](https://github.com/prebid/pg-del-stats) +- [Dimension Value API](https://github.com/prebid/pg-dim-val-api) + +Prebid does not offer specific guidance about fault-tolerant architectures. +It's left up to each Host Company to determine what will happen if one of the servers goes down. i.e. Will there be load-balancing, automatic failover, a warm stand-by, or no fault tolerance? + +## General notes on testing the service + +There are a fair number of moving parts in a Prebid PG installation. Prebid.org +does not run a test cluster. Changes are made by Prebid member companies, which do +have test clusters, but they may not test every possible configuration. e.g. different databases, geographic lookup vendors, + +We recommend that PG Host Companies commit to regular testing of software updates +against their specific configuration. + +The testing of PG Bidders and their pacing algorithms may be important to you, +as publishers and advertisers care about the delivery patterns of their ad campaigns +in a variety of challenging scenarios. Prebid.org may have extended recommendations +about PG Bidder testing in the future, but in the meantime, you should consider +joining Prebid.org and chatting with the development teams involved. + +## Announcing your service + +When ready to open their doors for business, Prebid.org members can ask to +have their contact info added to the list of [PG Managed Services](/prebid-server/features/pg/pbs-pg-idx.html#list-of-pg-managed-services). + +## Related Topics + +- [PG Home Page](/prebid-server/features/pg/pbs-pg-idx.html) +- [PG White Paper](https://files.prebid.org/pg/Prebid_Programmatic_Guaranteed_White_Paper.pdf) +- [PG Glossary](/prebid-server/features/pg/pbs-pg-glossary.html) diff --git a/prebid-server/features/pg/pbs-pg-idx.md b/prebid-server/features/pg/pbs-pg-idx.md new file mode 100644 index 0000000000..391b4e0b38 --- /dev/null +++ b/prebid-server/features/pg/pbs-pg-idx.md @@ -0,0 +1,67 @@ +--- +layout: page_v2 +sidebarType: 5 +title: Prebid Programmatic Guaranteed +--- + +# Prebid Programmatic Guaranteed +{: .no_toc} + +* TOC +{:toc} + +## Prebid Programmatic Guaranteed +In general, Programmatic Guaranteed (PG) has existed for several years as an ad server-based function. +While anchoring PG in the ad server is helpful from a deployment perspective, +the lack of transparency and configurability in the ad server has slowed down product momentum +and made it harder for buyers and sellers to flexibly adjust their strategy and +configurations for PG deals. The introduction of open-source, standards-based +Programmatic Guaranteed, anchored in Prebid Sever, helps both buyers and sellers in +several key ways: + +- It allows publishers to utilize preferred partners and data in the Programmatic infrastructure. +- It streamlines the traditional RFP and I/O process between buyers and sellers +- It separates the pacing, capping and forecasting functions from the ad server so publishers can more easily control and modify deals +- Enables a seamless, software-based negotiation process between buyers and sellers +- Ensures easier interoperability with a wider universe of buy-side platforms + +At a high level, the system allows any **Host Company** running Prebid Server (only PBS-Java for now) to integrate open source components into their existing UIs and data delivery systems. + +In addition, the Host Company can support other **PG Bidders** connecting into their system to make their environment richer for publishers. + +{: .pb-sm-img :} + +We want to encourage an ecosystem where programmatic vendors can compete on their strengths: some companies may be excellent at hosting a technical infrastructure, while others may excel at usability, reporting, or delivery algorithms. + + +## PG For Publishers + +Publishers interested in trying Programmatic Guaranteed through Prebid should +contact one of the companies hosting a PG cluster. They'll explain how it all works and walk you through the setup process. + +### List of PG Managed Services + +If you're a publisher looking to try Programmatic Guaranteed or a PG bidder that wants to integrate into an existing cluster, here's a list of Prebid.org members to consider: + +- **Magnite** - contact your account representative or globalsupport@magnite.com + +## PG for Bidders + +If you have a demand source and are ready to implement a guaranteed delivery algorithm, learn how to [become a PG Bidder](/prebid-server/features/pg/pbs-pg-bidder.html). + +## Hosting your own PG Cluster + +If you're ready to host a global high-performance cluster, learn how to [become a PG Host Company](/prebid-server/features/pg/pbs-pg-host.html). + +## Questions? + +Contact prebid-server@prebid.org. + +## Related Topics + +- Intro to PG: [video](https://files.prebid.org/pg/PG_in_Prebid.mp4), [pdf](https://files.prebid.org/pg/PG_in_Prebid_Overview.pdf) +- [PG White Paper](https://files.prebid.org/pg/Prebid_Programmatic_Guaranteed_White_Paper.pdf) +- [Becoming a PG Bidder](/prebid-server/features/pg/pbs-pg-bidder.html) +- [Becoming a PG Host Company](/prebid-server/features/pg/pbs-pg-host.html) +- [PG Targeting](/prebid-server/features/pg/pbs-pg-targeting.html) +- [PG Glossary](/prebid-server/features/pg/pbs-pg-glossary.html) diff --git a/prebid-server/features/pg/pbs-pg-plan.md b/prebid-server/features/pg/pbs-pg-plan.md new file mode 100644 index 0000000000..8c9c9e045e --- /dev/null +++ b/prebid-server/features/pg/pbs-pg-plan.md @@ -0,0 +1,284 @@ +--- +layout: page_v2 +sidebarType: 5 +title: Programmatic Guaranteed Plans +--- + +# Programmatic Guaranteed Plans +{: .no_toc} + +* TOC +{:toc} + +## What is a PG Plan? + +A `Plan` is a set of instructions to Prebid Server that tells it how often to serve a PG line item in a given period. + +1. Plans are created by each [PG Bidder](/prebid-server/features/pg/pbs-pg-bidder.html) as an output of their bidder-specific pacing algorithm. +1. The 'General Planner' run by the Host Company will spread the Plan out across the cluster of Prebid Servers. +1. Each Prebid Server works to deliver its part of the Plan. + +Here's what one looks like at a high level: + +``` +[ + { + "lineItemId": "2291", + ... other line item attributes ... + deliverySchedule: [{ + "planId": "2656179", + "startTimeStamp": "2020-08-28T11:50:00.000Z", + "endTimeStamp": "2020-08-28T11:55:00.000Z", + "updatedTimeStamp": "2020-08-28T10:04:12.000Z", + "tokens": [{ + "class": 1, + "total": 50 + }] + },{ + ... next delivery schedule ... + }] + }, + ... next line item ... + } +] +``` + +The key parts of the Plan are: +- Line item details. (See [example](#annotated-plan-example) below) +- An array of Delivery Schedules broken into 5-minute periods +- Each 5-minute period defines a number of `tokens` that need to be delivered + +### Tokens + +A `token` is an ad impression scaled up to overcome delivery obstacles. + +When Prebid Server (PBS) sends a PG line item to the ad server, it might be +chosen to win, or maybe not. In either case, the act of sending a +line item to the ad server causes PBS to create a "cool down" period for that +line item. This is what pacing is all about -- making sure that delivery of the +daily impression goal doesn't complete 20 minutes after midnight. PG delivery +needs to be spread through the day, through the hour, and through each 5-minute period. + +If we could guarantee that the ad server would choose the PG line item to win every time, +we wouldn't need tokens... PG could just use impressions. But that's not the case. There are several reasons why a candidate PG line item might not end up +getting a final certified ad impression: +- competing line items in the ad server +- competing PG line items from another vendor +- user leaves the page before ad render +- the impression may be discounted as non-human traffic + +Basically, the pacing algorithms are working in a "noisy" environment. Not only are there +many things that can get in the way of delivering a certified an ad impression, +conditions can change rapidly, e.g. competing line items may start or stop, or the DSP may change its bidding pattern. + +So a "token" is Prebid PG's way of dealing with noise in the system. +Instead of being satifisfied with offering a PG line item to the ad server +and assuming that it will become a certified impression, PG operates in tokens instead, knowing that some of those opportunities won't materialize. +You can think of it in terms of this basic formula: + +``` +Tokens = ImpressionsNeeded * Noise +``` + +Where the "noise" factor is how many tokens it's currently taking to get an ad +impression through the gauntlet of challenges. Determining this noise factor +is part of what the pacing algorithm needs to do -- adjusting it in real time +as needed. e.g. if it's been taking 2 trips to the ad server to get a "bid won", the noise factor is 2, so in a plan that requires 50 impressions, there would be 100 tokens. +You might wonder "why doesn't Prebid Server just take care of this?" Because Prebid Server is stateless... useful statistics are forwarded from hundreds of front-end servers and it's the job of the backend servers to aggregate and use that data. + +Of course noise could be infinite. For example, if there's a 'roadblock' +ad in the ad server, it's possible that a PG line item will just stop delivering +entirely for a day or more, and that's ok. But even though noise can be infinite, +tokens cannot be. The Host Company will cap tokens at some reasonable level, +but the best strategy for the infinite noise scenario is to give up and use a +very small token count, waiting for when the problem has lifted. + +A good real-time way to monitor noise is to compare two fields +in the Delivery Stats reports: sentToClientAsTopMatch vs events.bidsWon. (See the [glossary.](/prebid-server/features/pg/pbs-pg-glossary.html#metrics)) These values +are indications of how many times the line item was offered to the ad server +and accepted. But this value may also be tempered with data from your +clean financial pipeline that compares certified impressions with events.bidsWon. + +### Plan Attributes + +These are the attributes that are part of a Plan. See below for an [annotated example](#annotated-plan-example). + +{: .table .table-bordered .table-striped } +| Attribute | Required? | Description | Data Type | +| --- | --- |--- |--- | +| lineItemId | yes | Bidder-specific ID for this line item | string | +| source | yes | Your PG bidder code. e.g. "pgBidderA" | string | +| status | yes | Whether this line item is currently "active" or not. The only value that matters to the General Planner is "active". Any other value will cause the line item to be ignored. | string | +| dealId | yes | Bidder-specific deal ID. Note that a Deal ID may be used by multiple line items. | string | +| accountId | yes | Host Company-specific value for the publisher. | string | +| price.cpm | yes | The CPM of the line item. | float | +| price.currency | yes | The currency for the CPM of the line item. | string | +| relativePriority | yes | Relative ranking specific to your pacing algorithm. You can put every line item at the same priority, or create 1000 different levels managed by your pacing algorithm. | integer | +| sizes | yes | An array of creative sizes associated with the line item. e.g. `[{"w": 468,"h": 60},{"w": 728,"h": 90}]` | array of objects | +| frequencyCaps.fcapId | no | Bidder-specific frequency cap ID. Needs to be uniqueo within your line items. | string | +| frequencyCaps.count | no | How many impressions can be served | integer | +| frequencyCaps.periods | no | Over how many periods | integer | +| frequencyCaps.periodType | no | Period length. E.g. "day" or "hour" | string | +| targeting | yes | Defines which ad requests are of interest to this line item. See [PG Targeting](/prebid-server/features/pg/pbs-pg-targeting.html) | object | +| startTimeStamp | yes | Line start time in UTC. e.g. 2020-08-28T07:22:14.000Z | string | +| endTimeStamp | yes | Line end time in UTC. | string | +| updatedTimeStamp | no | When this plan was last modified. | string | +| deliverySchedules | yes | array of objects | +| deliverySchedules.planId | yes? | Bidder-specific ID for use in debugging. Should be unique. | string | +| deliverySchedules.startTimeStamp | yes | Start time of plan period in UTC | string | +| deliverySchedules.endTimeStamp | yes | End time of plan period in UTC | string | +| deliverySchedules.updatedTimeStamp | no | When this plan period was last modified.| string | +| deliverySchedules.tokens.class | no | For future use. Set to 1 for now. | integer | +| deliverySchedules.tokens.total | yes | Token count (Impressions * Noise) for this plan period. | integer | + +## Plans and the General Planner + +The General Planner will poll the PG Bidder endpoint frequently - e.g. every minute or every 5-minutes. The exact period will be determined between you and the Host Company, but it needs to be often because pacing line items is a dynamic business. +Even though it will be contacted frequently, they should still generate +several hours worth of the delivery schedule in case communication breaks down somehow. + +Once it receives the Plan, the General Planner will split up the tokens across +Prebid Servers. When a line item first starts, it does this in a really blunt way: just divides them evenly across the servers. But it will soon start adjusting for geographic differences +in line item delivery. e.g. if a line item only serves tokens in Europe, the Prebid Servers in Europe will get all the tokens within a few cycles. + +## Plans and Prebid Server + +Each PBS polls the General Planner once per minute, getting new and updated Plans. +Here's how it works: + +1. When an auction request comes in, check to see if the account has any active PG line items. If it doesn't, process the request normally. +2. If it is an account with active PG line items, enhance the request with geographic, device, user, and frequency capping information +3. Find out which PG line items have targets that match the current request +4. Loop through the matching line items + 1. Increment the "targetMatched" metric. + 1. If the PG line item has a frequency cap and there's no user ID or the lookup failed, increment the "targetMatchedButFcapLookupFailed" metric and take it off the list. + 1. If the PG line item has a frequency cap and it's met the cap, increment the "targetMatchedButFcapped" metric and take it off the list. + 1. If the PG line item is in "cool-down", increment the "pacingDeferred" metric and take it off the list +5. Sort the remaining line items into priority order based on the PG-bidder-provided "relative priority", with a random secondary sort. +6. Take the first 3 PG line items for each PG Bidder and send them the relevant bid adapter, incrementing the "sentToBidder" metric for each, and the "sentToBidderAsTopMatch" metric for one of them. +7. Wait for the auction delay for the results. Increment "receivedFromBidder" and "receivedFromBidderInvalidated" metrics as appropriate. +8. Take the highest priority bid from each PG Bidder and prepare ad server targeting. Increment the "sentToClient" metric. +9. If there's more than one bid from a PG Bidder, randomly choose one to be the overall winner and increment the "sentToClientAsTopMatch" metric. Only this line item is considered to have spent a token and is put into "cool-down": PBS calculates how many milliseconds it needs to wait before offering this line item to the ad server again. + +{: .alert.alert-info :} +Random numbers are used at a couple of points in the PG algorithm. This is to avoid choosing the same aggressive-but-blocked line item every time. + +## Annotated Plan Example + +Here's a complete example of a Plan with all line item and delivery schedule fields. + +``` +[ // each line item has a plan entry + { + "lineItemId": "2291", // this is specific to your internal systems + "dealId": "710216", // also specific to your internal systems + "accountId": "1001", // the Host Company's account ID for the publisher + "price": { + "cpm": 7.29, + "currency": "EUR" + }, + "relativePriority": 2, // relative stacking specific to your pacing algorithm + "sizes": [{ // creative sizes + "w": 468, + "h": 60 + }, + { + "w": 728, + "h": 90 + } + ], + "frequencyCaps": [{ // Host Company may support multiple cap levels + "fcapId": "LI-2291", // ID specific to your system + "count": 2, // show no more than 2 times per 1 day + "periods": 1, + "periodType": "day" + } + ], + "targeting": { // Line Item targeting + "$and": [{ + "adunit.size": { + "$intersects": [{ + "h": 60, + "w": 468 + }, + { + "h": 90, + "w": 728 + } + ] + } + },{ + "adunit.mediatype": { + "$intersects": [ + "banner" + ] + } + },{ + "device.ext.deviceatlas.browser": { + "$in": [ + "Chrome", + "Firefox" + ] + } + },{ + "device.geo.ext.netacuity.country": { + "$in": [ + "us", + "jp" + ] + } + },{ + "adunit.adslot": { + "$in": [ + "/1111/QA_Tests" + ] + } + } + ] + }, + "startTimeStamp": "2020-08-28T07:22:14.000Z", // line start time in UTC + "endTimeStamp": "2020-08-30T17:22:14.000Z", // line end time in UTC + "updatedTimeStamp": "2020-08-28T06:22:15.000Z", + "deliverySchedules": [ // now starts the plans + { + "planId": "2656177", // ID is specific to your system + "startTimeStamp": "2020-08-28T11:40:00.000Z", // UTC 11:40 to 11:45 + "endTimeStamp": "2020-08-28T11:45:00.000Z", + "updatedTimeStamp": "2020-08-28T11:36:30.000Z", + "tokens": [ + { + "class": 1, // always 1 for now + "total": 8 // number of tokens + } + ] + }, + { + "planId": "2656178", + "startTimeStamp": "2020-08-28T11:45:00.000Z", // UTC 11:45 to 11:50 + "endTimeStamp": "2020-08-28T11:50:00.000Z", + "updatedTimeStamp": "2020-08-28T11:38:19.000Z", + "tokens": [ + { + "class": 1, + "total": 10 + } + ] + },{ + ... more plans ... + } + ], + "source": "pgBidderCode", + "status": "active" + }, + { + ... next line item ... + } +] +``` + +## Related Topics + +- [PG Home Page](/prebid-server/features/pg/pbs-pg-idx.html) +- [Becoming a PG Bidder](/prebid-server/features/pg/pbs-pg-bidder.html) +- [PG Targeting](/prebid-server/features/pg/pbs-pg-targeting.html) +- [PG Glossary](/prebid-server/features/pg/pbs-pg-glossary.html) diff --git a/prebid-server/features/pg/pbs-pg-targeting.md b/prebid-server/features/pg/pbs-pg-targeting.md new file mode 100644 index 0000000000..dd8157733a --- /dev/null +++ b/prebid-server/features/pg/pbs-pg-targeting.md @@ -0,0 +1,177 @@ +--- +layout: page_v2 +sidebarType: 5 +title: Programmatic Guaranteed Targeting Syntax +--- + +# Programmatic Guaranteed Targeting Syntax +{: .no_toc} + +* TOC +{:toc} + +## Overview + +Targeting is the ability for Prebid Server (PBS) to match PG line items with +incoming OpenRTB auction requests. + +Here's a simple example target that says this line item will match any request for a 300x250 banner: + +``` +{ + "$and": [ + { + "adunit.size": {"$intersects": [{"w": 300,"h": 250}]} + }, + { + "adunit.mediatype": {"$intersects": ["banner"]} + } + ] +} +``` + +In general, the syntax is: +``` +{ + "$and/$or": [ + { "ATTRIBUTE": { "OPERATOR": CONDITION } }, + "$and/$or": [ ... ], + "$not": { "ATTRIBUTE": { "OPERATOR": CONDITION } } + ] +} +``` +Here are the supported OPERATORs: + +{: .table .table-bordered .table-striped } +| Operator | Description | Attribute Datatype | Condition Datatype | Example | +| --- | --- | --- | --- | +| $matches | True if the scalar ATTRIBUTE is the same as the CONDITION, or matches with an asterisk wildcard. | string | string | "$matches": "{::nomarkdown}*sports*{:/}" | +| $in | True if the scalar ATTRIBUTE is on the CONDITION's array. | string | array of strings | "$in": ["a","b"] | +| $intersects | True if at least one value from the ATTRIBUTE's array is on the CONDITION's array | array of strings | array of strings | "$intersects": ["hockey","soccer"] | +| $within | True if user's lat/long are available and within the circle defined by the CONDITION. | from geolookup service | object with attributes: lat, lon, and radiusMiles | "$within": {"lat": 123.456,"lon": 789.123,"radiusMiles": 50} | + +## Targeting Attributes + +The full list of attributes supported by Prebid Server may differ by PG Host Company because they might use different geographic and device information services. But here's an example list: + +{: .table .table-bordered .table-striped } +| Attribute | Description | Encoding | PBS Source | OpenRTB path | Operators | +| --- | --- | --- | --- | --- | --- | +| adunit.size | Ad Sizes | [{w: 300, h: 250},...] | OpenRTB | imp[].banner.format[] | intersects | +| adunit.mediatype | Mediatype | string | OpenRTB | mediatype="banner" if imp.banner exists. mediatype="video-instream" if imp.video exists and placement is 1. mediatype="video-outstream" if imp.video exists and placement is <> 1. mediatype="native" if imp.native exists | intersects | +| adunit.adslot | The ad server slot name | string | OpenRTB | imp[].ext.context.data.pbadslot | in, matches | +| site.domain | Site domain | string | OpenRTB | site.domain | in, matches | +| site.referrer | Referring URL | string | OpenRTB | site.page | in, matches | +| app.bundle | Mobile application bundle | string | OpenRTB | app.bundle | in, matches | +| pos | Page position | 0=unknown, 1=ATF, 3=BTF | OpenRTB | imp.banner.pos | in | +| geo.distance | User's lat/lon is within a defined circle | none | Geo vendor | device.geo.lat, device.geo.lon | within | +| device.geo.ext.VENDOR.country | Country | string | Geo vendor | device.geo.ext.VENDOR.country | in| +| device.geo.ext.VENDOR.region | Region | string | Geo vendor | device.geo.ext.VENDOR.region | in| +| device.geo.ext.VENDOR.metro | Metro (DMA) | string | Geo vendor | device.geo.ext.VENDOR.metro | in| +| device.geo.ext.VENDOR.city | City | string | Geo vendor | device.geo.ext.VENDOR.city | in| +| device.geo.ext.VENDOR.zip | Postal Code | string | Geo vendor | device.geo.ext.VENDOR.zip | in| +| device.ext.VENDOR.connspeed | Connection Speed | string | Device vendor | device.ext.VENDOR.connspeed | in| +| device.ext.VENDOR.type | Device Type | string | Device vendor | device.ext.VENDOR.type | in| +| device.ext.VENDOR.make | Device Make | string | Device vendor | device.ext.VENDOR.make | in| +| device.ext.VENDOR.model | Device Model | string | Device vendor | device.ext.VENDOR.model | in| +| device.ext.VENDOR.os | Operating System | string | Device vendor | device.ext.VENDOR.os | in| +| device.ext.VENDOR.browser | Browser | string | Device vendor | device.ext.VENDOR.browser | in| +| device.ext.VENDOR.browserver | Browser Version | string | Device vendor | device.ext.VENDOR.browserver | in| +| device.ext.VENDOR.language | Device Language | string | Device vendor | device.ext.VENDOR.language | in| +| device.ext.VENDOR.osver | Operating System Version | string | Device vendor | device.ext.VENDOR.osver | in| +| device.ext.VENDOR.carrier | Internet Carrier | string | Device vendor | device.ext.VENDOR.carrier | in| +| user.ext.time.userdow | User Day of Week | 1=sun, 7=sat | Geo vendor + clock | user.ext.time.userdow | in| +| user.ext.time.userhour | User Hour | 0-23 |Geo vendor + clock | user.ext.time.userhour | in| +| ufpd.ATTR | User First Party Data | string | OpenRTB | user.ATTR or user.ext.data.ATTR | in, matches, intersects | +| sfpd.ATTR | Site First Party Data | string | OpenRTB | imp[].ext.context.data.ATTR=VAL OR site.ext.data.ATTR=VAL OR app.ext.data.ATTR=VAL | in, matches, intersects | +| segment.SOURCE | User Segment Data | string | OpenRTB | user.data[].id=SOURCE AND VALUE in user.data[].segment[].id | intersects | +| bidp.BIDDER.ATTR | Bid Parameter Data | string | OpenRTB | imp[].ext.BIDDER.ATTR | in, matches, intersects| + +## Targeting Syntax + +Here's an example of a ridiculously specific target that uses most of the +attributes and specific geographic and device info services: + +``` +{ + "$and": [ + { + "adunit.size": {"$intersects": [{"w": 300,"h": 250},{"w": 300,"h": 600}]} + }, + { + "adunit.mediatype": {"$intersects": ["banner"]} + }, + { + "$or": [ + {"site.ext.domain": {"$matches": "*.example.com"}}, + {"site.ext.domain": {"$in": ["prebid.org"]}} + ] + }, + { + "$or": [ + {"site.referrer": {"$matches": "*sports*"}}, + {"site.referrer": {"$matches": "*prebid*"}} + ] + }, + { + "$or": [ + {"adunit.adslot": {"$matches": "/home/top*"}}, + {"adunit.adslot": {"$in": ["/home/bottom"]}} + ] + }, + { + "pos": {"$in": [1,3]} + }, + { + "device.geo.ext.netacuity.country": {"$in": ["us","de"]} + }, + { + "device.geo.ext.netacuity.region": {"$in": ["de-bw","de-by"]} + }, + { + "device.geo.ext.netacuity.metro": {"$in": ["111","222"]} + }, + { + "device.geo.ext.netacuity.city": {"$in": ["444","555"]} + }, + { + "geo.distance": {"$within": {"lat": 123.456,"lon": 789.123,"radiusMiles": 50}} + }, + { + "device.ext.deviceatlas.type": {"$in": ["tablet","phone"]} + }, + { + "$or": [ + {"bidp.rubicon.siteId": {"$in": [123,321]}}, + {"bidp.appnexus.placementName": {"$matches": "*99999*"}}, + ] + }, + { + "$or": [ + {"segment.rp": {"$intersects": [123,234,345]}}, + {"segment.bluekai": {"$intersects": [123,234,345]}} + ] + }, + { + "sfpd.sport": {"$intersects": ["hockey","soccer"]} + }, + { + "user.ext.time.userdow": {"$in": [5,6]} + }, + { + "user.ext.time.userhour": {"$in": [10,11,12,13,14]} + }, + { + "$not": { + "ufpd.registered": {"$matches": ["false"]} + } + } + ] +} +``` + + +## Related Topics + +- [PG Home Page](/prebid-server/features/pg/pbs-pg-idx.html) +- [PG Plans](/prebid-server/features/pg/pbs-pg-plan.html) diff --git a/prebid-server/hosting/pbs-database.md b/prebid-server/hosting/pbs-database.md index 4dfde3d158..08efe50163 100644 --- a/prebid-server/hosting/pbs-database.md +++ b/prebid-server/hosting/pbs-database.md @@ -99,7 +99,7 @@ create a view as desired. We'll fix this someday. Account data is queried on every request to pull in important data. There is an LRU cache in the server so the database isn't actually hit on every request. -In PBS-Java, many account-configuration options come from the database, while in PBS-Go, those options are available in YAML configuration. +In PBS-Java, many account-configuration options come from the database. In PBS-Go, those options are available in either a YAML configuration or from an HTTP API. In both versions the server can optionally validate the account against this database and reject accounts from unknown sources. @@ -108,7 +108,7 @@ The algorithm the server uses for determining the account ID of the incoming req 1. look in site.publisher.id 2. look in app.publisher.id -3. if AMP, look for the 'account' parameter on the query string (PBS-Java only) +3. if AMP, look for the 'account' parameter on the query string Here are the fields the server can recognize in the database response: diff --git a/prebid-server/hosting/pbs-hosting.md b/prebid-server/hosting/pbs-hosting.md index 89beba33db..144fd0f196 100644 --- a/prebid-server/hosting/pbs-hosting.md +++ b/prebid-server/hosting/pbs-hosting.md @@ -6,6 +6,10 @@ title: Prebid Server | Hosting --- # Hosting a Prebid Server Cluster +{:.no_toc} + +* TOC +{:toc} Spinning up a self-hosted cluster of Prebid Servers requires some up-front-planning. The components that will be needed are highlighted in this hardware @@ -64,7 +68,7 @@ populating data from their internal systems. You'll want to hook both Prebid Server and Prebid Cache up to an operational monitoring system. -- PBS-Go currently supports Influx and Promotheus +- PBS-Go currently supports Influx and Prometheus - PBS-Java currently supports Influx and Graphite ## Installing the Software @@ -73,6 +77,25 @@ The process for actually installing and configuring the software will differ for the Go and Java versions of the software. See the relevant section as a next step. +## Optional Registration + +Prebid does not track who downloads Prebid Server, but sometimes we make +announcements (bugs, features) and want to get feedback on proposals. You can get on +this mailing list by emailing prebid-server@prebid.org. It's low volume +Here's the information we're asking for: + +Required to get on the list: +- A group email address to place on the list. No individual addresses please. + +Optional: +- Which version of Prebid Server are you running: PBS-Go or PBS-Java? +- A host URL so we can occasionally check what versions people are running. +- Are there any features you'd like to see in Prebid Server? + +Even though this is not information about individuals, this information falls under the +[Prebid website privacy policy](/privacy.html). You can remove your company from the +email list at any time just by emailing us again at prebid-server@prebid.org. + ## Further Reading - [Prebid Server Database](/prebid-server/hosting/pbs-database.html) diff --git a/prebid-server/overview/prebid-server-overview.md b/prebid-server/overview/prebid-server-overview.md index 36bd6c5d42..493b0a9cfe 100644 --- a/prebid-server/overview/prebid-server-overview.md +++ b/prebid-server/overview/prebid-server-overview.md @@ -18,7 +18,7 @@ Prebid Server is a header bidding server with a growing list of features. At a h - Resolves dynamic stored requests - Enforces privacy regulations 2. Next, it calls server-side bid adapters - - There are currently 75+ server-side bid adapters available + - There are currently 100+ server-side bid adapters available 3. After everyone's responded (or the timeout period has expired), it formulates an appropriate response - Handles currency conversion - Quantizes bids @@ -47,7 +47,7 @@ Then you need to decide which of the two implementations to utilize: - [Prebid Server (Go)](/prebid-server/versions/pbs-versions-go.html) - the original Prebid Server is written in the Go language. - [Prebid Server (Java)](/prebid-server/versions/pbs-versions-java.html) - Prebid Server with a Java language port. -To choose between them, see the [Prebid Server version overview](/prebid-server/versions/pbs-versions-overview.html) and the [FAQ](http://prebid.org/faq/prebid-server-faq.html#why-are-there-two-versions-of-prebid-server-are-they-kept-in-sync). +To choose between them, see the [Prebid Server version overview](/prebid-server/versions/pbs-versions-overview.html) and the [FAQ](/faq/prebid-server-faq.html#why-are-there-two-versions-of-prebid-server-are-they-kept-in-sync). ## Which Server-Side Bidders to Utilize diff --git a/prebid-server/use-cases/pbs-amp.md b/prebid-server/use-cases/pbs-amp.md index e66dd874f1..d5ec56c52e 100644 --- a/prebid-server/use-cases/pbs-amp.md +++ b/prebid-server/use-cases/pbs-amp.md @@ -47,7 +47,7 @@ There are two basic ways of invoking AMP RTC: data-slot="/11111/amp_test" data-multi-size-validation="false" rtc-config='{"vendors": {"prebidrubicon": {"REQUEST_ID": "14062-amp-AMP_Test-300x250"}, "ACCOUNT_ID": "1001"}}' - json='{ "targeting": {"site":{"keywords":"article, las vegas","cat":{"blah":"1"},"other-attribute":"other-value","ext":{"data":{"entry_group":["front-page","featured-stories"],"page_type":"AMP"}}},"user":{"gender":"m"},"bidders":["bidderA","bidderB"],"keywords":"las vegas hospitality employees","foo":{"bar":"baz"}}' > + json='{ "targeting": {"attr1": "val1", "attr2": "val2"}}' >
Prebid ServerIn your ad unit you also need to define your list of bidders. For example, including AppNexus as a bidder would look something like this: @@ -124,7 +117,7 @@ Video players expect that the response from the ad server will be a URL that poi on the internet that stores the video ad creative. This URL can't point to the browser, so Prebid.js will send bid VAST XML out to a cache so it can be displayed if it wins in the ad server. -Configuring the video cache is done with [`setConfig`](/dev-docs/publisher-api-reference.html#setConfig-vast-cache): +Configuring the video cache is done with [`setConfig`](/dev-docs/publisher-api-reference/setConfig.html#setConfig-vast-cache): ``` pbjs.setConfig({ @@ -141,10 +134,10 @@ And this is where setups for instream and outstream diverge. Please follow one o - Instream: [Show Video Ads with Google Ad Manager]({{site.github.url}}/dev-docs/show-video-with-a-dfp-video-tag.html) - Outstream: [Show Outstream Video Ads]({{site.github.url}}/dev-docs/show-outstream-video-ads.html) -Be sure to note the setting for price granularity. You might need to set up a custom price granularity. (See “Custom CPM Bucket Sizing” under [Price Granularity]({{site.github.url}}/dev-docs/publisher-api-reference.html#setConfig-Price-Granularity). Or, if you’re monetizing both banner and video inventory with Prebid, you might need to define format-specific price granularity settings through [mediaTypePriceGranularity]({{site.github.url}}/dev-docs/publisher-api-reference.html#setConfig-MediaType-Price-Granularity). +Be sure to note the setting for price granularity. You might need to set up a custom price granularity. (See “Custom CPM Bucket Sizing” under [Price Granularity](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Price-Granularity). Or, if you’re monetizing both banner and video inventory with Prebid, you might need to define format-specific price granularity settings through [mediaTypePriceGranularity](/dev-docs/publisher-api-reference/setConfig.html#setConfig-MediaType-Price-Granularity). {: .alert.alert-info :} -**Prebid Server** If you’re using Prebid Server, you also need to configure your server-to-server bidder adapters. See [Getting Started with Prebid Server]({{site.github.url}}/dev-docs/get-started-with-prebid-server.html#step-4-configure-s2s-bidder-adapters) for details and examples. +**Prebid Server** If you’re using Prebid Server, you also need to configure your server-to-server bidder adapters. See [Getting Started with Prebid Server](/overview/prebid-server-overview.html). ### Examples @@ -153,13 +146,12 @@ This section contains working examples of instream and outstream video ads for v ### Using client-side adapters #### Instream - ++ [Akamai AMP]({{site.github.url}}/examples/video/instream/akamai/pb-ve-amp.html) + [Brid]({{site.github.url}}/examples/video/instream/brid/pb-ve-brid.html) + [Brightcove]({{site.github.url}}/examples/video/instream/brightcove/pb-ve-brightcove.html) + [Flowplayer]({{site.github.url}}/examples/video/instream/flowplayer/pb-ve-flowplayer.html) + [JWPlayer - Platform]({{site.github.url}}/examples/video/instream/jwplayer/pb-ve-jwplayer-platform.html) + [JWPlayer - Hosted]({{site.github.url}}/examples/video/instream/jwplayer/pb-ve-jwplayer-hosted.html) -+ [JWPlayer - Playlist]({{site.github.url}}/examples/video/instream/jwplayer/pb-ve-jwplayer-playlist.html) + [Kaltura]({{site.github.url}}/examples/video/instream/kaltura/pb-ve-kaltura.html) + [Ooyala]({{site.github.url}}/examples/video/instream/ooyala/pb-ve-ooyala.html) + [VideoJS]({{site.github.url}}/examples/video/instream/videojs/pb-ve-videojs.html) @@ -169,13 +161,11 @@ This section contains working examples of instream and outstream video ads for v + [Outstream with Google Ad Manager]({{site.github.url}}/examples/video/outstream/pb-ve-outstream-dfp.html) + [Outstream without an Ad Server]({{site.github.url}}/examples/video/outstream/pb-ve-outstream-no-server.html) -### Using Prebid Server +### Using Prebid Server + [Brid]({{site.baseurl}}/examples/video/server/brid/pbs-ve-brid.html) + [JW Player - Platform]({{site.baseurl}}/examples/video/server/jwplayer/pbs-ve-jwplayer-platform.html) + [JW Player - Hosted]({{site.baseurl}}/examples/video/server/jwplayer/pbs-ve-jwplayer-hosted.html) -+ [JW Player - Playlist]({{site.baseurl}}/examples/video/server/jwplayer/pbs-ve-jwplayer-playlist.html) -+ [JW Player - Player 7]({{site.baseurl}}/examples/video/server/jwplayer/pbs-ve-jwplayer-jwplayer7.html) + [Kaltura]({{site.baseurl}}/examples/video/server/kaltura/pbs-ve-kaltura.html) + [Ooyala]({{site.baseurl}}/examples/video/server/ooyala/pbs-ve-ooyala.html) + [VideoJS]({{site.baseurl}}/examples/video/server/videojs/pbs-ve-videojs.html) @@ -185,4 +175,3 @@ This section contains working examples of instream and outstream video ads for v - [Prebid.js for Video Overview]({{site.github.url}}/prebid-video/video-overview.html) - [What is Prebid?]({{site.github.url}}/overview/intro.html) - diff --git a/prebid/native-implementation.md b/prebid/native-implementation.md index 704fc5f89a..9e4c8985ac 100644 --- a/prebid/native-implementation.md +++ b/prebid/native-implementation.md @@ -77,7 +77,7 @@ The Prebid.js AdUnit needs to defines a native mediatype object to tell bidders | Attribute | Scope | Description | Example | Type | | --- | --- | --- | --- | --- | | sendTargetingKeys | optional | Defines whether or not to send the hb_native_ASSET targeting keys to the ad server. Defaults to `true` for now, though we recommend setting this to `false` and utilizing one of the ways to define a native template. | `false` | boolean | -| adTemplate | optional | Used in the ‘AdUnit-Defined Creative Scenario’, this value controls the Native template right in the page. | See [example](#5-implementing-adunit-defined-creative) below. | escaped ES5 string | +| adTemplate | optional | Used in the ‘AdUnit-Defined Creative Scenario’, this value controls the Native template right in the page. | See [example](#42-implementing-adunit-defined-template) below. | escaped ES5 string | | rendererUrl | optional | Used in the ‘Custom Renderer Scenario’, this points to javascript code that will produce the Native template. | 'https://host/path.js' | string | | type | optional | A “type” is like a macro that defines a group of assets. The only value currently supported is ‘image’, which implies the following assets: image, title, sponsoredBy, clickUrl, body, icon, and cta. The first 4 are required attributes. | `image` | string | | ASSETCODE. required | optional | Defines whether native bids must include this asset. Defaults to `false`. | `true` | boolean | @@ -136,9 +136,9 @@ In the native template, simply access the custom value with the normal Prebid ## ## 4. Implementing the Native Template -- If you want to manage your creative within the ad server (e.g. Google Ad Manager), follow the instructions for [AdServer-Defined Creative](#4-implementing-adserver-defined-creative). -- If you’d prefer to manage your creative within the Prebid.js AdUnit, follow the instructions for [AdUnit-Defined Creative](#5-implementing-adunit-defined-creative) -- If you’d prefer to manage your creative from a separate piece of JavaScript, follow the instructions for the [Custom Renderer](#6-implementing-the-custom-renderer-scenario). +- If you want to manage your creative within the ad server (e.g. Google Ad Manager), follow the instructions for [AdServer-Defined Creative](#41-implementing-adserver-defined-template). +- If you’d prefer to manage your creative within the Prebid.js AdUnit, follow the instructions for [AdUnit-Defined Creative](#42-implementing-adunit-defined-template) +- If you’d prefer to manage your creative from a separate piece of JavaScript, follow the instructions for the [Custom Renderer](#43-implementing-the-custom-renderer-scenario). ### 4.1. Implementing AdServer-Defined Template @@ -356,7 +356,7 @@ In this scenario, the body of the native creative is managed from an external Ja When the Native AdUnit is defined in the page: - Declare`sendTargetingKeys: false` in the Native Object. This will prevent Prebid.js from sending all the native-related ad server targeting variables. -- Define the `rendererUrl` as a URL that defines a `window.renderAd` function in the creative iframe. Any CSS definitions need to be defined in the body (e.g.If you’re using Prebid Server, you must also include the mediaTypes.video.mimes field, as this is required by OpenRTB.
- -- mediaTypes: { - video: { - context: 'instream', // or 'outstream' - playerSize: [640, 480], - mimes: ['video/mp4'], -- -For more on Prebid Server ad unit requirements, see Getting Started with Prebid Server – Video.
-