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

FLEDGE frequency capping

Stay organized with collections Save and categorize content based on your preferences.

Frequency capping is an advertising practice that limits the number of ads from a given category that are shown to a user within a given time period. Frequency capping improves the end-user experience by keeping ad impressions fresh and interesting, and helps advertisers manage ad spend.

This proposal introduces how FLEDGE on Android can be used to implement frequency capping functionality in an accurate and privacy-preserving way.

FLEDGE implements frequency capping by combining two features: The on-device storage of counters for ad-specific events, and the ability to filter ads according to a predefined set of filter strategies. Frequency capping enables advertisers to indicate a counter threshold over a sum of histogram values for a given time period.

Counters are unique for each combination of device profile, adtech, and counter key. Each ad should contain a set of counter keys to use in case a view or impression for the ad is registered. For each key, FLEDGE stores a set of counters, and each counter tallies all ad-specific events that occur within a specific time interval. On-device counters are incremented when an impression or view occurs, and counter data will be persisted on device. The exact persistence time will be defined later.

The ad filtering logic in FLEDGE's ad selection workflow has access to counters, remarketing ads, and contextual ads, giving FLEDGE frequency capping the ability to work with all such types of ad requests.

Note: Ad filtering is only available in the Privacy Sandbox on Android. Chrome's FLEDGE implementation does not currently implement a mechanism for filtering contextually-targeted non-FLEDGE ads. This proposal covers buy-side support only. If there is demand, we will add sell-side support at a later date.

FLEDGE frequency capping supports a broad range of requirements, including:

  • Real-time filtering, with minimal server-side delay when on-device counters are updated.
  • Flexible hierarchy of keys, including individual ads, campaigns, or any other grouping.
  • Congruence with other frequency capping methods, without dependency on AdID.
  • Works across apps on a given device user profile.
  • Accurate and complete counters.
  • Support for custom definitions of ad events, such as views or impressions.
  • One function for both remarketing and contextual ads.

To set up frequency capping, follow these steps:

Step 1: Add frequency capping information to ads

Contextual and remarketing ads will indicate what are the relevant histogram counters to update in case of a view or impression using a new field on_device_counters_keys that will contain a list of arbitrary key values. The field is not included in the metadata field that is not parsed by FLEDGE.

The following example shows the data format for the adsData field in AdSelectionConfig. For remarketing, the format of the list of ads for a given custom audience is consistent with the content of the ads field shown below:

'adsData': [
  {
    "buyer": "ads.example.com",
    "ads": [
      {
        'render_url': 'exampleUrl',
        'metadata': {...},   /* metadata are opaque to FLEDGE and
                                just required to be in valid JSON
                                format */
        'on_device_counters_keys': [
          'campaign_id:1234',
          'campaign_id:1234+adgroup_id:5678'
        ]
      }]
  }]
}

Step 2: Register a view or impression

Adtechs can invoke the updateEventHistogram method to register occurrences of events that are used for frequency capping. A method can be invoked repeatedly on the same event for keys specified in the winning ad's eventType.

void updateEventHistogram(@EventType eventType, long adSelectionId)

Inputs:

  • eventType: Identifies whether an event is counted as a view, an impression or the win of the ad selection process.
  • adSelectionId: ID values in the AdSelectionOutcome object that are returned by selectAds calls.

The updateEventHistogram call updates the histogram for the set of keys defined as part of either the remarketing ads fetched by a CustomAudience or the contextual ads included in the AdSelectionConfig parameter for selectAds. In addition to the keys in on_device_counters_keys, the call will also update the histogram for a counter identified by the ad's render_url value.

If we assume that the ad in Step 1 is the winner of an AdSelection with an id value of 9999, a call to updateEventHistogram(EventType.VIEW, adSelectionId: 999) increments the counters for the following three primary keys:

  • {'ads.example.com', 'campaign_id:1234', VIEW}
  • {'ads.example.com', 'campaign_id:1234+adgroup_id:5678', VIEW}
  • {'ads.example.com', 'exampleUrl', VIEW}.

The adtech name is taken from the buyer field, either from contextual ads or from custom audiences, depending on where the winning ads come from.

FLEDGE for Android will automatically increment all the counters mentioned above for the event type EventType.AD_SELECTION_WIN for ads returned by a selectAds API call. This is functionally equivalent to the addition of the prev_wins argument to browser_signals in generateBid in Chrome's FLEDGE implementation.

Step 3: Implement frequency cap filtering with filters

For optimal performance, the frequency cap filtering function is executed within AdServices. FLEDGE understands if a message has to be filtered by reading the filters field in the AdsData object. A list of filters is specified in frequency_cap. The values for key, event_type and interval_seconds are used to retrieve a histogram of events that are used for filtering and FLEDGE.

Filtering information can be specified for remarketing ads provided by a custom audience and for contextual ads as part of the AdSelectionConfig object.

For contextual ads with frequency cap filters, ads are passed in using the ads field in the AdSelectionConfig object. Ads are filtered, and the ad with the highest bid is returned as the result of the selectAds call.

For remarketing ads with frequency cap filters, ads are filtered before the buyer-provided generateBid() JavaScript function is invoked.

The following example shows a message with frequency cap filtering:

{
  'render_url': 'url',
  'metadata': {...},   /* metadata are opaque to FLEDGE and assumed
                        to be in valid JSON format */

  'on_device_counters_keys': [
    'campaign_id:1234',
    'campaign_id:1234+adgroup_id:5678'
  ],

  "filters": {
    "frequency_cap": {
      "view": {
        "campaign_id:1234": {
          "cap": 10,
          "interval_seconds": 86400
        },
        "adgroup_id:5678": {
          "cap": 10,
          "interval_seconds": 86400
        },
      },
      "win": {
        "campaign_id:1234": {
          "cap": 5,
          "interval_seconds": 604800
        },
        "adgroup_id:5678": {
          "cap": 5,
          "interval_seconds": 345600
        },
      }
    },

  // This field is only required in contextual ads and is used in
  // reportImpression calls to fetch the reportWin function.
  'reportingJS': "https://ads.example.com?reportWin.js"
}

Step 4: Report on winning Ads

Once the ad selection process is complete, it returns an AdSelectionOutcome object containing the renderUri and adSelectionId, a numeric identifier for the selectAds call. This ID can be used to invoke the reportImpression API that currently supports event-level reporting. In Beta 1, this method supports reporting for remarketing ads, and will be extended to support reporting for contextual ads in a later release. For contextual ads, the buyer is required to indicate where the reportWin function can be retrieved during a reportImpression call by using an extra field called reportingJS in the ad structure, as shown in the example above.

Best practices for selecting ad candidates

FLEDGE moves the enforcement of frequency capping from the server to the device. Although winning bids are reported with the Privacy Sandbox, developers won't know why an ad isn't shown. Ads might not be shown due to a lost bid, or due to frequency capping. With no full visibility into the reasons why certain ads don't win, bidding systems require additional work to ensure optimal ads are served. These best practices will help ensure optimal ad serving with FLEDGE.

Send enough remarketing ads

Remarketing ads cannot be optimized per user. If a user sees a significant number of ads from a custom audience and the ad limits are low, all ads may be filtered out. Remarketing ads are refreshed periodically, so enough ad inventory should pass through frequency capping to ensure remarketing ads continue to be served. This needs to be balanced with limitations on the size of the ads that can be specified during the joinCustomAudience call, and during the custom audience background fetch process. Buyers must consider that there might be an increase in latency during the bidding phase. To minimize the impact of these issues, frequency cap filtering is performed before the call to generateBid.

Keep contextual counters on the server

With server side estimation, a developer can have rough estimates for when frequency capping may be active. Those estimations can indicate that an ad has likely hit the frequency cap threshold, and should therefore be sent with more ad candidates or be eliminated completely.

Send multiple ad candidates on the contextual response

You should send multiple ad candidates with a contextual response before a FLEDGE auction. This ensures that if several ads are filtered out, other ads will still be shown. Ad candidates can be prioritized so that some ads are provided as backup.

Since execution is time-bound, ad candidates should be chosen according to their likelihood to win an auction and to not be filtered out.

Limitations

The following are known limitations of FLEDGE frequency capping:

  1. FLEDGE frequency capping operates at the device user profile level, currently with no shared counters on other devices and other profiles. Any increments of ads shown from other devices need to be incorporated manually, if desired.
  2. Device counters are stored and accessed on the device. Server-side counters need to be managed separately.
  3. As frequency capping and related ad filtering is processed on a device, adtech platforms don't have direct control over these operations. To clear the device's frequency capping threshold, adtech platforms can send multiple candidate ads.
  4. Bid adjustments based on recorded frequency are unsupported. The generateBid functions cannot view frequency counters.