diff --git a/assets/images/prebid-server/stored-requests-amp.png b/assets/images/prebid-server/stored-requests-amp.png new file mode 100644 index 0000000000..426a5bce4f Binary files /dev/null and b/assets/images/prebid-server/stored-requests-amp.png differ diff --git a/assets/images/prebid-server/stored-requests-app.png b/assets/images/prebid-server/stored-requests-app.png new file mode 100644 index 0000000000..9b0868d37a Binary files /dev/null and b/assets/images/prebid-server/stored-requests-app.png differ diff --git a/dev-docs/show-prebid-ads-on-amp-pages.md b/dev-docs/show-prebid-ads-on-amp-pages.md index d51f074c09..e03048365e 100644 --- a/dev-docs/show-prebid-ads-on-amp-pages.md +++ b/dev-docs/show-prebid-ads-on-amp-pages.md @@ -91,34 +91,40 @@ that doesn't come from /amp parameters: } } }, - "imp": [ - { - "id": "some-impression-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - } - ] - }, - "ext": { + "imp": [{ + "id": "some-impression-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "prebid": { + "bidder": { "bidderA": { // Insert parameters here }, "bidderB": { // Insert parameters here } - } + } } - ] + } + }] } - ``` This basic OpenRTB record will be enhanced by the parameters from the call to the [/amp endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html). ### AMP content page +First ensure that the amp-ad component is imported in the header. + +``` + +``` +This script provides code libraries that will convert `` properties to the endpoint query parameters usint the [Real Time Config](https://github.com/ampproject/amphtml/blob/main/extensions/amp-a4a/rtc-documentation.md) (RTC) protocol. + The `amp-ad` elements in the page body need to be set up as shown below, especially the following attributes: + `data-slot`: Identifies the ad slot for the auction. @@ -130,7 +136,7 @@ e.g. for the AppNexus cluster of Prebid Servers: ```html ``` @@ -139,11 +145,20 @@ e.g. for Rubicon Project's cluster of Prebid Servers: ```html ``` +For other hosts, you can specify the URL directly rather than using one of the convenient vendor aliases. e.g. +```html + +``` + ### HTML Creative This is the creative that your Ad Ops team needs to upload to the ad server (it's also documented at [Setting up Prebid for AMP in Google Ad Manager]({{site.github.url}}/adops/setting-up-prebid-for-amp-in-dfp.html)). diff --git a/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md b/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md index cf36b98875..c984822090 100644 --- a/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md +++ b/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.md @@ -6,10 +6,14 @@ title: Prebid Server | Endpoints | OpenRTB2 | AMP --- # Prebid Server | Endpoints | /openrtb2/amp +{:.no_toc} + +* TOC +{:toc} This document describes the behavior of the Prebid Server AMP endpoint in detail. For a more general reference, see the [Prebid AMP Implementation Guide -]({{site.baseurl}}/dev-docs/show-prebid-ads-on-amp-pages.html). +](/dev-docs/show-prebid-ads-on-amp-pages.html). ## GET /openrtb2/amp @@ -19,24 +23,28 @@ For a more general reference, see the [Prebid AMP Implementation Guide | Param | Scope | Type | Description | | --- | --- | --- | --- | | tag_id | Required | `String` | The `tag_id` ID must reference a [Stored BidRequest]({{site.baseurl}}/prebid-server/features/pbs-storedreqs.html). For a thorough description of bid request JSON, see the [/openrtb2/auction](/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html) docs. | -| w | recommended | `String` | Comes from the amp-ad.width attribute. The stored request may contain width already, but this parameter reflects what's actually in the page. It replaces imp.banner.format[0].w | -| h | recommended | `String` | Comes from the amp-ad.height attribute. The stored request may contain height already, but this parameter reflects what's actually in the page. It replaces imp.banner.format[0].h | +| w | recommended | `String` | Comes from the amp-ad.width attribute. The stored request may contain width already, but this parameter reflects what's actually in the page. It's used to help determine imp.banner.format[0].w. See [resolving sizes](#resolving-sizes). | +| h | recommended | `String` | Comes from the amp-ad.height attribute. The stored request may contain height already, but this parameter reflects what's actually in the page. It's used to help determine imp.banner.format[0].h. See [resolving sizes](#resolving-sizes). | | ms | optional | `String` | Comes from the amp-ad.data-multi-size attribute. e.g. "970x90, 728x90". Sizes are parsed and added to imp.banner.format | -| oh | optional | `String` | Comes from the amp-ad.data-override-height attribute. See below for details on size calculation. | -| ow | optional | `String` | Comes from the amp-ad.data-override-width attribute. See below for details on size calculation. | +| oh | optional | `String` | Comes from the amp-ad.data-override-height attribute. See [resolving sizes](#resolving-sizes). | +| ow | optional | `String` | Comes from the amp-ad.data-override-width attribute. See [resolving sizes](#resolving-sizes). | | curl | optional | `String` | Added to OpenRTB request as site.page | | slot | optional | `String` | Added to OpenRTB request as imp[0].tagid | | timeout | optional | `String` | Added to OpenRTB request as tmax | -| targeting | optional | `String` | First Party Data (PBS-Java only) | +| targeting | optional | `String` | First Party Data | | gdpr_consent | optional | `String` | Consent string passed from CMP. Note this is used for both GDPR and CCPA. | +| consent_type | optional | `String` | If "1", request is TCFv1 and GDPR fields are ignored. If "2", the 'gdpr_consent' field is interpreted as TCFv2. If "3", the 'gdpr_consent' field is interpreted as us_privacy. | +| gdpr_applies | optional | `String` | Takes the values "true", "false" or empty. This is used as the value of regs.ext.gdpr. If "true", regs.ext.gdpr:1, if "false", regs.ext.gdpr:0. | +| addtl_consent | optional | `String` | GAM "additional consent". If present, this value is copied to user.ext.ConsentedProvidersSettings.consented_providers | | account | optional | `String` | Can be used to pass the Prebid-Server specific account ID. This is useful if `tag_id` parameters aren't unique across accounts. | -| debug | optional | `integer` | If 1, returns additional debug info. | +| debug | optional | `integer` | If 1, sets ext.prebid.debug to true to obtain additional debug info. | To be compatible with AMP, this endpoint behaves different from normal `/openrtb2/auction` requests. -1. The Stored `request.imp` data must have exactly one element. -2. `request.imp[0].secure` will be always be set to `1`, because AMP requires all content to be `https`. -3. AMP query params will overwrite parts of your Stored Request. For details, see the [Query Parameters](#query_params) section. +1. The 'tag_id' parameter points to a stored request. +2. The stored request must have exactly one `imp` element. +3. The request `imp[0].secure` will be always be set to `1`, because AMP requires all content to be `https`. +4. AMP query params will overwrite parts of your Stored Request. See the table above. ### Request @@ -63,20 +71,22 @@ An example Stored Request is given below: } } }, - "imp": [ - { - "id": "some-impression-id", - "banner": {}, // The sizes are defined by your AMP tag query params settings - "ext": { - "appnexus": { + "imp": [{ + "id": "some-impression-id", + "banner": {}, // The sizes are defined by your AMP tag query params settings + "ext": { + "prebid": { + "bidder": { + "bidderA": { // Insert parameters here }, - "rubicon": { + "bidderB": { // Insert parameters here } } - } - ] + } + } + }] } ``` @@ -90,77 +100,38 @@ Note that other ext.prebid extensions can be specified in the stored request suc (Currently only supported in PBS-Java) -You can send first party data into an AMP request by encoding a JSON -targeting block like this: +The nature of AMP is that user-level FPD is difficult or impossible. All of the pages are cached on a CDN and page javascript that can modify RTC calls is severely limited. -``` -GET /openrtb2/amp?tag_id=7470-Eater_AMP_ROS_ATF&w=300&h=250&ow=&oh=&ms=&slot=%2F172968584%2Feater%2Fgoogle%2Famp_med_rec_02&targeting=%7B%22site%22%3A%7B%22keywords%22%3A%22article%2C%20las%20vegas%22%2C%22cat%22%3A%7B%22blah%22%3A%221%22%7D%2C%22other-attribute%22%3A%22other-value%22%2C%22ext%22%3A%7B%22data%22%3A%7B%22entry_group%22%3A%5B%22front-page%22%2C%22featured-stories%22%5D%2C%22page_type%22%3A%22AMP%22%7D%7D%7D%2C%22user%22%3A%7B%22gender%22%3A%22m%22%7D%2C%22bidders%22%3A%5B%22rubicon%22%2C%22appnexus%22%5D%2C%22keywords%22%3A%22las%20vegas%20hospitality%20employees%22%2C%22foo%22%3A%7B%22bar%22%3A%22baz%22%7D%7D... -``` +Contextual First Party Data must be defined in the stored request entries. -Prebid Server will expand the targeting value and merge the data into -the resulting OpenRTB JSON for the appropriate bidders. +The only field that PBS supports in the AMP call that can be considered FPD is the 'targeting' block. These are key-value pairs that are sent to the ad server. They are also copied to the ORTB JSON in imp[].ext.data. -For example, if this AMP targeting is provided: +For example, if the AMP JSON targeting provided is: ``` -{ - "site": { - "keywords": "article, las vegas", // (1) - "cat": { "blah": "1" }, // invalid data type, will be dropped - "other-attribute": "other-value", // not openrtb2, remove - "ext": { - "data": { - "entry_group": ["front-page","featured-stories"], // (4) - "page_type": "AMP" // (5) - } - } - }, - "user": { - "gender": "m", // (2) - }, - "bidders": ["rubicon","appnexus"], // (3) - "keywords": "las vegas hospitality employees", // (6) - "foo": { // (7) - "bar": "baz" - } -} + + +``` +The AMP URL would be something like this: ``` -The numbered elements from the raw targeting data above are merged into the resulting OpenRTB like this: +GET /openrtb2/amp?tag_id=1001-my-test&w=300&h=250&ow=&oh=&ms=&slot=%2F1111%2Famp_test&targeting=%7B%22attr1%22%3A%22val1%22%2C%22attr2%22%3A%22val2%22%7D&... +``` +And the resulting OpenRTB would merge these targeting values as FPD on imp.ext.data: ``` { - "imp": [...], - "site": { - "publisher": { … }, - "keywords": "article, las vegas" // (1) - "ext":{ - "data": { - "entry_group": ["front-page","featured-stories"], // (4) - "page_type": "AMP" // (5) - } - } - }, - "user": { - "gender": "m" // (2) - }, - "ext": { - "prebid": { - "data": { - "bidders": ["rubicon",appnexus"], // (3) - } - } - }, - "imp": [ + "imp": [{ ... "ext": { - "context": { - "data": { - "keywords": "las vegas hospitality employees", // (6) - "foo": { // (7) - "bar": "baz" - } - } - } + "data": { + "attr1": "val1", + "attr2": "val2" + } } - ] + }], + ... } ``` @@ -228,41 +199,7 @@ The following errors can occur when loading a stored OpenRTB request for an inco | Checking stored request for match against tag_id. | 999 | No AMP config found for tag_id `%s`. | Error is returned. | | Checking if imp exists. | 999 | Data for tag_id=`'%s'` does not define the required imp array. | Error is returned. | | Checking if imp count is greater than one. | 999 | Data for tag_id `'%s'` includes `%d` imp elements. Only one is allowed. | Error is returned. | -| Checking if request.app exists. | 999 | `request.app` must not exist in AMP stored requests. | Error is returned. | - - - -### Query Parameter Details - - - A configuration option `amp_timeout_adjustment_ms` may be set to account for estimated latency so that Prebid Server can handle timeouts from adapters and respond to the AMP RTC request before it times out. - -Ensure that the amp-ad component was imported in the header. - -```html - - ``` - -This script provides code libraries that will convert the `` properties to the endpoint query parameters. In the most basic usage pass `width` and `height` as well as `type` and a `rtc-config`. The `type` value is the ad network you will be using. The `rtc-config` is used to pass JSON configuration to the Prebid Server, which handles the communication with [AMP RTC](https://medium.com/ampfuel/better-than-header-bidding-amp-rtc-fc54e80f3999). Vendors is an object that defines any vendors that will be receiving the RTC callout. In this example, the required parameter `tag_id` will receive the `PLACEMENT_ID` (or `REQUEST_ID`) value. - -```html - -``` -Here's a simplified URL: - -``` -/openrtb2/amp?tag_id='ef8299d0-cc32-46cf-abcd-41cebe8b4b85'&w=300&h=250&timeout=500 -``` - -Some endpoint parameters will override parts of the Stored Request. - -1. `ow`, `oh`, `w`, `h`, and/or `ms` will be used to set `request.imp[0].banner.format` if `request.imp[0].banner` is present. -2. `curl` will be used to set `request.site.page` -3. `timeout` will generally be used to set `request.tmax`. However, the Prebid Server host can [configure](https://github.com/prebid/prebid-server/blob/master/docs/developers/configuration.md) their deploy to reduce this timeout for technical reasons. -4. `debug` will be used to set `request.test`, causing the `response.debug` to have extra debugging info in it. +| Checking if app exists. | 999 | The `app` object must not exist in AMP stored requests. | Error is returned. | ### Resolving Sizes @@ -271,15 +208,23 @@ track the logic used by `doubleclick` when resolving sizes used to fetch ads fro Specifically: -1. If `ow` and `oh` exist, `request.imp[0].banner.format` will be a single element with `w: ow` and `h: oh` -2. If `ow` and `h` exist, `request.imp[0].banner.format` will be a single element with `w: ow` and `h: h` -3. If `oh` and `w` exist, `request.imp[0].banner.format` will be a single element with `w: w` and `h: oh` -4. If `ms` exists, `request.imp[0].banner.format` will contain an element for every size it uses. -5. If `w` and `h` exist, `request.imp[0].banner.format` will be a single element with `w: w` and `h: h` -6. If `w` _or_ `h` exist, it will be used to override _one_ of the dimensions inside each element of `request.imp[0].banner.format` -7. If none of these exist then the Stored Request values for `request.imp[0].banner.format` will be used without modification. +1. If `ow` and `oh` exist, `imp[0].banner.format` will be a single element with `w: ow` and `h: oh` +2. If `ow` and `h` exist, `imp[0].banner.format` will be a single element with `w: ow` and `h: h` +3. If `oh` and `w` exist, `imp[0].banner.format` will be a single element with `w: w` and `h: oh` +4. If `ms` exists, `imp[0].banner.format` will contain an element for every size it uses. +5. If `w` and `h` exist, `imp[0].banner.format` will be a single element with `w: w` and `h: h` +6. If `w` _or_ `h` exist, it will be used to override _one_ of the dimensions inside each element of `imp[0].banner.format` +7. If none of these exist then the Stored Request values for `imp[0].banner.format` will be used without modification. + +## Configuration Options + +- settings.generate-storedrequest-bidrequest-id: replace the stored request `id` with a UUID (PBS-Java only) +- amp.default-timeout-ms: default operation timeout for AMP requests +- amp.timeout-adjustment-ms: reduces timeout value passed in AMP request. Can be used to account for estimated latency so that Prebid Server can respond to the AMP RTC request before it times out. +- amp.max-timeout-ms: maximum operation timeout for AMP requests ## Further Reading - [Prebid and AMP](/formats/amp.html) - [Prebid Server AMP Use Case Overview](/prebid-server/use-cases/pbs-amp.html) - [Prebid Server First Party Data](/prebid-server/features/pbs-fpd.html) +- [Stored Requests](/prebid-server/features/pbs-storedreqs.html) diff --git a/prebid-server/features/pbs-storedreqs.md b/prebid-server/features/pbs-storedreqs.md index 966eace171..822b9b5237 100644 --- a/prebid-server/features/pbs-storedreqs.md +++ b/prebid-server/features/pbs-storedreqs.md @@ -8,27 +8,35 @@ title: Prebid Server | Features | Stored Requests # Prebid Server | Features | Stored Requests 'Stored Requests' are blocks of OpenRTB stored on the server-side that are merged into -OpenRTB requests in a couple of scenarios. +OpenRTB requests for Mobile App and AMP scenarios. The data source can be local files on Prebid Server, but more commonly it would be a relational database distributed across all the Prebid Servers in the host company's installation. ## Mobile App -Hardcoding bidders and parameters in a mobile app isn't ideal. Prebid Server allows Stored Request IDs to be -used in two ways: +We want to avoid hardcoding parameters into a mobile app like bidders and parameters. Because of this, Prebid Server allows host companies to store two types of JSON that are retrieved with a key called a 'Stored Request ID': -1. Define cross-adunit parameters like currency and price granularity -1. Define adunit-specific details: bidders and their parameters +- "top-level" requests, also called "wrapper-level" requests. This block is merged into the root level of the incoming ORTB request. It's not expected to have an imp object. +- "impression-level" requests are merged into a particular ORTB imp element. + +![App stored request model](/assets/images/prebid-server/stored-requests-app.png){: .pb-lg-img :} + +1. The SDK creates a 'skeleton' framework of the OpenRTB JSON that doesn't +contain the bidders or any other parameter that might be changed by AdOps. +2. Prebid Server merges all the stored requests into this template. +3. Creating the final OpenRTB JSON just like Prebid.js would have sent using the PBS Bid Adapter. See the [Mobile SDK Use Case reference](/prebid-server/use-cases/pbs-sdk.html) for specific examples. ## AMP The AMP protocol is converted to OpenRTB primarily using Stored Requests: the `tag_id` is used to look up -the base OpenRTB from the data source. After getting the bulk of the OpenRTB, AMP query string parameters +a single base OpenRTB from the data source. After getting the bulk of the OpenRTB, AMP query string parameters are used to inject and adjust parameters like size, url, etc. See the [AMP endpoint documentation](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) for more details. +![AMP stored request model](/assets/images/prebid-server/stored-requests-amp.png){: .pb-lg-img :} + See the [AMP Use Case reference](/prebid-server/use-cases/pbs-amp.html) for specific examples. ## Creating Stored Requests diff --git a/prebid-server/use-cases/pbs-amp.md b/prebid-server/use-cases/pbs-amp.md index ecd191ed02..d5ec56c52e 100644 --- a/prebid-server/use-cases/pbs-amp.md +++ b/prebid-server/use-cases/pbs-amp.md @@ -47,7 +47,7 @@ There are two basic ways of invoking AMP RTC: data-slot="/11111/amp_test" data-multi-size-validation="false" rtc-config='{"vendors": {"prebidrubicon": {"REQUEST_ID": "14062-amp-AMP_Test-300x250"}, "ACCOUNT_ID": "1001"}}' - json='{ "targeting": {"site":{"keywords":"article, las vegas","cat":{"blah":"1"},"other-attribute":"other-value","ext":{"data":{"entry_group":["front-page","featured-stories"],"page_type":"AMP"}}},"user":{"gender":"m"},"bidders":["bidderA","bidderB"],"keywords":"las vegas hospitality employees","foo":{"bar":"baz"}}' > + json='{ "targeting": {"attr1": "val1", "attr2": "val2"}}' > ``` @@ -61,13 +61,10 @@ There are two basic ways of invoking AMP RTC: type="doubleclick" data-slot="/000/amp_test" data-multi-size-validation="false" - rtc-config='{"urls": ["https://prebid-server-qa.example.com/openrtb2/amp?tag_id=11111&w=300&h=50&slot=%2F000%2Famp_test&targeting=%7B%22site%22%3A%20%7B%22key1%22%3A%20%22val1%22%7D%2C%20%22user%22%3A%20%7B%22key2%22%3A%20%22val2%22%7D%7D%7D&purl=encoded_page_url&account=333&gdpr_consent=encoded_cmp_consent_string"] + rtc-config='{"urls": ["https://prebid-server-qa.example.com/openrtb2/amp?tag_id=11111&w=300&h=50&slot=%2F000%2Famp_test&purl=encoded_page_url&account=333&gdpr_consent=encoded_cmp_consent_string"] ``` -{: .alert.alert-info :} -First party data may be passed in on the "targeting" field. See the [`/openrtb2/amp` endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) documentation for more details. - ### Prebid Server Receives the AMP Request Prebid Server's first job on the [/openrtb2/amp endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) is to create an OpenRTB block to pass to the adapters. @@ -76,15 +73,8 @@ Prebid Server's first job on the [/openrtb2/amp endpoint](/prebid-server/endpoin The `tag_id` in the AMP URL is used to look up the bulk of the request. If the lookup fails, the request can't proceed. If it's successful, the next step is to parse the AMP query string parameters and place them -in the appropriate OpenRTB locations: - -- w added into the openrtb packet at imp.banner.format[0].w -- h added into the openrtb packet at imp.banner.format[0].h -- ms (multiple-sizes) - takes values like "970x90, 728x90". Parse sizes and add to imp.banner.format array -- ow, oh - override width, override height -- curl added as site.page -- slot added as imp.tagid -- timeout added as tmax +in the appropriate OpenRTB locations. See the [AMP endpoint documentation](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) +for details. So for the /openrtb2/amp URL above, the resulting OpenRTB might be: ``` @@ -116,17 +106,7 @@ So for the /openrtb2/amp URL above, the resulting OpenRTB might be: "id": "0000" }, "ext": { - "amp": 1, - "data": { - "key1": "val1" - } - } - }, - "user": { - "ext": { - "data": { - "key2": "val2" - } + "amp": 1 } }, "device": { @@ -169,7 +149,7 @@ Only a few dynamic parameters on the query string are integrated into the result #### First Party Data Support Ad Server targeting data passed in through the [`/openrtb2/amp`](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html) endpoint is merged -into the OpenRTB JSON in imp[].ext.data for each bidder if permissions allow. +into the OpenRTB JSON in imp[].ext.data. #### Auction and Response @@ -180,7 +160,6 @@ From here, the header bidding auction is mostly the same as it is for Prebid.js: 1. Collect responses 1. Prepare the response - ### AMP Gets the Response AMP RTC endpoints can only respond with targeting, not OpenRTB. The @@ -216,4 +195,5 @@ into an iframe for display. ## Further Reading -- [AMP Support](/formats/amp.html) +- [Prebid AMP Support](/formats/amp.html) +- [PBS AMP endpoint](/prebid-server/endpoints/openrtb2/pbs-endpoint-amp.html)