Przewodnik dla programistów dotyczący Protected App Signals

Aby pomóc deweloperom rozpocząć eksperymentowanie z interfejsem Protected App Signals API, w tym dokumencie znajdziesz opis wszystkich interfejsów API na platformie API, szczegółowe informacje o konfigurowaniu środowiska testowego oraz przykłady konfiguracji i skryptów.

Historia zmian

styczeń 2024 r.

Pierwsza wersja przewodnika dla programistów obsługującego wersję MVP PAS

marzec 2024 r.

Zmiany w interfejsie API związane z obsługą wersji M-2024-05 interfejsu Android API oraz wydanie w kwietniu 2024 r. komponentów po stronie serwera. Najważniejsze zmiany:

  • Dodaliśmy szczegółowe informacje o uprawnieniach wymaganych dla interfejsu API na urządzeniu.
  • Dodano informacje o zarządzaniu limitem sygnałów z urządzenia
  • Zaktualizowano podpis generateBid o zmiany związane z obsługą kontekstowego pobierania reklam i ruchu wychodzącego
  • Zaktualizowano dokumentację reportWin, w tym obsługę ruchu wychodzącego
  • Zaktualizowaliśmy dokumentację interfejsu Ad Retrieval API, usuwając obsługę pobierania reklam BYOS i dokumentowania funkcji UDF pobierania reklam

Przegląd interfejsów API

Interfejs Protected Signals API obejmuje różne podzbiory interfejsu API w różnych systemach:

  • Interfejsy API na Androida:
    • Interfejs Signal Curation API składa się z tych elementów:
    • Zaktualizuj interfejs Signals API
    • Interfejs Signals Encoding API
    • Interfejs Protected aukcji API: używany przez pakiety SDK do przeprowadzania aukcji chronionej na serwerach określania stawek i aukcji z wykorzystaniem chronionych sygnałów aplikacji.
  • Interfejsy API po stronie serwera:
    • Protected aukcji API: seria skryptów JavaScript działających na serwerach aukcji i określania stawek. Ten interfejs API umożliwia sprzedawcom i kupującym zapisanie logiki w celu wdrożenia aukcji chronionej.
    • Interfejs Ad Retrieval API: odpowiada za dostarczanie listy reklam kandydujących na podstawie informacji kontekstowych i informacji o użytkownikach udostępnionych serwerowi określania stawek kupującego.

Klient na Androida

Po stronie klienta platforma Protected App Signals składa się z 3 różnych interfejsów API:

  • Aktualizuj sygnały: interfejs API systemu Android, który umożliwia wybór sygnałów na urządzeniu.
  • Kodowanie sygnałów: interfejs API JavaScript służący do przygotowywania sygnałów, które będą wysyłane do serwera podczas aukcji.
  • Obsługa aukcji chronionych – interfejs API umożliwiający przeprowadzanie aukcji zabezpieczonej na serwerach określania stawek i na serwerach aukcji. Ten interfejs API nie dotyczy chronionych sygnałów aplikacji i służy również do obsługi aukcji na potrzeby tego interfejsu.

Zaktualizuj interfejs Signals API

Interfejs Update Signals API umożliwia technikom reklamowym rejestrowanie sygnałów związanych z użytkownikiem i aplikacją w imieniu kupującego. Interfejs API działa na modelu przekazywania dostępu. Element wywołujący udostępnia identyfikator URI, z którego platforma pobiera odpowiednie sygnały, i mechanizm kodowania tych sygnałów na potrzeby aukcji.

Interfejs API wymaga uprawnienia android.permission.ACCESS_ADSERVICES_PROTECTED_SIGNALS.

Interfejs updateSignals() API pobierze z identyfikatora URI obiekt JSON, który opisuje, które sygnały należy dodać, a które usunąć, oraz jak przygotować te sygnały do aukcji.

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);

Platforma wysyła żądanie https do identyfikatora URI podanego w żądaniu, aby pobrać aktualizacje sygnału. Oprócz aktualizacji sygnałów odpowiedź może zawierać punkt końcowy hostujący logikę kodowania służącą do konwertowania nieprzetworzonych sygnałów na zakodowany ładunek. Aktualizacje sygnałów powinny mieć postać JSON i mogą zawierać te klucze:

Klucze najwyższego poziomu obiektu JSON muszą odpowiadać jednemu z 5 poleceń:

klucz

Opis

put

Dodaje nowy sygnał, zastępując wszystkie istniejące sygnały tym samym kluczem. Wartość

to obiekt JSON, w którym klucze to ciągi tekstowe o długości 64 znaków odpowiadające kluczowi do umieszczenia, a wartości to ciąg 64 odpowiadający wartości do umieszczenia.

append

Dodaje nowy sygnał/sygnały do ciągu czasowego, usuwając najstarszy

aby zrobić miejsce na nowe, jeśli rozmiar serii przekracza podane maksimum. Wartością jest obiekt JSON, w którym klucze są ciągami 64-osobowymi odpowiadającymi kluczowi, do którego mają zostać dołączone, a wartościami są obiekty z 2 polami: „values” i „maxSignals”.

"wartości": lista ciągów w podstawie 64 odpowiadających wartościom sygnałów, które mają być dołączone do ciągu czasowego.

"maxSignals": maksymalna liczba wartości dozwolonych w tym ciągu czasowym. Jeśli

bieżąca liczba sygnałów powiązanych z kluczem przekracza wartość maxSignals, najstarsze sygnały zostaną usunięte. Pamiętaj, że możesz dołączyć do klucza dodanego metodą „put”. Pamiętaj, że dodanie większej liczby wartości spowoduje błąd.

put_if_not_present

Dodaje nowy sygnał tylko wtedy, gdy nie ma żadnych sygnałów z tym samym kluczem. Wartościami jest obiekt JSON, w którym klucze są ciągami 64-osobowymi odpowiadającymi kluczowi do umieszczenia, a wartościami są ciąg 64 odpowiadający wartości do umieszczenia.

remove

Usuwa sygnał kluczyka. Wartością jest lista ciągów w formacie Base64 odpowiadającym kluczom sygnałów, które należy usunąć.

update_encoder

Zawiera działanie aktualizacji punktu końcowego i identyfikator URI, którego można użyć

w celu pobrania logiki kodowania. Kluczem podrzędnym do określenia działania związanego z aktualizacją jest „działanie”,

Obecnie obsługiwane wartości to tylko „REGISTER”, co spowoduje zarejestrowanie punktu końcowego kodera, jeśli zostanie podany po raz pierwszy, lub zastąpienie dotychczasowego punktu końcowego nowo podanym punktem końcowym. Podanie punktu końcowego jest wymagane dla działania „REGISTER”. Kluczem podrzędnym dostarczającym punkt końcowy kodera jest „punkt końcowy”, a wartością jest identyfikator URI.

ciągu znaków dla punktu końcowego.

Przykładowe żądanie JSON wygląda tak:

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

Sygnały mają limit na urządzeniu wynoszący 10–15 KB. Po przekroczeniu limitu PPAPI usuwa sygnały za pomocą strategii FIFO. Proces usuwania pozwala na niewielkie przekraczanie limitu w krótkich odstępach czasu w celu zmniejszenia częstotliwości usuwania.

Interfejs Signals Encoding API

Kupujący muszą dostarczyć funkcję Java Script służącą do kodowania sygnałów przechowywanych na urządzeniu, które mają być wysyłane na serwer w trakcie aukcji chronionej. Kupujący mogą udostępnić ten skrypt, dodając adres URL, z którego można go pobrać za pomocą klucza „update_encoder” w dowolnej odpowiedzi na żądanie do interfejsu UpdateSignal API. Skrypt będzie miał taki podpis:

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)};
}

Parametr signals jest mapą z kluczy w postaci obiektów UInt8Arrays o rozmiarze 4 na listy obiektów Protected App Signals. Każdy obiekt Protected App Signals ma 3 pola:

  • signal_value: tablica UInt8argumentująca wartość sygnału.
  • creation_time: liczba określająca czas utworzenia sygnałów w sekundach epoki.
  • package_name: ciąg znaków reprezentujący nazwę pakietu, który utworzył sygnał.

Parametr maxSize to liczba opisująca największy dozwolony rozmiar tablicy dla danych wyjściowych.

Ta funkcja powinna zwrócić obiekt z 2 polami:

  • status: wartość powinna wynosić 0, jeśli skrypt został uruchomiony.
  • results: powinna być tablicą UInt8Track o długości mniejszej niż maksymalna lub równa maxSize. Ta tablica jest wysyłana do serwera podczas aukcji i przygotowana przez skrypt prepareDataForAdRetrieval.

Kodowanie zapewnia technikom reklamowym początkowy etap inżynierii cech, na którym mogą przeprowadzić transformacje, np. kompresować nieprzetworzone sygnały do połączonych wersji na podstawie własnej logiki niestandardowej. Pamiętaj, że w przypadku aukcji zabezpieczonej prowadzonej w zaufanych środowiskach wykonawczych (TEE) niestandardowa logika technologii reklamowych ma dostęp do odczytu ładunków sygnałów wygenerowanych przez kodowanie. Logika niestandardowa, zwana funkcją zdefiniowaną przez użytkownika (UDF), uruchamiana w teście B&A kupującego będzie mieć dostęp do odczytu zakodowanych sygnałów i innych sygnałów kontekstowych dostarczanych przez aplikację wydawcy na potrzeby wyboru reklam (pobieranie reklam i określanie stawek).

Kodowanie sygnałów

Co godzinę sygnały kupujących, którzy dostarczyli logikę kodowania za pomocą zarejestrowanych sygnałów, zostaną zakodowane w ładunku aukcji.Tablica bajtów ładunku aukcji jest przechowywana na urządzeniu, szyfrowana i rejestrowana przez sprzedawców w ramach danych o wyborze reklamy, która ma zostać uwzględniona w aukcji chronionej. Na potrzeby testowania możesz aktywować to kodowanie poza cyklem godzinowym, uruchamiając to polecenie:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 29
Obsługa wersji logiki kodera

Po wysłaniu żądania pobrania logiki niestandardowego kodera technologii reklamowych punkt końcowy tej technologii może w odpowiedzi podać numer wersji w nagłówkach odpowiedzi. Ta wersja jest przechowywana razem z logiką kodera na urządzeniu. Gdy nieprzetworzone sygnały są zakodowane, zakodowany ładunek jest zachowywany razem z wersją używaną do kodowania. Ta wersja jest też wysyłana do serwera B&A w trakcie aukcji zabezpieczonej, dzięki czemu technicy reklamowi mogą dostosować logikę określania stawek i kodowania do danej wersji.

Response header for providing encoder version : X_ENCODER_VERSION

Interfejs API obsługi aukcji chronionych

Po stronie urządzenia przeprowadzenie aukcji dotyczącej chronionych sygnałów aplikacji jest takie samo jak przeprowadzanie aukcji dla chronionych odbiorców.

Usługi aukcyjne i ustalania stawek

Interfejsy API po stronie serwera to między innymi:

  • Protected aukcji API: seria funkcji JS i UDF, które kupujący i sprzedawcy mogą wdrażać w swoich komponentach B&A, aby określać stawki i logikę aukcji.
  • Interfejs Ad Retrieval API: kupujący mogą wdrożyć ten interfejs API, implementując punkt końcowy REST, który będzie odpowiedzialny za przekazanie zestawu reklam kandydujących do aukcji Protected App Signal.

Interfejs Protected aukcji API

Interfejs Protected aukcji API składa się z interfejsu API JavaScript lub funkcji UDF, które kupujący i sprzedawcy mogą wykorzystać do wdrożenia logiki aukcji i ustalania stawek.

Technologie UDF reklam kupującego
Przygotuj daneForAdRetrieval UDF

Zanim będzie można używać chronionych sygnałów aplikacji do pobierania kandydatów reklam z usługi pobierania reklam TEE, kupujący muszą dekodować i przygotowywać chronione sygnały aplikacji oraz inne dane przekazywane przez sprzedawców. Dane wyjściowe UDF kupujących w prepareDataForAdRetrieval są przekazywane do usługi pobierania reklam w celu pobrania k najlepszych reklam kandydujących do ustalania stawek.

// 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 adtech.
function prepareDataForAdRetrieval(encodedOnDeviceSignals,encodedOnDeviceSignalsVersion,sellerAuctionSignals,contextualSignals) {
   return {};
}
Wygeneruj stawkę UDF

Po zwróceniu k najlepszych reklam kandydujących są przekazywane do mechanizmu ustalania stawek niestandardowych kupującego 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>
    };
}

Wynikiem tej funkcji jest pojedyncza stawka dla kandydata do wyświetlenia, przedstawiona jako odpowiednik JSON ProtectedAppSignalsAdWithBidMetadata. Funkcja może też zwracać 2 tablice, które są następnie przekazywane do reportWin, aby umożliwić trenowanie modelu (więcej informacji o ruchu wychodzącym i trenowaniu modelu znajdziesz w sekcji raportowania w objaśnieniu PAS).

raportWin UDF

Po zakończeniu aukcji usługa aukcji wygeneruje adresy URL do raportowania dla kupujących i zarejestruje sygnały typu beacon za pomocą funkcji reportWin UDF (to ta sama funkcja reportWin, która jest używana w przypadku chronionych odbiorców). Urządzenie zostanie pingowane po wyrenderowaniu reklamy przez klienta. Podpis tej metody jest prawie taki sam jak wersji Protected Audience, z wyjątkiem 2 dodatkowych parametrów egressPayload i temporaryUnlimitedEgressPayload, które służą do trenowania modelu i są wypełniane wynikami z generateBid.

// Inputs / Outputs
// ----------------
// See detailed documentation here.
function reportWin(auctionSignals, perBuyerSignals, signalsForWinner,
                   buyerReportingSignals,
                   egressPayload, temporaryUnlimitedEgressPayload) {
  // ...
}
Technologie reklam i funkcje UDF sprzedawców
wynik UDF

Ta funkcja UDF jest używana przez sprzedawców do wybierania, które reklamy otrzymane od kupujących wygrają aukcję.

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

Ta funkcja UDF umożliwia sprzedawcy (w ostatecznym rozrachunku) tworzenie raportów na poziomie zdarzenia z informacjami o zwycięskiej reklamie.

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

Interfejs Ad Retrieval API

W wersji MVP usługa pobierania reklam będzie usługą zarządzaną i hostowaną przez kupującego , a usługa określania stawek pobiera z niej kandydatów reklam. Od kwietnia 2024 r. serwer pobierania reklam musi działać w zaufanym środowisku wykonawczym (TEE) i udostępniać interfejs GRPC/proto. Firmy z branży technologii reklamowych muszą skonfigurować ten serwer i podać jego adres URL w ramach wdrażania stosu B&A. Implementacja tej usługi działającej w TEE jest dostępna na Piaskownicy prywatności na GitHubie, a w pozostałej części dokumentacji zakładamy, że to jest kod używany podczas wdrożenia.

Od kwietnia 2024 r. wersje B&A obsługują pobieranie reklam za pomocą ścieżki kontekstowej. W takim przypadku serwer Określanie stawek otrzyma listę identyfikatorów reklam wysłanych przez serwer RTB w kontekściej części aukcji. Identyfikatory będą wysyłane do serwera KV TEE w celu pobrania wszystkich informacji związanych z reklamami do wykorzystania podczas fazy określania stawek (np. ad-render-url, metadanych i reprezentacji właściwościowych reklam do wykorzystania w wyborze Top-K). Ta druga ścieżka nie wymaga wdrożenia żadnej konkretnej logiki, więc opiszemy tylko sposób konfigurowania pobierania reklam na podstawie TEE.

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

Gdzie:

  • requestMetadata: JSON. Metadane serwera z żądaniami do UDF. Na razie brak informacji.
  • preparedDataForAdRetrieval: zawartość tego pola zależy od strategii pobierania reklam. W przypadku kontekstowego pobierania reklam parametr ten zawiera nieprzetworzone sygnały pochodzące z urządzenia i przekazywane przez usługę określania stawek. W przypadku pobierania reklamy TEE za pomocą serwera pobierania reklam ten parametr będzie zawierał wynik funkcji UDF prepareDataForAdRetrieval. Uwaga: na tym etapie chronione sygnały aplikacji są dekodowane i nieszyfrowane.
  • deviceMetadata: obiekt JSON zawierający metadane urządzenia przekazane przez usługę reklamową sprzedawcy. Więcej informacji znajdziesz w dokumentacji B&A.
    • X-Accept-Language: język używany na urządzeniu.
    • X-User-Agent: klient użytkownika używany na urządzeniu.
    • X-BnA-Client-IP: adres IP urządzenia.
  • contextualSignals: dowolny ciąg znaków pochodzący z serwera określania stawek kontekstowych obsługiwanego przez tę samą platformę DSP. UDF ma być w stanie zdekodować ciąg i go użyć. Sygnały kontekstowe mogą zawierać dowolne informacje, takie jak informacje o wersji modelu ML na potrzeby chronionego umieszczania danych, przekazywane za pomocą chronionych sygnałów aplikacji.

W przypadku powodzenia funkcja UDF powinna zwrócić ciąg znaków. Ciąg znaków jest zwracany do serwera określania stawek, który przekazuje go do funkcji UDF generateBid. Może to być po prostu zwykły ciąg, jednak najprawdopodobniej powinien on być obiektem zserializowanym, którego schemat jest zdefiniowany przez każdą technologię reklamową osobno. Schemat nie jest objęty żadnymi ograniczeniami, o ile mechanizm generateBid technologii reklamowej rozpoznaje i używa ciągu znaków.

Konfigurowanie systemu do programowania

Android

Aby skonfigurować środowisko programistyczne Androida, musisz wykonać te czynności:

  1. Utwórz emulator (preferowane) lub urządzenie fizyczne z obrazem w wersji dla programistów w wersji 10.
  2. Wykonaj zapytanie:
adb shell am start -n com.google.android.adservices.api/com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity

Następnie wybierz widoczną opcję wyrażenia zgody na reklamy sugerowane przez aplikacje.

  1. Uruchom następujące polecenie, aby włączyć odpowiednie interfejsy API. Konieczne może być ponowne uruchomienie tej operacji, ponieważ domyślna konfiguracja wyłączona, będzie okresowo synchronizowana.
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. Uruchom urządzenie ponownie.
  2. Zastępować klucze aukcji urządzenia, aby wskazywały Twój serwer kluczy aukcji. Musisz wykonać ten krok przed rozpoczęciem aukcji, aby zapobiec zapisywaniu nieprawidłowych kluczy w pamięci podręcznej.

Określanie stawek i usługi aukcyjne

Aby skonfigurować serwery B&A, zapoznaj się z dokumentacją konfiguracji samoobsługowej.

Skupimy się w tym artykule na temat konfigurowania serwerów dla kupujących, ponieważ sprzedawcy nie muszą wprowadzać żadnych zmian.

Wymagania wstępne

Przed wdrożeniem stosu usług B&A technologie reklamowe kupującego muszą:

  • Upewnij się, że klient wdrożył własną usługę pobierania reklam TEE (patrz odpowiednia sekcja).
  • Upewnij się, że technologia reklamowa ma zdefiniowane i hostowane wszystkie niezbędne funkcje UDF (prepareDataForAdRetrieval, generateBid, reportWin, HandleRequest).

Wiedza o tym, jak działa aukcja chroniona z ochroną odbiorców w przypadku B&A, również jest przydatna, ale nie jest obowiązkowa.

Konfiguracja Terraform

Aby korzystać z chronionych sygnałów aplikacji, technologie reklamowe muszą:

  • Włącz obsługę Protected App Signals w B&A.
  • Podaj punkty końcowe adresu URL, z których można pobierać nowe funkcje UDF dla funkcji prepareDataForAdRetrieval, generateBid i reportWin.

Zakładamy dodatkowo, że technologie reklamowe, które chcą używać B&A do remarketingu, będą nadal ustawiać wszystkie dotychczasowe flagi konfiguracji na potrzeby aukcji remarketingu.

Konfiguracja technologii reklamowej kupującego

Korzystając z tego pliku demonstracyjnego jako przykładu, kupujący muszą ustawić następujące flagi:

  • Włącz Protected App Signals: ta opcja jest włączona, aby zbierać dane w ramach chronionych sygnałów aplikacji.
  • Adresy URL chronionych sygnałów aplikacji: ustaw adresy URL serwerów Protected App Signals.

Technologie reklamowe muszą zastąpić prawidłowe adresy URL w obiektach zastępczych w tych polach:

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"

Konfiguracja technologii reklamowej sprzedawcy

Korzystając z tego pliku demonstracyjnego jako przykładu, sprzedawcy muszą ustawić następujące flagi. Uwaga: w tym miejscu wyróżniona jest tylko konfiguracja związana z chronionymi sygnałami aplikacji. Technologie reklamowe muszą dopilnować, by wstawiały prawidłowe adresy URL w obiektach zastępczych:

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"

Usługi wyszukiwania słów kluczowych i reklam

W zależności od wybranych strategii obsługi pobierania reklam system będzie wymagać wdrożenia 1 lub 2 instancji usługi KV. Instancję KV używaną do pobierania reklam na podstawie TEE będziemy określać jako Ad Retrieval Server, a instancję obsługującą pobieranie kontekstowe na podstawie ścieżki – jako KV Lookup Server.

W obu przypadkach wdrożenie serwerów jest zgodne z dokumentacją na serwerze KV GitHub. Różnica między nimi polega na tym, że wyszukiwanie działa od razu bez konieczności dodatkowej konfiguracji, natomiast w przypadku pobierania konieczne jest wdrożenie logiki pobierania w HandleRequest. Więcej informacji znajdziesz w przewodniku wprowadzającym do serwera KV. Pamiętaj, że firma B&A oczekuje, że obie usługi będą wdrożone w tej samej siatce usług co usługa określania stawek.

Przykładowa konfiguracja

Rozważ taki scenariusz: gdy korzystasz z interfejsu Protected App Signals API, technologia reklamowa przechowuje odpowiednie sygnały na podstawie danych o użytkowaniu aplikacji przez użytkowników. W naszym przykładzie przechowywane są sygnały reprezentujące zakupy w kilku aplikacjach. Podczas aukcji zaszyfrowane sygnały są zbierane i przekazywane do aukcji chronionej w B&A. Funkcja UDF kupującego, która działa w B&A, wykorzystuje te sygnały do pobierania propozycji reklam i obliczenia stawki.

[Kupujący] Przykłady sygnałów

Dodaje sygnał o kluczu o wartości 0 i wartości 1.

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

Dodaje sygnał o kluczu o wartości 1 i wartości 2.

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

[Kupujący] – przykład kodu encodeSignals

Koduje każdy sygnał do 2 bajtów, gdzie pierwszy bajt to pierwszy bajt klucza sygnału, a drugi – pierwszy bajt wartości sygnału.

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

[Kupujący] – przykład AdjustDataForAdRetrieval

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

[Kupujący] Przykładowa funkcja UDF pobierania reklam

W naszym przykładzie serwer pobierania reklam wysyła metadane (w tym przykładzie identyfikator każdej reklamy, ale może zawierać inne dane dla każdej z nich, które mogą być przydatne w późniejszym generowaniu stawek) każdego z K najlepszych kandydatów reklamy.

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

[Kupujący] Przykład funkcji generateStawki

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

[Kupujący] – przykład raportu Win

Funkcja UDF reportWin informuje kupującego, że wygrał aukcję.

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

[Sprzedawca] Konfiguracja serwera KV

Sprzedawcy muszą skonfigurować serwer KV sygnałów punktowych tak, aby możliwe było mapowanie adresów URL renderowania reklamy na odpowiednie sygnały punktowe. Na przykład: jeśli kupujący mają zwrócić elementy https:/buyer-domain.com/get-fitness-app i https:/buyer-domain.com/get-fastfood-app, sprzedawca może otrzymać następującą przykładową odpowiedź z sygnałami punktowymi po wysłaniu zapytania przez SFE z użyciem metody GET w 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"
      ]
   }
}

[Sprzedawca] – przykład reklamy z wynikiem

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

[Sprzedawca] – przykład strony reportResult

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

Przykładowa aplikacja

Utworzyliśmy przykładową aplikację w ramach Protected App Signals, która znajduje się w tym przykładowym repozytorium.