Privacy Sandbox on Android Developer Preview is here! Learn how to get started, and continue to provide feedback.

Support custom audience targeting using FLEDGE

Provide feedback

In mobile advertising, advertisers commonly have the desire to serve ads to potentially-interested users based on how they have previously engaged with the advertiser's app. For example, the developer of SportingGoodsApp may want to advertise to users who have items left in the shopping cart, by showing ads to remind users to complete the purchase. The industry commonly describes this general idea with terms such as "remarketing" and "custom audience targeting".

Today, these use cases are typically implemented by sharing contextual information about how the ad is shown (such as the app name) and private information such as audience lists with adtech platforms. Using this information, advertisers can select relevant ads on their servers.

FLEDGE on Android encompasses the following APIs for ad tech platforms and advertisers to support common interaction-based use cases in ways that limit the sharing of both identifiers across apps and a user's app interaction information with third-parties:

  1. Custom Audience API: This is centered on the "custom audience" abstraction, which represents an advertiser-designated audience with common intentions. Audience information is stored on-device and can be associated with relevant candidate ads for the audience and arbitrary metadata, such as bidding signals. The information can be used to inform advertiser bids, ad filtering, and rendering.
  2. Ad Selection API: This provides a framework that orchestrates adtech platforms' workflows that leverage on-device signals to determine a "winning" ad by considering candidate ads stored locally, and performing additional processing on candidate ads that an adtech platform returns to the device.
Figure 1. Flow chart that shows the custom audience management and ad selection workflow in the Privacy Sandbox on Android.

At a high level, the integration works as follows:

  1. SportingGoodsApp wants to remind its users to purchase merchandise items left in their cart if they haven't completed the purchase within 2 days. SportingGoodsApp uses the Custom Audience API to add the user to the "products in cart" audience list. The platform manages and stores this audience list on the device, limiting the sharing with third-parties. SportingGoodsApp partners with an adtech platform to show its ads to users in its audience list. The ad tech platform manages metadata for audience lists and provides candidate ads, which will be made available to the ad selection workflow for consideration. The platform can be configured to periodically fetch updated audience-based ads in the background. This helps keep the list of audience-based candidate ads fresh and uncorrelated with requests sent to third-party ad servers during the ad opportunity (i.e. contextual ad request).

  2. When the user plays the FrisbeeGame on the same device, they may see an ad reminding them to complete the purchase of items left in SportingGoodsApp's shopping cart. This can be achieved by FrisbeeGame (with an integrated ads SDK) invoking the Ad Selection API to select a winning ad for the user based on any audience list they may be a part of (in this example, the "products in cart" custom audience created by SportingGoodsApp). The ad selection workflow can be set up to consider ads retrieved from adtech platforms' servers, in addition to on-device ads associated with the custom audiences as well as other on-device signals. The workflow can also be customized by the adtech platform and ads SDK with custom bidding and scoring logic to achieve appropriate advertising goals. This approach enables the user's interest or app interactions data to inform ads selection, while limiting the sharing of this data with third-parties.

  3. The ad-serving app or adtech platform's SDK renders the selected ad.

  4. The platform will facilitate the reporting of impressions and ad selection results. This reporting capability is complementary to the Attribution Reporting API. Adtech platforms may customize based on their reporting needs.

Get access to FLEDGE for Android APIs

Adtech platforms need to enroll to access the FLEDGE for Android APIs, see Enroll for a Privacy Sandbox account for more information.

Custom audience management

Custom Audience

A custom audience represents a group of users with common intentions or interests. An app or SDK may use a custom audience to indicate a particular audience such as someone who has "left items in their shopping cart" or "completed the beginner levels" of a game. The platform maintains and stores audience information locally on the device and does not expose which custom audiences the user is in. Custom audiences are distinct from FLEDGE on Chrome's interest groups, and they can't be shared across web and apps. This helps limit the sharing of user information.

An advertiser app or the integrated SDK may join or leave a custom audience based on, for example, user engagement in an app.

Custom audience metadata

Each custom audience contains the following metadata:

  • Owner: Package name of the owner app. This is implicitly set to the package name of the caller app.
  • Buyer: Buyer ad network which manages ads for this custom audience. Buyer also represents the party who may access the custom audience and fetch relevant ad information. The buyer is specified following the eTLD+1 format.
  • Name: An arbitrary name or identifier for the custom audience, such as a user that has "shopping cart abandoners". This attribute could be used as, for example, one of the targeting criteria in the advertiser’s ad campaigns, or a query string in the URL for fetching bidding code.
  • Activation time and expiration time: These fields define the time window when this custom audience will be effective. The platform uses this information to withdraw membership from a custom audience. Expiration time cannot exceed a maximum duration window to limit the life of a custom audience.
  • Daily update URL: The URL that the platform uses to fetch candidate ads and other metadata defined in the "User bidding signals" and "Trusted bidding signals" fields on a recurring basis. For more details, see the section on how to fetch candidate ads for custom audiences.
  • User bidding signals: Adtech platform-specific signals for any filtering and bidding of remarketing ads. Examples of signals include: the user's coarse location, preferred locale, and so on.
  • Trusted bidding data: Adtech platforms rely on real-time data to inform Ad retrieval and scoring. For instance, an Ad may run out of budget and needs to be stopped serving immediately. An Ad-tech can define a URL endpoint from where this real-time data can be fetched and the set of keys for which the real-time lookup needs to be performed. The server handling this request will be a trusted server managed by the adtech platform.
  • Bidding logic URL: The URL that the platform uses to fetch bidding code from the demand side platform. The platform performs this step when an ad auction is initiated.
  • Ads: A list of candidate ads for the custom audience. This includes adtech platform-specific ad metadata and a URL to render the ad. When an auction is initiated for the custom audience, this list of ad metadata will be considered. This list of ads will be refreshed using the daily update URL endpoint when feasible. Due to resource constraints on mobile devices, there's a limit on the number of ads that can be stored in a custom audience.

Join a custom audience

An app can request to join a custom audience by calling joinCustomAudience() after instantiating the CustomAudience object with the expected parameters. Here is an illustrative code snippet example:

CustomAudience audience = new CustomAudience(
    Buyer = "example-dsp.com",
    Name = "running-shoes",
    ActivationTime = now(),
    ExpirationTime = ActivationTime.plus(30 days),
    DailyUpdateURL = Uri.parse("https://..."),
    UserBiddingSignals = new JSONObject("{...}"),
    TrustedBiddingURL = Uri.parse("https://..."),
    TrustedBiddingKeys = {'key1","key2", ...,"key n"},
    BiddingLogicURL =  Uri.parse("https://..."),
    Ads = [new AdData(renderUrl = Uri.parse("https://..."),
           metadata = new JSONObject("{...}"), ...];

// Invoke ad services API to join a custom audience.
joinCustomAudience(audience);

Leave a custom audience

The owner of a custom audience may choose to leave by calling leaveCustomAudience(), as shown in the illustrative code snippet below:

// Invoke ad services API to leave a custom audience.
leaveCustomAudience(buyer, name);

To help conserve usage of storage and other device resources, custom audiences expire and are removed from the on-device store after a predetermined period of time. The default value is to be determined. The owner can override this default value.

User control

  • The proposal intends to give users visibility to the list of installed apps that have created at least one custom audience
  • Users can remove apps from this list. The removal will clear all the custom audiences associated with the apps and prevent the apps from joining new custom audiences.

The design of this capability is a work in progress, and the details will be included in a later update.

Adtech platform permissions and control

The proposal intends to provide apps control over its custom audiences:

  • An app can manage its associations with custom audiences.
  • An app can grant third-party adtech platforms permissions to manage custom audiences on its behalf.
  • The proposal intends to give user the ability to reset FLEDGE completely. When this happens, any existing custom audiences generated in the device are cleared.
  • The proposal also includes giving the users to opt-out completely from the Privacy Sandbox on Android, which includes FLEDGE. When this is the case, the FLEDGE APIs will fail silently.

The design of this capability is a work in progress, and the details will be included in a later update.

Fetch candidate ads for custom audiences

Buy-side platforms may have user interaction-based candidate ads stored on the device, so they can be evaluated when an auction for the custom audience is run. Candidate ads and related metadata for a custom audience can be fetched in two complementary ways.

  1. System daily fetch: When an app joins a custom audience, it may specify a daily update URL which the platform will query on a daily basis. Adtech platforms can use this feature to keep the list of ads fresh and remove any ads that are no longer active or have no remaining budget. The platform will ensure that a URL endpoint passes a k-anonymity privacy threshold before processing the ad fetch request.
  2. Custom audience owner-driven fetch: When an owner adds a user to a custom audience, it may fetch candidate ads from a buy-side platform. Returned ads and metadata can be stored in the custom audience's "ads" field. Adtech platforms may want to use this feature if they would like to start serving ads to this user right away.

Candidate ads and metadata response

Candidate ads and metadata returned from a buy-side platform should include the following fields:

  • Metadata: Buy-side, adtech-specific ads metadata. For example, this may include information about the ad campaign, and targeting criteria such as location and language.
  • Render URL: Endpoint for rendering the ad creative.
  • Filter: Optional information necessary for FLEDGE to filter ads based on on-device data. For more details, see Buyside filtering logic.

Ad selection workflow

This proposal aims to improve privacy by introducing the Ad Selection API, which orchestrates auction execution for adtech platforms.

Adtech platforms today typically perform bidding and ad selection exclusively on their servers. With this proposal, custom audiences and other sensitive user signals, such as available installed package information, will be accessible only through the Ad Selection API. Additionally for the remarketing use case candidate ads will be fetched out of band (i.e. not in the context in which ads will be shown). Ad tech platforms will need to prepare to have some parts of their current auction and ad selection logic deployed and executed on the device. Adtech platforms may consider the following changes to their ad selection workflow:

  • Without installed package information available on the server, adtech platforms may want to send multiple contextual ads back to the device and invoke the ad selection workflow to enable app install-based filtering in order to maximize chances to show a relevant ad.
  • Because remarketing ads are fetched out of band, current bidding models may need to be updated. Adtech platforms may want to create bidding sub-models (the implementation may be based on a pattern called two-tower model) that can work on ads features and contextual signals separately and combine the sub-model outputs on the device to predict bids. This can benefit from both server-side auctions and auctions for any given ad opportunity.

This approach enables the user's app interactions data to inform ads selection, while limiting the sharing of this data with third-parties.

Figure 2. Flow chart that shows the initiation of the ad selection workflow.

This ad selection workflow orchestrates the on-device execution of adtech-provided JavaScript code based on the following sequence:

  1. Buy-side bidding logic execution
  2. Buy-side ad filtering and processing
  3. Sell-side decision logic execution

For ad selections that involve custom audiences, the platform will fetch buy side-provided JavaScript code based on the public URL endpoint defined by the custom audience's "Bidding logic URL" metadata. The URL endpoint for sell-side decision code will also be passed as an input to initiate the ad selection workflow.

The design of ad selections that don’t involve custom audiences is under active design.

Initiate ad selection workflow

When an app needs to show an ad, the adtech platform SDK may initiate the ad selection workflow by calling the selectAds() method after instantiating the AdSelectionConfig object with the expected parameters:

  • Seller: Identifier for the sell-side ad platform, following the eTLD+1 format
  • Decision logic URL: When an ad auction is initiated, the platform will use this URL to fetch JavaScript code from the sell-side platform to score a winning ad.
  • Custom audience buyers: A list of buy-side platforms with custom audience-based demand for this auction, following the eTLD+1 format.
  • Ad selection signals: Information about the auction (ad size, ad format etc.).
  • Seller signals: Supply side platform specific signals.
  • Trusted Scoring Signals URL: URL endpoint of sell-side trusted signal from which creative specific realtime information can be fetched from.
  • Per buyer signals: Participating demand sides may use this parameter to provide inputs for the auction. For example, this parameter may include comprehensive contextual information useful for determining bids.

The following illustrative code snippet shows an adtech platform SDK initiating the ad selection workflow by first defining the AdSelectionConfig and then invoking selectAds to get the winning Ad:

AdSelectionConfig myAdSelectionConfig = new AdSelectionConfig {
    Seller = "example-ssp1.com",
    DecisionLogicURL = Uri.parse("https://..."),
    CustomAudienceBuyerList = Arrays.asList("example-dsp1.com","bexample-dsp2.com"),
    AdSelectionSignals = "{"min_price": 10,"auction_attempts": 3}"
    SellerSignals = "{"seller_type": "news", "content_category": "sports","mature_ads_accepted" :"false"}"
    PerBuyerSignals = " {"buyer1Name": {"key1" : "value1"},
                         "buyer2Name": {"key1" : "value1", "key2" : "value2" }"
};

// Invoke ad services API to initiate ad selection workflow.
Ad winningAd = selectAds(myAdSelectionConfig);

Buy-side bidding logic

The bidding logic is typically provided by buy-side platforms. The purpose of the code is to determine bids for candidate ads. It may apply additional business logic to determine the result.

The platform will use the custom audience's "Bidding logic URL" metadata to fetch the JavaScript code which should include the function signature below:

generateBid(ad, auction_signals, per_buyer_signals, trusted_bidding_signals,
        contextual_signals, user_signals, custom_audience_signals) {
    // ...
    return {'bid': ...};
}

The generateBid() method returns the calculated bid amount. The platform will invoke this function for all ads (contextual or remarketing) sequentially. If there are multiple bidding logic providers, the system does not guarantee the execution sequence among the providers.

The function expects the following parameters:

  • Ad: The ad being considered by the buy-side bidding code. This will be an Ad from an eligible custom audience
  • Auction signals: Sell-side, platform-specific signals.
  • Per buyer signals: Participating demand sides may use this parameter to provide inputs for the auction. For example, this parameter may include comprehensive contextual information useful for determining bids.
  • Trusted bidding signals: Adtech platforms rely on real-time data to inform ad retrieval and scoring. For instance, an ad campaign may run out of budget and needs to be stopped serving immediately. An Ad-tech can define a URL endpoint from where this real-time data can be fetched and the set of keys for which the real-time lookup needs to be performed. The adtech platform's managed server that serves this request will be a trusted server managed by the adtech platform.
  • Contextual signals: This may include coarsened timestamp or approximate location information.
  • User signals: This may include information such as available installed package information.

Buy-side filtering logic

Buy-side platforms will be able to filter ads based on additional on-device signals available during the ad selection phase. For example, adtech platforms can implement frequency capping capabilities here. If there are multiple filtering providers, the system does not guarantee the execution sequence among the providers.

The buy-side filtering logic will be run after the bidding logic.

Buy-side platforms will be able to signal that a given ad should be filtered based on additional on-device signals available to FLEDGE and that won’t leave the device. As we solidify the designs of additional filtering logic, buy-side platforms will follow this same structure to signal that the filtering should happen.

Sell-side scoring logic

The scoring logic is typically provided by the sell-side platform. The purpose of the code is to determine a winning ad based on bidding logic outputs. It may apply additional business logic to determine the result. If there are multiple decision logic providers, the system does not guarantee the execution sequence among the providers. The platform will use the "Decision logic URL" input parameter of the selectAds() API to fetch the JavaScript code which should include the function signature below:

scoreAd(ad, bid, auction_config, trusted_scoring_signals,
        contextual_signals, user_signals, custom_audience_signals) {
    // ...
    return score_for_this_ad;
}

The function expects the following parameters:

  • Ad: The Ad being evaluated; output from the generateBid() and filterAd() functions.
  • Bid: Bid amount output from the generateBid() function.
  • Auction config: Input parameter to selectAds() method.
  • Trusted Scoring Signals: Adtech platforms rely on real-time data to inform ad filtering and scoring. For instance, an app publisher may block an ad campaign from showing ads in the app. This data is fetched from trusted scoring signals url parameter of the auction configuration. The server serving this request should be an adtech-managed trusted server.
  • Contextual signal: This may include coarsened timestamp or approximate location information.
  • User signal: This may include information such as the app store that initiated the installation of the app.
  • Custom audience signal: If the Ad being scored is coming from an on-device custom audience, this will contain information such as the reader and name of the custom audience.

Ad selection code runtime

In the proposal, the system will fetch adtech platform-provided auction code from configurable URL endpoints and execute on the device. Given the resource constraints on mobile devices, auction code should adhere to the following guidelines:

  • The code should finish executing in a predefined amount of time. This bound will apply uniformly to all buyer ad networks. Details of this bound will be shared in a later update.
  • The code must be self-contained and not have any external dependencies.

Since the auction code, such as the bidding logic may need access to private user data such as app install sources, the runtime will not provide network or storage access.

Programming language

Adtech platform-provided auction code should be written in JavaScript. This would allow adtech platforms to, for example, share bidding code across platforms that support Privacy Sandbox.

Winning ad rendering

The ad with the highest score is considered the winner of the auction. In this initial proposal, the winning ad is passed into the SDK for rendering.

The plan is to evolve the solution to ensure that information about a user's custom audience membership, or app engagement history, cannot be determined by the app or SDK through information about the winning ad (similar to Chrome's fenced frames proposal)).

Impressions reporting

Once the ad has been rendered, the winning impression can be reported back to participating buy- and sell-side platforms. The platform will invoke reporting logic in this order:

  1. Sell-side reporting.
  2. Buy-side reporting.

This gives buy-side and sell-side platforms a way to send important on-device information such as bid information, custom audience name and so on back to the servers to enable capabilities such as real time budgeting, bidding model updates, and accurate billing workflows. This impression reporting support is complementary to the Attribution Reporting API.

Sell-side reporting

The platform will invoke the reportResult() JavaScript function in the supply side-provided code downloaded from the seller's Decision logic URL parameter for the selectAds() API:

reportResult(render_url, bid, auction_config, contextual_signals) {
    // ...
    return reporting_url, signals_for_buyer;
}

Output:

  • Reporting URL: The platform will invoke this URL returned from the function.

The supply side may encode relevant signals in the reporting URL to help them gain further insights into the auction and winning ad. For example, it may include signals below:

  • Ad render URL
  • Winning bid amount
  • App name
  • Query identifiers
  • Signals for buyer: To support data sharing between supply side and demand side, the platform will pass this return value as an input parameter to demand side reporting code.

Buy-side reporting

The platform will invoke the reportResult() JavaScript function in the demand side-provided code downloaded from the Bidding logic URL metadata of the custom audience associated with the auction.

reportResult(render_url, bid, auction_signals, per_buyer_signals,
        signals_for_buyer, contextual_signals, custom_audience_signals) {
    // ...
    return reporting_url;
}

Input:

  • auction_signals and per_buyer_signals will be fetched from AuctionConfig. Any information that the buy-side platform needs to pass into the reporting URL may come from this datum.
  • signals_for_buyer is the output of the sell-side reportResult. This provides the sell-side platform with an opportunity to share data with the buy-side platform for reporting purposes.
  • contextual_signals contains information such as app name and custom_audience_signals will contain the custom audience information. Other information may be added in the future.

Output:

  • Reporting URL: The platform will invoke this URL returned from the function.

Adtech platform managed trusted server

Ad selection logic today requires real-time information such as budget depletion status to determine if ad candidates should be selected for auction. Both buy-side and sell-side platforms will be able to get this information from servers they operate. In order to minimize leak of any sensitive information via these servers the proposal calls for the following restrictions:

  • The behaviors of these servers, described later in this section, would not leak user information.
  • The servers would not create pseudonymous profiles based on the data it sees, i.e. it will need to be ‘trusted'.

Buy side: Once buy side initiates the buy side bidding logic, the platform performs an HTTP fetch of trusted bidding data from the trusted server. The URL is composed by appending the URL and keys present in the Trusted Bidding Signals metadata of the custom audience being processed. This fetch is done only when processing ads from the on device custom audiences. At this stage, buy side can enforce budgets, check for campaign pause / unpause state, perform targeting, etc.

Below is a sample URL to fetch trusted bidding data, based on trusted bidding signal metadata from the custom audience:

https://www.kv-server.example/getvalues?keys=key1,key2

The response from the server should be a JSON object whose keys are key1, key2, etc., and whose values will be made available to the buyer's bidding functions.

Sell side: Similar to the buy side flow above, sell side may want to fetch information about creatives considered in the auction. For instance, a publisher may want to enforce that certain creatives are not shown in their app based on brand safety concerns. This information can be fetched and made available to the sell side auction logic. Similar to the buy side trusted server lookup, sell side trusted server lookup also happens via an HTTP fetch. The URL is composed by appending the Trusted Scoring Signals URL with render URLs of the creatives for which the data needs to be fetched.

Below is a sample URL to fetch information about creatives considered in the auction, based on creative render URLs:

https://www.kv-server.example/getvalues?renderUrls=render_url1,render_url2

Response from the server should be a JSON object whose keys are render URLs sent in the request.

These servers would operate in a trusted way to offer several security and privacy benefits:

  • The server's return value for each key can be trusted to be based only on that key.
  • The server does not perform event-level logging.
  • The server has no other side effects based on these requests.

As a temporary mechanism, the buyer and seller can fetch these bidding signals from any server, including one they operate themselves. However, in the release version, the request will only be sent to a trusted key-value-type server.

Buyers and sellers could use a common trusted key-value-type server for platforms compatible with Privacy Sandbox on Android and for the Web.