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

Prebid Server Stored Responses #861

Closed
bretg opened this issue Mar 28, 2019 · 12 comments
Closed

Prebid Server Stored Responses #861

bretg opened this issue Mar 28, 2019 · 12 comments
Labels
PBS-Go Ready For Dev Feature specification is ready to be developed.

Comments

@bretg
Copy link
Contributor

bretg commented Mar 28, 2019

While testing SDK and video integrations, it's important, but often difficult, to get consistent responses back from bidders that cover a range of scenarios like different CPM values, deals, etc.

We discussed in the Prebid Server PMC supporting a 'stored-response' feature. After discussing with the Prebid Server committee, we've decided to go with two approaches:

  1. a stored-auction-response that covers multiple bidder responses
  2. multiple stored-bid-reponses at the bidder adapter level

Single Stored Auction Response ID

When a storedauctionresponse ID is specified:

  • the rest of the ext.prebid block is irrelevant and ignored
  • nothing is sent to any bidder adapter for that imp
  • the response retrieved from the stored-response-id is assumed to be the entire contents of the seatbid object corresponding to that impression.

e.g. this request:

{
  "test":1,
  "tmax":500,
  "id": "test-auction-id",
  "app": { ... },
  "ext": {
      "prebid": {
             "targeting": {},
             "cache": { "bids": {} }
       }
  },
  "imp": [
    {
      "id": "a",
      "ext": { "prebid": { "storedauctionresponse": { "id": "1111111111" } } }
    },
    {
      "id": "b",
      "ext": { "prebid": { "storedauctionresponse": { "id": "22222222222" } } }
    }
  ]
}

could result in:

{
    "id": "78cb3c51-baa7-437b-b958-c7c6569a5041",
    "seatbid": [
        {
             // BidderA bids from storedauctionresponse=1111111111
             // BidderA bids from storedauctionresponse=22222222
        },
       {
             // BidderB bids from storedauctionresponse=1111111111
             // BidderB bids from storedauctionresponse=22222222
       }
  ]
}

Multiple Stored Bid Response IDs

In contrast, this approach lets some real auctions take place while some bidders have test responses that still exercise bidder code.

{
  "test":1,
  "tmax":500,
  "id": "test-auction-id",
  "app": { ... },
  "ext": {
      "prebid": {
             "targeting": {},
             "cache": { "bids": {} }
       }
  },
  "imp": [
    {
      "id": "a",
      "ext": {
          "prebid": {
            "storedbidresponse": [
                  { "bidder": "BidderA", "id": "333333" },
                  { "bidder": "BidderB", "id": "444444" },
             ]
           } 
      }
    },
    {
      "id": "b",
      "ext": {
          "prebid": {
            "storedbidresponse": [
                  { "bidder": "BidderA", "id": "5555555" },
                  { "bidder": "BidderB", "id": "6666666" },
             ]
           } 
      }
    }
  ]
}

Which could result in:

{
    "id": "78cb3c51-baa7-437b-b958-c7c6569a5041",
    "seatbid": [
        {
             "bid": [
             // contents of storedbidresponse=3333333 as parsed by bidderA adapter
             // contents of storedbidresponse=5555555 as parsed by bidderA adapter
             ]
        },
       {
             // contents of storedbidresponse=4444444 as parsed by bidderB adapter
             // contents of storedbidresponse=6666666 as parsed by bidderB adapter
       }
  ]
}

Setting up the Stored Response

We would add a new (logical) table within Prebid Server's DB alongside stored_requests. Entries in the DB designed for Single Stored Auction Responses would be the array portion of the seatbid with bids on one impression from many bidders:

[
    {
      "bid": [
        {
          "id": "f227a07f-1579-4465-bc5e-5c5b02a0c180",
          "impid": "a",
          "price": 1.24,
          ...
        }
      ],
      "seat": "rubicon",
      "group": 0
    },
    {
      "bid": [
        {
          "id": "a121a07f-1579-4465-bc5e-5c5b02a0c421",
          "impid": "a",
          "price": 1.24
          ...
        }
      ],
      "seat": "appnexus",
      "group": 0
    }
]

The impid should match what was placed into the request so that the response can be matched up properly to the ad unit.

Entries in the DB designed for Multiple Stored Bid Response IDs would reflect whatever a bidder actually responds with. e.g. Rubicon XAPI returns something like:

{"id":"test-auction-id","bidid":"500716d8-a9dc-46e0-8baa-0cf4fafd956a","seatbid":[{"seat":"0:::","bid":[{"id":"0","impid":"1","price":1.230000,"adm":"BODY", "crid":"4458534","w":300,"h":250,"ext":{"rp":{"targeting":[{"key":"rpfl_1001","values":["15_tier0100"]}],"mime":"text/html","size_id":15}}}]}],"statuscode":0}

Instead of actually calling their exchange, each bidder will be updated to have a debug mode where it can be told what the response would be, using that bidders parsing logic to create the PBS bidResponse object.

Coordinated changes in Prebid.js and SDK

In order to utilize this feature, the PrebidServerBidAdapter in Prebid.js could to be updated to pass the storedauctionrequestid and/or storedbidrequestid in the openrtb field(s). e.g. We may be able to have a simple invocation mechanism like adding a pbjs_stored_auction_response_id=111111111 to the page's query string. Or perhaps we can utilize the existing pbjs.setConfig("debugging") functionality. This feature will be worked out at a later time.

The SDK would also need to be updated to support passing the openrtb field(s), but the app would need to have a "debug mode" to pass the response IDs when necessary.

@bretg bretg added the Intent to implement An issue describing a plan for a major feature. These are intended for community feedback label Mar 28, 2019
@hhhjort
Copy link
Collaborator

hhhjort commented Mar 29, 2019

One variation might be to store the expected response from the bidder. This would allow for testing the bidder adapter code to some extent. The adapter reads the request and prepares a call (to the bidder). Instead of actually sending the request out over the internet, you feed the adapter the stored response, which it then processes into bids.

The upside is you get some validation on the bidder parameters you are sending to the adapter, and some testing of the adapter code. (it is almost an end to end test)

The downside is it requires knowledge of the bidder's expected response in order to set up, rather than a standard format that can be used for all bidders.

@hhhjort
Copy link
Collaborator

hhhjort commented Mar 29, 2019

Also a note on the above format, in the go version generating the targeting key/values is done by the base PBS code, not the adapters. Does the Java version generate targetting inside the adapter, or should that section be dropped as the parameters will be automatically generated in the normal execution flow after the stored bids are merged in with and adapter bids?

@bretg
Copy link
Contributor Author

bretg commented Mar 29, 2019

@hhhjort -

I'm not real fond of the work that will involved in trying to get valid bid response examples from 20+ adapters. But I agree that could be useful in setting up tests, including the end-to-end test environment we've discussed.

If we go with the "override" approach, then targeting key/values are just in the override. If not, then we let core generate them.

Another thing I don't love about the "per-bidder" approach is the difficulty in supplying multiple stored response IDs. My team wants a simple way of specifying a test scenario, and requiring them to enter multiple IDs isn't so simple. e.g. ?pbjs_stored_reponses=rubicon-test-bid-12,appnexus-test-bid-9,openx-test-bid-7 is more complicated than ?pbjs_stored_reponses=video-test-3

And the last thing I don't like is that every bidder is going to need to changed to understand this feature. And all future bidders. Rather invasive.

For my first concern, I guess we can give up on having the stored-responses look like actual responses, and just make up a new format that's processed by core.

{
    id: "video-test-3",
    bidderResponses: [
        {
            biddercode: "rubicon",
            storedresponse: {  RUBICON STORED RESPONSE HERE }
        },
        {
            biddercode: "appnexus",
            storedresponse: {  APPNEXUS STORED RESPONSE HERE }
        }
    ]
}

The second concern may also be relatively minor as it's only a couple lines of code added into each bidder hopefully.

Welcome feedback from the broader community. I'm still leaning slightly towards the simpler Option 1 as it's quite a bit easier to implement and doesn't require mass coordination.

@bretg bretg mentioned this issue Apr 3, 2019
@bretg
Copy link
Contributor Author

bretg commented Apr 5, 2019

We talked about this in the Prebid Server committee and realized both approaches have use cases. Proposal updated.

@bretg
Copy link
Contributor Author

bretg commented Jul 22, 2019

Note: updated what's stored in the DB to just the array portion of the seatbid.

@stale
Copy link

stale bot commented Aug 8, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Aug 8, 2019
@hhhjort hhhjort removed the stale label Aug 8, 2019
@bretg
Copy link
Contributor Author

bretg commented Aug 19, 2019

This has been implemented in PBS-Java. Waiting on the Prebid.js changes to be merged before we can really try it out.

@VeronikaSolovei9
Copy link
Contributor

Hello @bretg
I work on stored bid response part of this issue now and came up with the question. Is it possible to have more than one same bidder in stored bid response for one impression? Can we have an imp.ext.prebid look like this:

"prebid": {
                    "storedbidresponse": [
                        {"bidder":"appnexus", "id": "d3fa8c49-c36a-e2a5-a1fe-1f90afa27b93"},  <-- appnexus
                        {"bidder":"appnexus", "id": "d3fa8c49-c36a-e2a5-a1fe-1f90afa27b93"},  <--appnexus again
                        {"bidder":"rubicon", "id": "bc75546d-2e09-83d0-8231-5ca89894707b"}
                    ]
                }

is this a valid case? Should bidder name be unique? If yes - do we need to validate it?

Thank you!

@bretg
Copy link
Contributor Author

bretg commented Mar 16, 2022

Hadn't considered it @VeronikaSolovei9 , but I'd say yes, it should be supported. It's completely valid nowadays with the multibid feature for a single bidder to supply more than one bid.

@VeronikaSolovei9
Copy link
Contributor

@bretg
We briefly discussed it with a team and we don't think we need to support this.
Is there a use case for this king of request set up? single bidder to supply more than one bid - yes, we support multiple bid responses for one bidder per impression.
Adding this flexibility will add a lot of complexity to codebase and request set up can be tricky.
What if there are 2 or more same bidders with the same storedbidresponse.id? Should stored responses data be unique or duplicated?
To our perspective it will be much clearer to set up one bidder response (with any number of bids) per bidder per imp rather than using set up like I wrote in previous comment.

@bretg
Copy link
Contributor Author

bretg commented Mar 16, 2022

Bottom line: stored responses is a debug feature. And IMO, storedbidresponse is lower priority than storedauctionresponse.

So I'm fine with keeping the code simple.

@SyntaxNode SyntaxNode added Ready For Dev Feature specification is ready to be developed. and removed Intent to implement An issue describing a plan for a major feature. These are intended for community feedback labels Apr 25, 2022
@SyntaxNode
Copy link
Contributor

Implemented in PBS-Go 0.208.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PBS-Go Ready For Dev Feature specification is ready to be developed.
Projects
None yet
Development

No branches or pull requests

4 participants