为帮助开发者开始试用 Protected App Signals API,本文档将介绍 API Surface 中的所有 API,详细说明如何设置测试环境,并提供配置和脚本的示例。
版本历史记录
2024 年 1 月
支持 PAS MVP 版本的开发者指南首次发布
2024 年 3 月
对 API 进行了更改,以支持 Android API 的 M-2024-05 版本和服务器端组件的 2024 年 4 月版本。最显著的变化:
- 添加了有关设备端 API 所需权限的详细信息
- 添加了有关设备端信号配额管理的详细信息
- 更新了
generateBid
签名,其中包含与内容相关广告检索和出站流量支持相关的更改 - 更新了
reportWin
文档,包括出站流量支持 - 更新了 Ad Retrieval API 文档,移除了对 BYOS 广告检索的支持,并记录了广告检索 UDF
API 概览
Protected Signals API Surface 在不同系统上包含不同 API 子集:
- Android API:
- Signal Curation API,其中包含:
- Update Signals API
- Signals Encoding API
- Protected Auction Support API:供 SDK 使用,以便在使用 Protected App Signals 的出价和竞价 (B&A) 服务器上运行受保护竞价。
- 服务器端 API:
- Protected Auction API:在出价和竞价服务器中运行的一系列 JS 脚本。卖方和买方可以使用此 API 编写逻辑来实现受保护的竞价。
- Ad Retrieval API:负责根据买方出价服务器可用的情境信息和用户信息提供候选广告列表。
Android 客户端
在客户端,Protected App Signals Surface 由三个不同的 API 组成:
- Update Signals:一种 Android 系统 API,用于在设备上启用信号分类。
- Signals Encoding:一种 JavaScript API,用于准备要在竞价期间发送至服务器的信号。
- Protected Auction Support:支持在出价和竞价服务器上执行受保护的竞价的 API。此 API 并非特定于 Protected App Signals,也用于支持 Protected Audience API 竞价。
Update Signals API
Update Signals API 使广告技术平台能够代表买方注册用户和应用相关信号。该 API 基于委托模型。调用方会提供一个 URI,框架可从该 URI 中提取相应的信号以及对要在竞价中使用的那些信号进行编码的逻辑。
该 API 需要 android.permission.ACCESS_ADSERVICES_PROTECTED_SIGNALS
权限。
updateSignals()
API 将从 URI 中检索一个 JSON 对象,该对象说明了需要添加或移除哪些信号,以及如何为竞价准备这些信号。
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);
平台会向请求中提供的 URI 发出 https 请求,以提取信号更新。除了信号更新之外,响应还可以包含一个端点,该端点托管用于将原始信号转换为编码载荷的编码逻辑。信号更新应采用 JSON 的形式,并且可以具有以下键:
JSON 对象的顶级键必须与以下五个命令之一相对应:
键 |
说明 |
|
添加新信号,使用同一键覆盖所有现有信号。此元素的值 是一个 JSON 对象,其中键是与要输入的键对应的 base 64 字符串,值是与要放入的值对应的 base 64 字符串。 |
|
将新信号附加到信号的时间序列。 如果时间序列的大小超出指定的上限,则会移除最早的信号来为新数据腾出空间。此元素的值是一个 JSON 对象,其中键是与要附加的键对应的 base 64 个字符串,值是包含以下两个字段的对象:“values”和“maxSignals”。 “values”:与要附加到时间序列的信号值相对应的 base 64 字符串列表。 “maxSignals”:此时间序列中允许的值的数量上限。如果 与键关联的信号的当前数量超出了 maxSignals,最早的信号将被移除。请注意,您可以附加到通过 put 添加的键。请注意,附加的值数量超过上限将导致失败。 |
|
仅当不存在具有相同键的现有信号时,会添加一个新信号。此元素的值是一个 JSON 对象,其中键是与要输入的键对应的 base 64 字符串,值是与要放入的值对应的 base 64 字符串。 |
|
移除键的信号。此元素的值是一个 base 64 字符串的列表,与应删除的信号的键相对应。 |
|
提供用于更新端点的操作,以及可以用于 检索编码逻辑的 URI。用于提供更新操作的子键是“action”, 目前支持的值只有“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-15Kb。超出配额后,PPAPI 将使用 FIFO 策略驱逐信号。为了减少驱逐频率,驱逐流程会允许在短时间内略微超出配额。
Signals Encoding API
买方必须提供一个 Java 脚本函数,用于对存储在设备上的信号进行编码,以便在受保护的竞价期间发送到服务器。买方可通过在 UpdateSignal API 请求的任何响应中添加可使用键“update_encoder”提取相应脚本的网址,以提供此脚本。此脚本将具有以下签名:
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
参数是从大小为 4 的 UInt8Arrays 形式的键到 Protected App Signals 对象列表的映射。每个 Protected App Signals 对象都有三个字段:
signal_value
:一个表示信号值的 UInt8Array。creation_time
:一个数字,表示信号的创建时间(以新纪元秒数表示)。package_name
:一个字符串,表示创建信号的软件包的名称。
maxSize
参数是一个数字,用于描述输出的最大允许数组大小。
该函数应输出包含以下两个字段的对象:
status
:如果脚本成功运行,则应为 0。results
:应为长度小于或等于 maxSize 的 UInt8Array。 此数组将在竞价期间发送到服务器,并由prepareDataForAdRetrieval
脚本进行准备。
编码为广告技术平台提供了特征工程的初始阶段,在该阶段,广告技术平台可以执行转换,例如根据自己的自定义逻辑将原始信号压缩为串联版本。请注意,在可信执行环境 (TEE) 中运行 Protected Auction 期间,广告技术平台自定义逻辑将拥有对编码生成的信号载荷的读取权限。在买方的 B&A TEE 中运行的自定义逻辑(称为用户定义的函数 (UDF))将拥有对编码信号和发布商应用提供的其他情境信号的读取权限,以便执行执行广告选择操作(广告检索和出价)。
信号编码
每个小时,已为其注册信号提供编码逻辑的买方都会将其信号编码为竞价载荷。竞价载荷的字节数组持久保存在设备上并经过加密,将作为广告选择数据的一部分由卖方收集,并作为 Protected Auction 的一部分包含在内。对于测试,您可以通过运行以下命令,在每小时的节奏之外触发此编码:
adb shell cmd jobscheduler run -f com.google.android.adservices.api 29
编码器逻辑版本控制
发出下载广告技术自定义编码器逻辑的请求时,广告技术平台端点可以在响应标头中使用版本号进行响应。此版本与设备上的编码器逻辑一起持久保留。对原始信号进行编码时,编码的载荷会与用于编码的版本一起保留。此版本也会在 Protected Auction 期间随同 B&A 服务器一起发送,以便广告技术平台可以根据版本调整其出价和编码逻辑。
Response header for providing encoder version : X_ENCODER_VERSION
Protected Auction Support API
在设备端,为 Protected App Signals 运行竞价的方式与为受保护的受众群体运行竞价相同。
出价和竞价服务
服务器端 API 包括:
- Protected Auction API:一系列 JS 函数或 UDF,买方和卖方可以在他们拥有的 B&A 组件上部署这些函数,以确定出价和竞价逻辑。
- Ad Retrieval API:买方可通过实现 REST 端点来实现此 API,该端点负责为 Protected App Signal 竞价提供一组候选广告。
Protected Auction API
Protected Auction API 由 JS API 或 UDF 组成,买方和卖方可以使用它们来实现其竞价和出价逻辑。
买方广告技术平台 UDF
prepareDataForAdRetrieval UDF
买方必须先解码并准备 Protected App Signals 及其他卖方提供的数据,然后才能使用 Protected App Signals 从 TEE 广告检索服务提取候选广告。买方 prepareDataForAdRetrieval
UDF 输出传递给广告检索服务,以检索前 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 adtech.
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>
};
}
此函数的输出是对候选广告的单次出价,表示为与 ProtectedAppSignalsAdWithBidMetadata
等效的 JSON。该函数还可以返回两个数组,然后将其传递给 reportWin
以启用模型训练(如需详细了解出站流量和模型训练,请参阅 PAS 说明文档中的“报告”部分)
reportWin UDF
竞价结束后,竞价服务将为买方生成报告网址,并使用 reportWin
UDF(用于 Protected Audience 的同一 reportWin
函数)注册信标。
客户端呈现广告后,设备将对此执行 ping 操作。
除了两个额外的参数 egressPayload
和 temporaryUnlimitedEgressPayload
用于启用模型训练并填充 generateBid
中的结果之外,此方法的签名与 Protected Audience 版本几乎相同。
// Inputs / Outputs
// ----------------
// See detailed documentation here.
function reportWin(auctionSignals, perBuyerSignals, signalsForWinner,
buyerReportingSignals,
egressPayload, temporaryUnlimitedEgressPayload) {
// ...
}
卖方广告技术平台 UDF
ScoreAd 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;
}
Ad Retrieval API
在 MVP 版本中,广告检索服务将是由买方管理的托管服务,出价服务将从此服务中检索候选广告。自 2024 年 4 月起,广告检索服务器必须在可信执行环境 (TEE) 中运行,并且将公开 GRPC/proto 接口。广告技术公司必须设置此服务器,并在 B&A 堆栈部署中提供其网址。Privacy Sandbox GitHub 中提供了在 TEE 中运行的此服务的实现,在文档的其余部分中,我们假定这是部署中使用的代码。
自 2024 年 4 月起,B&A 版本支持内容相关路径广告检索。在这种情况下,出价服务器将在竞价的背景部分收到 RTB 服务器发送的广告标识符列表。这些标识符将发送到 TEE KV 服务器,以提取要在出价阶段使用的所有广告相关信息(例如要在前 k 个选择中使用的 ad-render-url、元数据和广告嵌入)。这第二条路径不需要部署任何特定逻辑,因此我们将在此处仅记录如何配置基于 TEE 的广告检索用例。
getCandidateAds UDF
function getCandidateAds(requestMetadata, preparedDataForAdRetrieval,
deviceMetadata, contextualSignals, contextualAdIds,) {
return adsMetadataString;
}
其中:
requestMetadata
:JSON。发送到 UDF 的每个请求服务器元数据。暂时留空。preparedDataForAdRetrieval
:此字段的内容取决于广告检索策略。如果是内容相关广告检索,此参数将包含来自设备的原始信号,并从出价服务传递。如果使用广告检索服务器进行 TEE 广告检索,此参数将包含prepareDataForAdRetrieval
UDF 的结果。注意:在此阶段,Protected App Signals 将被解码和解密。deviceMetadata
:包含卖方广告服务转发的设备元数据的 JSON 对象。如需了解详情,请参阅 B&A 文档。X-Accept-Language
:设备上使用的语言。X-User-Agent
:设备上使用的用户代理。X-BnA-Client-IP
:设备 IP 地址。
contextualSignals
:来自由同一 DSP 运营的情境出价服务器的任意字符串。UDF 应能够解码字符串并使用它。上下文信号可能包含任何信息,例如使用 Protected App Signals 传入的受保护嵌入的 ML 模型版本信息。contextualAdIds
:包含可选广告 ID 列表的 JSON 对象。
UDF 应在成功时返回字符串。该字符串会返回给出价服务器,然后由出价服务器传递给 generateBid
UDF。虽然该字符串可以只是一个简单的字符串,但它很可能是经过序列化的对象,其架构由各个广告技术平台自行定义。只要广告技术平台的 generateBid
逻辑能够识别和使用该字符串,架构就没有任何限制。
设置系统开发环境
Android
如需设置 Android 开发环境,您需要执行以下操作:
- 创建运行开发者预览版 10 映像的模拟器(首选)或实体设备
- 运行以下命令:
adb shell am start -n com.google.android.adservices.api/com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity
然后,选择显示的选项来同意使用应用建议的广告。
- 运行以下命令以启用相关 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;
- 重启设备。
- 替换设备的竞价键,以指向您的竞价键服务器。在尝试运行竞价之前一定要运行此步骤,以防止不正确的键被缓存。
出价和竞价服务
如需设置 B&A 服务器,请参阅自助设置文档。
本文档将重点介绍如何配置买方专用服务器,因为卖方无需进行任何更改。
前提条件
在部署 B&A 服务堆栈之前,买方广告技术平台需要确保以下事项:
- 他们已部署了自己的 TEE 广告检索服务(请参阅相关部分)。
- 确保广告技术平台已定义并托管所有必要的 UDF(
prepareDataForAdRetrieval
、generateBid
、reportWin
、getCandidateAds
)。
了解如何将 B&A 与通过 Protected Audience 开展 Protected Auction 竞价搭配使用也会有所帮助,但不是强制性要求。
Terraform 配置
如需使用 Protected App Signals,广告技术平台必须:
- 在 B&A 中启用 Protected App Signals 支持。
- 提供可从中提取
prepareDataForAdRetrieval, generateBid
和reportWin
的新 UDF 的网址端点。
此外,本指南假定希望使用 B&A 进行再营销的广告技术平台会继续照常为再营销竞价设置所有现有配置标志。
买方广告技术平台配置
以此演示文件为例,买方需要设置以下标志:
- 启用 Protected App Signals:启用以收集 Protected App Signals 数据。
- Protected App Signals 网址:设置为 Protected App Signals 服务器的网址。
广告技术平台必须将以下字段的占位符替换为正确的网址:
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"
卖方广告技术平台配置
以此 demo 文件为例,卖方必须设置以下标志。(注意:此处仅突出显示与 Protected App Signals 相关的配置)。广告技术平台需要确保将占位符替换为正确的网址:
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 和 Ad Retrieval Service
根据为支持广告检索而选择的策略,系统需要部署一个或两个 KV 服务实例。我们将用于基于 TEE 的广告检索的 KV 实例称为 Ad Retrieval Server
,将用于支持基于情境路径的检索的实例称为 KV Lookup Server
。
在这两种情况下,服务器部署均遵循 KV 服务器 GitHub 中提供的文档,这两种情况的区别在于,查找用例无需任何额外配置即可开箱即用,而检索用例则需要部署 getCandidateAds
UDF 才能实现检索逻辑。如需了解详情,请参阅 KV 服务器新手入门指南。请注意,B&A 希望这两项服务与出价服务部署在同一服务网格中。
设置示例
请考虑以下情形:广告技术平台借助 Protected App Signals API 根据用户应用使用情况存储相关信号。在我们的示例中,存储的信号表示多个应用中的应用内购买交易。在竞价期间,系统会收集加密信号,并将其传递到在 B&A 中运行的 Protected Auction 竞价。在 B&A 中运行的买方 UDF 会根据这些信号来提取候选广告并计算出价。
[买方] 信号示例
添加一个键为 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};
}
[买方] prepareDataForAdRetrieval 示例
/**
* `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;
}
[买方] 广告检索 UDF 示例
在我们的示例中,广告检索服务器为前 k 个候选广告中的每一个发送元数据(即本示例中每个广告的 ID,但可以包含每个广告的其他数据,这些数据有助于稍后生成出价)。
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 服务器,以便提供从广告呈现网址到相应得分信号的映射。例如:如果 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"
]
}
}
[Seller] 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 示例应用,该应用可在此示例代码库中找到。