TURTLEDOVE RTB Simulation API

As part of the Privacy Sandbox, Chrome proposed TURTLEDOVE—an in-browser API aimed to allow advertisers and ad tech companies to show interest group targeted ads without relying on third-party cookies, thus protecting users from cross-site tracking. Before Chrome implements TURTLEDOVE, Google RTB team offers a server-side TURTLEDOVE API simulation that allows its RTB partners (Authorized Buyers and Open Bidding partners) to experiment with the API. The simulation allows partners and Google to learn about the efficacy of TURTLEDOVE-style flow, to generate relevant feedback on potential API improvements in public forums, and to ease the transition to supporting personalized advertising without reliance on third-party cookies.

In the first phase of the simulation, bidders host interest group membership. Bidders also provide bidding functions to Google ahead of time via an API. At serving time, Google splits each bid request in scope for the simulation into two requests: a contextual request and an interest-based request. The contextual request will be similar to the current bid request but without user identifiers (such as google_user_id,hosted_match_data fields) available. Interest group requests do not contain any contextual information and contain only user identifying fields (subject to the existing privacy controls). Interest group bids do not contain a CPM value, but instead reference a bidding function that Google runs server-side in a sandboxed environment. The auction runs normally with contextual bids and bids computed by bidding functions.

During the first phase of the simulation, Google will send out pseudonymous user IDs on the interest-based requests. The purpose is to minimize the implementation work on both sides so that we can start experiments sooner. The presence of user identifiers in interest-based requests will be subject to the existing privacy protections and controls (such as when a user opts out of personalized advertising).

Flow

flowchart

  1. RTB Bidder works with advertisers to create, maintain and host interest groups for each advertiser and user membership in those interest groups.
  2. When the user visits a publisher webpage, the user's browser will download Google's ad tag. The user's browser requests an ad from the Google publisher platform.
  3. RTB bidder provides one or more bidding functions (as JavaScript functions) ahead of time to Google. (See section: Bidding functions).
  4. For the small fraction of requests in scope for the experiment, Google sends separate contextual bid requests and interest-based bid requests to each bidder participating in the experiment (See section: Bid requests).
  5. The bidder uses the pseudonymous user ID available in the interest group bid request and maps it to the corresponding interest groups. The RTB bidder will return contextual bid responses and interest-based bid responses (See section: Bid responses).
    1. Contextual bid responses will be similar to today's bid response with zero or more contextual bids; in addition to that, the contextual bid response can carry bidder custom contextual signals that will be provided to the bidding function as an input.
    2. Interest-based bid responses will not specify a bid but specify the name of bidding function. Google will execute the bidding function to get a bid.
  6. Google runs a server-side auction with the following candidates:

    1. Bids from the contextual response.
    2. Bids from the interest group response with bid prices computed by running the bidding functions.
    3. Regular bids from other bidders.

    Note that this is the same auction as today.

  7. Google returns a winning ad to the user's browser, which gets rendered normally.

Bidding functions

Bidding functions are functions provided by the bidders that will return a bid value for a given interest group-based ad and an ad slot . In the original TURTLEDOVE proposal, this function will be stored in the user's browser. In this simulation, bidders will upload the Bidding Functions to Google using an API before ad serving. During ad serving, the Interest Group response will specify a bidding function name. Google will execute that bidding function in a sandboxed environment to get a bid value. This interest-based bid value will enter the same auction as the contextual bid.

Bidding function interface

The bidding function should be a pure side-effect free function implemented in JavaScript that will be run in an exchange-provided sandbox. A bidding function does not have access to the network, storage or other forms of I/O and cannot retain any state between invocations for different bid requests. The bidding function computes and returns a bid price CPM for a given ad candidate algorithmically based on the combination of contextual data and interest group data.

A bidding function must accept and run with an empty object as its input parameter–an empty input is provided to bidding functions during their one-time initialization. At initialization time, a snapshot of the bidding function is created and invoked a few times to allow the JIT (just-in-time) compiler to optimize hot spots in the code.

/**
 * Returns a bid price CPM for a given ad candidate.
 *
 * @param {Object} inputs an object with the
 *                 following named fields:
 *                   - openrtbContextualBidRequest or googleContextualBidRequest
 *                   - customContextualSignal
 *                   - interestBasedBidData
 */
function biddingFunction(inputs) {
  ...
  return inputs.interestBasedBidData.cpm
      * inputs.customContextualSignals.placementMultiplier;
}

Named fields in inputs Object argument include (subject to change as the experiment progresses):

openrtbContextualBidRequest (JS Object) The contextual bid request in OpenRTB protocol. Bidders using Authorized Buyers RTB protocol should ignore this input and should not use it in their bidding functions.
googleContextualBidRequest (JS Object) The contextual bid request in Google Authorized Buyers protocol. Bidders using OpenRTB protocol should ignore this input and should not use it in their bidding functions.
customContextualSignal (JS Object) Custom data provided by the bidder in the contextual bid response. Bidder determines the format.
interestBasedBidData (JS Object) Custom data provided by the bidder in the interest group bid response. Bidder determines the format.

Managing bidding functions via an API

This experimental API resource allows bidders to upload bidding functions to Google and manage these functions.

Base Service Endpoint: https://realtimebidding.googleapis.com

Resource: Bidding function

{
  "name": string,
  "biddingFunction": string
}

The field, name, represents the name of the bidding function, should follow the format: bidders/{bidderAccountId}/biddingFunctions/{biddingFunctionName}, where biddingFunctionName is chosen by a bidder.

The field biddingFunction is the JavaScript source code of the bidding function, with the following requirements:

  • Size of < 5 MiB.
  • Follows the requirements of Bidding function interface.
  • Must support execution without any inputs during the initial creation in the sandbox.

Example:

{
  "name": "bidders/1234567678/biddingFunctions/my_bidding_function_name",
  "biddingFunction": "(function(inputs) {return 1.23;})"
}

Creating a bidding function

A bidding function will be available for use in interest group responses within about an hour after a successful CreateBiddingFunction API call.

POST https://realtimebidding.googleapis.com/v1alpha/{parent=bidders/*}/biddingFunctions
Path parameters
parent String in the format bidders/{bidderAccountId}
Body: Bidding function to create
{
  "name": "bidders/1234567678/biddingFunctions/my_bidding_function_name",
  "biddingFunction": "(function(inputs) {return 1.23;})"
}
Response (bidding function)
{
  "name": "bidders/1234567678/biddingFunctions/my_bidding_function_name",
  "biddingFunction": "(function(inputs) {return 1.23;};)"
}

Listing existing bidding functions

GET https://realtimebidding.googleapis.com/v1alpha/bidders/{bidderAccountId}/biddingFunctions
Path parameters
parent String in the format bidders/{bidderAccountId}.
Query parameters
pageToken String token identifying a page of results the server should return. This value is received from a previous ListBiddingFunctions call response, if the results do not fit on one page.
Response
{
  "biddingFunctions": [
    {
      object (BiddingFunction)
    }
  ],
  "nextPageToken": string
}
Example call
GET https://realtimebidding.googleapis.com/v1alpha/bidders/123456789/biddingFunctions

TURTLEDOVE simulation RTB protocol changes

Authorized Buyers RTB protocol

Bid requests

A contextual bid request in the experiment will look the same as the conventional bid requests but with pseudonymous user identifiers redacted.

// All fields will be filled unless otherwise specified.
message BidRequest {
  // Fields below would not be populated in the experiment
  optional string google_user_id = ...;
  optional uint32 cookie_version = ...;
  optional int32 cookie_age_seconds = ...;
  optional bytes hosted_match_data = ...;
  optional string session_id = ...;

  // Contextual fields below will be populated
  optional string publisher_id = ...;
  optional string url = ...;
  ...
  message Mobile {
    // Device advertising identifiers below would not be populated
    // in the contextual requests in the experiment
    optional bytes encrypted_advertising_id = ...;
    optional bytes advertising_id = ...;
    ...
    optional bytes encrypted_hashed_idfa = ...;
    optional bytes hashed_idfa = ...;
    ...
  }
  ...
  message AdSlot {
    message MatchingAdData {
      repeated int64 billing_id = ...;
      ...
    }
    ...
  }
  repeated AdSlot adslot = ...;
  ...
}

For example:

{
  id: "_\321\326\000\n\301\207\n\323\n\227",
  ip: "S\030\347",
  user_agent: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
  publisher_country: "RU",
  geo_criteria_id: 9061060,
   adslot: [{
    id: 1,
    ad_block_key: 3613182520,
    width:   [240,200,120],
    height:   [400,200,240],
    matching_ad_data:   [{
      billing_id:     [923487589],
      minimum_cpm_micros: 850000
    }]
  }]
}

An interest-based request in the experiment will contain conventional pseudonymous user identifiers, subject to all the existing privacy protections and controls, but would not contain the contextual information (page URL, publisher ID, etc.).

// Most fields would not be populated in the experiment unless otherwise specified.
message BidRequest {
   // Will be provided, subject to the existing privacy controls.
  optional string google_user_id = ...;
  optional uint32 cookie_version = ...;
  optional int32 cookie_age_seconds = ...;
  optional bytes hosted_match_data = ...;

  message AdSlot {
    // Will be filled.
    repeated int32 width = ...;
    repeated int32 height = ...;
    optional ConsentedProvidersSettings consented_providers_settings = ...;
    optional bool regs_gdpr = ...;
    optional bool regs_lgpd = ...;

    message MatchingAdData {
      // Will be filled.
      repeated int64 billing_id = ...;
      ...
    }
    ...
  }
  repeated AdSlot adslot = ...;
  ...
}

For example:

id: "_\322\207\000\003\320\n\031\177C\307\215\035"
adslot {
  id: 1
  width: 1200
  height: 60
  consented_providers_settings {
    consented_providers: 292
    tcf_consent_string: "CO-eDrRO-eDrREkAAAAAAAAeYwf95y3p-wzhheMCY70-vv__7v3ff_3g"
  }
  regs_gdpr: true
  matching_ad_data {
    billing_id: 9833784997
  }
}
google_user_id: "ABCDEF1"
hosted_match_data: "ABCABCABC2"

Bid responses

A contextual bid response can contain a custom, bidder-specific contextual data in arbitrary format that would be passed to the bidding function later.

message BidResponse {
  message Ad {
    message AdSlot {
      required int64 max_cpm_micros = ...;
      ...
    }
    repeated AdSlot adslot = ...;
    ...
  }
  repeated Ad ad = ...;
  // Contains contextual signals that will be passed to the bidding function.
  // This can be any JSON value. For example:
  // {"foo": "bar", "base": [1, 2, 3]}
  optional google.protobuf.Value custom_contextual_signal = ...;

  ...
}

For example,

ad {
  html_snippet: "<iframe src=\"http://example.com/something" width=\"300\" height=\"250\" scrolling=\"no\" frameBorder=\"0\" ></iframe>"
  adslot {
    id: 1
    max_cpm_micros: 100000
    billing_id: 1234567890
  }
  click_through_url: "https://www.example.com.pl"
  attribute: 47
  buyer_creative_id: "FFI399F3HI9HFH"
  width: 300
  height: 250
  impression_tracking_url: "http://example.com/impression"
}
custom_contextual_signal {
 struct_value {
   fields {
     name: "string_data_name"
     value {
       string_value: "string_value_1"
     }
   }
   fields {
     name: "bool_data_name"
     value {
       bool_value: true
     }
   }
 }
}
processing_time_ms: 1

An interest group-based bid

Each bid in the interest group bid response will contain a reference to the bidding function by its name. Bidding functions will be provided by a bidder ahead of time.

// All fields should be filled by a bidder as discussed in
// https://developers.google.com/authorized-buyers/rtb/response-guide
// unless otherwise specified.
message BidResponse {
  // Ad HTML code that will be rendered normally upon winning.
  optional string html_snippet = ...;

  message Ad {
    message AdSlot {
      // Should not be populated for interest group-based bids.
      required int64 max_cpm_micros = ...;
      ...
    }
    repeated AdSlot adslot = ...;

    // Will be filled.
    // This is the bidding function name that references a bidding function
    // that is provided ahead of time via Bidding functions API resource.
    optional string bidding_function_name = ...;

    // Contains interest group-related data that will be passed
    // to the bidding function. This can be any JSON value.
    optional google.protobuf.Value interest_group_data = ...;
    ...
  }
  repeated Ad ad = ...;
  ...
}

For example:

ad {
  html_snippet: "<iframe src=\"http://example.com/something" width=\"300\" height=\"250\" scrolling=\"no\" frameBorder=\"0\" ></iframe>"
  adslot {
    id: 1
    max_cpm_micros: 0
    billing_id: 1234567890
    bidding_function_name: "bidders/123/biddingFunctions/my_bidding_function_1"
    interest_group_data {
      struct_value {
        fields {
          name: "string_data_name"
          value {
            string_value: "string_value_1"
          }
        }
        fields {
          name: "bool_data_name"
          value {
            bool_value: true
          }
        }
      }
    }
  }
  click_through_url: "https://www.example.com.pl"
  attribute: 47
  buyer_creative_id: "FFI399F3HI9HFH"
  width: 300
  height: 250
  impression_tracking_url: "http://example.com/impression"
}
processing_time_ms: 1

OpenRTB

Bid requests

Contextual request (in JSON)
// All fields will be filled unless otherwise specified.
{
  // Fields below would not be populated in the experiment
  "user": {...}

  "device": {
    // Fields below would not be populated in the experiment
    "ifa": ...
    "dpidsha1": ...
    "dpidmd5": ...


    // Other fields will not be affected by the experiment
    ...
  }

  // Other fields will not be affected by the experiment
  ...
}
Interest-based request (in JSON)
// Most fields would not be populated in the experiment unless otherwise specified.
{
  // Will be provided, subject to the existing privacy controls.
  "user": {
    "id": "BFEUKH3"
    "buyeruid": "FEI3F3I29"
    "ext": {
      "consented_providers": [ 292 ]
      "tcf_consent_string": "CO-eDrRO-eDrREkAAilsbO2dYGD9Pn8HT3ZCY70-vv__7v3ff_3g"
    }
  }

  "imp": {
    // Will be provided, subject to the existing privacy controls.
    "banner": {
      "w": ...
      "h": ...
    }

    "ext": {
      // Will be provided, subject to the existing privacy controls.
      "billing_id": [...]

      // Other fields will not be provided by the experiment
      ...
    }
  }
}

Bid responses

A contextual bid response can contain a custom, bidder-specific contextual data that would be passed to the bidding function later.

// All fields should be filled by a bidder as discussed in
// https://developers.google.com/authorized-buyers/rtb/response-guide
// unless otherwise specified.
{
  ...
  "seatbid": [{
     "bid": [...],
     ...
  }],
  ...
  "ext": {
    // Contains contextual signals that will be passed to the bidding function.
    // This signal can be any JSON blob. For example:
    // {"foo", "bar", "base": [1, 2, 3]}
    "custom_contextual_signal": ...
  }
}

An interest group-based bid response

Each bid in the interest group bid response will contain a reference to the bidding function by its name. Bidding functions will be provided by a bidder ahead of time.

// All fields should be filled by a bidder as discussed in
// https://developers.google.com/authorized-buyers/rtb/response-guide
// unless otherwise specified.
{
  "bid": [{
       "id": ...
       ...
       "ext": {
         // This is the bidding function name that references a bidding function
         // that is provided ahead of time via Bidding functions API resource.
         "bidding_function_name": ...

         // Contains interest group related data that will be passed to the
         // bidding function.
         // This signal can be any JSON blob. For example:
         // {"foo", "bar", "base": [1, 2, 3]}
         "interest_group_data": ...
       }
    }
    ...
  ]
}