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

Frequency Capping

Frequency capping limits how many times a single user sees ads from the same advertiser, preventing ad fatigue.

How It Works

Per-User, Per-Creative Caps

Each campaign can specify a frequencyCap: Option[Int] — the maximum number of impressions per user for creatives from that campaign.

Check Process

At serve time, before the pacing gate:

// 1. Filter candidates with frequency caps
val cappedCandidates = candidates.filter(_.frequencyCap.isDefined)

// 2. Group by advertiser
val byAdvertiser = cappedCandidates.groupBy(_.advertiserId)

// 3. Query each AdvertiserEntity for user impression counts
//    Timeout: 100ms, fail-open

// 4. Filter
filtered = candidates.filter { c =>
  c.frequencyCap match {
    case None      => true  // No cap, always eligible
    case Some(cap) =>
      val impressions = impressionCountsMap.getOrElse(c.creativeId, 0)
      impressions < cap
  }
}

Fail-Open Semantics

If the AdvertiserEntity doesn’t respond within 100ms:

On timeout → include all candidates from that advertiser

Why fail-open? Frequency capping is a quality optimization. The alternative (fail-closed) would mean network issues cause no ads to show. It’s better to occasionally over-serve than to block serving entirely.

Pipeline Position

Frequency capping runs after content recency but before the pacing gate and Thompson Sampling:

Content recency → Frequency cap → Rate tracking → Pacing gate → Thompson Sampling

Running before TS ensures:

  • TS never wastes exploration on capped candidates
  • The filtered pool may be smaller but TS works correctly with any size ≥ 1
  • If all candidates are capped, no ad is shown (NoCandidates)

Interaction with Pacing

Frequency capping and pacing are independent filters. A candidate must pass both:

Candidates → Frequency Filter → Pacing Gate → Thompson Sampling

Running frequency cap first reduces the number of candidates the pacing gate needs to evaluate.