Руководство разработчика сигналов защищенных приложений

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

История версий

Янв. 2024 г.

Первый выпуск руководства разработчика, поддерживающего выпуск PAS MVP

Март 2024 г.

Изменения в API для поддержки версии Android API M-2024-05 и версии серверных компонентов, выпущенной в апреле 2024 года. Наиболее заметные изменения:

  • Добавлены сведения о разрешениях, необходимых для API на устройстве.
  • Добавлены сведения об управлении квотами сигналов на устройстве.
  • Обновленная сигнатура generateBid с изменениями, связанными с поиском и поддержкой контекстной рекламы.
  • Обновленная документация reportWin включая поддержку выхода
  • Обновление документации API поиска рекламы: удаление поддержки поиска рекламы с помощью BYOS и документирование UDF поиска рекламы.

Обзор API

Поверхность API защищенных сигналов включает в себя различные подмножества API в разных системах:

  • API Android:
    • API курирования сигналов, состоящий из:
    • API сигналов обновления
    • API кодирования сигналов
    • API поддержки защищенного аукциона: используется SDK для запуска защищенного аукциона на серверах торгов и аукционов (B&A) с использованием сигналов защищенных приложений.
  • API на стороне сервера:
    • API защищенного аукциона: набор JS-скриптов, работающих на серверах торгов и аукционов. Этот API позволяет продавцам и покупателям писать логику для реализации защищенного аукциона.
    • API поиска рекламы: отвечает за предоставление списка подходящих объявлений с учетом контекстной и пользовательской информации, предоставленной серверу торгов покупателя.

Android-клиент

На стороне клиента поверхность Protected App Signals состоит из трех различных API:

  • Обновление сигналов: API-интерфейс системы Android, позволяющий отслеживать сигналы на устройстве.
  • Кодирование сигналов: JavaScript API для подготовки сигналов для отправки на сервер во время аукциона.
  • Поддержка защищенных аукционов: API для поддержки проведения защищенных аукционов на серверах торгов и аукционов. Этот API не предназначен специально для сигналов защищенных приложений и также используется для поддержки аукционов для API защищенной аудитории.

API сигналов обновления

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

Для API требуется разрешение android.permission.ACCESS_ADSERVICES_PROTECTED_SIGNALS .

API updateSignals() извлекает JSON-объект из URI, который описывает, какие сигналы следует добавить или удалить, а также как подготовить эти сигналы для аукциона.

Executor executor = Executors.newCachedThreadPool();
ProtectedSignalsManager protectedSignalsManager
     =  ProtectedSignalsManager.get(context);

// Initialize a UpdateSignalsRequest
UpdateSignalsRequest updateSignalsRequest = new
  UpdateSignalsRequest.Builder(Uri.parse("https://example-adtech1.com/signals"))
      .build();

OutcomeReceiver<Object, Exception> outcomeReceiver = new OutcomeReceiver<Object, Exception>() {
  @Override
  public void onResult(Object o) {
    //Post-success actions
  }

  @Override
  public void onError(Exception error) {
    //Post-failure actions
  };

// Call updateSignals
protectedSignalsManager.updateSignals(updateSignalsRequest,
    executor,
    outcomeReceiver);

Платформа отправляет HTTPS-запрос к URI, указанному в запросе, для получения обновлений сигналов. Помимо обновлений сигналов, ответ может включать конечную точку, содержащую логику кодирования для преобразования необработанных сигналов в закодированную полезную нагрузку. Ожидается, что обновления сигналов будут представлены в формате JSON и могут иметь следующие ключи:

Ключи верхнего уровня для объекта JSON должны соответствовать одной из пяти команд:

ключ

Описание

put

Добавляет новый сигнал, перезаписывая все существующие сигналы с тем же ключом. Значение

поскольку это объект JSON, где ключи — это строки в кодировке base 64, соответствующие ключу, который нужно поместить, а значения — это строки в кодировке base 64, соответствующие значению, которое нужно поместить.

append

Добавляет новый сигнал/сигналы к временной серии сигналов, удаляя самые старые

Сигнализирует об освобождении места для новых сигналов, если размер серии превышает заданный максимум. Значением для этого является JSON-объект, где ключи — строки в кодировке base64, соответствующие ключу, к которому добавляется сигнал, а значения — объекты с двумя полями: «values» и «maxSignals».

«values»: список строк в кодировке base 64, соответствующих значениям сигнала для добавления к временному ряду.

"maxSignals": максимальное количество значений, допустимых в этом временном ряду. Если

Текущее количество сигналов, связанных с ключом, превышает maxSignals. Самые старые сигналы будут удалены. Обратите внимание, что вы можете добавлять значения к ключу, добавленному с помощью put. Обратите внимание, что добавление значений, превышающих максимальное количество, приведёт к ошибке.

put_if_not_present

Добавляет новый сигнал только при отсутствии существующих сигналов с таким же ключом. Значением для этого является JSON-объект, где ключи — это строки в кодировке base 64, соответствующие ключу, который нужно добавить, а значения — строки в кодировке base 64, соответствующие значению, которое нужно добавить.

remove

Удаляет сигнал для ключа. Значение — список строк в кодировке base64, соответствующих ключам сигналов, которые следует удалить.

update_encoder

Предоставляет действие для обновления конечной точки и URI, который можно использовать

для получения логики кодирования. Подключ для предоставления действия обновления — «действие», а

Поддерживается только значение "REGISTER", которое регистрирует конечную точку кодировщика, если она предоставляется впервые, или перезаписывает существующую новой конечной точкой. Предоставление конечной точки требуется для действия "REGISTER". Подключом для предоставления конечной точки кодировщика является "endpoint", а значением — URI.

строка для конечной точки.

Пример запроса JSON будет выглядеть следующим образом:

{
    "put": {
        "AAAAAQ==": "AAAAZQ==",
        "AAAAAg==": "AAAAZg=="
    },
    "append": {
        "AAAAAw==": {
            "values": [
                "AAAAZw=="
            ],
            "max_signals": 3
        }
    },
    "put_if_not_present": {
        "AAAABA==": "AAAAaQ==",
        "AAAABQ==": "AAAAag=="
    },
    "update_encoder": {
        "action": "REGISTER",
        "endpoint": "https://adtech1.com/Protected App Signals_encode_script.js"
    }
}

Для сигналов на устройстве установлена ​​квота порядка 10–15 КБ. После её превышения PPAPI будет удалять сигналы, используя стратегию FIFO. Процесс удаления позволит немного превышать квоту в течение коротких промежутков времени, чтобы снизить частоту удалений.

API кодирования сигналов

Покупатели должны предоставить функцию Java Script, которая будет использоваться для кодирования сигналов, хранящихся на устройстве, для отправки на сервер во время защищенного аукциона. Покупатели могут предоставить этот скрипт, добавив URL-адрес, по которому его можно получить, используя ключ «update_encoder» в любом ответе на запрос API UpdateSignal. Скрипт будет иметь следующую сигнатуру:

function encodeSignals(signals, maxSize) {
  let result = new Uint8Array(maxSize);
  // first entry will contain the total size
  let size = 1;
  let keys = 0;
  
  for (const [key, values] of signals.entries()) {
    keys++;
    // In this encoding we only care about the first byte
    console.log("key " + keys + " is " + key)
    result[size++] = key[0];
    result[size++] = values.length;
    for(const value of values) {
      result[size++] = value.signal_value[0];
    }
  }
  result[0] = keys;
  
  return { 'status': 0, 'results': result.subarray(0, size)};
}

Параметр signals представляет собой сопоставление ключей в виде массивов UInt8Arrays размером 4 элемента со списками объектов Protected App Signals. Каждый объект Protected App Signals имеет три поля:

  • signal_value : массив UInt8Array, представляющий значение сигнала.
  • creation_time : число, представляющее время создания сигналов в секундах эпохи.
  • package_name : строка, представляющая имя пакета, создавшего сигнал.

Параметр maxSize — это число, описывающее максимально допустимый размер массива для вывода.

Функция должна выводить объект с двумя полями:

  • status : Должно быть 0, если скрипт выполнен успешно.
  • results : Должен быть массив UInt8Array длиной не более maxSize. Этот массив будет отправлен на сервер во время аукционов и подготовлен скриптом prepareDataForAdRetrieval .

Кодирование предоставляет специалистам по рекламе начальный этап разработки функций, на котором они могут выполнять преобразования, такие как сжатие необработанных сигналов в конкатенированные версии на основе собственной логики. Обратите внимание, что во время защищенного аукциона, работающего в доверенных средах выполнения (TEE), специализированная логика рекламной технологии будет иметь доступ на чтение к полезной нагрузке сигналов, сгенерированной кодированием. Специальная логика, известная как определяемая пользователем функция (UDF) , работающая в B&A TEE покупателя, будет иметь доступ на чтение к закодированным сигналам и другим контекстным сигналам, предоставляемым приложением издателя, для выбора рекламы (поиск рекламы и назначение ставок).

Кодирование сигналов

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

adb shell cmd jobscheduler run -f com.google.android.adservices.api 29
Версионирование логики кодировщика

При запросе на загрузку логики кодировщика рекламных технологий конечная точка рекламной технологии может отправить номер версии в заголовках ответа. Эта версия сохраняется вместе с логикой кодировщика на устройстве. При кодировании необработанных сигналов закодированная полезная нагрузка сохраняется вместе с версией, использованной для кодирования. Эта версия также отправляется на сервер B&A во время защищенного аукциона, чтобы рекламные технологии могли согласовывать свою логику ставок и кодирования на основе этой версии.

Response header for providing encoder version : X_ENCODER_VERSION

API поддержки защищенного аукциона

Со стороны устройства проведение аукциона для защищенных сигналов приложений аналогично проведению аукциона для защищенных аудиторий .

Услуги по проведению торгов и аукционов

API-интерфейсы на стороне сервера включают в себя:

  • Защищенный API аукциона: ряд функций JS или UDF, которые покупатели и продавцы могут использовать в компонентах B&A, которыми они владеют, для определения ставок и логики аукциона.
  • API поиска рекламы: покупатели могут реализовать этот API, внедрив конечную точку REST, которая будет отвечать за предоставление набора потенциальных объявлений для аукциона Protected App Signal.

API защищенного аукциона

API защищенного аукциона состоит из JS API или UDF-функций, которые покупатели и продавцы могут использовать для реализации своей логики аукционов и торгов.

Пользовательские функции рекламных технологий покупателя
prepareDataForAdRetrieval UDF

Прежде чем использовать сигналы защищенных приложений для получения объявлений-кандидатов из сервиса поиска рекламы TEE, покупатели должны декодировать и подготовить сигналы защищенных приложений и другие данные, предоставленные продавцом. Выходные данные UDF-функции покупателя, prepareDataForAdRetrieval передаются в сервис поиска рекламы для получения k лучших объявлений-кандидатов для торгов .

// Inputs
// ------
// encodedOnDeviceSignals: A Uint8Array of bytes from the device.
// encodedOnDeviceSignalsVersion: An integer representing the encoded
//   version of the signals.
// sellerAuctionSignals: Information about auction (ad format, size) derived
//                       contextually.
// contextualSignals: Additional contextual signals that could help in
//                    generating bids.
//
// Outputs
// -------
// Returns a JSON structure to be used for retrieval.
// The structure of this object is left to the ad tech.
function prepareDataForAdRetrieval(encodedOnDeviceSignals,encodedOnDeviceSignalsVersion,sellerAuctionSignals,contextualSignals) {
   return {};
}
generateBid UDF

После возврата первых k объявлений-кандидатов они передаются в пользовательскую логику ставок покупателя, generateBid UDF :

// Inputs
// ------
// ads: Data string returned by the ads retrieval service. This can include Protected App Signals
//   ads and related ads metadata.
// sellerAuctionSignals: Information about the auction (ad format, size),
//                       derived contextually
// buyerSignals: Any additional contextual information provided by the buyer
// preprocessedDataForRetrieval: This is the output of this UDF.
function generateBid(ads, sellerAuctionSignals, buyerSignals,
                    preprocessedDataForRetrieval,
                    rawSignals, rawSignalsVersion) {
    return { "ad": <ad Value Object>,
             "bid": <float>,
             "render": <render URL string>,
             'adCost': <optional float ad cost>,
             "egressPayload": <limitedEgressPayload>,
             "temporaryUnlimitedEgressPayload": <temporaryUnlimitedEgressPayload>
    };
}

Выход этой функции — одна ставка для кандидата в объявления, представленная в виде JSON-эквивалентного ProtectedAppSignalsAdWithBidMetadata . Функция также может возвращать два массива, которые затем будут переданы в reportWin для обучения модели (подробнее об egress и обучении модели см. в разделе «Отчёты» в пояснительной записке PAS ).

reportWin UDF

По завершении аукциона служба аукциона сгенерирует URL-адреса для отчётов покупателей и зарегистрирует маяки с помощью UDF reportWin (эта же функция reportWin используется для защищённых аудиторий) . Устройство отправит пинг после того, как клиент отобразит рекламу. Сигнатура этого метода практически идентична версии для защищённой аудитории, за исключением двух дополнительных параметров: egressPayload и temporaryUnlimitedEgressPayload , которые используются для обучения модели и заполняются результатами generateBid .

// Inputs / Outputs
// ----------------
// See detailed documentation here.
function reportWin(auctionSignals, perBuyerSignals, signalsForWinner,
                   buyerReportingSignals,
                   egressPayload, temporaryUnlimitedEgressPayload) {
  // ...
}
Пользовательские функции рекламных технологий продавца
Оценка UDF

Этот UDF используется продавцами для выбора того, какое из объявлений, полученных от покупателей, победит на аукционе.

function scoreAd(adMetadata, bid, auctionConfig,
                 trustedScoringSignals, bid_metadata) {
  // ...
  return {desirability: desirabilityScoreForThisAd,
              allowComponentAuction: true_or_false};
}
reportResult UDF

Этот UDF позволяет продавцу (в конечном итоге) создавать отчеты на уровне событий с информацией относительно победившего объявления.

function reportResult(auctionConfig, reporting_metadata) {
  // ...
  registerAdBeacon({"click", clickUrl,"view", viewUrl});
  sendReportTo(reportResultUrl);
  return signalsForWinner;
}

API поиска рекламы

В версии MVP сервис поиска рекламы будет управляться и размещаться покупателем, а сервис торгов будет извлекать из него кандидатов на рекламу. Начиная с апреля 2024 года сервер поиска рекламы должен работать в доверенной среде выполнения (TEE) и предоставлять интерфейс GRPC/proto. Рекламные компании должны настроить этот сервер и предоставить его URL-адрес в рамках развертывания стека B&A. Реализация этого сервиса, работающего в TEE, доступна в Privacy Sandbox на GitHub , и в остальной части документации мы предполагаем, что это код, используемый при развертывании.

Начиная с апреля 2024 года, версии B&A поддерживают контекстный путь поиска рекламы. В этом случае сервер торгов получает список идентификаторов рекламы, отправленных RTB-сервером во время контекстной части аукциона. Эти идентификаторы будут отправлены на сервер TEE KV для получения всей информации, связанной с рекламой, которая будет использоваться на этапе торгов (например, ad-render-url, метаданные и встроенные рекламные объявления для отбора топ-k). Этот второй путь не требует реализации какой-либо специальной логики, поэтому здесь мы рассмотрим только настройку варианта использования поиска рекламы на основе TEE.

getCandidateAds UDF
function getCandidateAds(requestMetadata, preparedDataForAdRetrieval,
                      deviceMetadata, contextualSignals, contextualAdIds,) {
    return adsMetadataString;
}

Где:

  • requestMetadata : JSON. Метаданные сервера для каждого запроса в UDF. Пока пусто.
  • preparedDataForAdRetrieval : содержимое этого поля зависит от стратегии поиска рекламы. В случае поиска контекстной рекламы этот параметр будет содержать необработанные сигналы, поступающие с устройства и передаваемые службой ставок. В случае поиска рекламы TEE с использованием сервера поиска рекламы этот параметр будет содержать результат пользовательской функции prepareDataForAdRetrieval . Примечание: на этом этапе сигналы защищенного приложения будут декодированы и расшифрованы.
  • deviceMetadata : JSON-объект, содержащий метаданные устройства, переданные рекламной службой продавца. Подробнее см. в документации B&A.
    • X-Accept-Language : язык, используемый на устройстве.
    • X-User-Agent : пользовательский агент, используемый на устройстве.
    • X-BnA-Client-IP : IP-адрес устройства.
  • contextualSignals : произвольная строка, полученная с сервера контекстных торгов, обслуживаемого тем же DSP. Пользовательская функция (UDF) должна иметь возможность декодировать эту строку и использовать её. Контекстные сигналы могут содержать любую информацию, например, информацию о версии модели машинного обучения для защищённого встраивания, переданную с помощью защищённых сигналов приложения.
  • contextualAdIds : объект JSON, содержащий необязательный список идентификаторов объявлений.

Пользовательская функция (UDF) должна возвращать строку в случае успеха. Эта строка возвращается на сервер ставок, который затем передаёт её пользовательской функции generateBid . Хотя строка может быть просто строкой, скорее всего, это должен быть сериализованный объект, схема которого определяется каждым рекламным разработчиком самостоятельно. На схему нет ограничений, при условии, что логика generateBid рекламного разработчика может распознать и использовать эту строку.

Настройте свою систему для разработки

Андроид

Чтобы настроить среду разработки Android, вам необходимо сделать следующее:

  1. Создайте эмулятор (предпочтительно) или физическое устройство, на котором запущен образ Developer Preview 10.
  2. Выполните следующее:
adb shell am start -n com.google.android.adservices.api/com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity

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

  1. Выполните следующую команду, чтобы включить соответствующие API. Возможно, вам придётся периодически перезапускать её, так как конфигурация по умолчанию (отключено) будет периодически синхронизироваться.
adb shell device_config put adservices fledge_custom_audience_service_kill_switch false;  adb shell device_config put adservices fledge_select_ads_kill_switch false; adb shell device_config put adservices fledge_on_device_auction_kill_switch false; adb shell device_config put adservices fledge_auction_server_kill_switch false; adb shell "device_config put adservices disable_fledge_enrollment_check true";  adb shell device_config put adservices ppapi_app_allow_list '\*'; adb shell device_config put adservices fledge_auction_server_overall_timeout_ms 60000;
  1. Перезагрузите устройство.
  2. Переопределите ключи аукциона устройства, чтобы они указывали на ваш сервер ключей аукциона. Важно выполнить этот шаг перед попыткой проведения аукциона, чтобы предотвратить кэширование неверных ключей.

Услуги по проведению торгов и аукционов

Чтобы настроить серверы B&A, обратитесь к документации по самостоятельной настройке .

В этом документе основное внимание будет уделено настройке серверов, предназначенных для покупателей, поскольку для продавцов никаких изменений не требуется.

Предпосылки

Перед развертыванием комплекса услуг B&A специалисту по рекламе покупателя необходимо:

  • Убедитесь, что они развернули собственную службу поиска рекламы TEE (см. соответствующий раздел ).
  • Убедитесь, что в рекламной технологии определены и размещены все необходимые пользовательские функции ( prepareDataForAdRetrieval , generateBid , reportWin , getCandidateAds ).

Понимание того, как работает защищенный аукцион с защищенной аудиторией в B&A, также будет полезным, но не является обязательным.

Конфигурация Терраформа

Чтобы использовать защищенные сигналы приложений, специалисты по рекламе должны:

  • Включите поддержку защищенных сигналов приложений в B&A.
  • Укажите конечные точки URL, из которых можно извлечь новые пользовательские функции для prepareDataForAdRetrieval, generateBid и reportWin .

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

Конфигурация технологии рекламы покупателя

Используя этот демонстрационный файл в качестве примера, покупателям необходимо установить следующие флаги:

  • Включить сигналы защищенных приложений : включено для сбора данных сигналов защищенных приложений.
  • URL-адреса защищенных сигналов приложений : задайте URL-адреса серверов защищенных сигналов приложений.

Специалисты по рекламе должны подставить правильные URL-адреса в заполнители для следующих полей:

module "buyer" {
  # ... More config here.

  runtime_flags = {
    # ... More config here.

    ENABLE_PROTECTED_APP_SIGNALS                  = "true"
    PROTECTED_APP_SIGNALS_GENERATE_BID_TIMEOUT_MS = "60000"
    TEE_AD_RETRIEVAL_KV_SERVER_ADDR               = "<service mesh address of the instance>"
    AD_RETRIEVAL_TIMEOUT_MS                       = "60000"
    BUYER_CODE_FETCH_CONFIG                       = <<EOF
    {
        "protectedAppSignalsBiddingJsUrl": "<URL to Protected App Signals generateBid UDF>",
        "urlFetchTimeoutMs": 60001, # This has to be > 1 minute.
        "urlFetchPeriodMs": 13000000,
        "prepareDataForAdsRetrievalJsUrl": "<URL to the UDF>"
    }
    EOF

  }  # runtime_flags

}  # Module "buyer"

Конфигурация рекламной технологии продавца

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

module "seller" {
  # ... More config here.

  runtime_flags = {
    # ... More config here.

    ENABLE_PROTECTED_APP_SIGNALS                  = "true"

    SELLER_CODE_FETCH_CONFIG                           = <<EOF
  {
    "urlFetchTimeoutMs": 60001, # This has to be > 1 minute.
    "urlFetchPeriodMs": 13000000,
    "protectedAppSignalsBuyerReportWinJsUrls": {"<Buyer Domain>": "URL to reportWin UDF"}
  }
  EOF

  }  # runtime_flags

}  # Module "seller"

Услуги поиска KV и рекламы

В зависимости от выбранных стратегий поддержки поиска рекламы, системе потребуется развернуть один или два экземпляра сервиса KV. Экземпляр KV, используемый для поиска рекламы на основе TEE, будет называться Ad Retrieval Server , а экземпляр для поддержки поиска на основе контекстного пути — KV Lookup Server .

В обоих случаях развёртывание серверов осуществляется в соответствии с документацией, доступной на GitHub сервера KV . Разница заключается в том, что случай поиска работает «из коробки» без дополнительной настройки, в то время как случай извлечения требует развёртывания пользовательской функции getCandidateAds для реализации логики извлечения. Подробнее см. в руководстве по подключению сервера KV . Обратите внимание, что B&A ожидает, что обе службы будут развёрнуты в той же сервисной сетке, что и служба торгов.

Пример настройки

Рассмотрим следующий сценарий: используя API защищенных сигналов приложений (Protected App Signals API), рекламная технология сохраняет релевантные сигналы, основанные на использовании приложения пользователем. В нашем примере хранятся сигналы, представляющие покупки внутри нескольких приложений. Во время аукциона зашифрованные сигналы собираются и передаются на защищенный аукцион, работающий в B&A. Пользовательские функции покупателя, работающие в B&A, используют эти сигналы для выбора потенциальных объявлений и расчета ставки.

[Покупатель] Примеры сигналов

Добавляет сигнал с ключом 0 и значением 1.

{
  "put": {
    "AA==": "AQ=="
  },
  "update_encoder": {
    "action": "REGISTER",
    "endpoint": "https://example.com/example_script"
  }
}

Добавляет сигнал с ключом 1 и значением 2.

{
  "put": {
    "AQ==": "Ag=="
  },
  "update_encoder": {
    "action": "REGISTER",
    "endpoint": "https://example.com/example_script"
  }
}

Пример encodeSignals [Покупатель]

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

function encodeSignals(signals, maxSize) {
  // if there are no signals don't write a payload
  if (signals.size === 0) {
      return {};
  }

  let result = new Uint8Array(signals.size * 2);
  let index = 0;
  
  for (const [key, values] of signals.entries()) {
    result[index++] = key[0];
    result[index++] = values[0].signal_value[0];
  }
  
  return { 'status': 0, 'results': result};
}

Пример подготовки DataForAdRetrieval для [Покупателя]

/**
 * `encodedOnDeviceSignals` is a Uint8Array and would contain
 * the app signals emanating from device. For purpose of the
 * demo, in our sample example, we assume that device is sending
 * the signals with pair of bytes formatted as following:
 * "<ID><In app spending>". Where ID corresponds to an ad category
 * that user uses on device, and the in app spending is a measure
 * of how much money the user has spent in this app category
 * previously. In our example, an ID of 0 will correspond to a
 * fitness ad category and a non-zero ID will correspond to
 * food app category -- though this info will be useful
 * later in the B&A pipeline.
 *
 * Returns a JSON object indicating what type of ad(s) may be
 * most relevant to the user. In a real setup ad techs might
 * want to decode the signals as part of this script.
 *
 * Note: This example script makes use of only encoded device signals
 * but ad tech can take other signals into account as well to prepare
 * the data that will be useful down stream for ad retrieval and
 * bid generation. The max length of the app signals used in this
 * sample example is arbitrarily limited to 4 bytes.
 */
function prepareDataForAdRetrieval(encodedOnDeviceSignals,
                                   encodedOnDeviceSignalsVersion,
                                   sellerAuctionSignals,
                                   contextualSignals) {
  if (encodedOnDeviceSignals.length === 0 || encodedOnDeviceSignals.length > 4 ||
      encodedOnDeviceSignals.length % 2 !== 0) {
     throw "Expected encoded signals length to be an even number in (0, 4]";
  }

  var preparedDataForAdRetrieval = {};
  for (var i = 0; i < encodedOnDeviceSignals.length; i += 2) {
    preparedDataForAdRetrieval[encodedOnDeviceSignals[i]] = encodedOnDeviceSignals[i + 1];
  }
  return preparedDataForAdRetrieval;
}

[Покупатели] Пример UDF для поиска рекламы

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

function getCandidateAds(requestMetadata, protectedSignals, deviceMetadata,
                      contextualSignals,   contextualAdIds,) {
 return "[{\"adId\":\"0\"},{\"adId\":\"1\"}]"

[Покупатели] пример generateBid

/**
 * This script receives the data returned by the ad retrieval service
 * in the `ads` argument. This argument is supposed to contain all
 * the Protected App Signals related ads and the metadata obtained from the retrieval
 * service.
 *
 * `preparedDataForAdRetrieval` argument contains the data returned
 * from the `prepareDataForAdRetrieval` UDF.
 *
 * This script is responsible for generating bids for the ads
 * collected from the retrieval service and ad techs can decide to
 * run a small inference model as part of this script in order to
 * decide the best bid given all the signals available to them.
 *
 * For the purpose of the demo, this sample script assumes
 * that ad retrieval service has sent us most relevant ads for the
 * user and this scripts decides on the ad render URL as well as
 * what value to bid for each ad based on the previously decoded
 * device signals. For simplicity sake, this script only considers
 * 2 types of app categories i.e. fitness and food.
 *
 * Note: Only one bid is returned among all the
 * input ad candidates.
 */
function generateBid(ads, sellerAuctionSignals, buyerSignals, preparedDataForAdRetrieval) {
  if (ads === null) {
    console.log("No ads obtained from the ad retrieval service")
    return {};
  }     
        
  const kFitnessAd = "0";
  const kFoodAd = "1";
  const kBuyerDomain = "https://buyer-domain.com";
        
  let resultingBid = 0;
  let resultingRender = kBuyerDomain + "/no-ad";
  for (let i = 0 ; i < ads.length; ++i) {
    let render = "";
    let bid = 0;
    switch (ads[i].adId) {
      case kFitnessAd:
        render = kBuyerDomain + "/get-fitness-app";
        bid = preparedDataForAdRetrieval[kFitnessAd];
        break;
      case kFoodAd:
        render = kBuyerDomain + "/get-fastfood-app";
        bid = preparedDataForAdRetrieval[kFoodAd];
        break;
      default:
        console.log("Unknown ad category");
        render = kBuyerDomain + "/no-ad";
        break;
    }
    console.log("Existing bid: " + resultingBid + ", incoming candidate bid: " + bid);
    if (bid > resultingBid) {
      resultingBid = bid;
      resultingRender = render;
    }
  }
  return {"render": resultingRender, "bid": resultingBid};
}

[Покупатели] reportWin пример

reportWin UDF сообщает покупателю, что он выиграл аукцион.

function reportWin(auctionSignals, perBuyerSignals, signalsForWinner,
                                       buyerReportingSignals, directFromSellerSignals,
                                       egressPayload,
                                       temporaryUnlimitedEgressPayload) {
  sendReportTo("https://buyer-controlled-domain.com/");
  registerAdBeacon({"clickEvent":"https://buyer-controlled-domain.com/clickEvent"});
  return;
}

[Продавец] Настройка сервера KV

Продавцы должны настроить сервер KV сигналов оценки, чтобы было доступно сопоставление URL-адресов отображения рекламы с соответствующими сигналами оценки, например: если https:/buyer-domain.com/get-fitness-app и https:/buyer-domain.com/get-fastfood-app должны быть возвращены покупателем, продавец может получить следующий пример ответа сигналов оценки при запросе SFE с использованием GET на https://key-value-server-endpoint.com?client_type=1&renderUrls=<render-url-returned-by-the-buyer> :

{
   "renderUrls" : {
      "https:/buyer-domain.com/get-fitness-app" : [
         "1",
         "2"
      ],
      "https:/buyer-domain.com/get-fastfood-app" : [
         "3",
         "4"
      ]
   }
}

Пример рекламы [Продавец] scoreAd

/**
 * This module generates a random desirability score for the Protected App
 * Signals ad in this example. In a production deployment,
 * however, the sellers would want to use all the available signals to generate
 * a score for the ad.
 */
function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}

function scoreAd(adMetadata, bid, auctionConfig,
                                   trustedScoringSignals, deviceSignals,
                                   directFromSellerSignals) {
  return {
    "desirability": getRandomInt(10000),
    "allowComponentAuction": false
  };
}

Пример reportResult [Продавец]

function reportResult(auctionConfig, sellerReportingSignals, directFromSellerSignals){
  let signalsForWinner = {};
    sendReportTo("https://seller-controlled-domain.com");
    registerAdBeacon({"clickEvent":
                    "https://seller-controlled-domain.com/clickEvent"});
    return signalsForWinner;
}

Пример приложения

В качестве примера того, как API может использоваться для создания приложения, использующего этот поток, мы создали пример приложения Protected App Signals, который можно найти в этом репозитории примеров .