Overview
An ad server matches advertisers’ ads to available ad slots on publisher pages in real time. The two main models: direct (publisher sells inventory directly to advertisers at a fixed CPM) and programmatic (real-time bidding, RTB: advertisers bid for each impression in an auction lasting ~100ms). Google Display Network, Facebook Ads, and The Trade Desk use RTB. The components: a Supply-Side Platform (SSP, publisher-side), a Demand-Side Platform (DSP, advertiser-side), and an Ad Exchange that runs the auction between them.
Ad Request Flow (RTB)
User loads a page containing an ad slot. The publisher’s ad tag fires: it sends an ad request to the SSP with bid_request: {impression_id, publisher_id, page_url, ad_slot_size, user_id (cookie or device ID), geolocation, user_agent, floor_price}. The SSP fans out the bid request to multiple DSPs simultaneously (100ms deadline). Each DSP evaluates: does this user match any advertiser’s targeting criteria? What is the maximum bid for this impression? Returns bid_response: {bid_price, ad_markup}. The SSP runs a second-price auction (winner pays second-highest bid + $0.01). The winning ad markup is returned to the browser, which renders the ad. Total latency budget: 100ms end-to-end.
Targeting
Advertisers define targeting criteria: demographic (age, gender), geographic (country, city, zip), behavioral (retargeting users who visited the advertiser’s site), contextual (page content matches keywords), device (mobile, desktop), time of day, browser/OS. User matching: each user has a profile built from cookie data (browsing history, inferred interests, demographics). Stored in a user data platform (DMP): user_id → {segments: [sports_fan, tech_enthusiast], age_bracket: 25-34, location: NYC}. At bid time: the DSP loads the user profile from Redis (sub-millisecond lookup) and evaluates each active campaign’s targeting rules against the profile. Only matching campaigns generate bids.
Budget Pacing
Advertisers set daily budgets. If all impressions are served in the morning, the budget is exhausted and no ads run in the afternoon. Pacing: spread spend evenly across the day. Two approaches: throttling (set a probability P of bidding for each impression; adjust P to hit the target hourly spend rate), and target CPM bidding (the DSP dynamically adjusts bid prices down when ahead of pace, up when behind). Implementation: a pacing service runs every 5 minutes, computes each campaign’s ideal spend so far (budget * elapsed_fraction_of_day), compares to actual spend, and adjusts the bid multiplier. Store budget state in Redis: spend:{campaign_id}:{date} incremented on each win. Atomic INCR prevents race conditions.
Impression and Click Tracking
Impression tracking: when an ad is rendered, the browser fires a pixel (1×1 image) to the impression tracking URL: GET /impression?imp_id=XYZ&creative_id=ABC. The tracking server logs: {impression_id, campaign_id, creative_id, publisher_id, user_id, timestamp, bid_price}. Click tracking: the ad’s destination URL is wrapped: GET /click?imp_id=XYZ&url=https://advertiser.com. The click server logs the click, updates click count, and 302-redirects to the final URL. The redirect adds ~50ms but enables click attribution. Duplicate detection: SETNX imp_id in Redis with TTL=1 hour to deduplicate pixel fires from the same impression (browsers can fire pixels multiple times on slow connections).
Attribution
Attribution answers: which ad caused a conversion (purchase, signup)? Last-click attribution: credit the last ad clicked before the conversion. Multi-touch: distribute credit across all ads in the conversion path. Implementation: on conversion, the advertiser’s site fires a conversion pixel with the same user cookie. The attribution server looks up the user’s click history (last 30 days, stored in a clickstream table) and associates the conversion with the matching campaign. Report conversion counts back to the DSP for optimization. Privacy: third-party cookies are being deprecated. Modern attribution uses privacy-preserving APIs (Chrome’s Attribution Reporting API) and server-to-server postbacks using hashed email or phone as the match key.
Interview Tips
- Frequency capping: limit impressions per user per campaign per day. Track in Redis: INCR freq:{campaign_id}:{user_id}:{date} with EX 86400. If count > cap, skip the campaign for this user.
- Second-price auction: winner pays second-highest bid. Incentivizes truthful bidding (DSPs bid their true valuation). Vickrey auction theory.
- Cold start for new users: no behavioral profile. Use contextual targeting (page content) or lookalike modeling (match to similar known users).
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How does a second-price auction work in real-time bidding?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “In a second-price (Vickrey) auction, the highest bidder wins but pays the second-highest bid plus a small increment (e.g., $0.01). Advertiser A bids $2.00, Advertiser B bids $1.50 — A wins and pays $1.51. The key property: bidding your true valuation is the dominant strategy. If you bid above your valuation and win, you overpay (negative value). If you bid below your valuation, you may lose an impression worth more than what you would have paid. This incentive-compatibility reduces the need for sophisticated bid shading strategies and simplifies DSP optimization. In practice, many exchanges have moved to first-price auctions (winner pays their bid) due to concerns about unfair advantages for SSPs optimizing second prices. First-price requires DSPs to shade bids (bid below true valuation) to avoid overpaying.”
}
},
{
“@type”: “Question”,
“name”: “How do you implement frequency capping at scale?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Frequency capping limits the number of times a user sees an ad from a campaign (e.g., max 3 impressions per user per day per campaign). Implementation: Redis counter per (campaign_id, user_id, date). INCR camp:{cid}:user:{uid}:{date} and check if result <= cap. SET EXPIRE to 86400 (24 hours from midnight using a fixed key) or use the natural expiry of a daily key. At bid time: before generating a bid, check the frequency counter. If at or above cap, skip this campaign for this user. Scale challenge: with 1 billion unique users and 10,000 campaigns, storing all counters in Redis requires careful memory management. Only store active users (LRU eviction, 24-hour TTL). Probabilistic capping: for non-critical frequency limits, use HyperLogLog for approximate unique user counts per campaign — uses far less memory with ~0.8% error."
}
},
{
"@type": "Question",
"name": "How do you prevent click fraud in an ad server?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Click fraud: bots or malicious publishers generate fake clicks to drain advertiser budgets. Detection layers: (1) Duplicate detection: SETNX click:{imp_id} in Redis with TTL=24 hours. If key exists, reject the click (same impression cannot be clicked twice). (2) Velocity checks: more than 5 clicks from the same IP in 10 minutes u2192 flag. (3) User agent analysis: known bot user agents, headless browser fingerprints, missing or invalid JavaScript execution. (4) Time-between-events: click within 50ms of impression load (impossible for human). (5) Invalid traffic (IVT) scoring: Google IVT standards classify traffic as GIVT (general invalid, easily detected) and SIVT (sophisticated invalid, requires ML models on behavior patterns). Flag suspicious clicks for manual review; charge advertisers only for valid clicks. Refunds for confirmed fraudulent clicks are issued monthly."
}
},
{
"@type": "Question",
"name": "How does user targeting with behavioral segments work?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A Data Management Platform (DMP) builds user profiles from first-party data (publisher's own users) and third-party data (purchased from data brokers). Each user profile is a set of segment IDs: user A belongs to segments [sports_fan, male_25_34, tech_enthusiast, high_income]. Segment membership is stored in Redis as a bitset per segment (bit set = user is in the segment) or as a set of segment IDs per user. At bid time: load the user's segments. For each active campaign, check if the user's segments satisfy the campaign's targeting expression (e.g., sports_fan AND (male_25_34 OR male_35_44) AND geo=NYC). Targeting evaluation must be sub-millisecond. Pre-compute targeting matches: when a campaign's targeting changes, index it against segment combinations so bid-time matching is a simple lookup rather than expression evaluation."
}
},
{
"@type": "Question",
"name": "What is the difference between CPM, CPC, and CPA pricing models?",
"acceptedAnswer": {
"@type": "Answer",
"text": "CPM (Cost Per Mille): advertiser pays per 1000 impressions shown, regardless of clicks or conversions. Predictable for advertisers; risk is low conversion rate. Used for brand awareness campaigns. CPC (Cost Per Click): advertiser pays only when a user clicks the ad. Publisher bears the risk of low CTR. Used for performance campaigns where clicks signal intent. CPA (Cost Per Action/Acquisition): advertiser pays only when a user completes an action (purchase, signup). Publisher and DSP bear the conversion risk. Highest advertiser ROI certainty. RTB auctions typically clear in CPM, even for CPC/CPA campaigns — the DSP converts its target CPC or CPA to an equivalent CPM bid: expected CPM = target CPC * expected CTR * 1000. Getting CTR and conversion rate prediction right is the DSP's core competency."
}
}
]
}
Asked at: Meta Interview Guide
Asked at: Twitter/X Interview Guide
Asked at: Snap Interview Guide
Asked at: LinkedIn Interview Guide