App install ads filtering

New mobile app installations are commonly driven by app install ads. To maximize your ad spend ROI, it's a good idea to not show an ad to install an app on devices that already have that same app installed. In this proposal, we refer to this practice as "app install ads filtering."

This proposal introduces how Protected Audience on Android supports contextual ads filtering, in particular app install ads filtering, in a privacy-preserving way. To participate, the app on the device needs to explicitly opt-in to app install ads filtering. During ad selection, ad candidates are filtered out based on the list of apps installed on the device known by the ad tech. The list of installed apps is only visible within the ad selection flow, and relies on the buy-side platform to signal that a particular ad should be filtered based on the existence of an app on the device.

To set up app install ads filtering, follow these steps:

Step 1: Register app for app install ads filtering

To opt-in to app install ads filtering, the app developer invokes the registerForAdFiltering app registration API from their app, or an ad tech SDK, with a list of ad tech buyer eTLD+1s. This allows the buyers on the list, and only those buyers, to filter ads based on the app’s install status, whether directly or via their ad tech’s SDK. Registration gives complete control to the app developer on whether their app should participate or not in app install ads filtering.

void registerForAdFiltering(List<AdTechIdentifier> buyers);

Step 2: Request to filter out app install ads

When an ad is considered for bidding, buyers can choose to flag the ad to be filtered out based on an app's install status. This is done by including the app's package name in the ad's metadata. The app install ads filtering request is part of the ads data fed into the Protected Audience auction process. This ads data is created differently based on whether this is a contextual or remarketing ad.

  • For the contextual ad use case, which is the main use case for app install ads filtering, filtering information is included as part of the ads data that buyers can give to sellers when responding to a contextual bid outside of Protected Audience. Protected Audience expects filtering information to be returned as part of the contextual response, just like any other ad-specific metadata.
  • For the remarketing use case, Protected Audience expects filtering information to be included in the custom audience. There are 2 opportunities for this inclusion to happen: when joining the audience and when fetching new audience data as part of the update audience process.

The request to filter out app install ads should look like the following within the AdData JSON object:

{
  "render_uri": "https://..",
  "metadata": {..},
  "filters": {
    "app_install": {
       "app_package_names": ["app1.package", "app2.package"]
    }
  }
}

Note: You can filter out app install ads for multiple apps at once. To do that, simply list all the app package names that should be evaluated. If any of the packages are found in the app install list, the ad are filtered out.

We are exploring ways to enable encryption and/or signing of the contextual ads information, and we request your feedback on this topic.

Step 3: Filter out app install ads during ad selection

During an ad request, the buyer can pass multiple ads back to the seller with filtering information so that ads for installed apps can be filtered out. The sell-side is required to pass the filtering information as part of the selectAds function configuration in the adData field. Android expects a message format similar to the one below.

AdData myAdData = new AdData.Builder()
        .setRenderUri(Uri.parse("https://.."))
        .setMetadata("{...}")
        .setFilters(new AdFilters.Builder()
                .setAppInstalledFilter(new AppInstalledFilter.Builder()
                    .setPackageNames(ImmutableList.of("app1.package", "app2.package"))
                    .build())
                .build())
        .build();

AdSelectionConfig myAdSelectionConfig = new AdSelectionConfig.Builder()
    .setSeller(AdTechIdentifier.fromString("example-ssp1.com"))
    .setDecisionLogicUri(Uri.parse("https://..."))
    ...
    .setContextualAds(ImmutableList.of(new ContextualAd.Builder()
                      .setBuyer(AdTechIdentifier.fromString("example.com"))
                      .setReportingUri("https://example.com/reporting")
                      .setBid(20)
                      // myAdData could be taken from the JSON above
                      .setAd(myAdData)
                      .build()))
    .build();

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

Filtering is processed within the selectAds API. Protected Audience filters out the ad if the app specified in the message match the app in the ad tech buyers’ specific app install list. Two outcomes are possible:

  • The app is not found in this list, meaning it is not installed and opened.
  • The app is found in this list, meaning it is installed and opened.

If Protected Audience detects that an app already exists, then the ad is excluded from the list of ads that the auction uses to run scoreAds on.

Considerations when contextual ads are involved

With app install ads filtering, the Protected Audience APIs start to support contextual ads filtering. A few things are important to specify in the situations where the auction is a mix of contextual and remarketing ads, or composed entirely only of contextual ads.

  • When a selectAd auction is run, the buyer has the option to pass in a list of ContextualAd objects. These objects contain the eTLD+1 of the ad buyer, the bid for the ad, a URL pointing to the reporting logic for the ad, and the AdData containing the actual ad content URL, and a verification signature belonging to the buyer (see contextual ad signing for more details. Note that the AdData format is used in both contextual and remarketing ads.

  • At the beginning of the auction process, contextual and remarketing ads are filtered using the set of package names specified in the included in the AdData.adFilters.appInstallFilters.packageNames. Then, bid values are decided for any remarketing ads, and both the remarketing and contextual ads are scored using the provided scoreAds function. The ad with the highest score wins. Note that this process works even if no remarketing ads are present.

  • If a contextual ad wins the auction and impression reporting is triggered by the app, Protected Audience downloads and executes a JS function named reportWin() from the reporting URL included in the contextual ad data. This is similar to how reporting is done for a remarketing ad winning the auction.

    Sample JavaScript reporting function:

    function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer,
    contextual_signals) {
    let reporting_address = 'https://reporting.example.com';
    return {'status': 0, 'results': {'reporting_uri':
         reporting_address + '?some_signal=' + per_buyer_signals.some_signal} };
    }
    

Contextual ad signing

  • Contextual ads that include app install filtering must be signed by the buyer. The platform uses this signature to verify the ad tech that provided the ads and which ad tech app install filters to apply to the ads. This is done to prevent a malicious ad tech from using another ad tech's identity to benefit from the other ad tech's app install filtering registration.

  • Privacy Sandbox will fetch these keys from the ad tech endpoint provided during enrollment. We recommend, as best practice, that the keys must be updated often, but no later than every 6 months.

  • Privacy Sandbox will ask that ad techs confirm the availability of the ad tech provided endpoint during the enrollment process. For more detail on action required by current and newly enrolled ad techs, see the Enrollment instructions.

  • A Developer Guide with more detailed instructions for implementation will be published in the near future.