From 0cb513b454e0e4ba52ee1048943b7543692e8198 Mon Sep 17 00:00:00 2001 From: redaguermas Date: Thu, 19 Mar 2020 13:29:27 -0700 Subject: [PATCH 01/76] Nobid version 1.2.4 (#1859) * Adde support for CCPA * Placement ID support * Fix merge conflict * Resolving conflict --- dev-docs/bidders/nobidBidAdapter.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev-docs/bidders/nobidBidAdapter.md b/dev-docs/bidders/nobidBidAdapter.md index e7c85ac0a1..9d0a48b517 100644 --- a/dev-docs/bidders/nobidBidAdapter.md +++ b/dev-docs/bidders/nobidBidAdapter.md @@ -9,13 +9,15 @@ gdpr_supported: true usp_supported: true schain_supported: true coppa_supported: true +--- ### Bid Params {: .table .table-bordered .table-striped } | Name | Scope | Description | Example | Type | |---------------|----------|-------------|---------|----------| -| `siteId` | required | siteId is provided by your Nobid account manager | | `integer` | +| `siteId` | required | siteId is provided by your NoBid account manager(s) | | `integer` | +| `placementId` | optional | placementId is provided by your NoBid account manager(s). This parameter allows to report on a specific ad unit | | `integer` | # Test Parameters ``` @@ -31,7 +33,8 @@ coppa_supported: true { bidder: "nobid", params: { - siteId: 2 + siteId: 2, + placementId: 3 } } ] From 20e403486430b4f1b3225c10347c260a9499afd4 Mon Sep 17 00:00:00 2001 From: bretg Date: Fri, 20 Mar 2020 14:14:09 -0400 Subject: [PATCH 02/76] refactoring the video creative process (#1870) * refacting the video creative process * Edit Co-authored-by: Jean Stemp --- _includes/adops/adops-gam-video-setup.html | 92 ++++++++++++------ .../dfp-creative-setup/appnexus_vast_tag.png | Bin 0 -> 66292 bytes .../video_creatives_final.png | Bin 0 -> 62527 bytes 3 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 assets/images/ad-ops/dfp-creative-setup/appnexus_vast_tag.png create mode 100644 assets/images/ad-ops/dfp-creative-setup/video_creatives_final.png diff --git a/_includes/adops/adops-gam-video-setup.html b/_includes/adops/adops-gam-video-setup.html index d8c04b4b25..5aa6714df9 100644 --- a/_includes/adops/adops-gam-video-setup.html +++ b/_includes/adops/adops-gam-video-setup.html @@ -1,5 +1,5 @@
- +

Setting up Prebid Video in Google Ad Manager

This page describes how to set up video creatives in Google Ad Manager for use with Prebid.js.

@@ -12,40 +12,40 @@

Setting up Prebid Video in

Line Item Setup

-
    -
  • -

    In the New line item dialog, under Inventory sizes, select the Video VAST radio button.

    -
  • -
  • -

    In the Master text area, add your video player size(s).

    -
  • -
+
    +
  1. In the New line item dialog, choose "Video".
  2. +
  3. Select the appropriate Line Item Type, etc.
  4. +
  5. In the Expected creatives section, choose your video size, e.g., 640x480v.
  6. +
  7. Set the dates, rate, limit, and targeting as desired. For example, for SendAllBids include targeting for "hb_bidder_rubicon=rubicon" as well as the hb_pb_rubicon targeting. This isn't needed if only creating one set of orders for all bidders.
  8. +
  9. Remember to set the hb_pb=BUCKET targeting for each line item, or hb_pb_BIDDER=BUCKET if using separate line items for each bidder.
  10. +
  11. Save the line item.
  12. +
+

Be sure to duplicate your line item and video creative for each Prebid price bucket you intend to create.

+

By default, Prebid.js caps all CPMs at $20. As a video seller, you may expect to see CPMs higher than $20. In order to receive those bids, you’ll need to make sure your dev team implements custom price buckets as described in the engineering setup instructions. Once those changes are made on the engineering side, there should be no changes required from the ad ops side to support CPMs over $20.

-

Google Ad Manager New Line Item

+

Multiple Cache Services
You might need separate video line items for each cache service being used. For example, if both AppNexus and Rubicon Project are bidders, you’ll either need to create separate line items to support the different cache URLs required or provide separately-targeted creatives, as described below.

-

Other line item settings and key/value targeting are the same as those recommended for Prebid display, with one exception:

+

Creative Setup

+When setting up video creatives, it's important to understand where the VAST XML is stored for each of your bidders. The most common place to store VAST XML is AppNexus' cache, but some bidders (such as RubiconProject and SpotX) use their own cache services. To support such +bidders, you will need to have either:
    -
  • By default, Prebid.js caps all CPMs at $20. As a video seller, you may expect to see CPMs higher than $20. In order to receive those bids, you’ll need to make sure your dev team implements custom price buckets as described in the engineering setup instructions. Once those changes are made on the engineering side, there should be no changes required from the ad ops side to support CPMs over $20.
  • +
  • a separate line item for each bidder, or
  • +
  • a creative for each cache service utilized by your implementation.
-

Be sure to duplicate your line item and video creative for each Prebid price bucket you intend to create. You may also need separate video line items for each cache service being used. For example, if both AppNexus and Rubicon Project are bidders, you’ll need separate line items to support the different cache URLs required.

+

Single Cache Location

-

Creative Setup

+

1. For each line item you create, click on the Creatives tab, click the ADD CREATIVE button, and choose the size you're entering.

-

1. For each line item you created above, select new creative set.

+

2. In the dialog that appears, choose Redirect.

-

2. In the dialog that appears, set the creative set type to “Redirect”

- -

3. Set the VAST tag URL to the cache location. Note that each bidder, e.g. Rubicon Project, may have a different cache location URL.

+

3. Set the VAST tag URL to the cache location.

If you’re using a single order for all bidders, then the VAST URL will be the same for each bidder:

@@ -53,29 +53,59 @@

Creative Setup

or [other bidder cache location] -

If you’re using different orders for each bidder, the VAST URL for each will need to be different:

+

If you’re using different orders for each bidder, the VAST URL for each will include the bidder-specific targeting variable:

   https://prebid.adnxs.com/pbc/v1/cache?uuid=%%PATTERN:hb_uuid_BIDDERCODE%%
 or
    [other bidder cache location]
-

This VAST tag URL is required in order to show video ads. It points to - a server-side cache hosted by your Prebid Server provider.

+

This VAST tag URL is required in order to show video ads. It points to a server-side cache hosted by your Prebid Server provider.

Prebid Cache and the VAST creative URL warning
- Google Ad Manager will show you a warning that fetching VAST from the creative + Google Ad Manager will show you a warning stating that fetching VAST from the creative URL failed. This is expected, since the creative URL above points to a server-side asset cache hosted by Prebid Server.

-

4. Set the duration to 1

+

4. Set the Duration to 1.

The resulting creative should look something like the following:

-

Google Ad Manager Video Creative Setup

+

Google Ad Manager Video Creative Setup

+ +

Multiple Cache Locations

+ +To set up multiple video creatives in the same line item (i.e., to run AppNexus, Rubicon, and SpotX all together in the same video line item), you can utilize creative targeting. +
+
+

+1. In the line item's Expected creatives box, choose Creative Targeting and "Add New Targeting". + +

+2. Give the targeting set a name like "Prebid Default Video Cache URL" and set Custom Targeting as appropriate, e.g., "hb_bidder is none of rubicon, spotx". Save the targeting. -

That’s it as far as Prebid setup is concerned. At this point you can add any other options you would normally use, e.g., labels or tracking URLs.

+

+3. For each bidder that uses their own cache, click ADD SIZE in the "Expected creatives" section. Again, choose Creative Targeting and "Add New Targeting". -

Additional Setup for Long-Form (ad pods)

+

+4. Give the targeting a name like "Prebid Rubicon Video Cache URL". Set Custom Targeting appropriately, e.g., "hb_bidder is any of rubicon". Save the targeting. + +

+5. Save the line item. + +

Now that the targeting is defined, we're going to add the creatives.

+ +

+6. Go to the line item's Creatives tab. + +

+7. Make one creative for each of the targets. There are a couple of ways to do this on the GAM UI, but each approach will result in a creative entry screen similar to the screenshot above for the "Single Cache Location" process. Enter a name (e.g. "AppNexus VAST tag") and the VAST URL as described above. + +

+8. The end result should look something like this: + +

Google Ad Manager Video Creative Setup

+ +

That’s it as far as Prebid setup is concerned. At this point you can add any other options you would normally use, such as labels or tracking URLs.

Further Reading

@@ -85,5 +115,3 @@

Further Reading

  • Add Key-Values to a Master Video Ad Tag (Google Ad Manager)
  • Google Ad Manager Macros (Google Ad Manager)
  • - -
    diff --git a/assets/images/ad-ops/dfp-creative-setup/appnexus_vast_tag.png b/assets/images/ad-ops/dfp-creative-setup/appnexus_vast_tag.png new file mode 100644 index 0000000000000000000000000000000000000000..851fbabf76ab55b270c568ba905bc222140d55b5 GIT binary patch literal 66292 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 z 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 Date: Tue, 24 Mar 2020 20:55:52 +0100 Subject: [PATCH 03/76] Fix for wrong link in overview/getting-started (#1879) --- overview/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overview/getting-started.md b/overview/getting-started.md index bf1efce976..6a1ebd92b2 100644 --- a/overview/getting-started.md +++ b/overview/getting-started.md @@ -51,6 +51,6 @@ To see how it works, follow the instructions in [Send all bids to the ad server For more information, check out the following: -+ [Before You Start](/overview/getting-started.html): Learn about considerations of your Prebid.js setup such as price granularity, line item configuration, and more. ++ [Before You Start](/adops/before-you-start.html): Learn about considerations of your Prebid.js setup such as price granularity, line item configuration, and more. + [Supported Ad Servers](/adops/before-you-start.html#supported-ad-servers): Ad ops docs arranged by ad server. + [Docs by Format](/dev-docs/docs-by-format.html): Engineering and ad ops docs arranged by ad format (video, native, etc.). From aae410dc7627154f6ebff4284b8c503a19a11634 Mon Sep 17 00:00:00 2001 From: Kotaro Shikata Date: Wed, 25 Mar 2020 21:04:58 +0900 Subject: [PATCH 04/76] add UNICORN bid adapter docs (#1827) * add UNICORN bid adapter documentation * Update unicorn.md Co-authored-by: Jean Stemp <38964447+jeanstemp@users.noreply.github.com> --- dev-docs/bidders/unicorn.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 dev-docs/bidders/unicorn.md diff --git a/dev-docs/bidders/unicorn.md b/dev-docs/bidders/unicorn.md new file mode 100644 index 0000000000..6bad86489a --- /dev/null +++ b/dev-docs/bidders/unicorn.md @@ -0,0 +1,18 @@ +--- +layout: bidder +title: UNICORN +description: Prebid UNICORN Bidder Adaptor +hide: true +media_types: banner +biddercode: unicorn +--- + +### bid params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|---------------|----------|-------------------------------------------|------------|-----------| +| `placementId` | optional | Your placement ID | `'rectangle-ad-1'` | `string` | +| `accountId` | required | Account ID for charge request (provided by UNICORN) | `12345` | `integer` | +| `bidfloorCpm` | optional | Floor CPM (JPY); defaults to 0. | `0.2` | `float` | +| `bcat` | optional | Blocked IAB categories | `['IAB-1', 'IAB-2']` | `[string]` | From 765641e522b9b7447e1a23eeef2750be1977166d Mon Sep 17 00:00:00 2001 From: bretg Date: Wed, 25 Mar 2020 15:03:23 -0600 Subject: [PATCH 05/76] adding vast-cache explanation to video overview (#1884) --- prebid-video/video-getting-started.md | 33 +++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/prebid-video/video-getting-started.md b/prebid-video/video-getting-started.md index 933bdb024b..ec5e60eb93 100644 --- a/prebid-video/video-getting-started.md +++ b/prebid-video/video-getting-started.md @@ -3,9 +3,6 @@ layout: page_v2 title: Getting Started with Video for Prebid.js description: Prebid Video Getting Started pid: 1 -is_top_nav: yeah -top_nav_section: pbjs-video -nav_section: pbjs-video-get-started sidebarType: 4 --- @@ -117,10 +114,32 @@ For full details on creating outstream video ad units, see [Show Outstream Video ### Configuration -After you’ve defined your ad units, you can continue with the rest of your configuration. This is where setups for instream and outstream more drastically diverge. For complete configuration details, see the following: +After you’ve defined your ad units, you can continue with the rest of your configuration. In +most cases for video, the first step will be to define where the VAST XML coming back in the bids +will be stored. Some bidders have you covered here -- the VAST is stored on their servers. But +many bidders don't have their own server-side cache. -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) +{: .alert.alert-success :} +Video players expect that the response from the ad server will be a URL that points to somewhere +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): + +``` + pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + /* Or whatever your preferred video cache URL is */ + } + }); +``` + + +And this is where setups for instream and outstream diverge. Please follow one of these links: + +- 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). @@ -129,7 +148,7 @@ Be sure to note the setting for price granularity. You might need to set up a c ### Examples -See our working examples of instream and outstream video ads. +This section contains working examples of instream and outstream video ads for various players. ### Using client-side adapters From 886ad87dafa789e1c6323b35ceaffd8b8a81a501 Mon Sep 17 00:00:00 2001 From: bretg Date: Thu, 26 Mar 2020 08:09:30 -0600 Subject: [PATCH 06/76] defaultGdprScope flag (#1880) --- dev-docs/modules/consentManagement.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dev-docs/modules/consentManagement.md b/dev-docs/modules/consentManagement.md index 3d18f40a0e..22ebd538f5 100644 --- a/dev-docs/modules/consentManagement.md +++ b/dev-docs/modules/consentManagement.md @@ -65,6 +65,7 @@ but we recommend migrating to the new config structure as soon as possible. | gdpr | `Object` | | | | gdpr.cmpApi | `string` | The CMP interface that is in use. Supported values are **'iab'** or **'static'**. Static allows integrations where IAB-formatted consent strings are provided in a non-standard way. Default is `'iab'`. | `'iab'` | | gdpr.timeout | `integer` | Length of time (in milliseconds) to allow the CMP to obtain the GDPR consent string. Default is `10000`. | `10000` | +| gdpr.defaultGdprScope | `boolean` | (TCF v2.0 only) Defines what the `gdprApplies` flag should be when the CMP doesn't respond in time. | `true` | | gdpr.allowAuctionWithoutConsent | `boolean` | (TCF v1.1 only) Determines what will happen if obtaining consent information from the CMP fails; either allow the auction to proceed (`true`) or cancel the auction (`false`). Default is `true` | `true` | | gdpr.consentData | `Object` | An object representing the GDPR consent data being passed directly; only used when cmpApi is 'static'. Default is `undefined`. | | | gdpr.consentData.getTCData.tcString | `string` | (TCF v2.0 only) Base64url-encoded TCF v2.0 string with segments. | | @@ -87,7 +88,7 @@ A related parameter is `deviceAccess`, which is at the global level of Prebid.js ### TCF v2.0 Examples -Example 1: IAB CMP using custom timeout +Example 1: IAB CMP using custom timeout and setting GDPR in-scope by default {% highlight js %} var pbjs = pbjs || {}; @@ -97,7 +98,8 @@ Example 1: IAB CMP using custom timeout consentManagement: { gdpr: { cmpApi: 'iab', - timeout: 8000 + timeout: 8000, + defaultGdprScope: true } } }); @@ -271,12 +273,13 @@ Page JavaScript can prevent Prebid.js from performing various activities that co Here are some things that publishers can do to control various activities: -1. If the user hasn't consented to Purpose 1: +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) - Don't enable [userId](/dev-docs/modules/userId.html) modules -2. 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. +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. ### Publishers Not Using an IAB-Compliant CMP From 9a0bf4510f77e66a4509b59d7963bc45a706f5c3 Mon Sep 17 00:00:00 2001 From: Aaron Mitchell Date: Thu, 26 Mar 2020 04:11:54 -1000 Subject: [PATCH 07/76] Adds Clicktripz bidder adapter to dev-doc notes (#1836) --- dev-docs/bidders/clicktripz.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 dev-docs/bidders/clicktripz.md diff --git a/dev-docs/bidders/clicktripz.md b/dev-docs/bidders/clicktripz.md new file mode 100644 index 0000000000..819a9772e4 --- /dev/null +++ b/dev-docs/bidders/clicktripz.md @@ -0,0 +1,16 @@ +--- +layout: bidder +title: Clicktripz +description: Prebid Clicktripz Bidder Adaptor +hide: true +biddercode: clicktripz +media_types: banner +--- + +### Bid Params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|---------------|----------|-------------|---------|----------| +| `placementId` | required | The Placement ID from Clicktripz | `'4312c63f'` | `string` | +| `siteId` | required | The site ID from Clicktripz | `'prebid'` | `string` | \ No newline at end of file From ff92172c13a8540dbb9cea10eb0eaea1266d4997 Mon Sep 17 00:00:00 2001 From: Mikael Lundin Date: Thu, 26 Mar 2020 15:12:48 +0100 Subject: [PATCH 08/76] Adnuntius Bidder documentation added (#1821) * Adnuntius Bidder documentation added * Fixed targeting text. --- .../main.scssc | Bin 0 -> 502 bytes dev-docs/bidders/adnuntius.md | 52 ++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 .sass-cache/a8ae1fbf8fe3cf0ae44282e4f927a25624204c54/main.scssc create mode 100644 dev-docs/bidders/adnuntius.md diff --git a/.sass-cache/a8ae1fbf8fe3cf0ae44282e4f927a25624204c54/main.scssc b/.sass-cache/a8ae1fbf8fe3cf0ae44282e4f927a25624204c54/main.scssc new file mode 100644 index 0000000000000000000000000000000000000000..6db4f74c3a9fee8e8dc651dd996b91b928e63d22 GIT binary patch literal 502 zcmb7=F;BxV5QRISQc_A0QxOa5ij)M>w2iZ5p;8uvXg7w)i7$;sVn;q#2qFGEmz0GK zw!3HFz58C^uH1zqco6XbAcSSU$bAt!gkfGn8HG##ejWL|6l;IwN6yJev+FHKWNc>u z7<amSpbmI~yM zT_vawrhv?FwFk{+N1tskl2fOiv1x*q8=JKnHM{x!5ok3p;ze!yhavp;Ble6)<7Q+P)h0i?r%P{eM6WAc%A)!aF!sYo^{b@@7yS<_7v1; N3$_EUI96YS%{Th+qY(fA literal 0 HcmV?d00001 diff --git a/dev-docs/bidders/adnuntius.md b/dev-docs/bidders/adnuntius.md new file mode 100644 index 0000000000..fc68317fa1 --- /dev/null +++ b/dev-docs/bidders/adnuntius.md @@ -0,0 +1,52 @@ +--- +layout: bidder +title: Adnuntius +description: Prebid Adnuntius Bidder Adaptor +hide: true +biddercode: adnuntius +media_types: banner +gdpr_supported: false +--- + + +### Bid Params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|-------------|----------|----------------------------------------------------------------------|----------|----------| +| `auId` | required | The ad unit ID `'0000000000072345'` leading zeros can be omitted. | `string` | | +| `network` | optional | Used if you want to make requests to multiple networks in adnuntius. | `string` | | +| `targeting` | optional | Targeting to be sent through to adnuntius with the request. | `string` | | + + + +#### Targeting + +The [Adnuntius Documentation](https://docs.adnuntius.com/adnuntius-advertising/requesting-ads/intro) provides detailed information on sending targeting data to the Adnuntius adserver. + + +#### Example + +Here's an example of sending targeting information about categories to adnuntius via the bid request: +``` +{ + code: "0000000000072345", + mediaTypes: { + banner: { + sizes: [[980, 360], [980, 300], [980, 240], [980, 120]] + } + }, + bids: [ + { + bidder: "adnuntius", + params: { + auId: "8b6bc", + network: "adnuntius", + targeting: { + c: ['prebids'] + } + } + } + ] +} +``` \ No newline at end of file From 2bb6ac2b4c8b5bc9a0145da799fb77bf6ca95124 Mon Sep 17 00:00:00 2001 From: Harshad Mane Date: Thu, 26 Mar 2020 07:21:27 -0700 Subject: [PATCH 09/76] ORTB eids (#1831) --- dev-docs/modules/userId.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev-docs/modules/userId.md b/dev-docs/modules/userId.md index a7dbd3873b..f83333a32e 100644 --- a/dev-docs/modules/userId.md +++ b/dev-docs/modules/userId.md @@ -36,8 +36,9 @@ The User ID module supports multiple ways of establishing pseudonymous IDs for u 1. The publisher builds Prebid.js by specifying one or more ID sub-modules they would like to include. e.g. "gulp build --modules=____IdSystem" 1. The page defines User ID configuration in `pbjs.setConfig()` 1. When `setConfig()` is called, and if the user has consented to storing IDs locally, the module is invoked to call the URL if needed - 1. If the relevant local storage is present, the module doesn't call the URL and instead parses the scheme-dependent format, injecting the resulting ID into bidRequest.userIds. -1. An object containing one or more IDs (bidRequest.userIds) is made available to Prebid.js adapters and Prebid Server S2S adapters. + 1. If the relevant local storage is present, the module doesn't call the URL and instead parses the scheme-dependent format, injecting the resulting ID into bidRequest.userId. +1. An object containing one or more IDs (bidRequest.userId) is made available to Prebid.js adapters and Prebid Server S2S adapters. +1. In addition to bidRequest.userId, bidRequest.userIdAsEids is made available to Prebid.js adapters and Prebid Server S2S adapters. bidRequest.userIdAsEids has userIds in ORTB EIDS format. Note that User IDs aren't needed in the mobile app world because device ID is available in those ad serving scenarios. From efdee06e7c54bfb9fa50c0efaa934fdf565fa5fe Mon Sep 17 00:00:00 2001 From: e-volution-tech <61746103+e-volution-tech@users.noreply.github.com> Date: Thu, 26 Mar 2020 16:24:32 +0200 Subject: [PATCH 10/76] New evolution tech bid adapter (#1839) * initial * fix --- dev-docs/bidders/evolution_tech.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 dev-docs/bidders/evolution_tech.md diff --git a/dev-docs/bidders/evolution_tech.md b/dev-docs/bidders/evolution_tech.md new file mode 100644 index 0000000000..a6f6de689c --- /dev/null +++ b/dev-docs/bidders/evolution_tech.md @@ -0,0 +1,21 @@ +--- +layout: bidder +title: E-volution tech +description: Prebid E-volution tech Bidder Adapter +hide: true +biddercode: e_volution +gdpr_supported: true +media_types: banner, video +--- + +### Note: + +The E-volution Bidding adapter requires setup before beginning. Please contact us at admin@e-volution.ai + +### Bid Params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|---------------|----------|-----------------------|-----------|-----------| +| `id` | required | E-volution tech placement id | `1234asdf` | `string` | + From f817354e21a4f551d6e9d77397607475681deac0 Mon Sep 17 00:00:00 2001 From: adfinity-prebid <58843903+adfinity-prebid@users.noreply.github.com> Date: Thu, 26 Mar 2020 16:25:37 +0200 Subject: [PATCH 11/76] Adfinity: gdpr support - true (#1849) * new adpter * gdpr support Co-authored-by: root --- dev-docs/bidders/adfinity.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-docs/bidders/adfinity.md b/dev-docs/bidders/adfinity.md index 8192ccfbbb..162f005d20 100644 --- a/dev-docs/bidders/adfinity.md +++ b/dev-docs/bidders/adfinity.md @@ -5,6 +5,7 @@ description: Prebid Adfinity Bidder Adaptor hide: true biddercode: adfinity media_types: banner, video, native +gdpr_supported: true --- ### Bid Params From a78b6c94b011f3234f34307360280e971014a696 Mon Sep 17 00:00:00 2001 From: thuyhq <61451682+thuyhq@users.noreply.github.com> Date: Thu, 26 Mar 2020 21:26:06 +0700 Subject: [PATCH 12/76] Add Valueimpression Bid Adapter docs (#1860) * Add Valueimpression Bid Adapter docs * Updade Valueimpression Bid Adapter docs --- dev-docs/bidders/valueimpression.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 dev-docs/bidders/valueimpression.md diff --git a/dev-docs/bidders/valueimpression.md b/dev-docs/bidders/valueimpression.md new file mode 100644 index 0000000000..019df8aeec --- /dev/null +++ b/dev-docs/bidders/valueimpression.md @@ -0,0 +1,19 @@ +--- +layout: bidder +title: Valueimpression +description: Prebid Valueimpression Bidder Adapter +hide: true +biddercode: valueimpression +media_types: banner, video +gdpr_supported: true +schain_supported: true +usp_supported: true +--- + + +### Bid Params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|-------------|----------|--------------------------------------------------------------------------------------------------------------------------------|------------|----------| +| `siteId` | required | Publisher site ID from Valueimpression | `'vi-site-id'` | `string` | From 9e4ad02724d483887ed0b0b22afb4f9568077c7b Mon Sep 17 00:00:00 2001 From: Michael Kuryshev Date: Thu, 26 Mar 2020 15:27:31 +0100 Subject: [PATCH 13/76] VIS.X: update docs regarding schain & userId support (#1871) --- dev-docs/bidders/visx.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev-docs/bidders/visx.md b/dev-docs/bidders/visx.md index ff59f381bf..d37b16500c 100644 --- a/dev-docs/bidders/visx.md +++ b/dev-docs/bidders/visx.md @@ -5,6 +5,8 @@ description: Prebid VIS.X Bidder Adaptor hide: true biddercode: visx gdpr_supported: true +schain_supported: true +userIds: unifiedId, digitrust, id5 --- ### Note From 2c02ba217e6f6184a668c0e951b65a343d52d0d3 Mon Sep 17 00:00:00 2001 From: Vedant Seta Date: Thu, 26 Mar 2020 19:58:38 +0530 Subject: [PATCH 14/76] Media.net Adapter: Add support for userId modules in bidder-docs (#1872) Co-authored-by: binoy --- dev-docs/bidders/medianet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-docs/bidders/medianet.md b/dev-docs/bidders/medianet.md index 80adc8e487..6dbb006ff2 100644 --- a/dev-docs/bidders/medianet.md +++ b/dev-docs/bidders/medianet.md @@ -7,6 +7,7 @@ hide: true gdpr_supported: true media_types: banner,native usp_supported: true +userIds: criteo,digitrust,pubCommonId --- ### Bid Params From 9faa1e1350fcd9b395d1de7287dbc3c10a844772 Mon Sep 17 00:00:00 2001 From: Harshad Mane Date: Thu, 26 Mar 2020 07:29:17 -0700 Subject: [PATCH 15/76] PubMatic tosupport NetId user id sub module (#1873) --- dev-docs/bidders/pubmatic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-docs/bidders/pubmatic.md b/dev-docs/bidders/pubmatic.md index f2bb87c1b8..2c7084e9ca 100644 --- a/dev-docs/bidders/pubmatic.md +++ b/dev-docs/bidders/pubmatic.md @@ -9,7 +9,7 @@ gdpr_supported: true usp_supported: true coppa_supported: true schain_supported: true -userIds: pubcommonId, unifiedId/tradedesk, digitrustId, id5Id, criteo, identityLink, liveIntent, parrable, britepoolId +userIds: pubcommonId, unifiedId/tradedesk, digitrustId, id5Id, criteo, identityLink, liveIntent, parrable, britepoolId, NetId prebid_member: true --- From 8e03f676d588f932be66386f65ee3fbee6581b27 Mon Sep 17 00:00:00 2001 From: Index Exchange 3 Prebid Team Date: Thu, 26 Mar 2020 10:38:32 -0400 Subject: [PATCH 16/76] Index Exchange: Registering user syncs (#1874) * Updated TTL from 35 to 300 seconds * added user sync info for ix * Update indexExchange.md minor edit Co-authored-by: Zicong Zhou Co-authored-by: Jean Stemp <38964447+jeanstemp@users.noreply.github.com> --- dev-docs/bidders/indexExchange.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dev-docs/bidders/indexExchange.md b/dev-docs/bidders/indexExchange.md index 9d4145ace6..8235b354a4 100644 --- a/dev-docs/bidders/indexExchange.md +++ b/dev-docs/bidders/indexExchange.md @@ -273,6 +273,23 @@ pbjs.setConfig({ }); ``` +#### User Sync +Add the following code to enable user sync. IX strongly recommends enabling user syncing through iFrames. This functionality improves DSP user match rates and increases the IX bid rate and bid price. Be sure to call `pbjs.setConfig()` only once. + +``` +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + filterSettings: { + iframe: { + bidders: ['ix'], + filter: 'include' + } + } + } +}); +``` + ### 2. Include `ixBidAdapter` in your build process When running the build command, include `ixBidAdapter` as a module, as well as `dfpAdServerVideo` if you require video support. From cc95668cad78108c4b962bbdc19359d232695f9d Mon Sep 17 00:00:00 2001 From: Yevhenii Melnyk Date: Thu, 26 Mar 2020 16:06:55 +0100 Subject: [PATCH 17/76] Add a new param for LiveIntent Id module. Describe the LiveIntent identity resolution. (#1783) * Add an new param for LiveIntent Id module. Describe the identity resolution. * Add all the configuration params of the LiveIntent submodule * Renamed hashes -> encrypted email Co-authored-by: janko --- dev-docs/modules/userId.md | 69 +++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/dev-docs/modules/userId.md b/dev-docs/modules/userId.md index f83333a32e..e3cd0a4e7e 100644 --- a/dev-docs/modules/userId.md +++ b/dev-docs/modules/userId.md @@ -378,14 +378,14 @@ pbjs.setConfig({ ### LiveIntent ID -LiveIntent offers audience resolution by leveraging our next-generation identity solutions. The LiveIntent identity graph is built around a people-based set of data that is authenticated daily through active engagements with email newsletters and media across the web. The LiveIntent ID is a user identifier tied to an active, anonymized email hash in our graph that functions in cookie-challenged environments like mobile browsers. +LiveIntent offers audience resolution by leveraging our next-generation identity solutions. The LiveIntent identity graph is built around a people-based set of data that is authenticated daily through active engagements with email newsletters and media across the web. The LiveIntent ID is a user identifier tied to an active, encrypted email in our graph and functions in cookie-challenged environments and browsers. Add LiveIntent ID to your Prebid.js package with: {: .alert.alert-info :} -gulp build --modules=liveIntentIdSystem +gulp build --modules=userId,liveIntentIdSystem -The `request.userId.lipb` object would then look like +The `request.userId.lipb` object would look like: ``` { "lipbid": "T7JiRRvsRAmh88", @@ -393,13 +393,29 @@ The `request.userId.lipb` object would then look like } ``` -The adapters can be implemented to use the lipibid as the identifier, and segments to which that identifier is associated with. +The adapters can be implemented to use the lipibid as the identifier and segments to which that identifier is associated with. To enable identity resolution for a specific publisher, LiveIntent builds a model on the backend with data collected via an additional call issued on each page load. -#### LiveIntent ID Registration +#### How does LiveIntent ID work + +The LiveIntent ID sub-module resolves the identity of audiences by connecting impression opportunities to a stable identifier (LIID). In order to provide resolution one or more first-party cookies are used to create a stable identifier. + +How does LiveIntent ID sub-module decide, which first-cookies to use: +1. By default LiveIntent ID sub-module generates its own first-party identifier on the publisher’s domain. Publishers have the option to disable the cookie generation when configuring the LiveIntent ID sub-module. +2. A publisher can also define in the configuration which additional first-party cookies should be used. These can be used in a combination with the LiveIntent first-party cookie. -To leverage the LiveIntent ID, you need to first set up a first-party cookie sync with LiveIntent. Please reach out to peoplebased@liveintent.com for more information. +The LiveIntent ID sub-module sends the defined identifiers to the identity graph, which processes them and creates a stable identifier (LIID). The detailed description of the parameters being sent is described here: https://github.com/liveintent-berlin/live-connect/blob/HEAD/COLLECTOR_PARAMS.md -The LiveIntent privacy policy is at [https://www.liveintent.com/services-privacy-policy/](https://www.liveintent.com/services-privacy-policy/). +For the identity resolution the LiveIntent ID sub-module makes a request to the LiveIntent’s identity resolution API, which returns a stable identifier and the audience segment(s) a user belongs to. The identifier and the segment are then exposed by the Prebid User ID Module to Prebid adapters to be sent out in a bid request. An SSP can then make the impression opportunity available to any buyers targeting the segment via a deal. + +The first-party cookie generation and identity resolution functionality is provided by the LiveConnect JS library, included within the LiveIntent ID sub-module. LiveIntent has created a shared library that is open source, available at https://www.npmjs.com/package/live-connect-js. + +The LiveIntent ID sub-module follows the standard Prebid.js initialization based on the GDPR consumer opt-out choices. With regard to CCPA, the LiveConnect JS receives a us_privacy string from the Prebid US Privacy Consent Management Module and respects opt-outs. + +#### LiveIntent ID Registration + +You are not required to register with LiveIntent to start using the LiveIntent ID sub-module. However, we do recommend reaching out to us at peoplebased@liveintent.com so that we can guide you through the optimal setup and the ways you can benefit from LiveIntent identity solutions: +1. Providing buyers a stable identifier, which can solve cross-browser and cross-channel frequency capping challenges. +2. Leveraging your first-party audiences to increase the value of your inventory. #### LiveIntent ID configuration @@ -407,10 +423,17 @@ The LiveIntent privacy policy is at [https://www.liveintent.com/services-privacy |---|:---:|:---:|---:|---:| |`name`|Required | `String`|The name of this module.|`'liveIntentId'`| |`params`| Required|`Object`|Container of all module params.|| -|`params.publisherId`| Required|`String`| The unique identifier for each publisher.|`'12432415'`| +|`params.publisherId`|Required|`String`| The unique identifier for each publisher.|`'12432415'`| +|`params.ajaxTimeout`|Optional|`Number`|This configuration parameter defines the maximum duration of a call to the IdentityResolution endpoint. By default, 1000 milliseconds.|`1000`| |`params.partner`| Optional|`String`|The name of the partner whose data will be returned in the response.|`'prebid'`| |`params.identifiersToResolve`|Optional|`Array[String]`|Used to send additional identifiers in the request for LiveIntent to resolve against the LiveIntent ID.|`['my-id']`| -|`params.url`| Optional|`String`|Use this to change the default endpoint URL if you can call the LiveIntent Identity Exchange within your own domain.|`'//idx.my-domain.com'`| +|`params.url`| Optional|`String`|Use this to change the default endpoint URL if you can call the LiveIntent Identity Exchange within your own domain.|`'https://idx.my-domain.com'`| +|`params.providedIdentifierName`| Optional|`String`|This parameter should be used whenever a customer is able to provide the most stable identifier possible, e.g. a cookie which is set via HttpHeaders on the first party domain.|`'my-best-id'`| +|`params.liCollectConfig`|Optional|`Object`|Container of all collector params.|| +|`params.liCollectConfig.fpiStorageStrategy`|Optional|`String`|This parameter defines whether the first party identifiers that LiveConnect creates and updates are stored in a cookie jar, or in local storage. If nothing is set, default behaviour would be `cookie`. Allowed values: [`cookie`, `ls`, `none`]|`'cookie'`| +|`params.liCollectConfig.fpiExpirationDays`|Optional|`Number`|The expiration time of an identifier created and updated by LiveConnect.By default, 730 days.|`729`| +|`params.liCollectConfig.collectorUrl`|Optional|`String`|The parameter defines where the signal pixels are pointing to. The params and paths will be defined subsequently. If the parameter is not set, LiveConnect will by default emit the signal towards `https://rp.liadm.com`.|`'https://rp.liadm.com'`| +|`params.liCollectConfig.appId`|Optional|`String`|LiveIntent's media business entity application id.|`'a-0012'`| #### LiveIntent ID examples @@ -443,6 +466,34 @@ pbjs.setConfig({ }) ``` +3. If lll the supported configuration params are passed, then the setup looks like this. +``` +pbjs.setConfig({ + userSync: { + userIds: [{ + name: "liveIntentId", + params: { + publisherId: "9896876", + identifiersToResolve: ["my-own-cookie"], + providedIdentifierName: "my-best-cookie", + url: "https://publisher.liveintent.com/idex", + partner: "prebid", + ajaxTimeout: 1000, + storage: { + expires: 3 + }, + liCollectConfig: { + fpiStorageStrategy: "cookie", + fpiExpirationDays: 730, + collectorUrl: "https://rp.liadm.com", + appId: "a-0012" + } + } + }] + } +}) +``` + ### Parrable ID The Parrable ID is a Full Device Identifier that can be used to identify a device across different browsers and webviews on a single device including browsers that have third party cookie restrictions. From 7ca33105b1af38d0bf56b1ada02c1634f494b90d Mon Sep 17 00:00:00 2001 From: MartianTribe Date: Thu, 26 Mar 2020 14:32:38 -0400 Subject: [PATCH 18/76] Pbm tcf20 (#1887) * added iOS purpose consent code samples * Added GDPR purpose consent for Android Co-authored-by: Steve --- .../android/pbm-targeting-params-android.md | 31 +++++++++++++++++-- .../pbm-api/ios/pbm-targeting-ios.md | 23 ++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) 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 003d1435d5..57bd5862e7 100755 --- a/prebid-mobile/pbm-api/android/pbm-targeting-params-android.md +++ b/prebid-mobile/pbm-api/android/pbm-targeting-params-android.md @@ -248,22 +248,47 @@ TargetingParams.addBidderToAccessControlList(TargetingParams.BIDDER_NAME_RUBICON Prebid Mobile supports the [IAB GDPR recommendations](https://www.iab.com/topics/consumer-privacy/gdpr/). For a general overview of Prebid Mobile support for GDPR, see [Prebid Mobile Guide to European Ad Inventory and Providing Notice, Transparency and Choice](/prebid-mobile/privacy-regulation.html) +### Subject To GPDR + Enable (true) or disable (false) the ability to provide consent. +#### Retrieve subjectToGDPR + +``` +TargetingParams.isSubjectToGDPR(); +``` +#### Set subjectToGDPR + ``` TargetingParams.setSubjectToGDPR(context, true); ``` -Retrieve the consent string. +### GDPR Consent String + +#### Retrieve gdprConsentString ``` context = TargetingParams.getGDPRConsentString(); ``` -Enable publishers to set the consent string. +#### Set gdprConsentString + +``` +TargetingParams.setGDPRConsentString(string); +``` + +### Purpose Consent + +#### Retrieve purposeConsent + +``` +TargetingParams.getPurposeConsents(); +``` + +#### Set purposeConsent ``` -TargetingParams.setGDPRConsentString(context, "consent_string"); +TargetingParams.setPurposeConsents(string); ``` Prebid mobile also checks if the values are present in the [SharedPreferences](https://developer.android.com/training/data-storage/shared-preferences) keys specified by the IAB. If the values are also set in these objects they will be passed in the OpenRTB request object. diff --git a/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md b/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md index 24a001a87c..1b4f547984 100644 --- a/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-targeting-ios.md @@ -379,6 +379,29 @@ guard let gdprConsentString = Targeting.shared.gdprConsentString else { Targeting.shared.gdprConsentString = "A String" ``` +### Purpose Consent + +``` +public var purposeConsents: String? +``` + +You can retrieve and set the purposeConsents for targeting: + +``` +//given + +Targeting.shared.purposeConsents = "100000000000000000000000" + +defer { + + Targeting.shared.purposeConsents = nil + +} + +//when + +let deviceAccessConsent = Targeting.shared.getDeviceAccessConsent() +``` ### Subject to COPPA Prebid supports passing of the Child Online Privacy Prection (COPPA) signal to Prebid Server (PBS) for all COPPA traffic. When PBS receives the COPPA flag we strip out all personal data from the requeset. For a general overview of COPPA, see the [FTC's guidlines](https://www.ftc.gov/enforcement/rules/rulemaking-regulatory-reform-proceedings/childrens-online-privacy-protection-rule). From c87435759a3f31e4f116377ff4258ef3e991a382 Mon Sep 17 00:00:00 2001 From: Bryan Szekely <49168870+bszekely1@users.noreply.github.com> Date: Thu, 26 Mar 2020 17:23:30 -0400 Subject: [PATCH 19/76] =?UTF-8?q?PBSDK=201.5:=20Added=20Rewarded=20video?= =?UTF-8?q?=20and=20corrected=20a=20few=20errors=20on=20other=20p=E2=80=A6?= =?UTF-8?q?=20(#1881)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * PBSDK 1.5: Added Rewarded video and corrected a few errors on other pages * Added a spelling mistake * Added a spelling mistake2 * Added a spelling mistake2 --- _data/sidebar.yml | 18 ++- .../pbm-video-rewarded-adunit-android.md | 149 ++++++++++++++++++ .../pbm-videointerstitialadunit-android.md | 2 +- .../pbm-videooutstreamadunit-android.md | 2 +- .../ios/pbm-video-rewarded-adunit-ios.md | 86 ++++++++++ .../ios/pbm-videointerstitialadunit-ios.md | 57 +------ .../ios/pbm-videooutstreamadunit-ios.md | 20 +-- 7 files changed, 261 insertions(+), 73 deletions(-) create mode 100755 prebid-mobile/pbm-api/android/pbm-video-rewarded-adunit-android.md create mode 100755 prebid-mobile/pbm-api/ios/pbm-video-rewarded-adunit-ios.md diff --git a/_data/sidebar.yml b/_data/sidebar.yml index d34fbd32a7..305aa7afcf 100644 --- a/_data/sidebar.yml +++ b/_data/sidebar.yml @@ -737,7 +737,6 @@ isSectionHeader: 0 sectionTitle: subgroup: 1 - - sbSecId: 2 title: Video interstitial Ad Unit link: /prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.html @@ -746,6 +745,14 @@ sectionTitle: subgroup: 1 +- sbSecId: 2 + title: Video Rewarded Ad Unit + link: /prebid-mobile/pbm-api/ios/pbm-video-rewarded-adunit-ios.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 1 + - sbSecId: 2 title: Targeting Parameters link: /prebid-mobile/pbm-api/ios/pbm-targeting-ios.html @@ -851,6 +858,15 @@ sectionTitle: subgroup: 2 +- sbSecId: 2 + title: Video Rewarded Ad Unit + link: /prebid-mobile/pbm-api/android/pbm-video-rewarded-adunit-android.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 2 + + - sbSecId: 2 title: Targeting Parameters link: /prebid-mobile/pbm-api/android/pbm-targeting-params-android.html diff --git a/prebid-mobile/pbm-api/android/pbm-video-rewarded-adunit-android.md b/prebid-mobile/pbm-api/android/pbm-video-rewarded-adunit-android.md new file mode 100755 index 0000000000..aa1452d242 --- /dev/null +++ b/prebid-mobile/pbm-api/android/pbm-video-rewarded-adunit-android.md @@ -0,0 +1,149 @@ +--- +layout: page_v2 +title: RewardedVideoAdUnit - Android +description: RewardedVideoAdUnit - Android +top_nav_section: prebid-mobile +nav_section: prebid-mobile +sidebarType: 2 +--- + +# RewardedVideoAdUnit Object +{:.no_toc} + +Use the `RewardedVideoAdUnit` object to create and configure a rewarded video ad unit in your app. + + + +* TOC +{:toc} + +## Object + +### RewardedVideoAdUnit + +Create a new Video Rewarded Ad Unit associated with a Prebid Server configuration ID. + + +```java +RewardedVideoAdUnit("configId"); +``` + +**Parameters** + +`configId`: String; Prebid Server configuration ID. + + + +## Methods + +`RewardedVideoAdUnit` inherits all methods from the [AdUnit](/prebid-mobile/pbm-api/android/pbm-adunit-android.html) object. + + + +## Example + +**Google Ad Manager** + +```java +//setup PB RewardedVideo +RewardedVideoAdUnit adUnit = new RewardedVideoAdUnit("configId"); +//setup AM RewardedVideo +RewardedAd amRewardedAd = new RewardedAd(this, "adUnitId"); +//load AM RewardedVideo +PublisherAdRequest.Builder builder = new PublisherAdRequest.Builder(); +PublisherAdRequest request = builder.build(); +adUnit.fetchDemand(request, new OnCompleteListener() { + @Override + public void onComplete(ResultCode resultCode) { + amRewardedAd.loadAd(request, new RewardedAdLoadCallback() { + @Override + public void onRewardedAdLoaded() { + // Ad successfully loaded. + if (amRewardedAd.isLoaded()) { + amRewardedAd.show(DemoActivity.this, new RewardedAdCallback() { + @Override + public void onRewardedAdOpened() { + // Ad opened. + } + @Override + public void onRewardedAdClosed() { + // Ad closed. + } + @Override + public void onUserEarnedReward(@NonNull RewardItem reward) { + // User earned reward. + } + @Override + public void onRewardedAdFailedToShow(int errorCode) { + // Ad failed to display. + } + }); + } + } + @Override + public void onRewardedAdFailedToLoad(int errorCode) { + // Ad failed to load. + } + }); +} +}); + +``` + + +**Mopub** + +```java +//setup PB RewardedVideo +RewardedVideoAdUnit adUnit = new RewardedVideoAdUnit("configId"); +//setup MP RewardedVideo +SdkConfiguration sdkConfiguration = new SdkConfiguration.Builder("adUnitId").build(); +MoPub.initializeSdk(this, sdkConfiguration, null); +MoPubRewardedVideos.setRewardedVideoListener(this); +//loadMPRewardedVideo +final Map keywordsMap = new HashMap<>(); +adUnit.fetchDemand(keywordsMap, new OnCompleteListener() { + @Override + public void onComplete(ResultCode resultCode) { + MoPubRewardedVideoManager.RequestParameters parameters = new MoPubRewardedVideoManager.RequestParameters(Util.convertMapToMoPubKeywords(keywordsMap)); + MoPubRewardedVideos.loadRewardedVideo("adUnitId", parameters, (MediationSettings) null); + } +}); +//MoPub Rewarded Video Listener + @Override + public void onRewardedVideoLoadSuccess(@NonNull String adUnitId) { + if (MoPubRewardedVideos.hasRewardedVideo(MP_ADUNITID_REWARDED)) { + MoPubRewardedVideos.showRewardedVideo(MP_ADUNITID_REWARDED); + } + } + @Override + public void onRewardedVideoLoadFailure(@NonNull String adUnitId, @NonNull MoPubErrorCode errorCode) { + LogUtil.d("onRewardedVideoLoadFailure:" + errorCode); + } + @Override + public void onRewardedVideoStarted(@NonNull String adUnitId) { + } + @Override + public void onRewardedVideoPlaybackError(@NonNull String adUnitId, @NonNull MoPubErrorCode errorCode) { + } + @Override + public void onRewardedVideoClicked(@NonNull String adUnitId) { + } + @Override + public void onRewardedVideoClosed(@NonNull String adUnitId) { + } + @Override + public void onRewardedVideoCompleted(@NonNull Set adUnitIds, @NonNull MoPubReward reward) { + } + +``` + +## Related Topics + +- [Ad Unit]({{site.baseurl}}/prebid-mobile/pbm-api/android/pbm-adunit-android.html) +- [Prebid Mobile API - Android]({{site.baseurl}}/prebid-mobile/pbm-api/android/pbm-api-android.html) +- [Banner Ad Unit]({{site.baseurl}}/prebid-mobile/pbm-api/android/pbm-banneradunit-android.html) +- [Result Codes]({{site.baseurl}}/prebid-mobile/pbm-api/android/pbm-api-result-codes-android.html) +- [Targeting Parameters]({{site.baseurl}}/prebid-mobile/pbm-api/android/pbm-targeting-params-android.html) +- [Prebid Mobile Object]({{site.baseurl}}/prebid-mobile/pbm-api/android/prebidmobile-object-android.html) +- [Prebid Mobile API - iOS]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-api-ios.html) diff --git a/prebid-mobile/pbm-api/android/pbm-videointerstitialadunit-android.md b/prebid-mobile/pbm-api/android/pbm-videointerstitialadunit-android.md index f6e9ae4042..299dd3edfa 100755 --- a/prebid-mobile/pbm-api/android/pbm-videointerstitialadunit-android.md +++ b/prebid-mobile/pbm-api/android/pbm-videointerstitialadunit-android.md @@ -13,7 +13,7 @@ sidebarType: 2 Use the `VideoInterstitialAdUnit` object to create and configure an interstitial ad unit in your app. -Currently Google Ad Manager is the only supported ad server. We plan to provide support for additional ad servers in subsequent releases. +Video Interstital is only supported with Google Ad Manager. {: .alert .alert-info} * TOC diff --git a/prebid-mobile/pbm-api/android/pbm-videooutstreamadunit-android.md b/prebid-mobile/pbm-api/android/pbm-videooutstreamadunit-android.md index cae1b44088..0cc2fea7da 100755 --- a/prebid-mobile/pbm-api/android/pbm-videooutstreamadunit-android.md +++ b/prebid-mobile/pbm-api/android/pbm-videooutstreamadunit-android.md @@ -12,7 +12,7 @@ sidebarType: 2 Use the `VideoAdUnit` object to create and configure an outstream video ad unit in your app. -Currently Google Ad Manager is the only supported ad server. We plan to provide support for additional ad servers in subsequent releases. +Video Outstream is only supported with Google Ad Manager. {: .alert .alert-info} * TOC 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 new file mode 100755 index 0000000000..e2b3ded75a --- /dev/null +++ b/prebid-mobile/pbm-api/ios/pbm-video-rewarded-adunit-ios.md @@ -0,0 +1,86 @@ +--- +layout: page_v2 +title: VideoRewardedAdUnit - iOS +description: VideoRewardedAdUnit - iOS +top_nav_section: prebid-mobile +nav_section: prebid-mobile +sidebarType: 2 +--- +# RewardedVideoAdUnit + +Create a new Video Rewarded Ad Unit associated with a Prebid Server configuration ID and a video size. + + + +`RewardedVideoAdUnit(configId: String)` + + +**Parameters** + +`configId(String)`: Prebid Server configuration ID. + + +See [AdUnit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-adunit-ios.html) for additional parameters and methods. + +--- + +## Example + + +**Google Mobile Ads** +Import the GoogleMobileAds from [google-mobile-sdk](https://developers.google.com/admob/ios/download). + +**Swift** +``` +//setup PB RewardedVideo +let adUnit = RewardedVideoAdUnit(configId: "1001-1") +//setup AM RewardedVideo +let amRewardedAd = GADRewardedAd(adUnitID: "adUnitId") +//load AM RewardedVideo +let amRequest = GADRequest() +let adUnit.fetchDemand(adObject: amRequest) { (resultCode: ResultCode) in + amRewardedAd.load(amRequest) { error in + if let error = error { + print("loadAMRewardedVideo failed:\(error)") + } else { + if amRewardedAd?.isReady == true { + amRewardedAd?.present(fromRootViewController: self, delegate:self) + } + } + } + } + +``` + +**Mopub** +Import the Mopub SDK from [Mopub](https://developers.mopub.com/publishers/ios/integrate/). + +**Swift** +``` +//setup PB RewardedVideo +let adUnit = RewardedVideoAdUnit(configId: "1001-1") +//setup MP RewardedVideo +MPRewardedVideo.setDelegate(self, forAdUnitId: "adUnitId") +//load MP RewardedVideo +let targetingDict = NSMutableDictionary() +adUnit.fetchDemand(adObject: targetingDict) { (resultCode: ResultCode) in + print("Prebid demand fetch for mopub \(resultCode.name())") + if let targetingDict = targetingDict as? Dictionary { + let keywords = Utils.shared.convertDictToMoPubKeywords(dict: targetingDict) + MPRewardedVideo.loadAd(withAdUnitID: "adUnitId", keywords: keywords, userDataKeywords: nil, location: nil, mediationSettings: nil) + } +} + + +``` + + +## Related Topics + +- [Prebid Mobile API - iOS]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-api-ios.html) +- [Ad Unit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-adunit-ios.html) +- [Banner Ad Unit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-banneradunit-ios.html) +- [Result Codes]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-api-result-codes-ios.html) +- [Targeting Parameters]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-targeting-ios.html) +- [Prebid Mobile Object]({{site.baseurl}}/prebid-mobile/pbm-api/ios/prebidmobile-object-ios.html) +- [Prebid Mobile API - Android]({{site.baseurl}}/prebid-mobile/pbm-api/android/pbm-api-android.html) diff --git a/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md b/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md index 6950cd8c72..29bec1a7aa 100755 --- a/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-videointerstitialadunit-ios.md @@ -10,61 +10,14 @@ sidebarType: 2 Create a new Video Outstream Ad Unit associated with a Prebid Server configuration ID and a video size. -Currently Google Ad Manager is the only supported ad server. We plan to provide support for additional ad servers in subsequent releases. +Video Insterstital is only supported with Google Ad Manager. {: .alert .alert-info} -See [AdUnit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-adunit-ios.html) for additional parameters and methods. - -`VideoInterstitialAdUnit(configId: String, size: CGSize(width: Int, height: Int), type:Enum)` - -**Parameters** - -`configId(String)`: Prebid Server configuration ID - -`size(CGSize)`: Width and height of the video ad unit - -`type:Enum`: OpenRTB Placement Type - - -#### CGSize - -Size of video ad unit. - -**Parameters** - -`width`: Width of video ad unit in DIPs. - -`height`: Height of video ad unit in DIPs. - - -#### type - -OpenRTB Placement Type represented as an enumeration of values: - -* `inBanner` is transformed into OpenRTB value 2 to bid adapters -* `inArticle` is transformed into OpenRTB value 3 to bid adapters -* `inFeed` is transformed into OpenRTB value 4 to bid adapters - - - -## videoAd: Video Events - -### videoAd - -* Video event listeners - -`videoAd (event: PBVideoAdEvent)`: Event to listen to. +`VideoInterstitialAdUnit(configId: String)` **Parameters** -Events - one of these event types: - -* AdLoadSuccess -* AdLoadFail -* AdClicked -* AdStarted -* AdDidReachEnd - +`configId(String)`: Prebid Server configuration ID. See [AdUnit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-adunit-ios.html) for additional parameters and methods. @@ -74,7 +27,7 @@ See [AdUnit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-adunit-ios.html) for **Google Mobile Ads** -Import the GoogleMobileAds from [google-mobile-sdk](https://developers.google.com/admob/ios/download) into the UIViewController displaying the VideoAdUnit. +Import the GoogleMobileAds from [google-mobile-sdk](https://developers.google.com/admob/ios/download) into the UIViewController displaying the VideoInterstitialAdUnit. **Swift** ``` @@ -92,7 +45,7 @@ Import the GoogleMobileAds from [google-mobile-sdk](https://developers.google.co func setupPBInterstitialVAST() { Prebid.shared.prebidServerHost = .Rubicon Prebid.shared.prebidServerAccountId = "accountId" - adUnit = VideoInterstitialAdUnit(configId: "configId", size: CGSize(width: 300, height: 250), type: .inBanner) + adUnit = VideoInterstitialAdUnit(configId: "configId") } func setupAMInterstitialVAST() { diff --git a/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md b/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md index e19862f9eb..981afc7b00 100755 --- a/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md +++ b/prebid-mobile/pbm-api/ios/pbm-videooutstreamadunit-ios.md @@ -12,7 +12,7 @@ sidebarType: 2 The VideoAdUnit is a subclass of the [AdUnit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-adunit-ios.html) class. Use the VideoAdUnit object to create and configure a video outstream ad unit in your app. -Currently Google Ad Manager is the only supported ad server. We plan to provide support for additional ad servers in subsequent releases. +Video Outstream is only supported with Google Ad Manager. {: .alert .alert-info} - TOC @@ -24,6 +24,7 @@ Currently Google Ad Manager is the only supported ad server. We plan to provide Create a new Video Outstream Ad Unit associated with a Prebid Server configuration ID and a video size. + See [AdUnit]({{site.baseurl}}/prebid-mobile/pbm-api/ios/pbm-adunit-ios.html) for additional parameters and methods. `VideoAdUnit(configId: String, size: CGSize(width: Int, height: Int), type:Enum)` @@ -56,23 +57,6 @@ OpenRTB Placement Type represented as an enumeration of values: * `inArticle` is transformed into OpenRTB value 3 to bid adapters * `inFeed` is transformed into OpenRTB value 4 to bid adapters -## videoAd: Video Events - -### videoAd - -* Video event listeners - -`videoAd (event: PBVideoAdEvent)`: Event to listen to. - -**Parameters** - -Events - one of the below event types: - -* AdLoadSuccess -* AdLoadFail -* AdClicked -* AdStarted -* AdDidReachEnd From 694288aca2d75af494bdcacfdc41c280ef72a44d Mon Sep 17 00:00:00 2001 From: Bryan Szekely <49168870+bszekely1@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:01:26 -0400 Subject: [PATCH 20/76] Floors documentation update (#1895) * Floors: Latest documentation --- _data/sidebar.yml | 8 + assets/images/floors/floors_flow.png | Bin 0 -> 30389 bytes dev-docs/modules/floors.md | 1026 ++++++++++++++++++-------- 3 files changed, 744 insertions(+), 290 deletions(-) create mode 100644 assets/images/floors/floors_flow.png diff --git a/_data/sidebar.yml b/_data/sidebar.yml index 305aa7afcf..015654d62a 100644 --- a/_data/sidebar.yml +++ b/_data/sidebar.yml @@ -439,6 +439,14 @@ sectionTitle: subgroup: 5 +- sbSecId: 1 + title: Floors Module + link: /dev-docs/modules/floors.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 5 + - sbSecId: 1 title: Supply Chain Object link: /dev-docs/modules/schain.html diff --git a/assets/images/floors/floors_flow.png b/assets/images/floors/floors_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..5f0bf1683347b030d00136a56e165d3fbcde5b84 GIT binary patch literal 30389 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 I(xz|zANN8x>;M1& literal 0 HcmV?d00001 diff --git a/dev-docs/modules/floors.md b/dev-docs/modules/floors.md index 3c1e70a288..8ef38c861b 100644 --- a/dev-docs/modules/floors.md +++ b/dev-docs/modules/floors.md @@ -12,9 +12,6 @@ sidebarType : 1 # Price Floors Module {:.no_toc} -{: .alert.alert-warning :} -DRAFT - * TOC {:toc} @@ -22,447 +19,896 @@ DRAFT The Floors module provides an open source framework in Prebid for Publishers to configure price floors on their own or to work with a vendor who can provide floors. -A 'floor' is defined as the lowest price that a publisher will accept for a -bid on a Prebid AdUnit. It's a way for publishers to protect the value of -their inventory by requiring buyers to keep bids at a minimum level. +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 floors to be defined, passes them to -bidders and enforces that bid responses meet the floor in any supported currency. The floors utilized by Prebid.js are fairly simple, spanning only three dimensions: +The module provides several ways for 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: -- AdUnit or AdSlot + +- AdUnit +- GPT Slot Name - MediaType - Ad Size +- Domain -The entire set of floors defined for a given page view are called 'Page Floors'. They may be defined in several ways: +{: .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. -1. Right in the AdUnit -1. With `setConfig` -1. Retrieved from a real-time data service +The entire set of floors selected by the 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) -Examples for each of these scenarios follows. {: .alert.alert-info :} -Even though Page Floors are defined with only three attributes, -it's possible to utilize other attributes of the page or user to define the -Page Floors. For example, of floor values could be dynamically created -based on device type, country, page category, etc. +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. + + +## 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: + +![Floors Module Flow](/assets/images/floors/floors_flow.png) + +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 +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. +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 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 + ## Defining Floors -How price floors are defined in the page environment will depend on how you're -obtaining the floors and how Prebid.js is integrated into the pages. We strongly recommend an automated analytical process rather than sporadic manual updates. +How price floors are used in the page will depend on how you’re obtaining the floors and how Prebid.js is integrated into the pages. For optimal revenue performance, we strongly recommend an automated flooring method compared to manual, sporadic updates. ### Floors Defined in the AdUnit -In this approach, the Publisher configures the floors directly into the Prebid.js -AdUnits. This method can be used on simple pages or as part of a content -management system that dynamically creates AdUnits. - -{% highlight js %} - var adUnits = [ - { - code: 'test-div', - mediaTypes: { - banner: { sizes: [[300,250],[300,600]] }, - video: { - context: 'outstream', - playerSize: [300,250], - ... - } - }, - floors: { - currency: 'USD', - schema: { - delimiter: '|', - fields: [ 'mediaType', 'size' ] - }, - values: [ - {key: 'banner|300x250', floor: 1.10}, - {key: 'banner|300x600', floor: 1.35}, - {key: 'video|300x250', floor: 2.00} - ] - }, - bids: [ - ... - ] +In this approach, the Publisher configures the floors directly into the Prebid.js AdUnits. This method can be used on simple pages or as part of a content management system that dynamically creates AdUnits. + +Below are some basic principles of ad unit floor definitions: + +- Ad unit defined rules only apply to the ad unit they are created in +- Setting a rule with a value that does not match the context of that given ad unit will never be used +- If multiple ad units have configured floor objects, the first ad unit’s schema would apply to all subsequent ad unit floor definitions + - Values can differ between ad units + + +{% highlight js %} + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { sizes: [[300,250],[300,600]] }, + video: { + context: 'outstream', + playerSize: [300,250], + ... + } + }, + floors: { + currency: 'USD', + schema: { + delimiter: '|', + fields: [ 'mediaType', 'size' ] + }, + values: { + 'banner|300x250': 1.10, + 'banner|300x600': 1.35, + 'video|300x250': 2.00 + } + }, + bids: [ + ... + ] + } + ]; +{% 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 %} +floors: { + currency: 'USD', + skipRate: 5, + modelVersion: 'Sports Ad Unit Floors', + schema: { + fields: [ 'mediaType'] + }, + values: { + 'banner': 0.8, + 'video': 2.01 } - ]; + } {% endhighlight %} -Note that the `values` object is what contains the actual floors, and in this -example they're based on a combination of the mediaType and size. Since many -adapters don't currently support defining a floor for each size, a simpler -definition would be: +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: {% highlight js %} - ... - floors: { - currency: 'USD', - schema: { - fields: [ 'mediaType' ] - }, - values: [ - {key: 'banner', floor: 1.10}, - {key: 'video', floor: 2.00} - ] - }, - ... +floors: { + currency: 'USD', + skipRate: 5, + modelVersion: 'Sports Ad Unit Floors', + schema: { + fields: [ 'mediaType', 'size'] + }, + values: { + 'banner|300x250': 0.8, + 'banner|300x600': 1.8, + 'banner|728x90': 0.90, + 'banner|*': 1.00, + 'video|300x250': 2.01, + 'video|*': 2.01 + } +} {% endhighlight %} -Or if there's only one mediaType in the AdUnit and a single global floor, the syntax gets easier: +Alternatively, if there’s only one mediaType in the AdUnit and a single global floor, the syntax gets easier: {% highlight js %} - ... - floors: { - default: 1.00 // default currency is USD - }, - ... +... + floors: { + default: 1.00 // default currency is USD + }, + ... {% endhighlight %} ### Package-Level Floors -This approach is intended for scenarios where the Publisher or their Prebid managed -service provider periodically appends updated floor data to the Prebid.js package. -In this model, there could be a more floor data present to -cover AdUnits across many pages. +This approach is intended for scenarios where the Publisher or their Prebid managed service provider periodically appends updated floor data to the Prebid.js package. In this model, there could be more floor data present to cover AdUnits across many pages. {% highlight js %} pbjs.setConfig({ floors: { - auctionDelay: 0, // this is the default - data: { + enforcement: { + floorDeals: false, //default to false + bidAdjustment: true + }, + data: { // default if endpoint doesn't return in time currency: 'USD', + skipRate: 5, + modelVersion: 'some setconfig model version', schema: { - fields: [ 'gptSlot' ] + fields: [ 'gptSlot', 'mediaType' ] }, - values: [ - {key: '/1111/homepage/top-rect', floor: 0.80}, - {key: '/1111/homepage/left-nav', floor: 0.90}, + values: { + '/1111/homepage/top-rect|banner': 0.80, + '/1111/homepage/top-rect|video': 2.20, + '/1111/homepage/top-rect|*': 1.50, + '/1111/homepage/left-nav|banner': 1.20, + '/1111/homepage/left-nav|video': 2.20, + '/1111/homepage/left-nav|*': 1.50, ... there could be hundreds of these ... - {key: '/1111/tech/left-nav', floor: 1.50} - ], - default: 0.75 + '*|banner': 0.98, + '*|video': 1.74 + } } } }); {% 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 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: +Here’s another example that includes more fields: {% highlight js %} pbjs.setConfig({ floors: { - data: { + data: { // default if endpoint doesn't return in time currency: 'USD', + skipRate: 5, + modelVersion: 'some setconfig model version', schema: { - fields: [ 'gptSlot', 'mediaType' ] + fields: [ 'domain', 'gptSlot', 'mediaType', 'size'] }, - values: [ - {key: '/1111/homepage/top-rect|banner', floor: 0.80}, - {key: '/1111/homepage/top-rect|video', floor: 1.20}, - {key: '/1111/homepage/left-nav|banner', floor: 0.90}, + 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 ... - {key: '/1111/tech/left-nav|banner', floor: 1.50} - ], - default: 0.75 + } } } }); {% endhighlight %} ### Dynamic Floors -The final method of obtaining floor data allows the publisher to delay the auction for a certain time period to obtain up-to-date floor data tailored to this specific pageview. The assumed workflow is: - +The final method of obtaining floor data allows the publisher to delay the auction for a certain time period to obtain up-to-date floor data tailored to each page or auction context. The assumed workflow is: + 1. The Publisher signs up with a floor data provider -1. The Publisher configures Prebid.js to resolve and enforce the price floor -1. The Floor provider makes a JSON file available with floor data +2. The Publisher configures Prebid.js to resolve and enforce the price floor +3. The Floor provider makes a JSON file available with floor data + +Here’s an example defining a simple GET endpoint: + +{% highlight js %} +pbjs.setConfig({ + floors: { + enforcement: { + floorDeals: true, //default to false + }, + auctionDelay: 100, // in milliseconds + endpoint: { + url: 'https://floorprovider.com/a1001-mysite.json' + } + } +}); +{% 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. -Here's an example defining a simple GET endpoint: {% highlight js %} pbjs.setConfig({ floors: { + enforcement: { + floorDeals: false, //default to false + }, auctionDelay: 100, // in milliseconds endpoint: { - url: 'https://floorprovider.com/a1001-mysite.json', - method: 'GET' + url: 'https://floorprovider.com/a1001-mysite.json' }, data: { // default if endpoint doesn't return in time currency: 'USD', + skipRate: 5, + modelVersion: ‘new model 1.0’ schema: { fields: [ 'mediaType' ] }, - values: [ - {key: 'banner', floor: 0.80}, - {key: 'video', floor: 1.20} - ] + values: { + 'banner': 0.80, + 'video': 1.20 + } } } }); {% endhighlight %} -If the dynamic data doesn't come back from the endpoint in time, the floors defined in the data object will be utilized. -### SetConfig Syntax +### Floors Syntax The examples above covered several different scenarios. Here are all the options supported by the Floors module. {: .table .table-bordered .table-striped } -| Param | Required? | Type | Description | Default | +| Param | Type | Description | Default | |---+---+---+---+---| -| auctionDelay | no | integer | number of milliseconds to delay the auction. Will always be 0 if there's no endpoint param. Must be > 0 if endpoint is defined. | 100 if the 'endpoint' param is defined. 0 otherwise.| -| endpoint | no | object | defines how PBJS should call out to a floor provider to obtain dynamic floor data | none | -| endpoint.url | no | string | URL of the endpoint | none | -| endpoint.method | no | string | Only GET is currently supported. | "GET" | -| data | object | yes | floor data that may be used by the module to send to bidders and enforce floors. Used as a fallback if a dynamic floor service doesn't respond within the auctionDelay period. | none | -| data.currency | no | floor data will expressed in a given currency, which will be converted as needed to pass to adapters or enforce. | 'USD' | -| data.schema | no | allows for flexible definition of how floor data is formatted. | none | -| data.schema.delimiter | no | which character separates the floor keys | '\|' | -| data.schema.fields | no | array of strings | supported values are: gptSlot, adUnitCode, mediaType, size | none | -| data.values | no | array of objects | a series of attributes representing a hash of floor data in a format defined by the schema object. | none | -| data.values.key | no | string | delimited field of attribute values that define a floor | none | -| data.values.floor | no | float | the floor value for this key | none | -| data.default | no | float | floor to use if there aren't any values or if none of them match | none | +| enforcement | object | Controls the enforcement behavior within the Floors Module.| - | +| enforcement.enforceJS | boolean | If set to true, the floor 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 PBS 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 | Adjust floors passed to Bid Aapters. If bid adjustment is passed to PBS and flag set is not set to false | 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.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. | 0 | +| 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.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 | - | +| data.values | key / values | a series of attributes representing a hash of floor data in a format defined by the schema object. | - | +| data.values."rule key" | string | delimited field of attribute values that define a floor | - | +| data.values."floor" | float | the floor value for this key | - | +| data.default | float | Floor used if no matching rules are found | - | -## How it Works -There are several places where the Floor module changes the behavior of the Prebid.js auction process. +## 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. + +The Floors Module will use the below prioritization scheme on determining which Rule Location is selected at run-time: + +- 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 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. + +Priority order behavior where “\_” is a specific value, and the “\*” is a catch all + +Priority order for one column rule sets: + + \_ + \* + +Priority order for two column rule set: + + \_ \| \_ + \_ \| \* + \* \|\_ + \* \| \* + +Priority order for three column rule sets: + + \_ \| \_ \| \_ + \_ \| \_ \| \* + \_ \| \* \| \_ + \* \| \_ \| \_ + \* \| \_ \| \* + \_ \| \* \| \* + \* \| \_ \| \* + \* \| \* \| \_ + \* \| \* \| \* + + + +Below are some real example behaviors. + +#### Example 1 + +Domain = www.website.com + +Floor provider rule definition + +{% highlight js %} +{ + "modelVersion": "Fancy Model", + "currency": "USD", + "schema": { + "fields": [ "mediaType", "size", "domain"], + }, + "values": { + "banner|300x250|www.website.com": 1.01, + "banner|300x250|*": 2.01, + "banner|300x600|www.website.com": 3.01, + "banner|300x600|*": 4.01, + "banner|728x90|www.website.com": 5.01, + "banner|728x90|*": 6.01, + "banner|*|www.website.com": 7.01, + "banner|*|*": 8.01, + "*|300x250|www.website.com": 9.01, + "*|300x250|*": 10.01, + "*|300x600|www.website.com": 11.01, + "*|300x600|*": 12.01, + "*|728x90|www.website.com": 13.01, + "*|728x90|*": 14.01, + "*|*|www.website.com": 15.01, + "*|*|*": 16.01 + }, + "default": 0.01 +} +{% endhighlight %} + +**Bidder A Bid** + +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. + +{% highlight js %} +{ + "banner|300x600|www.website.com", //Most specific possible rule match against floor provider rule set + "banner|300x600|*", + "banner|*|www.website.com", + "*|300x600|www.website.com”, + "banner|*|*", + "*|300x600|*", + "*|300x600|*", + "*|*|www.website.com", + "*|*|*" + } +{% endhighlight %} + +Matching rule: "banner|300x600|www.website.com" +Floor enforced: 3.01 + + +**Bidder B Bid** + +mediaType = video +Size = 640x480 +Domain context = www.website.com + +Price Floor internal possible permutations sorted by priority: +{% highlight js %} +{ + "video|640x480|www.website.com", //Fails to match due to no video specific rule + "video|640x480|*", //Fails to match due to no video specific rule + "video|*|www.website.com", //Fails match due to no video specific rule + "*|640x480|www.website.com", //Fails match due to no size 480 specific rule + "video|*|*", //Fails match due to no size video specific rule + "*|640x480|*", //Fails match due to no size 480 specific rule + "*|*|www.website.com", //Matching rule + "*|*|*" + } +{% endhighlight %} + +Matching rule: "\*|\*|www.website.com" +Enforced Floor: 15.01 + + +**Bidder C Bid** + +mediaType = video +Size = 300x250 +Domain context = www.website.com + +Price Floor internal possible permutations sorted by priority: +{% highlight js %} +{ + "video|300x250|www.website.com", //Fails to match due to no video specific rule + "video|300x250|*", //Fails to match due to no video specific rule + "video|*|www.website.com", //Fails to match due to no video specific rule + "*|300x250|www.website.com", //Matching rule + "video|*|*", + "*|300x250|*", + "*|*|www.website.com", + "*|*|*" + } +{% endhighlight %} + +Matching Rule "\*|300x250|www.website.com” +Enforced floor: 10.01 + +#### Example 2 + +Similar data set with slightly different rules and same bids from each bidder. Matching rules will differ from example 1. + +Domain = www.website.com + +Floor provider rule definition + +{% highlight js %} +{ + "modelVersion": "Fancy Model", + "currency": "USD", + "schema": { + "fields": [ "mediaType", "size", "domain"], + }, + "values": { + "banner|300x250|www.publisher.com": 1.01, + "banner|300x250|*": 2.01, + "banner|300x600|www.publisher.com": 3.01, + "banner|300x600|*": 4.01, + "banner|728x90|www.website.com": 5.01, + "banner|728x90|*": 6.01, + "banner|*|www.website.com": 7.01, + "banner|*|*": 8.01, + "video|*|*": 9.01, + "*|300x250|www.website.com": 9.01, + "*|300x250|*": 10.01, + "*|300x600|www.website.com": 11.01, + "*|300x600|*": 12.01, + "*|728x90|www.website.com": 13.01, + "*|728x90|*": 14.01, + "*|*|www.website.com": 15.01, + "*|*|*": 16.01 + }, + "defaultValue": 0.01 +} +{% endhighlight %} + +**Bidder A Bid** + +mediaType = banner +Size = 300x600 +Domain context = www.website.com + +{% highlight js %} +{ + "banner|300x600|www.website.com", // Fails due to website.com does not match with banner and 300x600 + "banner|300x600|*", // Banner, 300x600 * matches first + "banner|*|www.website.com", + "*|300x600|www.website.com”, + "banner|*|*", + "*|300x600|*", + "*|300x600|*", + "*|*|www.website.com", + "*|*|*" + } +{% endhighlight %} + +Matching rule: "banner|300x600|\*" +Floor enforced: 4.01 + +**Bidder B Bid** + +mediaType = video +Size = 640x480 +Domain context = www.website.com. + +Price Floor internal possible permutations sorted by priority: + +{% highlight js %} +{ + "video|640x480|www.website.com", //Fails to match due to no video specific rule + "video|640x480|*", //Fails to match due to no video specific rule + "video|*|www.website.com", //Fails match due to no video specific rule + "*|640x480|www.website.com", //Fails match due to no size 480 specific rule + "video|*|*", //Matches existing rule + "*|640x480|*", + "*|*|www.website.com", + "*|*|*" + } +{% endhighlight %} + +Matching rule: "video\|\*\|\*" +Enforced Floor: 9.01 + + +**Bidder C Bid** + +mediaType = video +Size = 300x250 +Domain context = www.website.com + +Price Floor internal possible permutations sorted by priority: + +{% highlight js %} +{ + "video|300x250|www.website.com", //Fails to match due to no video specific rule + "video|300x250|*", //Fails to match due to no video specific rule + "video|*|www.website.com", //Fails to match due to no video specific rule + "*|300x250|www.website.com", //Matching existing rule + "video|*|*", + "*|300x250|*", + "*|*|www.website.com", + "*|*|*" + } +{% endhighlight %} + +Matching Rule "\*|300x250|www.website.com” +Enforced floor: 10.01 -1. When building the Prebid.js package, the Floors module needs to be included with 'gulp build --modules=floors,...' -1. As soon as the setConfig({'floors'}) call is made, the Floors module will immediately initiate any calls to a dynamic floor endpoint. -1. When an auction is initiated with requestBids(), the Floors module will request to delay the auction if the auctionDelay option is set. -1. If it hasn't converted floor currencies already, the Floors module will look for the existence of a configured Ad Server Currency, converting floor prices as needed. -1. Bid Adapters are responsible for utilizing the getFloors() function and passing the floor values to their bidding endpoints. -1. Prebid.js core gives the Floors module a chance to review each bid response, which will be invalidated if they exceed the floor value. -1. Analytics adapters have access to the floor data and any invalidated bid statuses. ## Interfaces ### Floor Data Provider Interface -Dynamic endpoints must return JSON data that's formatted like the data object -in the floor `setConfig` call. Floor data should be returned quickly because -the auction may be waiting on it. This implies that it should either be -stored on a CDN or be provided by a distributed tier of high performance servers. +Floor data providers can supply data to publishers either within the setConfig as part of a Prebid.js Package if the provider is also a host provider of the Prebid library, or via a real-time Dynamic fetch, prior to the auction. + +Data providers can optionally build Analytics Adapters to ingest bid data within Prebid for algorithm learning and review floor performance. Please refer to the Analytics Interface section for more details. + + + +{% capture warning_note %} +As a floor provider, your goal is to provide effective floors, with minimal page impact. If you are performing a Dynamic fetch to retrieve data prior to auctions, the following recommendations are advised to reduce page performance issues: + +- Return results to the page quickly. This implies data should be stored on a CDN or be provided by a distributed tier of high performance services +- 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 +{% 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. + + +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. + +#### Example Dynamic fetch -Example Response 1 - floor determined by GPT Ad Slot and mediatype {% highlight js %} -{ - data: { - currency: 'USD', - schema: { - fields: [ 'gptSlot', 'mediaType' ] - }, - values: [ - {key: '/1111/homepage/top-rect|banner', floor: 0.80}, - {key: '/1111/homepage/top-rect|video', floor: 1.20}, - {key: '/1111/homepage/left-nav|banner', floor: 0.90}, - ... - {key: '/1111/tech/left-nav|banner', floor: 1.50} - ], - default: 0.75 +pbjs.setConfig({ + floors: { + enforcement: { + floorDeals: true + }, + auctionDelay: 100, + endpoint: { + url: 'https://floorprovider.com/a1001-mysite.json' } + } +}); +{% endhighlight %} + +#### Example Response 1 + +floor determined by AdUnit code and Media Type: + +{% highlight js %} +{ + currency: 'USD', + skipRate: 5, + modelVersion: ‘new model 1.0’ + schema: { + fields: [ 'gptSlot', 'mediaType' ] + }, + values: { + '/1111/homepage/top-rect|banner': 0.80, + '/1111/homepage/top-rect|video': 1.20, + '/1111/homepage/left-nav|banner': 0.90, + ... + '/1111/tech/left-nav|banner': 1.50 + }, + default: 0.75 } + {% endhighlight %} -Example Response 2 - floor determined by AdUnit code and size: +#### Example Response 2 + +floor determined by Domain, GPT Slot, Media Type and Size: + {% highlight js %} { - data: { - currency: 'EUR', - schema: { - fields: [ 'adUnitCode', 'size' ] - }, - values: [ - {key: 'div-1|300x250', floor: 0.80}, - {key: 'div-2|300x600', floor: 1.20}, - {key: 'div-2|300x250', floor: 0.90}, - ... - {key: 'div-3|640x480', floor: 1.50} - ], - default: 0.75 - } + currency: 'EU', + skipRate: 20, + modelVersion: ‘High_skip_rate’ + 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 } {% endhighlight %} -The format of the request for dynamic floor data has been left open - -each floor provider can determine the URL structure, working -with the publisher to integrate their service into the page. -### Prebid.js Bid Adapter Interface +### 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. -Many Prebid.js bid adapters already allow the publisher to define a floor in -their bidder-specific params. This module establishes a new and more powerful -convention, but requires each adapter look for the floor data in the -appropriate place. Rather than forcing adapters to look in the AdUnit and -the global config and parse complicated floor data, we've thoughtfully -provided a utility function called 'getFloors()'. To use it: +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. -1. import getFloor function -1. call getFloors() with the desired parameters -1. parse the results -1. pass floor value(s) to the bid endpoint +Intended changes for bid adapters: + + +1. Check for presence of getFloor within the bidRequest obect +1. If getFloors exists, call getFloor 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: {% highlight js %} -getFloors(paramsObj); +getFloor({ + currency: string, + mediaType: string //Required + size : [ w, h] OR "*" +}); {% endhighlight %} {: .table .table-bordered .table-striped } -| Param | Required? | Type | Description | Default | -|---+---+---+---+---| -| bidRequest | yes | object | bidRequest object passed to buildRequests function | none | -| currency | no | string | preferred floor currency | adServerCurrency | -| mediaType | no | string | some adapters don't support all media types, so this constrains results to just the type needed by the current ad unit. e.g. 'banner' | none | -| supportMultipleSizes | no | boolean | supporting different floors per size isn't yet a common feature, but we default it to true. By supplying 'false' to this argument, a single floor value will be returned | true | +| 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 | "\*" | +| 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 + +{% highlight js %} +{ + currency: string, + floor: float +} +{% endhighlight %} + +Or empty object if a floor was not found for a given input -The JSON object returned by the function looks similar to the floors object in the adunit. +{% highlight js %} +{ } +{% endhighlight %} -For example, a bidder adapter that can only handle one floor value could make this call: +#### Example getFloor scenarios + +Example rules file used for getFloor {% highlight js %} -getFloors({ - bidRequest: bidRequestObj, +{ + "data": { + "currency": "USD", + "schema": { + "fields": [ "gptSlot", "mediaType", "size"] + }, + "values": { + "/1111/homepage/top-rect|banner|300x250": 0.60, + "/1111/homepage/top-rect|banner|300x600": 1.78, + "/1111/homepage/top-rect|banner|*": 1.10, + "/1111/homepage/top-rect|video|480x600": 3.20, + "/1111/homepage/top-leaderboard|banner|728x90": 1.50 + }, + "default": 0.75 + } +} +{% endhighlight %} + +**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. + +{% highlight js %} +getFloor({ currency: 'USD', - mediaType: 'banner', - supportMultipleSizes: false + mediatype: ‘banner’, + Size: ‘*’ }); {% endhighlight %} -The response in this case would quite easy to parse: +**Response** {% highlight js %} { currency: 'USD', - default: 1.80 + floor: 1.10 } {% endhighlight %} -But if the `mediaType` field isn't passed in the params object, the response would provide different floor values for each mediaType: +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: {% highlight js %} { currency: 'USD', - schema: { - fields: [ 'mediaType' ] - }, - data: [ - {key: 'banner', floor: 1.60}, - {key: 'video', floor: 1.80} - ] + floor: 0.60 } {% endhighlight %} -And adapters that support full floor flexibility could receive something they need to parse: + +**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. + +{% highlight js %} +getFloor({ + currency: 'USD', + size: [300,600], + mediatype: ‘banner’ +}); +{% endhighlight %} + +**Response** {% highlight js %} { currency: 'USD', - schema: { - fields: [ 'mediaType', 'size' ] - }, - data: [ - {key: 'banner|300x250', floor: 1.50}, - {key: 'banner|300x600', floor: 1.60}, - {key: 'video|300x250', floor: 1.80}, - ] + floor: 1.78 } {% endhighlight %} -{: .alert.alert-info :} -Note that whenever the `getFloors` function combines multiple underlying floors -into one, it always chooses the highest floor in order to avoid any scenario -where a bid is later discarded due to more granular flooring rules. Yes, -this will affect bid density. +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. + +{% highlight js %} + if (typeof bidRequest.getFloor === 'function') { + let floorInfo = bidRequest.getFloor({ + currency: 'USD', + mediaType: 'banner', + size: '\*' + }); + data['adapter_floor'] = floorInfo.currency === 'USD' ? floorInfo.floor : undefined; + } +{% endhighlight %} + +### Analytics Adapter Interface -### Prebid.js 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. -Analytics adapters may want to report on floor-related events: +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. -- which floors were sent to the bidders on each AdUnit -- whether any bids were discarded because the bidder did not respect the floor +**bidRequest**: Bid Requests objects are updated to contain some basic top level information which a floor provider may need: -Like bid adapters, analytics adapters can call the 'getFloors()' utility -function with each bidrequest object to obtain the floor data. They can -check the status of the bid, which would be NO_BID_FLOOR if the bid was -discarded because it was below the floor. +{: .table .table-bordered .table-striped } +| bidRequest.floorData. | Type | Description | example | +|---+---+---+---+---| +| skipped | Boolean | Whether the skipRate resolved to be true or false| true | +| modelVersion | String | The name of the model| ‘floor-model-4.3’ | +| location | String | Where the floor rules came from adUnit, setConfig, fetch | ‘floor-model-4.3’ | + +**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: + +{: .table .table-bordered .table-striped } +| bidResponse.floorData. | Type | Description | example | +|---+---+---+---+---| +| floorValue | number | The value of the floor chosen | 2.33 | +| modelVersion | String | The name of the model| ‘floor-model-4.3’ | +| floorRule | String | The matching rule for the given bidResponse | ‘div-1\|300x250\|\*’ | +| floorCurrency | string | Currency of the matched floor | ‘USD’ | +| cpmAfterAdjustments | number | The bidder response CPM after any applicable adjustments (currency and / or bidCpmAdjustments) | 2.20 | +| enforcements | object | The input floor enforcements object. Keys are enforceJS, enforcePBS, floorDeald, bidAdjustment | { enforceJS: true, enforcePBS: false, floorDeals: false, bidAdjustment: true } | +| matchedFields | object | Fields of the prebid auction used to match against the floorData.schema.fields. | { mediaType: ‘banner’, Size: ‘300x250, Domain: ‘www.prebid.org’, gptSlot: ‘/12345/prebid/sports’ } | ### Prebid Server Interface -The Prebid Server Bid Adapter copies floor configuration to the OpenRTB2 protocol: +Not supported in initial build. S2S config support will be coming in the subsequent release. + + +## Currency -- It copies AdUnit-specific floor values directly to the relevant imp object -- It copies floors data coming from setConfig to ext.prebid.floors -- It does not copy any endpoint information -- it is assumed that if dynamic floor data is used, that transaction is being handled by Prebid.js and should not be done again on the server side. -- It always sets ext.prebid.options.enforcefloors to false because there's no way in OpenRTB to return no-bid status per-impression. +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. -AdUnit-specific Floors in OpenRTB: +{% 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. +{% 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 **enforcement** side when each bidder submits a bidResponse + + +**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. + +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. + +Example Rule: +currency = ‘USD’, +‘banner|300x250’: 1.00 + +{% highlight js %} +getFloor({ + currency: ‘EUR’, + mediaType: ‘banner’, + size: [300, 250] +}); +{% endhighlight %} + +If successfully returned the requested currency: {% highlight js %} { - "cur": "USD", - "imp": [{ - ... - "ext": { - "prebid": { - "floors": { - "data": { - "currency": "USD", - "schema": { - "delimiter": "|", - "fields": [ "mediaType", "size" ] - }, - "values": [ - {"key": "banner|300x250", "floor": 0.90}, - {"key": "banner|300x360", "floor": 1.07}, - {"key": "banner|*", "floor": 0.56}, - ] - } - } - } - } - }], - "ext": { - "prebid": { - "options": { - "enforcefloors": false, - } - } - } + floor: 0.85, + currency: ‘EUR’ } {% endhighlight %} -Floors defined in `setConfig` are placed in the top-level `ext` object: +If unsuccessfully returned the requested currency: {% highlight js %} { - "cur": "USD", - "imp": [{ - ... - }], - "ext": { - "prebid": { - "options": { - "enforcefloors": false, - }, - "floors": { - "data": { - "currency": "USD", - "schema": { - "delimiter": "|", - "fields": [ "mediaType", "size" ] - }, - "values": [ - {"key": "banner|300x250", "floor": 0.90}, - {"key": "banner|300x360", "floor": 1.07}, - {"key": "banner|*", "floor": 0.56}, - ] - } - } - } - } + floor:1.0, + currency: ‘USD’ } {% endhighlight %} -When called from Prebid.js, the convention is that Prebid Server will pass floors provided by Prebid.js to the adapters, but will not enforce floors. +Currency conversion can fail for the following reasons: +- Currency module is not included in the prebid bundle. +- Currency module is included but not enabled +- Currency module is included and enabled but: + - No default rates were set + - Currency rates fetch failed + - Data has not returned yet +- 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** + +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. -A separate document will describe how Prebid Server handles floors for SDK and AMP. +There exist three locations where currencies can differ within enforcement: + +- adServerCurrency: The currency the publisher set in their currency module setConfig call +- 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: + +- 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: + +{: .table .table-bordered .table-striped } +| bid.currency | bid.originalCurrency | floor.currency | result | +|---+---+---+---+---| +| USD | USD | USD | Bid.cpm is compared to floor. If bid meets or exceeds the floor, bid.originalCpm is sent to the ad server. | +| USD | USD | EUR | Bid.cpm is converted to EUR then compared with floor. If bid meets or exceeds the floor, bid.originaCpm is sent to the ad server. | +| USD | EUR | EUR | bid.originalCpm is compared to floor. If bid meets or exceeds the floor, bid.Cpm is sent to the ad server. | +| USD | JPY | EUR | Bid.cpm is converted to EUR then compared with floor. If bid meets or exceeds the floor, bid.Cpm is sent to the ad server. | +| EUR | USD | EUR | Bid.cpm is compared to floor. If bid meets or exceeds the floor, bid.Cpm is sent to the ad server. | +| USD | Undefined (currency module possibly not included) | USD | Bid.cpm is compared to floor. If bid meets or exceeds the floor, bid.originalCpm is sent to the ad server. | +| USD | Undefined (currency module possibly not included) | EUR | Bid.cpm is converted to EUR then compared with floor. Bid.cpm is compared to floor. If bid meets or exceeds the floor, bid.originalCpm is sent to the ad server. | + +If the currency function is unable to derive the correct cpm in any of the scenarios above where a conversion is needed, then the associated bidResponse will just pass through into the auction as if a matching floor was not found. \ No newline at end of file From 1e06486a6e8e156b241d6e5445aacdf971ee8b10 Mon Sep 17 00:00:00 2001 From: Bryan Szekely <49168870+bszekely1@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:19:31 -0400 Subject: [PATCH 21/76] Update floors.md --- dev-docs/modules/floors.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-docs/modules/floors.md b/dev-docs/modules/floors.md index 8ef38c861b..9a05f48aef 100644 --- a/dev-docs/modules/floors.md +++ b/dev-docs/modules/floors.md @@ -742,7 +742,7 @@ getFloor({ } {% 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 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: {% highlight js %} { @@ -911,4 +911,4 @@ Below is a chart explaining the behavior of currency conversion, if necessary, w | USD | Undefined (currency module possibly not included) | USD | Bid.cpm is compared to floor. If bid meets or exceeds the floor, bid.originalCpm is sent to the ad server. | | USD | Undefined (currency module possibly not included) | EUR | Bid.cpm is converted to EUR then compared with floor. Bid.cpm is compared to floor. If bid meets or exceeds the floor, bid.originalCpm is sent to the ad server. | -If the currency function is unable to derive the correct cpm in any of the scenarios above where a conversion is needed, then the associated bidResponse will just pass through into the auction as if a matching floor was not found. \ No newline at end of file +If the currency function is unable to derive the correct cpm in any of the scenarios above where a conversion is needed, then the associated bidResponse will just pass through into the auction as if a matching floor was not found. From 1b4866a4c478a3ad7f80291b49f8a9f1568c089a Mon Sep 17 00:00:00 2001 From: Denis Logachov Date: Tue, 31 Mar 2020 19:35:58 +0300 Subject: [PATCH 22/76] Document native support for adkernel adapter (#1893) --- dev-docs/bidders/adkernel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-docs/bidders/adkernel.md b/dev-docs/bidders/adkernel.md index 9f6764a07d..da75aa8ec2 100644 --- a/dev-docs/bidders/adkernel.md +++ b/dev-docs/bidders/adkernel.md @@ -4,7 +4,7 @@ title: AdKernel description: Prebid AdKernel Bidder Adaptor hide: true biddercode: adkernel -media_types: banner, video +media_types: banner, native, video gdpr_supported: true usp_supported: true --- From e442270c2a072bdc1bd104b2fffef43fe66b488f Mon Sep 17 00:00:00 2001 From: Index Exchange 3 Prebid Team Date: Tue, 31 Mar 2020 13:19:22 -0400 Subject: [PATCH 23/76] Index Exchange: Update documentation to include TCF 2.0 (#1891) * Updated TTL from 35 to 300 seconds * added tcf2 support to doc Co-authored-by: Zicong Zhou --- dev-docs/bidders/indexExchange.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-docs/bidders/indexExchange.md b/dev-docs/bidders/indexExchange.md index 8235b354a4..64aad5e038 100644 --- a/dev-docs/bidders/indexExchange.md +++ b/dev-docs/bidders/indexExchange.md @@ -7,6 +7,7 @@ hide: true schain_supported: true gdpr_supported: true usp_supported: true +tcf2_supported: true media_types: banner, video --- From fa04a21d9fc28c2771bc00d6c6499d204270b7d6 Mon Sep 17 00:00:00 2001 From: JonGoSonobi Date: Tue, 31 Mar 2020 13:25:19 -0400 Subject: [PATCH 24/76] Added param documentation for sonobi bid request url (#1886) --- dev-docs/bidders/sonobi.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-docs/bidders/sonobi.md b/dev-docs/bidders/sonobi.md index f0f1f63fba..79998df49e 100644 --- a/dev-docs/bidders/sonobi.md +++ b/dev-docs/bidders/sonobi.md @@ -25,6 +25,7 @@ implementing our adapter please don't hesitate to contact us at apex.prebid@sono | `hfa` | optional | Publisher Unique Identifier | `'123985'` | `string` | | `referrer` | optional | Overrides the default value for the ref param in a bid request | `'prebid.org'` | `string` | | `keywords` | optional | Comma separated list of keywords about the site | `'sports,news,food'` | `string` | +| `bid_request_url`| optional | String representing the url the Sonobi adapter should make to request bids | `'https://iad-2-apex.go.sonobi.com/trinity.json'` | `string` | ### Configuration *You *must* only include one ID field - either `placement_id` or `ad_unit`, not both. If you have questions on which parameter to use, please reach out to your Account Manager. From 968578dfc69670fd168ad31dd7fc409f05498e9c Mon Sep 17 00:00:00 2001 From: Bryan Szekely <49168870+bszekely1@users.noreply.github.com> Date: Tue, 31 Mar 2020 13:46:29 -0400 Subject: [PATCH 25/76] Update floors.md --- dev-docs/modules/floors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-docs/modules/floors.md b/dev-docs/modules/floors.md index 9a05f48aef..2664870604 100644 --- a/dev-docs/modules/floors.md +++ b/dev-docs/modules/floors.md @@ -572,7 +572,7 @@ Data providers can optionally build Analytics Adapters to ingest bid data within {% capture warning_note %} As a floor provider, your goal is to provide effective floors, with minimal page impact. If you are performing a Dynamic fetch to retrieve data prior to auctions, the following recommendations are advised to reduce page performance issues: -- Return results to the page quickly. This implies data should be stored on a CDN or be provided by a distributed tier of high performance services +- Return results to the page quickly. This implies data should be stored on a CDN or be provided by a distributed tier of high performance services - 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 From f1f3236501ee9c4b476154ca92f73d6396b85d39 Mon Sep 17 00:00:00 2001 From: Bryan Szekely <49168870+bszekely1@users.noreply.github.com> Date: Tue, 31 Mar 2020 15:11:44 -0400 Subject: [PATCH 26/76] Update floors.md --- dev-docs/modules/floors.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-docs/modules/floors.md b/dev-docs/modules/floors.md index 2664870604..1f2c6cfab4 100644 --- a/dev-docs/modules/floors.md +++ b/dev-docs/modules/floors.md @@ -50,11 +50,11 @@ There are several places where the Floor module changes the behavior of the Preb 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 + - 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. 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 as bids rejected. Prebid core will submit all eligible bids to the publisher ad server +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 From c9c4519f96b40261d0ff1372d3fba988906ae0d7 Mon Sep 17 00:00:00 2001 From: bretg Date: Tue, 31 Mar 2020 23:00:38 -0400 Subject: [PATCH 27/76] TCF2 docs (#1892) * TCF2 docs * Edit the note on GVL ids. * edits * wordsmithing Co-authored-by: MartianTribe Co-authored-by: Jean Stemp --- _data/sidebar.yml | 8 + dev-docs/modules/consentManagement.md | 25 +++- dev-docs/modules/gdprEnforcement.md | 201 ++++++++++++++++++++++++++ dev-docs/modules/index.md | 2 +- 4 files changed, 227 insertions(+), 9 deletions(-) create mode 100644 dev-docs/modules/gdprEnforcement.md diff --git a/_data/sidebar.yml b/_data/sidebar.yml index 015654d62a..6e8399acc4 100644 --- a/_data/sidebar.yml +++ b/_data/sidebar.yml @@ -431,6 +431,14 @@ sectionTitle: subgroup: 5 +- sbSecId: 1 + title: GDPR Enforcement + link: /dev-docs/modules/gdprEnforcement.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 5 + - sbSecId: 1 title: Consent Management - US Privacy (CCPA) link: /dev-docs/modules/consentManagementUsp.html diff --git a/dev-docs/modules/consentManagement.md b/dev-docs/modules/consentManagement.md index 22ebd538f5..b7b82630d8 100644 --- a/dev-docs/modules/consentManagement.md +++ b/dev-docs/modules/consentManagement.md @@ -24,18 +24,19 @@ This consent management module is designed to support the EU General Data Protec This module works with supported [Consent Management Platforms](https://www.cmswire.com/information-management/what-is-a-consent-management-platform/) (CMPs) to fetch an encoded string representing the user's consent choices and make it available for adapters to consume and process. -{: .alert.alert-info :} -See also the [Prebid Consent Management - US Privacy Module](/dev-docs/modules/consentManagementUsp.html) for supporting the California Consumer Protection Act (CCPA) - {: .alert.alert-warning :} Prebid functionality created to address regulatory requirements does not replace each party's responsibility to determine its own legal obligations and comply with all applicable laws. **We recommend consulting with your legal counsel before determining how to utilize these features in support of your overall privacy approach.** -Here's a summary of the interaction process: +This base EU GDPR consent management module performs these actions: 1. Fetch the user's GDPR consent data from the CMP. 2. Incorporate this data into the auction objects for adapters to collect. -3. Proceed with the auction. + +The optional [GDPR enforcement module](/dev-docs/modules/gdprEnforcement.html) adds on these actions: + +3. Allows the page to define which activities should be enforced at the Prebid.js level. +4. Actively enforces those activities based on user consent data. In the case of a new user, CMPs will generally respond only after there is consent information available (i.e., the user has made their consent choices). Making these selections can take some time for the average user, so the module provides timeout settings. @@ -184,10 +185,12 @@ Follow the basic build instructions in the GitHub Prebid.js repo's main [README] gulp build --modules=consentManagement,bidAdapter1,bidAdapter2 {% endhighlight %} +You can also use the [Prebid.js Download](/download.html) page. + ## Adapter Integration {: .alert.alert-info :} -Prebid.js adapters don't need to change to support TCF v2.0 if they already support TCF 1.1 -- the consent string is passed through the same bidrequest location. The bidder's endpoint, however, will need to change to support TCF v2.0. Once the endpoint supports TCF2, you can update the documentation.md file as described below above the table showing the list of TCF2-compliant bidders. +Prebid.js adapters don't need to change to support TCF v2.0 if they already support TCF 1.1 -- the consent string is passed through the same bidrequest location. The bidder's endpoint, however, will need to change to support TCF v2.0. Once the endpoint supports TCF2, you can update the documentation.md file as described below above the table showing the list of TCF2-compliant bidders. If you are submitting changes to an adapter to support this approach, please also submit a PR to the [docs repo](https://github.com/prebid/prebid.github.io) to add the `gdpr_supported: true` variable to your respective page in the [bidders directory](https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders). **This will ensure that your adapter's name will automatically appear on the list of adapters supporting GDPR.** @@ -379,7 +382,7 @@ This should be be set to true once the parameters listed above are processed. ## Adapters Supporting TCF v1.1 -Bidders on this list have self-declared their TCF 1.1 support in their https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders md file by adding "gdpr_supported: true". +Bidders on this list have self-declared their TCF 1.1 support in their https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders md file by adding "gdpr_supported: true". @@ -405,7 +408,7 @@ var idx_gdpr=0; ## Adapters Supporting TCF v2.0 -Bidders on this list have self-declared their TCF 2.0 support in their https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders md file by adding "tcf2_supported: true". +Bidders on this list have self-declared their TCF 2.0 support in their https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders md file by adding "tcf2_supported: true". + +## Further Reading + +- [GDPR Enforcement Module](/dev-docs/modules/gdprEnforcement.html) +- [IAB Transparancy and Consent Framework Policies](https://iabeurope.eu/iab-europe-transparency-consent-framework-policies/) +- [Prebid Consent Management - US Privacy Module](/dev-docs/modules/consentManagementUsp.html) diff --git a/dev-docs/modules/gdprEnforcement.md b/dev-docs/modules/gdprEnforcement.md new file mode 100644 index 0000000000..eb0caf12bc --- /dev/null +++ b/dev-docs/modules/gdprEnforcement.md @@ -0,0 +1,201 @@ +--- +layout: page_v2 +page_type: module +title: GDPR Enforcement Module +description: Module to enforce GDPR consent +module_code : gdprEnforcement +display_name : GDPR Enforcement +enable_download : true +sidebarType : 1 +--- + +# GDPR Enforcement Module +{: .no_toc } + +* TOC +{: toc } + +{: .alert.alert-warning :} +This module requires the [EU GDPR consent management module](/dev-docs/modules/consentManagement.html), which reads consent values from the Consent Management Platform (CMP). The GDPR enforcement module +will then enforce the results. See the base module page for general background, usage, and legal disclaimers. + +## Overview + +The base [EU GDPR consent management module](/dev-docs/modules/consentManagement.html) performs the following actions: + +1. Fetch the user's GDPR consent data from the CMP. +2. Incorporate this data into the auction objects for adapters to collect. + +This GDPR enforcement module adds the following: + +3. Allows the page to define which activities should be enforced at the Prebid.js level. +4. Actively enforces those activities based on user consent data. + +The following table details the Prebid.js activities that fall under the [Transparency and Consent Framework (TCF)](https://iabeurope.eu/iab-europe-transparency-consent-framework-policies/) scope: + +{: .table .table-bordered .table-striped } +| TCF Purpose | In-Scope Activity | Enforcement Activity | Optional Controls | +| --- | --- | --- | --- | +| Purpose 1 - Store and/or access information on a device | usersync pixels | May prevent one or more vendor usersyncs. | Do not enforce Purpose 1. Do not enforce Purpose 1 vendor signals. Do not enforce Purpose 1 for vendor V. | +| Purpose 1 - Store and/or access information on a device | user ID modules | May prevent one or more UserID modules from activating. | Do not enforce Purpose 1. Do not enforce Purpose 1 vendor signals. Do not enforce Purpose 1 for vendor V. | +| Purpose 1 - Store and/or access information on a device | device storage | May prevent one or more adapters or modules from being able to read or write cookies or localstorage in the user's browser. | Do not enforce Purpose 1. Do not enforce Purpose 1 vendor signals. Do not enforce Purpose 1 for vendor V. | + +There are plans to add more TCF Purposes and activities in future releases. + +## Page Integration + +A page needs to define configuration rules about how Prebid.js should enforce each in-scope activity. + +{: .alert.alert-warning :} +**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. + +These are the fields related to GDPR enforcment that are supported in the [`consentManagement.gdpr`](/dev-docs/modules/consentManagement.html) object: + +{: .table .table-bordered .table-striped } +| Param | Type | Description | Example | +| --- | --- | --- | --- | +| gdpr.rules | `Array of Objects` | Lets the publisher override the default behavior. | | +| gdpr.rules[].purpose | `String` | The only currently supported value is "storage", corresponding to TCF Purpose 1. | "storage" | +| gdpr.rules[].enforcePurpose | `Boolean` | Determines whether to enforce the purpose consent or not. The default in Prebid.js 3.x is not to enforce purposes. The plan for Prebid.js 4.0 is to enforce consent for Purpose 1 and no others. | true | +| gdpr.rules[].enforceVendor | `Boolean` | Determines whether to enforce vendor signals for this purpose or not. The default in Prebid.js 3.x is not to enforce vendor signals. The plan for Prebid.js 4.0 to enforce signals for Purpose 1 and no others. | true | +| gdpr.rules[].vendorExceptions | `Array of Strings` | Defines a list of biddercodes or module names that are exempt from the enforcement of this Purpose. | true | + +Note: + +- The vendorExceptions list is based on Prebid.js biddercodes instead of Global Vendor List (GVL) IDs, i.e. "rubicon" instead of "52". This was done to accomodate Prebid.js modules and adapters that don't have GVL IDs. + +### Examples + +The following examples cover a range of use cases and how Prebid.js supports +configuration of different business rules. + +1) Enforce that the user consents to DeviceAccess as an activity and consider their per-vendor selection. + +``` +pbjs.setConfig({ + consentManagement: { + gdpr: { + ... + rules: [{ + purpose: "storage", + enforcePurpose: true, + enforceVendor: true + } + } + } +}); +``` + +2) Enforce that the user consents to DeviceAccess as an activity and consider their per-vendor selection. However, BidderA is a special case - the publisher has entrusted BidderA for this activity regardless of what the user says. + + ... + rules: [{ + purpose: "storage", + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: ["bidderA"] + } + +3) Enforce that the user consents to DeviceAccess as an activity, but don't consider their per-vendor selection. + + ... + rules: [{ + purpose: "storage", + enforcePurpose: true, + enforceVendor: false, + } + +4) Enforce that the user consents to DeviceAccess as an activity, but don't consider their per-vendor selection for any bidders except BidderA. BidderA is entrusted to enforce the rules on their own. + + ... + rules: [{ + purpose: "storage", + enforcePurpose: true, + enforceVendor: false, + vendorExceptions: ["bidderA"] + } + +5) Turn off enforcement of Purpose 1: don't enforce either the user's DeviceAccess consent or their per-vendor selection. + + ... + rules: [{ + purpose: "storage", + enforcePurpose: false, + enforceVendor: false + } + +6) Don't enforce the user's DeviceAccess consent, but do consider their per-vendor selection. + + ... + rules: [{ + purpose: "storage", + enforcePurpose: false, + enforceVendor: true + } + +7) Don't enforce the user's DeviceAccess consent, but do consider their per-vendor selection; don't enforce vendor selection for BidderA. + + ... + rules: [{ + purpose: "storage", + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: ["bidderA"] + } + +## Basic Enforcement + +Prebid.js does not have access to the Global Vendor List (GVL), so it implements +a "basic" form of TCF validation using the supplied consent string. + +A goal of basic enforcement is to confirm that there's enough evidence of consent to pass data on to vendors who do have access to the GVL and can fully parse and enforce. + +Before allowing an activity tied to a TCF-protected Purpose for a given vendor, one of these scenarios must be true: + +- Configuration rules enforce both consent and vendor signals and either: + - we have the user’s purpose consent and the user’s vendor consent, or + - we confirmed the user’s LI (Legitimate Interest) Transparency is established for this purpose and the user’s Vendor LI field didn’t reject this vendor. +- Configuration rules enforce only purpose consent and either: + - we have the user’s purpose consent, or + - we confirmed the user’s LI Transparency is established for this purpose. +- Configuration rules enforce only vendor signals and either: + - we have the user’s vendor consent, or + - we confirmed the user’s Vendor LI field didn’t reject this vendor +- Configuration rules enforce neither purpose consent nor vendor signal. + +Technically these rules are defined as follows: + +1. enforcePurpose[P]==true AND PurposesConsent[P]==1 AND enforceVendor[P,V]==true AND VendorConsentBitfield[V]==1 +1. enforcePurpose[P]==true AND PurposesConsent[P]==1 AND enforceVendor[P,V]==false +1. enforcePurpose[P]==false AND enforceVendor[P,V]==true AND VendorConsentBitfield[V]==1 +1. enforcePurpose[P]==true AND PurposesLITransparency[P]==1 AND enforceVendor[P,V]==true AND VendorLegitimateInterestBitfield[V]==1 +1. enforcePurpose[P]==true AND PurposesLITransparency[P]==1 AND enforceVendor[P,V]==false +1. enforcePurpose[P]==false AND enforceVendor[P,V]==true AND VendorLegitimateInterestBitfield[V]==1 +1. enforcePurpose[P]==false AND enforceVendor[P,V]==false + +Where: + +- P is the Purpose number +- V is the vendor ID +- 'enforcePurpose' and 'enforceVendor' are Prebid.js config rules +- 'PurposesConsent' is the consent string field of the same name +- 'VendorConsentBitfield' is the consent string 'Vendor Consent Section' +- 'PurposesLITransparency' is the consent string field of the same name +- 'VendorLegitimateInterestBitfield' is the consent string 'Vendor Legitimate Interest Section' + +See the [IAB TCF Consent String Format](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20Consent%20string%20and%20vendor%20list%20formats%20v2.md) for details. + +## Build the Package + +Follow the basic build instructions in the GitHub Prebid.js repo's main [README](https://github.com/prebid/Prebid.js/blob/master/README.md). Include the base consent management module and this enforcement module as additional options on the **gulp build** command: + +{% highlight bash %} +gulp build --modules=consentManagement,gdprEnforcement,bidAdapter1,bidAdapter2 +{% endhighlight %} + +You can also use the [Prebid.js Download](/download.html) page. + +## Further Reading + +- [EU GDPR Consent Management Module](/dev-docs/modules/consentManagement.html) +- [IAB TCF Consent String Format](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20Consent%20string%20and%20vendor%20list%20formats%20v2.md) diff --git a/dev-docs/modules/index.md b/dev-docs/modules/index.md index 1db7e6a8e9..41806bdfab 100644 --- a/dev-docs/modules/index.md +++ b/dev-docs/modules/index.md @@ -31,7 +31,7 @@ If you are looking for bidder adapter parameters, see [Bidders' Params]({{site.b | Module | Description | |---------------------+--------------| | [**Currency**](/dev-docs/modules/currency.html) | Converts bid currency into ad server currency based on data in a supplied exchange rate file. | -| **ConsentManagement** | Facilitates collecting and passing consent information in support of privacy regulations: [EU GDPR](/dev-docs/modules/consentManagement.html) and [US Privacy](/dev-docs/modules/consentManagementUsp.html) (CCPA). | +| **ConsentManagement** | Collecting and passing consent information in support of privacy regulations:{::nomarkdown}

    {:/} | | [**Google Ad Manager Express**](/dev-docs/modules/dfp_express.html) | A simplified installation mechanism for publishers that have Google Publisher Tag (GPT) ad calls in their pages. | | [**Supply Chain Object**](/dev-docs/modules/schain.html) | Validates and makes the Supply Object available to bidders | | [**User ID**](/dev-docs/modules/userId.html) | Sub-modules are available to support a range of identification approaches: Criteo RTUS, DigiTrust, ID5 Universal ID, IdentityLink, PubCommon ID, and Unified ID. | From ccaca43359e582ab431bd2c38c552c6ec85e39b9 Mon Sep 17 00:00:00 2001 From: bretg Date: Tue, 31 Mar 2020 23:05:12 -0400 Subject: [PATCH 28/76] released PBJS purpose 1 support (#1900) --- _posts/2020-03-12-tcf2.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_posts/2020-03-12-tcf2.md b/_posts/2020-03-12-tcf2.md index 89ff754139..7129ab59e5 100644 --- a/_posts/2020-03-12-tcf2.md +++ b/_posts/2020-03-12-tcf2.md @@ -33,10 +33,10 @@ Support for TCF2 is broken into several phases: {: .table .table-bordered .table-striped } | Phase | Description | Est. Availability | | ----- | ----------- | ----------------- | -| 1 | DONE - Support a ['deviceAccess' flag](/dev-docs/publisher-api-reference.html#setConfig-deviceAccess). Publishers can parse the TCF string on their own and configure Prebid.js appropriately. | Mar 18, 2020 | -| 2 | DONE - Update the [GDPR ConsentManagement module(/dev-docs/modules/consentManagement.html) to [read TCF v2.0 strings](https://github.com/prebid/Prebid.js/issues/4801) and forward to bid adapters. | Mar 18, 2020 | -| 3 | Support a 'default GDPR scope' flag to allow control over scenarios where the CMP doesn't respond in time. | Mar 25, 2020 | -| 4 | Update the GDPR ConsentManagement module to support parsing TCF v2.0 strings and enforcing Device Access. | Apr 1, 2020 | +| 1 | DONE - Support a ['deviceAccess' flag](/dev-docs/publisher-api-reference.html#setConfig-deviceAccess). Publishers can parse the TCF string on their own and configure Prebid.js appropriately. | Released with v3.12 | +| 2 | DONE - Update the [GDPR ConsentManagement module(/dev-docs/modules/consentManagement.html) to [read TCF v2.0 strings](https://github.com/prebid/Prebid.js/issues/4801) and forward to bid adapters. | Released with v3.12 | +| 3 | DONE - Support a ['default GDPR scope'](/dev-docs/modules/consentManagement.html) flag to allow control over scenarios where the CMP doesn't respond in time. | Released with v3.13 | +| 4 | DONE - Add a new ['GDPR Enforcement Module'](/dev-docs/modules/gdprEnforcement.html) to support parsing TCF v2.0 strings and enforcing Device Access. | Released with v3.14 | | 5 | Update the GDPR ConsentManagement module to support parsing TCF v2.0 strings and enforcing Purposes 2 and 4 | Apr 30, 2020 | ## Prebid Server From d4cb7a16da8faa84ed1baaccfd06fb5bdb3c48d4 Mon Sep 17 00:00:00 2001 From: Vedant Seta Date: Wed, 1 Apr 2020 23:29:06 +0530 Subject: [PATCH 29/76] Media.net : adds Analytics Adapter (#1888) * Media.net Analytics Adapter added * Media.net Analytics Adapter added Co-authored-by: vedant.s --- download.md | 8 ++++++++ overview/analytics.md | 1 + 2 files changed, 9 insertions(+) diff --git a/download.md b/download.md index 104001eb4c..3b1afa19e5 100644 --- a/download.md +++ b/download.md @@ -313,6 +313,14 @@ Note: If you receive an error during download you most likely selected a configu +
    +
    + +
    +
    +