From 87fcb64ff31757cd0fc9a98aef0524402e46fc38 Mon Sep 17 00:00:00 2001 From: omerdotan Date: Sun, 15 Dec 2019 10:11:11 +0200 Subject: [PATCH 1/8] auction delay and timeout --- dev-docs/modules/browsiRtdProvider.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dev-docs/modules/browsiRtdProvider.md b/dev-docs/modules/browsiRtdProvider.md index e400ef56f9..4da46cac9a 100644 --- a/dev-docs/modules/browsiRtdProvider.md +++ b/dev-docs/modules/browsiRtdProvider.md @@ -55,7 +55,9 @@ Syntax details: {: .table .table-bordered .table-striped } | Name |Type | Description | Notes | | :------------ | :------------ | :------------ |:------------ | -| name | String | Real time data module name | Always 'browsi' | +| name | String | Real time data module name | Always 'browsi' | +| auctionDelay | Number | Max time in ms to delay the auction | Optional. Default to 0 | +| timeout | Number | timeout in ms (only if auctionDealy is 0) | Optional. Default to 1000 | | params | Object | | | | params.siteKey |String |Site key| | | params.pubKey |String |Publisher key| | @@ -64,6 +66,7 @@ Syntax details: + ## Output For each ad slot, the module returns expected viewability prediction in a JSON format. From 3f2b5819aae44d0fa97724523bf3f2669b16e7e7 Mon Sep 17 00:00:00 2001 From: omerdotan Date: Mon, 24 Aug 2020 13:09:56 +0300 Subject: [PATCH 2/8] RTD docs --- _data/sidebar.yml | 8 + assets/images/prebid-rtd-architecture.jpg | Bin 0 -> 83217 bytes dev-docs/add-rtd-submodule.md | 230 ++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 assets/images/prebid-rtd-architecture.jpg create mode 100644 dev-docs/add-rtd-submodule.md diff --git a/_data/sidebar.yml b/_data/sidebar.yml index bfdaf25bd9..c6088c0b19 100644 --- a/_data/sidebar.yml +++ b/_data/sidebar.yml @@ -397,6 +397,14 @@ sectionTitle: subgroup: 4 +- sbSecId: 1 + title: How to Add an RTD submodule + link: /dev-docs/add-rtd-submodule.html + isHeader: 0 + isSectionHeader: 0 + sectionTitle: + subgroup: 4 + - sbSecId: 1 title: Prebid Modules link: diff --git a/assets/images/prebid-rtd-architecture.jpg b/assets/images/prebid-rtd-architecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18340beeacaaaf8a7e89585bf63bd5ebb9f08229 GIT binary patch literal 83217 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 literal 0 HcmV?d00001 diff --git a/dev-docs/add-rtd-submodule.md b/dev-docs/add-rtd-submodule.md new file mode 100644 index 0000000000..8f1109e947 --- /dev/null +++ b/dev-docs/add-rtd-submodule.md @@ -0,0 +1,230 @@ +--- +layout: page_v2 +title: How to Add a Prebid.js RTD submodule +description: How to Add a Prebid.js RTD submodule +pid: 28 +top_nav_section: dev_docs +nav_section: adapters + +sidebarType: 1 +--- + + + +# How to Add a Real Time Data Submodule +{:.no_toc} + +Sub-modules will interact with the Real-Time Data core module in order to add any type of data to bidders and to the primary ad server. + + +* TOC +{:toc } + +## Overview +1. RTD module is a generic core module, allowing sub-modules to register and use it to modify bid request/response and set targeting data for the publisher’s ad server. +2. This will be done using hooks (with optional auction delay) and events. +3. Sub-modules functions will be invoked by the RTD module, eliminating race conditions and data override issues. +4. As a rule, sub-modules should delay the auction as little as possible. + +## Architecture + +The RTD module using hooks and event listeners to genrate the flow for the data modificatios. +On each step it calls the submodules to retrive the data. +Here is the flow for the RTD module and submodules: + +![Prebid RTD Architecture Diagram]({{ site.baseurl }}/assets/images/prebid-rtd-architecture.jpg){: .pb-md-img :} + +## Creating a submodule + +Working with any Prebid project requires using Github. In general, we recommend the same basic workflow for any project: + +1. Fork the appropriate Prebid repository (e.g. [Prebid.js](https://github.com/prebid/Prebid.js)). +2. Create a branch in your fork for your proposed code change. (e.g. feature/exRtdSProvider) +3. Build and test your feature/bug fix in the branch. +4. Open a [pull request](https://help.github.com/en/desktop/contributing-to-projects/creating-a-pull-request) to the appropriate repository's master branch with a good description of the feature/bug fix. +5. If there's something that needs to change on the prebid.org website, follow the above steps for the [website repo](https://github.com/prebid/prebid.github.io). + +{: .alert.alert-warning :} +Analytics adapters are subject to a number of specific technical rules. Please become familiar +with the [module rules](/dev-docs/module-rules.html) that apply globally and to real time data modules in particular. + +### Step 1: Add a markdown file describing the module + +Create a markdown file under `modules` with the name of the module suffixed with 'RtdProvider', e.g., `exRtdProvider.md` + +Example markdown file: +{% highlight text %} +# Overview + +Module Name: Ex Rtd Provider +Module Type: Rtd Provider +Maintainer: prebid@example.com + +# Description + +RTD provider for Example.com. Contact prebid@example.com for information. + +{% endhighlight %} + +### Step 2: Mandatory functions and parameters + +#### Submodule object + +Create an object with the following parameters: + +{: .table .table-bordered .table-striped } +| param name | type | +| :------------ | :------------ | +| name | string | +| getData | function | +| init | function | + +#### Register submodule + +Register submodule to the real time data module: + +{% highlight text %} +submodule('realTimeData', subModuleObject); +{% endhighlight %} + + +#### initialization function +1. The function receives module configuration, GDPR consent, and USP consent as parameters. +2. If the function returns `false`, the submodule will be ignored. + + + +#### getData function +1. The function receives adUnits and callback function as parameters +2. This data will be set as key values on the primary ad server and bidders. +3. For empty data, call the callback function with an empty object. +4. The function should call the callback function with an object in the following structure: +{% highlight text %} +{ + "slotA":{ + "p":0.56, // ad server targeting variable (e.g. p) for slotA is 0.56 + }, + "slotB":{ + "p":0.824, // ad server targeting variable (e.g. p) for slotB is 0.824 + } +} +{% endhighlight %} + +#### Code example + +{% highlight text %} +/** @type {RtdSubmodule} */ +export const submoduleObj = { + name: 'Sוubmodule name', + getData: sendDataToModule, + init: init +}; + +function init(params, gdprData, uspData) { + return gdprData.consentRequired; +} + +function sendDataToModule(adUnits, callback) { + let data = {}; + adUnits.forEach(unit => { + data[unit.code] = {data: 'data'} + }); + callback(data); +} + +submodule('realTimeData', submoduleObj); +{% endhighlight %} + +### Step 3: Optional functions + +#### Using event listeners +1. RTD module listens to 4 events - `auctionInit`, `auctionEnd`, `beforeRequestBids` and `bidResponse`. +2. Each time one of the events fires, the RTD module will invoke its corresponding function on the sub-modules, allowing the sub-module to make changes to the event object. +3. To use this on your sub-module, define the required functions (`onAuctionInit` / `onAuctionEnd` / `updateBidRequest` / `updateBidResponse`). + + + +#### beforeInit +1. Use this function to take action to make sure data will be served as soon as possible (AJAX calls, pixels, etc..) +2. This function is **not** invoked by the RTD module, and should be invoked within the submodule. + +#### code example +here is a code example with both mandatory and optional functions: +{% highlight text %} +/** @type {RtdSubmodule} */ +export const submoduleObj = { + name: 'Sוubmodule name', + getData: sendDataToModule, + auctionInit: onAuctionInit, + auctionEnd: onAuctionEnd, + updateBidRequest: onUpdateBidRequest, + updateBidResponse: onUpdateBidResponse, + init: init +}; + +function onAuctionInit(obj, params) { + //place code to run on auction init +} + +function onAuctionEnd(obj,params) { + //place code to run on auction end +} + +function onUpdateBidRequest(obj,params) { + //place code to run on beforeRequestBids +} + +function onUpdateBidResponse(obj) { + //place code to run on bidResponse +} + +function init(params, gdprData, uspData) { + return gdprData.consentRequired; +} + +function sendDataToModule(adUnits, callback) { + let data = {}; + adUnits.forEach(unit => { + data[unit.code] = {data: 'data'} + }); + callback(data); +} + +function beforeInit(){ + //take actions to get data as soon as possible + submodule('realTimeData', submoduleObj); +} + +beforeInit(); +{% endhighlight %} + + + +### Step 4: Add unit tests + +1. Create a JS file under `test/spec/modules` with the name of the bidder suffixed with 'RtdProvider_spec', e.g., `exRtdProvider_spec.js` + +2. Write great unit tests. See the other `RtdProvider_spec.js` files for examples. + +### Step 5: Submit the code + +Once everything looks good, submit the code, tests, and markdown as a pull request to the [Prebid.js repo](https://github.com/prebid/Prebid.js). + +### Step 6: Website pull request + +There are two files that need to be updated to list your new RTD provider. + +1. Create a fork of the [website repo](https://github.com/prebid/prebid.github.io) and a branch for your new adapter. (e.g. feature/exRtdProvider) + +*******not sure how we want to handle docs - do we want to have some category for it? ******* + +2. Update `overview/analytics.md` to add your adapter alphabetically into the list. + +3. Update `download.md` to add your new adapter alphabetically into the li +st of other analytics adapters. + +4. Submit the pull request to the prebid.github.io repo. + +### Step 6: Wait for Prebid volunteers to review + +We sometimes get pretty busy, so it can take a couple of weeks for the review process to complete, so while you're waiting, consider [joining Prebid.org](/partners/partners.html) to help us out with code reviews. (!) From 8b116d433b09c11d2831961c85537208132fe5d9 Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 24 Aug 2020 12:46:01 -0400 Subject: [PATCH 3/8] testing ability to make commits --- _data/sidebar.yml | 2 +- dev-docs/add-rtd-submodule.md | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/_data/sidebar.yml b/_data/sidebar.yml index c6088c0b19..3b3256682d 100644 --- a/_data/sidebar.yml +++ b/_data/sidebar.yml @@ -398,7 +398,7 @@ subgroup: 4 - sbSecId: 1 - title: How to Add an RTD submodule + title: How to Add A Real Time Data submodule link: /dev-docs/add-rtd-submodule.html isHeader: 0 isSectionHeader: 0 diff --git a/dev-docs/add-rtd-submodule.md b/dev-docs/add-rtd-submodule.md index 8f1109e947..a52552dc52 100644 --- a/dev-docs/add-rtd-submodule.md +++ b/dev-docs/add-rtd-submodule.md @@ -2,19 +2,13 @@ layout: page_v2 title: How to Add a Prebid.js RTD submodule description: How to Add a Prebid.js RTD submodule -pid: 28 -top_nav_section: dev_docs -nav_section: adapters - sidebarType: 1 --- - - # How to Add a Real Time Data Submodule {:.no_toc} -Sub-modules will interact with the Real-Time Data core module in order to add any type of data to bidders and to the primary ad server. +Sub-modules will interact with the Real-Time Data (RTD) core module in order to add any type of data to bidders and to the primary ad server. * TOC From e968c2839362f4a79792f48300c49503a561a8a8 Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 24 Aug 2020 15:07:01 -0400 Subject: [PATCH 4/8] review revisions --- dev-docs/add-rtd-submodule.md | 168 +++++++++++++++----------- dev-docs/modules/browsiRtdProvider.md | 3 +- dev-docs/modules/index.md | 23 +++- 3 files changed, 122 insertions(+), 72 deletions(-) diff --git a/dev-docs/add-rtd-submodule.md b/dev-docs/add-rtd-submodule.md index a52552dc52..e43cbff124 100644 --- a/dev-docs/add-rtd-submodule.md +++ b/dev-docs/add-rtd-submodule.md @@ -8,7 +8,8 @@ sidebarType: 1 # How to Add a Real Time Data Submodule {:.no_toc} -Sub-modules will interact with the Real-Time Data (RTD) core module in order to add any type of data to bidders and to the primary ad server. +Sub-modules interact with the Real-Time Data (RTD) core module to +add data to bid requests or add targeting values for the primary ad server. * TOC @@ -16,19 +17,23 @@ Sub-modules will interact with the Real-Time Data (RTD) core module in order to ## Overview 1. RTD module is a generic core module, allowing sub-modules to register and use it to modify bid request/response and set targeting data for the publisher’s ad server. -2. This will be done using hooks (with optional auction delay) and events. -3. Sub-modules functions will be invoked by the RTD module, eliminating race conditions and data override issues. -4. As a rule, sub-modules should delay the auction as little as possible. +2. This is done using hooks (with optional auction delay) and events. +3. Publishers will decide which RTD sub-modules they want to use, and can set parameters like timeout, endpoints, etc. +4. Sub-module functions are invoked by the RTD core module. +5. As a rule, sub-modules should delay the auction as little as possible. ## Architecture The RTD module using hooks and event listeners to genrate the flow for the data modificatios. On each step it calls the submodules to retrive the data. -Here is the flow for the RTD module and submodules: +Here is the flow for how the RTD-core module interacts with its sub-modules: -![Prebid RTD Architecture Diagram]({{ site.baseurl }}/assets/images/prebid-rtd-architecture.jpg){: .pb-md-img :} +![Prebid RTD Architecture Diagram](/assets/images/prebid-rtd-architecture.jpg){: .pb-xlg-img :} -## Creating a submodule +The activities performed by the RTD-core module are on the left-hand side, while the functions +that can be provided by your RTD sub-module are on the right-hand side. Note that you don't need to implement all of the functions - you'll want to plan out your functionality and develop the appropriate functions. + +## Creating a Sub-Module Working with any Prebid project requires using Github. In general, we recommend the same basic workflow for any project: @@ -39,10 +44,10 @@ Working with any Prebid project requires using Github. In general, we recommend 5. If there's something that needs to change on the prebid.org website, follow the above steps for the [website repo](https://github.com/prebid/prebid.github.io). {: .alert.alert-warning :} -Analytics adapters are subject to a number of specific technical rules. Please become familiar -with the [module rules](/dev-docs/module-rules.html) that apply globally and to real time data modules in particular. +RTD sub-modules are subject to a number of specific technical rules. Please become familiar +with the [module rules](/dev-docs/module-rules.html) that apply globally and to Real Time Data modules in particular. -### Step 1: Add a markdown file describing the module +### Step 1: Add a markdown file describing the sub-module Create a markdown file under `modules` with the name of the module suffixed with 'RtdProvider', e.g., `exRtdProvider.md` @@ -60,37 +65,51 @@ RTD provider for Example.com. Contact prebid@example.com for information. {% endhighlight %} -### Step 2: Mandatory functions and parameters +### Step 2: Build the Module + +Now create a javascript file under `modules` with the name of the module suffixed with 'RtdProvider', e.g., `exRtdProvider.js` -#### Submodule object +#### The Sub-Module object -Create an object with the following parameters: +In order to let RTD-core know where to find the functions in your sub-module, create an object called `submoduleObj` that contains key values: {: .table .table-bordered .table-striped } -| param name | type | -| :------------ | :------------ | -| name | string | -| getData | function | -| init | function | +| param name | type | Scope | Description | Params | +| :------------ | :------------ | :------ | :------ | :------ | +| name | string | required | must match the name provided by the publisher in the on-page config | n/a | +| getData | function | required? | ? | adUnitArray, onDoneCallback | +| init | function | required | does any auction-level initialization required | config, gdpr, usp | +| auctionInit | function | optional | lets sub-module inspect and/or update the auction | auctionDetails, config | +| auctionEnd | function |optional | lets sub-module know when auction is done | auctionDetails, config | +| updateBidRequest | function |optional | lets sub-module inspect and/or update adunits before the auction | adUnitArray, config | +| updateBidResponse | function |optional | lets sub-module inspect and/or update bidresponses | bidResonse, config | + +For example: +{% highlight text %} +export const subModuleObj = { + name: 'ExampleRTDModule', + getData: sendDataToModule, + init: init +}; +{% endhighlight %} -#### Register submodule +#### Register the submodule -Register submodule to the real time data module: +Register submodule to RTD-core: {% highlight text %} submodule('realTimeData', subModuleObject); {% endhighlight %} - -#### initialization function -1. The function receives module configuration, GDPR consent, and USP consent as parameters. +#### The init() function +1. This function receives module configuration, GDPR consent, and USP consent as parameters. 2. If the function returns `false`, the submodule will be ignored. +See the [Building the Request](/dev-docs/bidder-adaptor.html#building-the-request) section of the Bid Adapter documentation for more details about GDPR and USP. - -#### getData function -1. The function receives adUnits and callback function as parameters -2. This data will be set as key values on the primary ad server and bidders. +#### The getData() function +1. RTD-core will call this function with an array of adUnits and a callback function as parameters +2. Your sub-module will respond with data that should be set as key values on the ad server targeting and bid requests. 3. For empty data, call the callback function with an empty object. 4. The function should call the callback function with an object in the following structure: {% highlight text %} @@ -104,18 +123,20 @@ submodule('realTimeData', subModuleObject); } {% endhighlight %} -#### Code example +**Code Example** {% highlight text %} /** @type {RtdSubmodule} */ -export const submoduleObj = { - name: 'Sוubmodule name', +export const subModuleObj = { + name: 'ExampleRTDModule', getData: sendDataToModule, init: init }; function init(params, gdprData, uspData) { - return gdprData.consentRequired; + // do init stuff + if (initfailed) return false; + return true; } function sendDataToModule(adUnits, callback) { @@ -126,28 +147,20 @@ function sendDataToModule(adUnits, callback) { callback(data); } -submodule('realTimeData', submoduleObj); +submodule('realTimeData', subModuleObj); {% endhighlight %} -### Step 3: Optional functions - -#### Using event listeners -1. RTD module listens to 4 events - `auctionInit`, `auctionEnd`, `beforeRequestBids` and `bidResponse`. -2. Each time one of the events fires, the RTD module will invoke its corresponding function on the sub-modules, allowing the sub-module to make changes to the event object. -3. To use this on your sub-module, define the required functions (`onAuctionInit` / `onAuctionEnd` / `updateBidRequest` / `updateBidResponse`). - - - #### beforeInit 1. Use this function to take action to make sure data will be served as soon as possible (AJAX calls, pixels, etc..) -2. This function is **not** invoked by the RTD module, and should be invoked within the submodule. +2. This function is **not** invoked by the RTD module, and should be invoked at the bottom of the submodule. + +**Code Example** -#### code example -here is a code example with both mandatory and optional functions: +Here is a code example with both mandatory and optional functions: {% highlight text %} /** @type {RtdSubmodule} */ -export const submoduleObj = { - name: 'Sוubmodule name', +export const subModuleObj = { + name: 'ExampleRTDModule', getData: sendDataToModule, auctionInit: onAuctionInit, auctionEnd: onAuctionEnd, @@ -156,24 +169,26 @@ export const submoduleObj = { init: init }; -function onAuctionInit(obj, params) { - //place code to run on auction init +function onAuctionInit(auctionDetails, config) { + // inspect/update auction details } -function onAuctionEnd(obj,params) { - //place code to run on auction end +function onAuctionEnd(auctionDetails,config) { + // take note of auction end } -function onUpdateBidRequest(obj,params) { - //place code to run on beforeRequestBids +function onUpdateBidRequest(adUnitArray,config) { + //optionally update adUnits } -function onUpdateBidResponse(obj) { - //place code to run on bidResponse +function onUpdateBidResponse(bidResponse,config) { + //optionally update bidResponse } function init(params, gdprData, uspData) { - return gdprData.consentRequired; + // do init stuff + if (initfailed) return false; + return true; } function sendDataToModule(adUnits, callback) { @@ -186,39 +201,52 @@ function sendDataToModule(adUnits, callback) { function beforeInit(){ //take actions to get data as soon as possible - submodule('realTimeData', submoduleObj); + submodule('realTimeData', subModuleObj); } beforeInit(); {% endhighlight %} +#### Using event listeners +1. The RTD-core module listens for 4 events - `auctionInit`, `auctionEnd`, `beforeRequestBids` and `bidResponse`. +2. Each time one of the events fires, RTD-core will invoke the corresponding function on each sub-module, allowing the sub-module to make changes to the event object. +3. To use this on your sub-module, define the required functions (`onAuctionInit` / `onAuctionEnd` / `updateBidRequest` / `updateBidResponse`). -### Step 4: Add unit tests +### Step 3: Add unit tests 1. Create a JS file under `test/spec/modules` with the name of the bidder suffixed with 'RtdProvider_spec', e.g., `exRtdProvider_spec.js` 2. Write great unit tests. See the other `RtdProvider_spec.js` files for examples. -### Step 5: Submit the code +### Step 4: Submit the code Once everything looks good, submit the code, tests, and markdown as a pull request to the [Prebid.js repo](https://github.com/prebid/Prebid.js). -### Step 6: Website pull request - -There are two files that need to be updated to list your new RTD provider. +### Step 5: Website pull request 1. Create a fork of the [website repo](https://github.com/prebid/prebid.github.io) and a branch for your new adapter. (e.g. feature/exRtdProvider) -*******not sure how we want to handle docs - do we want to have some category for it? ******* - -2. Update `overview/analytics.md` to add your adapter alphabetically into the list. - -3. Update `download.md` to add your new adapter alphabetically into the li -st of other analytics adapters. - -4. Submit the pull request to the prebid.github.io repo. +2. Create a new file for your RTD sub-module in dev-docs/modules/ExampleRtdProvider.md. Take a look at the other *RtdProvider.md files in that directory for the important header values. Specifically it requires the following: + + ``` + --- + layout: page_v2 + title: Example Module + description: Useful statement for what this does + page_type: module + module_type: rtd + module_code : example + enable_download : true + sidebarType : 1 + --- + + # Example Module + + [Useful publisher-facing documentation] + ``` +3. Submit the pull request to the prebid.github.io repo. ### Step 6: Wait for Prebid volunteers to review -We sometimes get pretty busy, so it can take a couple of weeks for the review process to complete, so while you're waiting, consider [joining Prebid.org](/partners/partners.html) to help us out with code reviews. (!) +We sometimes get pretty busy, so it can take a couple of weeks for the review process to complete, so while you're waiting, consider [joining Prebid.org](https://prebid.org/membership/) to help us out with code reviews. (!) diff --git a/dev-docs/modules/browsiRtdProvider.md b/dev-docs/modules/browsiRtdProvider.md index 4da46cac9a..e4cad91c2d 100644 --- a/dev-docs/modules/browsiRtdProvider.md +++ b/dev-docs/modules/browsiRtdProvider.md @@ -2,8 +2,9 @@ layout: page_v2 title: Browsi Viewability Module description: Browsi Real Time Viewability +page_type: module +module_type: rtd module_code : browsi -display_name : Browsi enable_download : true sidebarType : 1 --- diff --git a/dev-docs/modules/index.md b/dev-docs/modules/index.md index c7731e994a..eb5d38d0dc 100644 --- a/dev-docs/modules/index.md +++ b/dev-docs/modules/index.md @@ -35,11 +35,32 @@ If you are looking for bidder adapter parameters, see [Bidders' Params]({{site.b | [**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, Unified ID and LiveIntent ID. | -| [**Browsi Viewability**]({{site.baseurl}}/dev-docs/modules/browsiRtdProvider.html) | Browsi provider for real time data module. | | [**Advanced Size Mapping**](/dev-docs/modules/sizeMappingV2.html) | Display Responsive AdUnits in demanding page environments. | | [**Price Floors Module**](/dev-docs/modules/floors.html) | Configure and enforce minimum bids. | | [**GPT Pre-Auction Module**](/dev-docs/modules/gpt-pre-auction.html) | Adds a PB Ad Slot and matching GAM ad unit name to each ad unit's first-party data before bid requests are sent to the adapters. | +## Real-Time Data Providers + +{% assign module_pages = site.pages | where: "page_type", "module" | where: "module_type", "rtd" %} + + + + + + + + + +{% for page in module_pages %} + {% if page.enable_download == false %}{% continue %}{% endif %} + + + + +{% endfor %} + +
ModuleDescription
{{page.title}}{{page.description}}
+ ## Video Modules {: .table .table-bordered .table-striped } From 050c29d1dd92f6ae436452ee082d35f86c3e6d2b Mon Sep 17 00:00:00 2001 From: bretg Date: Fri, 28 Aug 2020 11:47:42 -0400 Subject: [PATCH 5/8] changing getData to addTargeting --- dev-docs/add-rtd-submodule.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/dev-docs/add-rtd-submodule.md b/dev-docs/add-rtd-submodule.md index e43cbff124..1aeb1d26f0 100644 --- a/dev-docs/add-rtd-submodule.md +++ b/dev-docs/add-rtd-submodule.md @@ -1,4 +1,4 @@ ---- +/-- layout: page_v2 title: How to Add a Prebid.js RTD submodule description: How to Add a Prebid.js RTD submodule @@ -77,19 +77,19 @@ In order to let RTD-core know where to find the functions in your sub-module, cr | param name | type | Scope | Description | Params | | :------------ | :------------ | :------ | :------ | :------ | | name | string | required | must match the name provided by the publisher in the on-page config | n/a | -| getData | function | required? | ? | adUnitArray, onDoneCallback | -| init | function | required | does any auction-level initialization required | config, gdpr, usp | -| auctionInit | function | optional | lets sub-module inspect and/or update the auction | auctionDetails, config | -| auctionEnd | function |optional | lets sub-module know when auction is done | auctionDetails, config | -| updateBidRequest | function |optional | lets sub-module inspect and/or update adunits before the auction | adUnitArray, config | -| updateBidResponse | function |optional | lets sub-module inspect and/or update bidresponses | bidResonse, config | +| init | function | required | defines the function that does any auction-level initialization required | config, gdpr, usp | +| getTargtingData | function | optional | defines a function that provides ad server targeting data to RTD-core | adUnitArray, onDoneCallback | +| auctionInit | function | optional | defines a function that lets the sub-module inspect and/or update the auction | auctionDetails, config | +| auctionEnd | function |optional | defines a function that lets the sub-module know when auction is done | auctionDetails, config | +| updateBidRequest | function |optional | defines a function that lets a sub-module inspect and/or update adunits before the auction | adUnitArray, config | +| updateBidResponse | function |optional | defines a function that lets a sub-module inspect and/or update bidresponses | bidResonse, config | For example: {% highlight text %} export const subModuleObj = { name: 'ExampleRTDModule', - getData: sendDataToModule, - init: init + init: init, + addTargeting: sendDataToModule }; {% endhighlight %} @@ -107,9 +107,9 @@ submodule('realTimeData', subModuleObject); See the [Building the Request](/dev-docs/bidder-adaptor.html#building-the-request) section of the Bid Adapter documentation for more details about GDPR and USP. -#### The getData() function +#### The addTargeting() function 1. RTD-core will call this function with an array of adUnits and a callback function as parameters -2. Your sub-module will respond with data that should be set as key values on the ad server targeting and bid requests. +2. Your sub-module will respond with data that should be set as key values on the ad server targeting. 3. For empty data, call the callback function with an empty object. 4. The function should call the callback function with an object in the following structure: {% highlight text %} @@ -129,8 +129,8 @@ See the [Building the Request](/dev-docs/bidder-adaptor.html#building-the-reques /** @type {RtdSubmodule} */ export const subModuleObj = { name: 'ExampleRTDModule', - getData: sendDataToModule, - init: init + init: init, + addTargeting: sendDataToModule }; function init(params, gdprData, uspData) { @@ -161,12 +161,12 @@ Here is a code example with both mandatory and optional functions: /** @type {RtdSubmodule} */ export const subModuleObj = { name: 'ExampleRTDModule', - getData: sendDataToModule, + init: init, + addTargeting: sendDataToModule, auctionInit: onAuctionInit, auctionEnd: onAuctionEnd, updateBidRequest: onUpdateBidRequest, - updateBidResponse: onUpdateBidResponse, - init: init + updateBidResponse: onUpdateBidResponse }; function onAuctionInit(auctionDetails, config) { From a11147ae3ed54f118598fcb0b77dc89531d8b966 Mon Sep 17 00:00:00 2001 From: bretg Date: Thu, 24 Sep 2020 17:27:25 -0400 Subject: [PATCH 6/8] revised for phase 3 --- dev-docs/add-rtd-submodule.md | 126 +++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 49 deletions(-) diff --git a/dev-docs/add-rtd-submodule.md b/dev-docs/add-rtd-submodule.md index 1aeb1d26f0..42c3fea950 100644 --- a/dev-docs/add-rtd-submodule.md +++ b/dev-docs/add-rtd-submodule.md @@ -1,4 +1,4 @@ -/-- +--- layout: page_v2 title: How to Add a Prebid.js RTD submodule description: How to Add a Prebid.js RTD submodule @@ -77,19 +77,19 @@ In order to let RTD-core know where to find the functions in your sub-module, cr | param name | type | Scope | Description | Params | | :------------ | :------------ | :------ | :------ | :------ | | name | string | required | must match the name provided by the publisher in the on-page config | n/a | -| init | function | required | defines the function that does any auction-level initialization required | config, gdpr, usp | -| getTargtingData | function | optional | defines a function that provides ad server targeting data to RTD-core | adUnitArray, onDoneCallback | -| auctionInit | function | optional | defines a function that lets the sub-module inspect and/or update the auction | auctionDetails, config | -| auctionEnd | function |optional | defines a function that lets the sub-module know when auction is done | auctionDetails, config | -| updateBidRequest | function |optional | defines a function that lets a sub-module inspect and/or update adunits before the auction | adUnitArray, config | -| updateBidResponse | function |optional | defines a function that lets a sub-module inspect and/or update bidresponses | bidResonse, config | +| init | function | required | defines the function that does any auction-level initialization required | config, userConsent | +| getTargetingData | function | optional | defines a function that provides ad server targeting data to RTD-core | adUnitArray, config, userConsent | +| getBidRequestData | function | optional | defines a function that provides ad server targeting data to RTD-core | reqBidsConfigObj, callback, config, userConsent | +| onAuctionInitEvent | function | optional | listens to the AUCTION_INIT event and calls a sub-module function that lets it inspect and/or update the auction | auctionDetails, config, userConsent | +| onAuctionEndEvent | function |optional | listens to the AUCTION_END event and calls a sub-module function that lets it know when auction is done | auctionDetails, config, userConsent | +| onBidResponseEvent | function |optional | listens to the BID_RESPONSE event and calls a sub-module function that lets it know when a bid response has been collected | bidResponse, config, userConsent | For example: {% highlight text %} export const subModuleObj = { name: 'ExampleRTDModule', init: init, - addTargeting: sendDataToModule + getTargetingData: sendDataToModule }; {% endhighlight %} @@ -101,17 +101,27 @@ Register submodule to RTD-core: submodule('realTimeData', subModuleObject); {% endhighlight %} +#### User Consent + +Several of the interfaces get a `userConsent` object. It's an object that carries these attributes: +- [gdpr](/dev-docs/modules/consentManagement.html#bidder-adapter-gdpr-integration) - GDPR +- [usp](/dev-docs/modules/consentManagementUsp.html#bidder-adapter-us-privacy-integration) - US Privacy (aka CCPA) +- [coppa](/dev-docs/publisher-api-reference.html#setConfig-coppa) - the Child Online Privacy Protection Act + +These are provided so you can do the right thing with respect to regulations. The only privacy requirement imposed by the RTD-core is that sub-modules make make use of the StorageManager instead of attempting to access cookies or localstorage directly. + #### The init() function -1. This function receives module configuration, GDPR consent, and USP consent as parameters. +1. This function receives module configuration and userConsent parameters 2. If the function returns `false`, the submodule will be ignored. See the [Building the Request](/dev-docs/bidder-adaptor.html#building-the-request) section of the Bid Adapter documentation for more details about GDPR and USP. -#### The addTargeting() function -1. RTD-core will call this function with an array of adUnits and a callback function as parameters -2. Your sub-module will respond with data that should be set as key values on the ad server targeting. -3. For empty data, call the callback function with an empty object. -4. The function should call the callback function with an object in the following structure: +#### getTargetingData + +This is the function that will allow RTD sub-modules to merge ad server targeting data into the auction. It's called at the AUCTION_END event for each auction. + +1. RTD-core will call this function with an array of adUnits, config, and userConsent as parameters +2. Your sub-module should respond with per-adslot data that should be set as key values on the ad server targeting in this format: {% highlight text %} { "slotA":{ @@ -130,21 +140,53 @@ See the [Building the Request](/dev-docs/bidder-adaptor.html#building-the-reques export const subModuleObj = { name: 'ExampleRTDModule', init: init, - addTargeting: sendDataToModule + getTargetingData: returnTargetingData +}; + +function init(config, userConsent) { + // do init stuff + if (initfailed) return false; + return true; +} + +function returnTargetingData(adUnits, config, userConsent) { + // do stuff + return data; +} + +submodule('realTimeData', subModuleObj); +{% endhighlight %} + +#### getBidRequestData + +This is the function that will allow RTD sub-modules to modify the AdUnit object for each auction. It's called as part of the requestBids hook. + +1. RTD-core will call this function with: + - reqBidsConfigObj: the object that's passed to [`pbjs.requestBids`](). Note that several auctions can happen concurrently, so the sub-module must be ready to support this. + - callback: lets RTD-core know which auction the sub-module is done with. + - config: the sub-module's config params provided by the publisher + - userConsent object (see above) +2. Your sub-module may update the reqBidsConfigObj and hit the callback with the auctionID. + +**Code Example** + +{% highlight text %} +/** @type {RtdSubmodule} */ +export const subModuleObj = { + name: 'ExampleRTDModule2', + init: init, + setBidRequestsData: alterBidRequests }; -function init(params, gdprData, uspData) { +function init(config, userConsent) { // do init stuff if (initfailed) return false; return true; } -function sendDataToModule(adUnits, callback) { - let data = {}; - adUnits.forEach(unit => { - data[unit.code] = {data: 'data'} - }); - callback(data); +function alterBidRequests(reqBidsConfigObj, callback, config, userConsent) { + // do stuff + callback(reqBidsConfigObj.auctionId); } submodule('realTimeData', subModuleObj); @@ -154,51 +196,42 @@ submodule('realTimeData', subModuleObj); 1. Use this function to take action to make sure data will be served as soon as possible (AJAX calls, pixels, etc..) 2. This function is **not** invoked by the RTD module, and should be invoked at the bottom of the submodule. +#### Using event listeners +1. The RTD-core module listens for 3 events - `AUCTION_INIT`, `AUCTION_END`, and `BID_RESPONSE`. +2. Each time one of the events fires, RTD-core will invoke the corresponding function on each sub-module, allowing the sub-module to make changes to the event object. +3. To use this on your sub-module, define the required functions as noted in the table above and the examples below. + **Code Example** Here is a code example with both mandatory and optional functions: {% highlight text %} /** @type {RtdSubmodule} */ export const subModuleObj = { - name: 'ExampleRTDModule', + name: 'ExampleRTDModule3', init: init, - addTargeting: sendDataToModule, - auctionInit: onAuctionInit, - auctionEnd: onAuctionEnd, - updateBidRequest: onUpdateBidRequest, - updateBidResponse: onUpdateBidResponse + onAuctionInitEvent: onAuctionInit, + onAuctionEndEvent: onAuctionEnd, + onBidResponseEvent: onBidResponse }; -function onAuctionInit(auctionDetails, config) { +function onAuctionInit(auctionDetails, config, userConsent) { // inspect/update auction details } -function onAuctionEnd(auctionDetails,config) { +function onAuctionEnd(auctionDetails, config, userConsent) { // take note of auction end } -function onUpdateBidRequest(adUnitArray,config) { - //optionally update adUnits -} - -function onUpdateBidResponse(bidResponse,config) { +function onBidResponse(bidResponse, config, userConsent) { //optionally update bidResponse } -function init(params, gdprData, uspData) { +function init(config, userConsent) { // do init stuff if (initfailed) return false; return true; } -function sendDataToModule(adUnits, callback) { - let data = {}; - adUnits.forEach(unit => { - data[unit.code] = {data: 'data'} - }); - callback(data); -} - function beforeInit(){ //take actions to get data as soon as possible submodule('realTimeData', subModuleObj); @@ -207,11 +240,6 @@ function beforeInit(){ beforeInit(); {% endhighlight %} -#### Using event listeners -1. The RTD-core module listens for 4 events - `auctionInit`, `auctionEnd`, `beforeRequestBids` and `bidResponse`. -2. Each time one of the events fires, RTD-core will invoke the corresponding function on each sub-module, allowing the sub-module to make changes to the event object. -3. To use this on your sub-module, define the required functions (`onAuctionInit` / `onAuctionEnd` / `updateBidRequest` / `updateBidResponse`). - ### Step 3: Add unit tests From 5eef4d4071a596c317d960e83c14e1c752eb8cd3 Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 5 Oct 2020 22:38:10 -0400 Subject: [PATCH 7/8] removing auctionId param from callback --- dev-docs/add-rtd-submodule.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-docs/add-rtd-submodule.md b/dev-docs/add-rtd-submodule.md index 42c3fea950..8ec06b6838 100644 --- a/dev-docs/add-rtd-submodule.md +++ b/dev-docs/add-rtd-submodule.md @@ -166,7 +166,7 @@ This is the function that will allow RTD sub-modules to modify the AdUnit object - callback: lets RTD-core know which auction the sub-module is done with. - config: the sub-module's config params provided by the publisher - userConsent object (see above) -2. Your sub-module may update the reqBidsConfigObj and hit the callback with the auctionID. +2. Your sub-module may update the reqBidsConfigObj and hit the callback. **Code Example** @@ -186,7 +186,7 @@ function init(config, userConsent) { function alterBidRequests(reqBidsConfigObj, callback, config, userConsent) { // do stuff - callback(reqBidsConfigObj.auctionId); + callback(); } submodule('realTimeData', subModuleObj); From 41d92e6b000e61b6cc99d79f8d119a9a2dc9c9b6 Mon Sep 17 00:00:00 2001 From: bretg Date: Wed, 21 Oct 2020 17:23:53 -0400 Subject: [PATCH 8/8] added display name to browsi --- dev-docs/modules/browsiRtdProvider.md | 1 + download.md | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/dev-docs/modules/browsiRtdProvider.md b/dev-docs/modules/browsiRtdProvider.md index e4cad91c2d..a41193b68b 100644 --- a/dev-docs/modules/browsiRtdProvider.md +++ b/dev-docs/modules/browsiRtdProvider.md @@ -1,6 +1,7 @@ --- layout: page_v2 title: Browsi Viewability Module +display_name: Browsi Viewability description: Browsi Real Time Viewability page_type: module module_type: rtd diff --git a/download.md b/download.md index 75df60e3ee..5afada8bf3 100644 --- a/download.md +++ b/download.md @@ -179,9 +179,7 @@ Prebid.js is open source software that is offered for free as a convenience. Whi

Select Bidder Adapters

{% for page in bidder_pages %} - {% if page.s2s_only == true %} - {% continue %} - {% endif %} + {% if page.s2s_only == true %} {% continue %} {% endif %}