Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Per-Campaign Diversity

Promovolve ensures diversity through two mechanisms: the auction-time fair selection algorithm and serve-time aggregate pacing.

Auction-Time Diversity

The candidate shortlisting algorithm (in AuctioneerEntity) guarantees per-campaign representation:

1. Group candidates by campaign
2. Pick best creative per campaign (by CPM)
3. If #campaigns ≥ #slots:
     Take top campaigns by CPM → one creative each
4. Else:
     Each campaign gets 1 slot (guaranteed)
     Fill remaining slots with next-best creatives

This means 3 campaigns competing for 3 slots each get exactly 1 slot, rather than a single high-CPM campaign filling all 3.

Serve-Time Aggregate Pacing

The pacing gate operates on aggregate campaign metrics, not per-campaign:

PacingContext(
  dailyBudget = sum of all participating campaign budgets,
  todaySpend = sum of all campaign spends (including pending),
  avgCpm = CPM-weighted average across campaigns,
  competingCampaigns = count of campaigns with budget remaining,
  ...
)

Why Aggregate?

Per-campaign pacing would allow a high-budget campaign to crowd out a low-budget one:

  • Campaign A ($1000/day): barely paced, always serving
  • Campaign B ($10/day): heavily paced, rarely serving

Aggregate pacing asks: “Given the total budget of all campaigns here, is the combined spend rate appropriate?” This naturally balances delivery.

Thompson Sampling as Natural Diversifier

Thompson Sampling itself provides diversity without explicit constraints:

  • Each creative has its own Beta(clicks+1, impressions-clicks+1) posterior
  • Sampling from Beta naturally introduces variance — even a dominant creative samples low sometimes
  • New creatives have wide distributions → high variance → get explored
  • Per-creative independence means every creative gets its own learning trajectory

Ad Product Blocklist

Publishers can configure per-site ad product category blocklists:

adProductBlocklist: Set[AdProductCategoryId]

Distributed via DData (AdProductBlocklistKey), this filter runs at auction time to exclude entire categories of ads (e.g., gambling, alcohol) from the publisher’s inventory.

Creative Deduplication

When merging new auction results with existing candidates:

mergedViews = (newCandidates ++ orphanedCreatives).distinctBy(_.creativeId)

This prevents the same creative from appearing multiple times, which would bias Thompson Sampling.