TURTLEDOVE API моделирования RTB

В рамках песочницы конфиденциальности Chrome предложил TURTLEDOVE — встроенный в браузер API, позволяющий рекламодателям и компаниям, занимающимся рекламными технологиями, показывать рекламу, ориентированную на группы интересов, не полагаясь на сторонние файлы cookie, тем самым защищая пользователей от межсайтового отслеживания. Прежде чем Chrome реализует TURTLEDOVE, команда Google RTB предлагает симуляцию API TURTLEDOVE на стороне сервера, которая позволяет ее партнерам RTB (авторизованным покупателям и партнерам Open Bidding) экспериментировать с API. Моделирование позволяет партнерам и Google узнать об эффективности потока в стиле TURTLEDOVE, генерировать соответствующие отзывы о потенциальных улучшениях API на общедоступных форумах и упростить переход к поддержке персонализированной рекламы без использования сторонних файлов cookie.

На первом этапе моделирования участники торгов принимают членство в группе интересов. Участники торгов также заранее предоставляют Google функции для ставок через API. Во время обслуживания Google разделяет каждый запрос ставки в рамках моделирования на два запроса: контекстный запрос и запрос на основе интересов. Контекстный запрос будет аналогичен текущему запросу ставки, но без идентификаторов пользователей (таких как google_user_id , поля hosted_match_data ). Запросы группы интересов не содержат никакой контекстной информации и содержат только поля, идентифицирующие пользователя (с учетом существующих элементов управления конфиденциальностью). Ставки групп интересов не содержат значения цены за тысячу показов, а ссылаются на функцию назначения ставок, которую Google запускает на стороне сервера в изолированной среде. Аукцион проходит нормально с контекстными ставками и ставками, вычисляемыми функциями торгов.

На первом этапе моделирования Google будет отправлять псевдонимные идентификаторы пользователей по запросам на основе интересов. Цель состоит в том, чтобы свести к минимуму работу по реализации с обеих сторон, чтобы мы могли начать эксперименты раньше. Наличие идентификаторов пользователей в запросах на основе интересов будет регулироваться существующими средствами защиты и контроля конфиденциальности (например, когда пользователь отказывается от персонализированной рекламы).

Поток

flowchart

  1. RTB Bidder работает с рекламодателями, чтобы создавать, поддерживать и размещать группы по интересам для каждого рекламодателя и членства пользователей в этих группах по интересам.
  2. Когда пользователь посещает веб-страницу издателя, браузер пользователя загружает рекламный тег Google. Браузер пользователя запрашивает рекламу с платформы Google для издателей.
  3. Устройство назначения ставок в режиме реального времени заранее предоставляет Google одну или несколько функций назначения ставок (как функции JavaScript). (См. раздел: Функции торгов ).
  4. Для небольшой части запросов в рамках эксперимента Google отправляет отдельные контекстные запросы ставок и запросы ставок на основе интересов каждому участнику, участвующему в эксперименте (см. раздел « Запросы ставок» ).
  5. Участник торгов использует псевдонимный идентификатор пользователя, доступный в запросе ставки группы интересов, и сопоставляет его с соответствующими группами интересов. Участник назначения ставок в режиме реального времени будет возвращать ответы на контекстные запросы и ответы на запросы на основе интересов (см. раздел « Ответы на запросы » ).
    1. Ответы на контекстные ставки будут аналогичны сегодняшним ответам на ставки с нулевым или более контекстными ставками; в дополнение к этому, контекстный ответ заявки может нести пользовательские контекстные сигналы участника торгов, которые будут предоставлены функции назначения ставок в качестве входных данных.
    2. В ответах на ставки на основе интересов не указывается ставка, но указывается имя функции назначения ставок. Google выполнит функцию торгов, чтобы получить ставку.
  6. Google проводит аукцион на стороне сервера со следующими кандидатами:

    1. Ставки из контекстного ответа.
    2. Предложения из ответа группы интересов с ценами предложений, рассчитанными путем запуска функций назначения ставок.
    3. Регулярные ставки от других участников торгов.

    Обратите внимание, что это тот же аукцион, что и сегодня.

  7. Google возвращает выигрышную рекламу в браузер пользователя, который отображается нормально.

Функции торгов

Функции назначения ставок — это функции, предоставляемые участниками торгов, которые возвращают значение ставки для данного объявления на основе группы интересов и рекламного места . В исходном предложении TURTLEDOVE эта функция будет храниться в браузере пользователя. В этом моделировании участники торгов будут загружать функции назначения ставок в Google с помощью API перед показом рекламы. Во время показа рекламы в ответе группы интересов будет указано имя функции назначения ставок. Google будет выполнять эту функцию торгов в изолированной среде, чтобы получить значение ставки. Это значение ставки на основе интересов будет участвовать в том же аукционе, что и контекстная ставка.

Интерфейс функции торгов

Функция торгов должна быть чистой функцией без побочных эффектов, реализованной на JavaScript, которая будет выполняться в изолированной программной среде, предоставленной биржей. Функция торгов не имеет доступа к сети, хранилищу или другим формам ввода-вывода и не может сохранять какое-либо состояние между вызовами для разных запросов ставок. Функция назначения ставок вычисляет и возвращает цену за тысячу показов для заданного рекламного кандидата алгоритмически на основе комбинации контекстных данных и данных группы интересов.

Функция торгов должна принимать и запускаться с пустым объектом в качестве входного параметра — пустой вход предоставляется функциям торгов во время их однократной инициализации. Во время инициализации создается моментальный снимок функции торгов, который вызывается несколько раз, чтобы компилятор JIT (точно в срок) оптимизировал проблемные места в коде.

/**
 * 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;
}

Именованные поля во inputs . Аргумент объекта включает (может быть изменено по ходу эксперимента):

openrtbContextualBidRequest (JS Object) Контекстный запрос ставки в протоколе OpenRTB. Участники торгов, использующие протокол авторизованных покупателей RTB, должны игнорировать этот вход и не должны использовать его в своих функциях торгов.
googleContextualBidRequest (JS Object) Контекстный запрос ставки в протоколе Google Authorized Buyers. Участники торгов, использующие протокол OpenRTB, должны игнорировать этот вход и не должны использовать его в своих функциях торгов.
customContextualSignal (Объект JS) Пользовательские данные, предоставленные участником торгов в ответе на контекстную заявку. Претендент определяет формат.
interestBasedBidData (Объект JS) Пользовательские данные, предоставленные участником торгов в ответе группы интересов. Претендент определяет формат.

Управление функциями торгов через API

Этот экспериментальный ресурс API позволяет участникам торгов загружать функции назначения ставок в Google и управлять этими функциями.

Базовая конечная точка службы: https://realtimebidding.googleapis.com .

Ресурс: функция торгов

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

Поле name представляет название функции назначения ставок и должно иметь следующий формат: bidders/{bidderAccountId}/biddingFunctions/{biddingFunctionName} , где biddingFunctionName выбирается участником торгов.

Поле biddingFunction представляет собой исходный код JavaScript функции назначения ставок со следующими требованиями:

  • Размер < 5 МБ.
  • Соответствует требованиям интерфейса функции торгов .
  • Должен поддерживать выполнение без каких-либо входных данных во время первоначального создания в песочнице.

Пример:

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

Создание функции торгов

Функция назначения ставок будет доступна для использования в ответах групп по интересам примерно через час после успешного вызова API CreateBiddingFunction.

POST https://realtimebidding.googleapis.com/v1alpha/{parent=bidders/*}/biddingFunctions
Параметры пути
parent Строка в формате bidders/{bidderAccountId}
Текст: функция назначения ставок для создания
{
  "name": "bidders/1234567678/biddingFunctions/my_bidding_function_name",
  "biddingFunction": "(function(inputs) {return 1.23;})"
}
Ответ (функция торгов)
{
  "name": "bidders/1234567678/biddingFunctions/my_bidding_function_name",
  "biddingFunction": "(function(inputs) {return 1.23;};)"
}

Список существующих функций назначения ставок

GET https://realtimebidding.googleapis.com/v1alpha/bidders/{bidderAccountId}/biddingFunctions
Параметры пути
parent Строка в формате bidders/{bidderAccountId} .
Параметры запроса
pageToken Строковый токен, идентифицирующий страницу результатов, которую должен вернуть сервер. Это значение получено из предыдущего ответа на вызов ListBiddingFunctions , если результаты не помещаются на одной странице.
Ответ
{
  "biddingFunctions": [
    {
      object (BiddingFunction)
    }
  ],
  "nextPageToken": string
}
Пример вызова
GET https://realtimebidding.googleapis.com/v1alpha/bidders/123456789/biddingFunctions

Изменения протокола RTB моделирования TURTLEDOVE

Протокол RTB авторизованных покупателей

Запросы ставок

Контекстный запрос ставки в эксперименте будет выглядеть так же, как и обычный запрос ставки, но с отредактированными псевдонимными идентификаторами пользователей.

// 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 = ...;
  ...
}

Например:

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

Запрос на основе интересов в эксперименте будет содержать обычные псевдонимные идентификаторы пользователей, на которые распространяются все существующие средства защиты и контроля конфиденциальности, но не будет содержать контекстную информацию (URL-адрес страницы, идентификатор издателя и т. д.).

// 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 = ...;
  ...
}

Например:

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"

Ответы на ставки

Контекстный ответ заявки может содержать настраиваемые контекстные данные для конкретного участника торгов в произвольном формате, которые позже будут переданы в функцию назначения ставок.

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 = ...;

  ...
}

Например,

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

Ставка на основе групп интересов

Каждая заявка в ответе на заявку заинтересованной группы будет содержать ссылку на функцию назначения ставок по ее названию. Функции участия в торгах будут предоставлены участником торгов заблаговременно .

// 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 through 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 = ...;
  ...
}

Например:

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

Запросы ставок

Контекстный запрос (в формате 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
  ...
}
Запрос на основе интересов (в 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
      ...
    }
  }
}

Ответы на ставки

Контекстный ответ заявки может содержать настраиваемые контекстные данные для конкретного участника торгов, которые позже будут переданы в функцию назначения ставок.

// 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": ...
  }
}

Ответ на запрос заявки на основе групп интересов

Каждая заявка в ответе на заявку заинтересованной группы будет содержать ссылку на функцию назначения ставок по ее названию. Функции участия в торгах будут предоставлены участником торгов заблаговременно .

// 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 through 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": ...
       }
    }
    ...
  ]
}