Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Price Floor Module #4273

Closed
bszekely1 opened this issue Oct 8, 2019 · 7 comments
Closed

Price Floor Module #4273

bszekely1 opened this issue Oct 8, 2019 · 7 comments

Comments

@bszekely1
Copy link

bszekely1 commented Oct 8, 2019

Type of issue

As the ad tech ecosystem moves to a first price model, buyers are starting to adjust to this new model. Publishers will need a mechanism to maintain a market rate for their inventory to prevent eroded valuation. Today publishers have to set floors in each platform they work with, where many of the platforms are not self-serve and each have various levels of control and configuration.

Using the Price Floor Module within Prebid, the intent is to provide an open source flooring framework in Prebid for Publishers to either configure floors themselves or work with a floor provider for an automated floor mechanism to floor all Prebid demand.

Intended workflow:

  1. Publisher signs with a Price Floor provider
  2. Price Floor provider makes a JSON file available with the data
  3. Publisher configures Prebid.js to resolve and enforce the price floor

This feature should be designed to work with Prebid.js, Prebid Server, and Prebid SDK.

Goals

  • Provide a Prebid unified floor solution controlled by the publisher
  • Allow for an open framework to set floors manually or work with a floor provider
  • Provide a flexible framework to allow floor providers to integrate with the floor sub-module

Requirements

  1. The feature should support the following modes:
    • Floor data is obtained for each ad unit
    • Floor data is configured for a Prebid package context
    • Floor data is configured on the page with an attempted real-time fetch on each Prebid request
  2. The attributes used to determine the price floor must be flexible. e.g. one floor provider may determine a specific floor value with a combination of domain, ad size, and ad format, while another provider may utilize ad slot name
    • Provider may use wildcard values to express the concept of any for a particular field, used as a catch all
  3. The Price Floor Module must allow a skip rate that will skip enforcement and not expose floors to bid adapters for A / B testing performance of the flooring service (i.e. control vs exploit)
  4. Allow for floor providers to pass model name to be ingested in their analytics adapter for learning which model is more performant
  5. The attributes used for choosing the default price floor may differ from attributes used for a real-time data fetch
  6. It should be possible to delay the auction for a configurable amount of time to allow for real-time fetching of up-to-date floor data
    • If data does not return in that period, it should be possible to initiate the auction with either a default, ad unit, setConfig or no floor
  7. Price floors must be exposed to all bidders for bidders to retrieve floor
  8. There should be a standard method the bidders can call to obtain the floor
  9. Where Prebid.js is enforcing floors and using Prebid Server for monetization, Prebid.js must pass floors data when available to Prebid Server for floor context to bid adapters
  10. Prebid Server should operate it’s own floors from Prebid.js for in-app and AMP integrations
  11. Analytics adapters must have the following information available:
    • The floor enforced per bid
    • The original bid value from each bidder before enforcing the floor
    • New event for floor not met bids
    • Location of where floor was derived (fetch, local setConfig, ad unit)
    • Bid adjustment if present
      • Each bid’s response data whose bid does not clear floor along with new bid status of floor not met
      • Bid adjustment
      • Location of where floor was derived (fetch, local setConfig, ad unit)
  12. The price floor must be enforced before pricegranularity rounding occurs
  13. The size determined by the floor module must be determined after any size labeling and responsive size mappings
  14. For security, responses for floor data must be JSON, not javascript
  15. The system must support specifying the floor currency
  16. The system should support an overall default floor in case the lookup completely fails
  17. The floor provider should be able to specify ad server slot name as an attribute
    • It should be possible to link an ad server slot name to an ad unit before an auction
  18. Allow Publisher to configure prebid to floor enforcement in js or server, support floors for deals and support CPM bid adjustments in get floor function for bid adapters
  19. Floor enforcement support will have no CPM decimal point precision limit
  20. The get floors function will support a max CPM precision of 4 decimal points
    • For larger precision decimal points (defined in data or cause by Bid Adjustment) the Floor Module will round up to the 4th decimal point
  21. A utility function must be provided to encapsulate the desired floor for the bid adapter interface
    • Attributes
      • Media type
      • Size (* to signify the average CPM of all sizes)
      • Currency
  22. The allow fields for floor schema are:
    • Domain
    • gptSlot
    • adUnit
    • Size
    • Mediatype

Prebid.js Proposed Interfaces

Floors Module

A new Floors Module will be built that supports three scenarios:

  • Floor data is configured on ad unit grain
  • Floor data is configured at the Prebid package level in setConfig
  • A real-time data fetch that delays the auction, with an optionally configured default set of data

In all cases, the job of the module is:

  1. Conditions on get data:
    -If fetch url specified, attempt to fetch new data with an auction delay
    - If auction delay is not set, default to 0ms and emit a warning
    - It is beholden of the floor provider to do http caches in the browser (i.e. Prebid will not perform caches)
    • GET will be the only supported fetch method in this current phase
    • If fetch fails (by time or other error condition) use local data if specified
  2. If skipRate is set, roll dice to determine if floors module will expose floors to bidders and enforce floors
    • Skip rate will roll the dice once per auction
    • Skip will be evaluated at auction init, after the auction delay but before bid requests
  3. Within an “Enforcement” object the publisher or floor provider can utilize different options for enforcing floors:
    • Boolean flag to enforce floors in Prebid.js
      - If both pbjs and PBS flags are set to true, pbjs enforcement prevails
    • Boolean flag to enforce floors in Prebid Server
    • Boolean flag to enforce flooring deals
    • Boolean flag to adjust floor using bidCpmAdjustment (bid / bidCpmAdjustment)
  4. If the rules file has multiple matching rules, the floors module will match on the first matched rule
  5. Expose a lookup function for bidders retrieve the supported flooring method per bidder
    • Bidders provide what floor format they can / want to support:
      • Currency : three letter ISO 4217 currency code
      • Media Type : one of “banner”, “video” or “native”
      • Size : allowed values are [ w, h] or [‘*’]
  6. Looking up the floor value for each bidrequest (lookup call from bidders) will utilize the defined schema for the matching rule:
    • The following order will apply for looking up the matching rule sets if URL, setConfig and adUnit data are set (only one data set can be selected per auction):
      • Fetch data from URL if present
      • Else, data set in setConfig if present
      • Else, data set in Ad Unit grain if present
      • Else, do not provide a floor
    • The Floor Module will be responsible for looking up defined schema attributes if the request (i.e. adUnit.code)
      • If gptSlot is defined, an attempt to match the adUnit.code, else look for gpt slot name on the page
        • * can be used as a catch for any gptSlot
      • If domain is specified, the Prebid Floors Module will assume the root domain is supplied (example: domain.com)
        • Domains will not include www or http://
        • Domains will not include sub-domains in initial iteration
        • Country codes such as co.uk should be inclusive of the root domain
        • The Prebid Floor Module will extract the page domain from the page referrer using the above logic
        • The Prebid Floor Module will perform exact pattern matches
        • * can be used for a catch all as a standalone string, referring to any domain name, but not for a wildcard with the second level domain
      • Size is to be expressed a string in the format “WxH”
        • * can be used as a catch all for any size
      • If the delimiter field is not specified, the floors module will default to “|”
      • If schema references an attribute that is not available, emit an error and do not use a floor
    • If the getfloor lookup requests a currency different from data currency, use the currency module to lookup the converted currency
      • If the currency module or data is not available, return data in available currency (bidder responsible for handling non-requested currency)
  7. After the auction, use the hook for each bidresponse object after currency conversion (if required) and enforce the floor if enforce floor option is enabled:
    • If enforce floors is false, bids should be passed to the ad server as a normal auction without floors
    • If enforce floors is true:
      - Suppress any bids below floor from auction
      - Set new BidFloorStatus
      - If prebid is using bid caching, only bids surpassing the bid floor will enter cache
  8. Analytics adapters can check for the new bid status and floors enforced
    • Floor that was used to enforce this bid
      • If bidAdjustment is used, log the adjusted bid to keep what is actually enforced logged
    • New floor bid status signaling floor passed / not passed

Example Configuration 1

Floor data is configured on the page to apply to the whole Prebid package where just gptSlot is defined in the schema:

pbjs.setConfig({
    floors: {
        enforcement: {
           enforceJS: true, //default to true
           enforcePBS: false, //default to false
           floorDeals: false, //default to false
           bidAdjustment: false //default to false
        },
        data: {
            currency: 'USD',
            delimiter: '|',  //default to ‘|’
            skipRate: 5,  //default to zero
            modelVersion: ‘new model 1.0'
            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
        }
    }
});

Example Configuration 2

Real-time data fetch that delays the auction, with a configured default set of data:

pbjs.setConfig({
    floors: {
        enforcement: {
           floorDeals: false, //default to false
        },
        auctionDelay: 100,   // in milliseconds
        endpoint: {
            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}
            ]
        }
    }
});

Example Configuration 3

Ad Unit defined floor data
Sample data for http://floors.com/floors/1001-floors.json

    var adUnits = [
           {
               code: 'test-div',
               mediaTypes: {
                   banner: { sizes: [[300,250],[300,600]] },
                   video: {
                       context: 'outstream',
                       playerSize: [300,250],
                       ...
                   }
               },
               floors: {
                   enforceFloors: false,
                   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: [
                   ...
               ]
           }
       ];

Floors Provider Interface

Floor data provider providers endpoints must return a JSON data formatted like the data object in the “setConfig” call.

Example response to https://floors.com/floors/1001-floors.json

{
    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
}

Bid Adapter Floor Interface

There exist several scenarios where more than one price floor can be matched:

  • Multi-ad size requests
  • Multi-format requests

While some bidders are able to break out requests per size / format (i.e. one request per ad size), giving them the ability to add floors per size or format is available, however many bid adapters do not have this flexibility. Having prebid define the floor for either situations would favor one bidder group over another.
The proposal is to expose a function call each bidder can utilize on every bidrequest, media type and size combination. The converted currency of the ad server is provided if the currency module is provided and ad server currency is able to be fetched.

The floors function will be attached to the Bid Request object each Bid Adapter utilizes today for context of the Prebid ad request to pass to their bid adapter endpoint.

Format

getFloor({
    currency: string,   //default to currency specified in data
    mediatType: string  //Required,one of “banner”, “video” or “native”
    Size : [ w, h] OR ‘*’  //default size is “*”
});

The job of the get floors function will be:

  • Encapsulate full rules file by pull matching rules against attributes of the bidRequest object
    • Bidders will be required to call getFloor for each mediaType and ad size combination or once per mediaType if they don’t support floors per size
    • getFloor will return a single price floor specific for that ad unit, media type and size combination of the bidrequest object for that bidder context
  • Convert the currency into the desired currency using the currency conversion module if available, otherwise, return specified currency in utilized data set
  • If supportMultipleSizes is set to false, the getFloor function will seek to return the floor associated with “*” (any) if defined, otherwise getFloor will return the average of all sizes for that media type
  • Read from appropriate data set if URL fetch, adUnit and setConfig data are provided (or a mix data set provided)

Examples

Example rules file used for getFloor examples below

{
    "data": {
            "currency": "USD",
            "schema": {
                "fields": [ "gptSlot", "mediaType", "size"]
            },
            "values": [
                {"key": "/1111/homepage/top-rect|banner|300x250", "floor": 0.60},
                {"key": "/1111/homepage/top-rect|banner|300x600", "floor": 1.78},
                {"key": "/1111/homepage/top-rect|banner|*", "floor": 1.10},
                {"key": "/1111/homepage/top-rect|video|480x600", "floor": 3.20},
                {"key": "/1111/homepage/top-leaderboard|banner|728x90", "floor": 1.50}
            ],
            "default": 0.75
        }
}

Example 1
getFloor for media type Banner for a bid requests in the context of the gpt slot “/1111/homepage/top-rect” where the bid adapter does not support multiple sizes.

getFloor({
    currency: 'USD',
    mediatType: ‘banner’,
    Size: [*]
});

Response

{
    currency: 'USD',
    floor: 1.10
}

Example 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 multiple sizes.

getFloor({
    currency: 'USD',
    supportMultipleSizes: true
});

Response

{
    currency: 'USD',
    floor: 1.78
}

PBJS to PBS Interface

In Prebid JS to Prebid Server environments, the below requirements are mandated:

  • Prebid JS will signal to PBS if enforcing floors is required
  • Prebid JS will pass the bid adjustment factor in the request.ext.prebid.bidadjustmentfactor
  • Entire floors data object is passed in each imp
  • If gptSlot is defined in the utilized data set, the Floors Module should map each matched gptSlot to its corresponding impression object by way of imp.id.

Floors are defined per ad unit in pbjs and passed to PBS in imp.ext.floors object

{
    "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,
            }
        }
    }
}

Prebid Server
With Prebid Server, the client's job is easier -- just pass all relevant data and let the server figure out how to keep floor data fresh and apply it to bids.
Additional Requirements
For the most part, the requirements for Prebid Server are the same as for Prebid.js, with a few extras:

  • It must be possible to configure the server to recognize that a given account requires price-floor support, the URL from which this data should be obtained, and how often the data should be updated.
  • Have a signal for enforcement
  • The endpoint should return all price floor data for the whole account in the same JSON format defined for Prebid.js
  • It's assumed that the price floor provider can generate separate data files for Prebid.js and Prebid Server, as the source attributes are in different locations.

Other information

@bretg
Copy link
Collaborator

bretg commented Oct 30, 2019

FYI - we've iterated on this feature. Posted draft user documentation at http://prebid.org/dev-docs/modules/floors.html (not linked in anywhere yet. Except here.)

The description above will change soon.

@bszekely1 bszekely1 changed the title Real Time Data Module: Price Floors Price Floor Module Oct 30, 2019
@pm-harshad-mane
Copy link
Contributor

When we are implementing on Requirement 2, if we could make it part of core logic then with floors we will be able to map other data points t slots as well like bidder-config, position attribute, etc.
It will be a centralized logic any data to slots.

@markd-fs
Copy link

Will price floors work with setBidderConfig, if a publisher wants to set floors unique to certain bidders?

@bszekely1
Copy link
Author

Will price floors work with setBidderConfig, if a publisher wants to set floors unique to certain bidders?

the setBidderConfig is a new feature that has yet to be implemented and still needs a review. Our initial goal is to keep the amount of supported fields to a limited set for "supported" fields even if technically it may work with a larger set.

@pdmeyer
Copy link

pdmeyer commented Nov 20, 2019

I have a few questions which relate to floor provider interface:

  1. What metadata is included in the floor data fetch to a floor provider? Taking the User ID module as an example, many User ID providers require at a minimum a Publisher ID or something of the sort. Going further, I could imagine that floor providers may need more data such as adUnit names. I imagine that anything that is available among "fields" would need to be able to be appended to requests to floor providers.

  2. What mechanism is there for a "feedback loop" that would feed relevant data about auction results back to the floor provider to allow them to train machine learning algorithms?

@bszekely1
Copy link
Author

I have a few questions which relate to floor provider interface:

  1. What metadata is included in the floor data fetch to a floor provider? Taking the User ID module as an example, many User ID providers require at a minimum a Publisher ID or something of the sort. Going further, I could imagine that floor providers may need more data such as adUnit names. I imagine that anything that is available among "fields" would need to be able to be appended to requests to floor providers.

The floor provider will work with publisher to set the appropriate URL for the fetch. gptSlots and adUnit code are both supported. The floor provider can specify in the schema what fields they are looking to support. The call to the floor provider will be a fetch, meaning no data is sent do them. It's a retrieval of info. In the future we will be supporting a POST method where we can post some arbitrary data set to allow for context driven floor data per impression.

  1. What mechanism is there for a "feedback loop" that would feed relevant data about auction results back to the floor provider to allow them to train machine learning algorithms?

Analytics modules already today have access to auction data. This will continue to operate the same way going forward. A floor provider will need to use an analytics adapter for the feedback loop. This iteration does not include the usage of sub-modules.

@robertrmartinez
Copy link
Collaborator

Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants