Design an Ads Frequency Cap system that limits how many times a specific ad (or category of ads) is shown to a user within a time window. The system must operate in an ad-serving environment where the read and write paths are separate — checking an ad's eligibility during bidding doesn't guarantee the ad will be served, so impressions are recorded asynchronously through event tracking.
This design challenge covers config management with advertisers, real-time frequency lookups during ad bidding, impression tracking, and handling per-user and per-ad caps at scale. Unlike a standard rate limiter, frequency capping must handle separated read/write paths, per-ad impression caps (not just per-user), and a config layer for advertiser-defined rules.
Advertiser config management -- allow advertisers to define frequency cap rules (e.g., show ad X at most 3 times per user per day)
Real-time frequency check during bidding -- during the ad auction, check if showing a specific ad to a user would violate the frequency cap
Asynchronous impression tracking -- record impressions after an ad is served, updating the frequency counters
Per-user and per-ad caps -- support limits like "user U can see ad A at most N times per day" or "user U can see at most M ads from campaign C per week"
Time window support -- enforce caps over rolling or fixed time windows (hourly, daily, weekly)
Low latency -- frequency checks during bidding must complete in single-digit milliseconds to not slow down the auction
High throughput -- handle millions of ad requests and impression events per second
Eventual consistency -- tolerate slight delays between impression recording and frequency counter updates (read/write path separation)
Scalability -- scale horizontally as the number of users, ads, and impressions grows
High availability -- graceful degradation if frequency cap service is unavailable (default to allowing or blocking ads)
Based on common interview patterns for ads systems and rate limiters, these are the areas interviewers probe most deeply:
Interviewers want to see that you understand the ad-serving context where bidding (read) and impression tracking (write) are decoupled.
During bidding, the system checks the current frequency count to decide if an ad is eligible
If the ad wins the auction and is shown, an impression event is sent asynchronously to update the counter
The frequency counter may be slightly stale during the read path due to eventual consistency
Discuss the trade-off between strict consistency (slower, more expensive) and eventual consistency (faster, cheaper)
Consider using a distributed cache (Redis) for fast frequency lookups during bidding
Interviewers expect you to design a flexible config system for advertisers to define frequency cap rules.
Config schema: ad ID or campaign ID, cap limit (e.g., 3 impressions), time window (e.g., 24 hours), user segment
Store configs in a database (PostgreSQL, DynamoDB) and cache them for fast lookups
Support multiple cap levels: per-ad, per-campaign, per-advertiser
Allow time window variations: rolling windows (last 24 hours) or fixed windows (calendar day)
Validate configs before activation to prevent invalid rules
Interviewers probe on how you store and update frequency counters at scale.
Use Redis or Memcached with keys like user:U:ad:A:day:2026-02-10 and increment on each impression
Set TTL on keys to match the time window (24 hours for daily caps)
For rolling windows, use sorted sets or time-series data structures
Handle high write throughput with sharding (shard by user ID or ad ID)
Consider batching impression events to reduce write load
Interviewers want to see how you optimize for low-latency reads during the ad auction.
Cache frequency counters in Redis with sub-millisecond read latency
Prefetch or pre-warm cache for active users and ads
Use asynchronous reads if the auction can tolerate slight delays
Fallback strategy if cache is unavailable: allow ads (optimistic) or block ads (conservative)
Bloom filters to quickly rule out users who have never seen a particular ad