diff --git a/_data/sidebar.yml b/_data/sidebar.yml
index f067a78785..d7e99973c8 100644
--- a/_data/sidebar.yml
+++ b/_data/sidebar.yml
@@ -596,6 +596,14 @@
sectionTitle:
subgroup: 8
+- sbSecId: 1
+ title: First Party Data
+ link: /features/firstPartyData.html
+ isHeader: 0
+ isSectionHeader: 0
+ sectionTitle:
+ subgroup: 8
+
#--------------Prebid Mobile--------------|
@@ -1770,6 +1778,14 @@
sectionTitle:
subgroup: 3
+- sbSecId: 5
+ title: First Party Data
+ link: /prebid-server/features/pbs-fpd.html
+ isHeader: 0
+ isSectionHeader: 0
+ sectionTitle:
+ subgroup: 3
+
- sbSecId: 5
title: Developers
link:
diff --git a/assets/images/flowcharts/FirstPartyData-Detailed.png b/assets/images/flowcharts/FirstPartyData-Detailed.png
new file mode 100644
index 0000000000..1e4125ffb8
Binary files /dev/null and b/assets/images/flowcharts/FirstPartyData-Detailed.png differ
diff --git a/assets/images/flowcharts/FirstPartyData-Summary.png b/assets/images/flowcharts/FirstPartyData-Summary.png
new file mode 100644
index 0000000000..cd9ac8cd84
Binary files /dev/null and b/assets/images/flowcharts/FirstPartyData-Summary.png differ
diff --git a/dev-docs/publisher-api-reference.md b/dev-docs/publisher-api-reference.md
index aebe9b1ff5..3245cc5547 100644
--- a/dev-docs/publisher-api-reference.md
+++ b/dev-docs/publisher-api-reference.md
@@ -2278,14 +2278,13 @@ pbjs.setConfig({coppa: true});
#### First Party Data
-A number of adapters support taking key/value pairs as arguments, but they're all different. For example:
+Historically, a number of adapters supported taking key/value pairs as arguments, but they were all different. For example:
-- RubiconProject takes `keywords`, `inventory` and `visitor` parameters
-- AppNexus takes `keywords` and `user`
-- OpenX takes `customParams`
+- RubiconProject took `keywords`, `inventory` and `visitor` parameters
+- AppNexus took `keywords` and `user`
+- OpenX took `customParams`
-This feature allows publishers a way to specify key/value data in one place where each compatible bid adapter
-can read it.
+First party data allows publishers to specify key/value data in one place where each compatible bid adapter can read it.
{: .alert.alert-warning :}
Not all bid adapters currently support reading first party data in this way, but support should increase over time.
@@ -2352,6 +2351,8 @@ pbjs.setBidderConfig({
+See [Prebid Server First Party Data](/prebid-server/features/pbs-fpd.html) for details about passing data server-side.
+
#### Client-side Caching of VAST XML
When serving video ads, VAST XML creatives must be cached on the network so the
diff --git a/features/firstPartyData.md b/features/firstPartyData.md
new file mode 100644
index 0000000000..c1786fbfa2
--- /dev/null
+++ b/features/firstPartyData.md
@@ -0,0 +1,160 @@
+---
+layout: page_v2
+title: Prebid.js First Party Data
+description: First Party Data - Prebid.js
+sidebarType: 1
+---
+
+# First Party Data - Prebid.js
+{: .no_toc}
+
+* TOC
+{:toc}
+
+Prebid allows publishers to supply attributes related to their content
+and users, and to apply permissions so only certain bidders are allowed
+to access those attributes.
+
+{: .alert.alert-warning :}
+These conventions aren't implemented by all adapters. Please
+check with each of your bidders to make sure they're reading first
+party data from the standard Prebid locations.
+
+## How It Works
+
+Here's a summary of how first party data (FPD) works:
+
+![First Party Data Summary](/assets/images/flowcharts/FirstPartyData-Summary.png){: .pb-lg-img :}
+
+This diagram shows a page that can provide:
+
+- Global context (site) data that applies to all AdUnits and all bidders
+- Global user data that applies to all AdUnits and all bidders
+- AdUnit-specific data that applies to all bidders
+- Bidder-specific context data that applies to all AdUnits
+- Bidder-specific user data that applies to all AdUnits
+
+## In-Page Examples
+
+The Prebid First Party Data JSON structure reflects the OpenRTB standard.
+Arbitrary values should go in fpd.context.data or fpd.user.data. Fields
+that are meant to be standard [OpenRTB 2.5](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf) values should be in fpd.context or fpd.user. Specfically, the standard values for `site` are: name, domain, cat, sectioncat, pagecat, page, ref, search, keywords. For `user` these are: yob, gender, keywords.
+
+{: .alert.alert-info :}
+'Context' corresponds to the OpenRTB 'site' object.
+
+### Supplying Global Data
+
+Here's how a publisher can let all bid adapters have access
+to first party data that might be useful in ad targeting:
+{% highlight js %}
+pbjs.setConfig({
+ fpd: {
+ context: {
+ keywords: "power tools", // keywords is a standard OpenRTB field
+ search: "drill", // same with search and content
+ content: { userrating: 4 },
+ data: {
+ pageType: "article",
+ category: "tools"
+ }
+ },
+ user: {
+ keywords: "a,b", // keywords is a standard OpenRTB field
+ data: {
+ registered: true,
+ interests: ["cars"]
+ }
+ }
+ }
+});
+{% endhighlight %}
+
+{: .alert.alert-warning :}
+Note that supplying first party **user** data may require special
+consent in certain regions. Prebid does **not** police the passing
+of user data as part of its GDPR or CCPA modules.
+
+### Supplying AdUnit-Specific Data
+
+If an attribute is specific to an AdUnit, it can be passed this way:
+
+{% highlight js %}
+pbjs.addAdUnits({
+ code: "test-div",
+ mediaTypes: {
+ banner: {
+ sizes: [[300,250]]
+ }
+ },
+ fpd: {
+ context: {
+ pbAdSlot: "homepage-top-rect",
+ adUnitSpecificContextAttribute: "123"
+ }
+ },
+ ...
+});
+{% endhighlight %}
+
+{: .alert.alert-info :}
+Prebid does not support AdUnit-Specific **user** data.
+
+### Supplying Bidder-Specific Data
+
+Use the [`setBidderConfig()`](/dev-docs/publisher-api-reference.html#module_pbjs.setBidderConfig) function to supply bidder-specific data. In this example, only bidderA and bidderB will get access to the supplied
+global data.
+
+{% highlight js %}
+pbjs.setBidderConfig({
+ bidders: ['bidderA', 'bidderB'],
+ config: {
+ fpd: {
+ context: {
+ data: {
+ pageType: "article",
+ category: "tools"
+ }
+ },
+ user: {
+ data: {
+ registered: true,
+ interests: ["cars"]
+ }
+ }
+ }
+ }
+});
+
+pbjs.setBidderConfig({ // different bidders can receive different data
+ bidders: ['bidderC'],
+ config: {
+ fpd: { ... }
+ }
+});
+{% endhighlight %}
+
+{: .alert.alert-info :}
+Applying permissions to AdUnit-specific First Party Data has
+to be done manually by using an event handler -- [pbjs.onEvent('beforeRequestBids', function())](/dev-docs/publisher-api-reference.html#module_pbjs.onEvent)
+
+## How Bid Adapters Should Read First Party Data
+
+To access global data, a Prebid.js bid adapter needs only to call [`getConfig()`](/dev-docs/publisher-api-reference.html#module_pbjs.getConfig), like this:
+
+{% highlight js %}
+config.getConfig('fpd.context'))
+config.getConfig('fpd.user'))
+{% endhighlight %}
+
+AdUnit-specific values must be parsed out of the AdUnit object.
+
+The assumption is that bid adapters will copy the values to the appropriate protocol location for their endpoint.
+
+See [Prebid Server First Party Data](/prebid-server/features/pbs-fpd.html) for a discussion of this feature for Prebid Server bid adapters.
+
+## Further Reading
+
+- The [Prebid.js Publisher API](/dev-docs/publisher-api-reference.html)
+- The [AdUnit Reference](/dev-docs/adunit-reference.html)
+- [Prebid Server First Party Data support](/prebid-server/features/pbs-fpd.html)
diff --git a/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md b/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md
index 493c7b37aa..6dd89dfe28 100644
--- a/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md
+++ b/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md
@@ -27,7 +27,7 @@ For a more general reference, see the [Prebid AMP Implementation Guide
| curl | optional | `String` | Added to OpenRTB request as site.page |
| slot | optional | `String` | Added to OpenRTB request as imp[0].tagid |
| timeout | optional | `String` | Added to OpenRTB request as tmax |
-| targeting | optional | `String` | First Party Data |
+| targeting | optional | `String` | First Party Data (PBS-Java only) |
| gdpr_consent | optional | `String` | Consent string passed from CMP. Note this is used for both GDPR and CCPA. |
| account | optional | `String` | Can be used to pass the Prebid-Server specific account ID. This is useful if `tag_id` parameters aren't unique across accounts. |
| debug | optional | `integer` | If 1, returns additional debug info. |
@@ -80,6 +80,84 @@ An example Stored Request is given below:
}
```
+#### First Party Data
+
+(Currently only supported in PBS-Java)
+
+You can send first party data into an AMP request by encoding a JSON
+targeting block like this:
+
+```
+GET /openrtb2/amp?tag_id=7470-Eater_AMP_ROS_ATF&w=300&h=250&ow=&oh=&ms=&slot=%2F172968584%2Feater%2Fgoogle%2Famp_med_rec_02&targeting=%7B%22site%22%3A%7B%22keywords%22%3A%22article%2C%20las%20vegas%22%2C%22cat%22%3A%7B%22blah%22%3A%221%22%7D%2C%22other-attribute%22%3A%22other-value%22%2C%22ext%22%3A%7B%22data%22%3A%7B%22entry_group%22%3A%5B%22front-page%22%2C%22featured-stories%22%5D%2C%22page_type%22%3A%22AMP%22%7D%7D%7D%2C%22user%22%3A%7B%22gender%22%3A%22m%22%7D%2C%22bidders%22%3A%5B%22rubicon%22%2C%22appnexus%22%5D%2C%22keywords%22%3A%22las%20vegas%20hospitality%20employees%22%2C%22foo%22%3A%7B%22bar%22%3A%22baz%22%7D%7D...
+```
+
+Prebid Server will expand the targeting value and merge the data into
+the resulting OpenRTB JSON for the appropriate bidders.
+
+For example, if this AMP targeting is provided:
+```
+{
+ "site": {
+ "keywords": "article, las vegas", // (1)
+ "cat": { "blah": "1" }, // invalid data type, will be dropped
+ "other-attribute": "other-value", // not openrtb2, remove
+ "ext": {
+ "data": {
+ "entry_group": ["front-page","featured-stories"], // (4)
+ "page_type": "AMP" // (5)
+ }
+ }
+ },
+ "user": {
+ "gender": "m", // (2)
+ },
+ "bidders": ["rubicon","appnexus"], // (3)
+ "keywords": "las vegas hospitality employees", // (6)
+ "foo": { // (7)
+ "bar": "baz"
+ }
+}
+```
+The numbered elements from the raw targeting data above are merged into the resulting OpenRTB like this:
+```
+{
+ "imp": [...],
+ "site": {
+ "publisher": { … },
+ "keywords": "article, las vegas" // (1)
+ "ext":{
+ "data": {
+ "entry_group": ["front-page","featured-stories"], // (4)
+ "page_type": "AMP" // (5)
+ }
+ }
+ },
+ "user": {
+ "gender": "m" // (2)
+ },
+ "ext": {
+ "prebid": {
+ "data": {
+ "bidders": ["rubicon",appnexus"], // (3)
+ }
+ }
+ },
+ "imp": [
+ ...
+ "ext": {
+ "context": {
+ "data": {
+ "keywords": "las vegas hospitality employees", // (6)
+ "foo": { // (7)
+ "bar": "baz"
+ }
+ }
+ }
+ }
+ ]
+}
+```
+
### Response
A sample response payload looks like this:
@@ -198,3 +276,4 @@ Specifically:
## Further Reading
- [Prebid and AMP](/formats/amp.html)
- [Prebid Server AMP Use Case Overview](/prebid-server/use-cases/pbs-amp.html)
+- [Prebid Server First Party Data](/prebid-server/features/pbs-fpd.html)
diff --git a/prebid-server/features/pbs-feature-idx.md b/prebid-server/features/pbs-feature-idx.md
index 6ba375ee3e..18683d93b4 100644
--- a/prebid-server/features/pbs-feature-idx.md
+++ b/prebid-server/features/pbs-feature-idx.md
@@ -35,8 +35,8 @@ title: Prebid Server | Features
| [Stored Requests](/prebid-server/features/pbs-storedreqs.html) | Core | Accepts a stored request ID in the OpenRTB, looks it up against a local data store, and merges with the OpenRTB request record. | | |
| Stored Responses | Stored Responses | Accepts a stored response ID in the OpenRTB, looks it up against a local data store, and merges with the OpenRTB response record. | | |
| First Party Data | Core | Accepts core first party data attributes and supports ext.prebid.data.bidders. | | |
-| First Party Data | Bidder-specific data | Accepts bidder-specific first party data attributes. | | |
-| First Party Data | AMP first party data | Accepts first party data attributes on an AMP request. | | |
+| First Party Data | Bidder-specific data | Accepts bidder-specific first party data attributes. | | |
+| First Party Data | AMP first party data | Accepts first party data attributes on an AMP request. | | |
| [Supply Chain](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#supply-chain-support) | Bidder-specific schains | Accepts bidder-specific schain | | |
| Publisher Accounts | Core | Ability to enforce that requests coming in have a valid account ID. | | |
| Publisher Accounts | AMP account parameter | Accept the account parameter on the AMP request. | | |
diff --git a/prebid-server/features/pbs-fpd.md b/prebid-server/features/pbs-fpd.md
new file mode 100644
index 0000000000..a488c46dac
--- /dev/null
+++ b/prebid-server/features/pbs-fpd.md
@@ -0,0 +1,130 @@
+---
+layout: page_v2
+sidebarType: 5
+title: First Party Data - Prebid Server
+---
+
+# First Party Data - Prebid Server
+{: .no_toc}
+
+* TOC
+{:toc}
+
+Prebid allows publishers to supply attributes related to their content
+and users, and to apply permissions so only certain bidders are allowed
+to access those attributes.
+
+{: .alert.alert-warning :}
+For now, this feature is only supported in PBS-Java and these conventions aren't implemented by all adapters. Please
+check with each of your bidders to make sure they're reading first
+party data from the standard Prebid locations.
+
+## How It Works
+
+Each of the three main sources of Prebid Server traffic will place
+First Party Data in the OpenRTB JSON in several places:
+
+{: .table .table-bordered .table-striped }
+| OpenRTB Attribute | Description | PBJS Source | SDK Source | AMP Source |
+| --- | --- | --- | --- | --- |
+| site.ATTR | Only standard OpenRTB attributes should be here: name, domain, cat, sectioncat, pagecat, page, ref, search, keywords. | config.fpd.context.ATTR | n/a | site.ATTR |
+| site.ext.data.ATTR | Any other site-related attributes should go here. | config.fpd.context.data | n/a | site.ext.data.ATTR |
+| app.ext.data.ATTR | Any app-related attributes should go here. | n/a | Targeting addContextData() | n/a |
+| user.ATTR | Only standard OpenRTB attributes should be here: yob, gender, keywords. | config.fpd.user.ATTR | n/a | user.ATTR |
+| user.ext.data.ATTR | Any other user-related attributes should go here. | config.fpd.user.data.ATTR | Targeting addUserData() | user.ext.data.ATTR |
+| imp[].ext.context.data.ATTR | AdUnit-specific attributes should go here. | AdUnit.fpd.context | AdUnit addContextData() | n/a |
+| ext.prebid.data.bidders[] | If specified, only these bidders are allowed to see fields in {site/app/user}.ext.data. | n/a | addBidderToAccessControlList() | bidders |
+| ext.prebid.bidderconfig | Bidder-specific config | [setBidderConfig()](/dev-docs/publisher-api-reference.html#module_pbjs.setBidderConfig) | n/a | n/a |
+
+This diagram summarizes how first party data flows into the OpenRTB JSON:
+
+![First Party Data Summary](/assets/images/flowcharts/FirstPartyData-Detailed.png){: .pb-lg-img :}
+
+{: .alert.alert-info :}
+Note that Prebid.js supports the [`setBidderConfig`](/dev-docs/publisher-api-reference.html#module_pbjs.setBidderConfig) method of defining
+bidder-specific first party data, while SDK and AMP only support the `ext.prebid.data.bidders[]` approach.
+
+## OpenRTB Examples
+
+In this example, only BidderA has access to the global first party data:
+```
+{
+ ext: {
+ prebid: {
+ data: { bidders: [ "bidderA" ] } // limit bidders that receive global data
+ }
+ },
+ site: {
+ keywords: "",
+ search: "",
+ ext: {
+ data: {
+ // only seen by bidderA as named in ext.prebid.data.bidders[]
+ GLOBAL CONTEXT DATA
+ }
+ }
+ },
+ user: {
+ keywords: "",
+ gender: "",
+ yob: 1999,
+ geo: {},
+ ext: {
+ data: {
+ // only seen by bidderA as named in ext.prebid.data.bidders[]
+ GLOBAL USER DATA
+ }
+ }
+ },
+ imp: [
+ ...
+ ext: {
+ context: {
+ keywords: "",
+ search: "",
+ data: {
+ // everyone sees this data
+ ADUNIT SPECIFIC CONTEXT DATA
+ }
+ }
+ }
+ ]
+}
+```
+
+This example shows an array of bidder-specific config:
+```
+{
+ ext: {
+ prebid: {
+ bidderconfig: [ {
+ bidders: [ 'bidderA', 'bidderB' ],
+ config: {
+ fpd: { site: { ... }, user: { ...} }
+ }
+ },{
+ bidders: [ 'bidderC' ],
+ config: {
+ fpd: { site: { ... }, user: { ...} }
+ }
+ }]
+ }
+ }
+}
+```
+
+## How Server-Side Bid Adapters Read First Party Data
+
+Bid adapters don't need to worry about whether the request came from
+Prebid.js, the SDK, or AMP -- everything is merged into the OpenRTB JSON. If a bid adapter receives first party data on any of the fields noted in
+the table above, they can simply pass that data to their endpoint in
+the expected way.
+
+In other words, just be aware of site.ext.data.ATTR, app.ext.data.ATTR, user.ext.data.ATTR,
+and imp[].ext.context.data.ATTR and either pass them straight through or map
+attributes to where your endpoints expect them.
+
+## Further Reading
+
+- [Prebid.js First Party Data](/features/firstPartyData.html)
+- [Prebid Server and AMP](/prebid-server/use-cases/pbs-amp.html)
diff --git a/prebid-server/use-cases/pbs-amp.md b/prebid-server/use-cases/pbs-amp.md
index 98ae98d184..cfa2db3d5d 100644
--- a/prebid-server/use-cases/pbs-amp.md
+++ b/prebid-server/use-cases/pbs-amp.md
@@ -6,6 +6,10 @@ title: Prebid Server | Use Cases | AMP
---
# Use Case: Prebid Server | AMP
+{: .no_toc}
+
+* TOC
+{:toc}
[Accelerated Mobile Pages (AMP)](https://ampproject.org/) is an alternate web technology that can speed page performance, but
as part of the tradeoff, header bidding wrappers like Prebid.js don't work well. Instead, AMP supports a method of header bidding called Real Time Configuration(RTC), which is implemented by Prebid Server.
@@ -43,11 +47,12 @@ There are two basic ways of invoking AMP RTC:
data-slot="/11111/amp_test"
data-multi-size-validation="false"
rtc-config='{"vendors": {"prebidrubicon": {"REQUEST_ID": "14062-amp-AMP_Test-300x250"}, "ACCOUNT_ID": "1001"}}'
- json='{ "targeting": {"site": {"tags": "autoestima","url": "/amp/familia/materias/33559-princesa-africana-da-disney-lembra-por-que-toda-crianca-precisa-se-sentir-representada"}}}' >
+ json='{ "targeting": {"site":{"keywords":"article, las vegas","cat":{"blah":"1"},"other-attribute":"other-value","ext":{"data":{"entry_group":["front-page","featured-stories"],"page_type":"AMP"}}},"user":{"gender":"m"},"bidders":["bidderA","bidderB"],"keywords":"las vegas hospitality employees","foo":{"bar":"baz"}}' >
```
-**Note:** the `prebidrubicon` and `prebidappnexus` AMP vendors define different parameters. AppNexus uses "PLACEMENT_ID" as the argument to rtc-config while Rubicon uses "REQUEST_ID".
+{: .alert.alert-info :}
+**Note:** the `prebidrubicon` and `prebidappnexus` AMP vendor strings define slightly different parameters; AppNexus uses "PLACEMENT_ID" as the argument to rtc-config while Rubicon uses "REQUEST_ID". They both translate to `tag_id` when passed to Prebid Server.
- The other option is to construct a direct URL from component pieces: w, h, slot, targeting, gdpr_consent, account, page url (purl), etc.
@@ -60,6 +65,9 @@ There are two basic ways of invoking AMP RTC:
```
+{: .alert.alert-info :}
+First party data may be passed in on the "targeting" field. See the [`/openrtb2/amp` endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) documentation for more details.
+
### Prebid Server Receives the AMP Request
Prebid Server's first job on the [/openrtb2/amp endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) is to create an OpenRTB block to pass to the adapters.
@@ -158,6 +166,11 @@ So for the /openrtb2/amp URL above, the resulting OpenRTB might be:
Note that most of the above OpenRTB was prepared offline and stored in the Prebid Server database indexed by the `tag_id`.
Only a few dynamic parameters on the query string are integrated into the results from the database.
+#### First Party Data Support
+
+Any targeting data passed in through the [`/openrtb2/amp`](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) endpoint is merged
+into the OpenRTB JSON and permissions, if defined, are applied to each bidder.
+
#### Auction and Response
From here, the header bidding auction is mostly the same as it is for Prebid.js:
diff --git a/prebid-server/use-cases/pbs-lfv.md b/prebid-server/use-cases/pbs-lfv.md
index 164dd35ed8..f61c5e085e 100644
--- a/prebid-server/use-cases/pbs-lfv.md
+++ b/prebid-server/use-cases/pbs-lfv.md
@@ -6,6 +6,10 @@ title: Prebid Server | Use Cases | Long Form Video
---
# Use Case: Prebid Server | Long Form Video
+{: .no_toc}
+
+* TOC
+{:toc}
Prebid Server (PBS) supports filling _pods_ of multiple video advertisements, including support for competitve separation.
diff --git a/prebid-server/use-cases/pbs-pbjs.md b/prebid-server/use-cases/pbs-pbjs.md
index da9b6a888c..414d745f3c 100644
--- a/prebid-server/use-cases/pbs-pbjs.md
+++ b/prebid-server/use-cases/pbs-pbjs.md
@@ -6,6 +6,10 @@ title: Prebid Server | Use Cases | Prebid.js
---
# Use Case: Prebid Server | Prebid.js
+{: .no_toc}
+
+* TOC
+{:toc}
When publishers specify bidders in [Prebid.js `s2sConfig`](/dev-docs/publisher-api-reference.html#setConfig-Server-to-Server), the browser connects to Prebid Server to coordinate the header bidding auction for those bidders.
diff --git a/prebid-server/use-cases/pbs-sdk.md b/prebid-server/use-cases/pbs-sdk.md
index 37daa28bdb..f1500f8b2e 100644
--- a/prebid-server/use-cases/pbs-sdk.md
+++ b/prebid-server/use-cases/pbs-sdk.md
@@ -6,6 +6,10 @@ title: Prebid Server | Use Cases | Mobile SDK
---
# Use Case: Prebid Server | Prebid Mobile SDK
+{: .no_toc}
+
+* TOC
+{:toc}
Unlike Prebid.js, the [Prebid Mobile SDK](/prebid-mobile/prebid-mobile.html) doesn't make requests to demand sources directly. Instead, it relies entirely on Prebid Server to handle the bidder communication.