Financial & Trading
Design Google Ads
01
What the ad system must do
What the ad system must do
Focus on search ads: a user types a query, a few sponsored results appear above and below the organic ones, and the advertiser pays only when someone clicks. Display and video ads share most of the machinery and can be mentioned at the end.
- Advertisers create campaigns with keywords, a maximum cost per click, a daily budget, ad text, landing pages and targeting by location, language, device and schedule.
- For each eligible query, pick which ads to show and in what order through an auction that weighs bid against expected usefulness.
- Charge per click at a price set by the auction, never more than the advertiser's maximum bid.
- Spread each campaign's daily budget across the day and stop serving when it is spent.
- Filter invalid clicks (bots, accidental double clicks, competitors clicking repeatedly) and do not bill for them.
- Report impressions, clicks, cost and conversions per campaign, keyword and hour.
- The ad decision fits inside the search page's budget: about 60 ms server-side at p99. If ads are late, the page renders without them.
- Every valid click is billed exactly once. Billing errors erode advertiser trust faster than anything else.
- Daily spend stays within a small, published tolerance of the budget.
- Bid and budget changes take effect within a minute or two.
- Reports are available within a few hours, with final, invoice-grade numbers after invalid click review.
Ask whether this is search ads, display ads bought through exchanges, or both, because display brings real-time bidding with outside buyers. Ask whether billing is per click or per impression. And ask how strict budgets must be: "never overspend by a cent" and "close enough over a day" are very different systems.
02
Sizing the ad system
Sizing the ad system
Assume 100,000 search queries a second on average and 250,000 at peak, with about 65% commercial enough to run an auction. There are 30 million active campaigns holding about 2 billion keywords between them.
| Quantity | Working | Result |
|---|---|---|
| Auctions at peak | 250K x 65% | about 160,000 / s |
| Candidates per auction | keyword matches after targeting filters | a few hundred to a few thousand |
| Model scorings at peak | 160K auctions x 300 candidates after pre-filter | about 48M click predictions / s |
| Ads shown per auction | average after reserve thresholds | about 3 |
| Clicks per day | 100K x 65% x 3 ads x 3% click rate x 86,400 s | about 500M |
| Click rate | 500M / 86,400 s | about 5,800 / s average |
| Invalid clicks | assume 10% of raw clicks | about 50M a day not billed |
| Impression log | 160K x 3 ads x about 400 B, average load lower | roughly 10 TB a day |
| Keyword index | 2B keyword entries x about 120 B | about 240 GB, replicated in every serving region |
| Budget state | 30M campaigns x about 200 B | about 6 GB |
The striking number is tens of millions of click predictions a second, each inside a 60 ms window. That pushes toward cheap pre-filters and a compact model served next to the auction. The billing side is modest in rate but must be exact, which is a completely different engineering style.
03
API design
API design
The click URL carries the price that the auction already computed, signed so it cannot be edited. When the click arrives, billing does not need to rerun anything: it validates the signature, deduplicates, and records the charge. That decouples billing from the serving path entirely.
04
Architecture overview
Architecture overview
flowchart LR
SF["Search frontend"] --> AS["Ad server"]
AS --> KI[("Keyword index shards")]
AS --> PM["Click prediction model"]
AS --> BP["Local pacing state"]
BP <-->|"spend leases"| BS[("Budget service")]
AS -. "impressions" .-> K[["Kafka: impressions and clicks"]]
U["User clicks ad"] --> CS["Click server"]
CS --> K
K --> IV["Invalid click filter"]
IV --> LED[("Billing ledger")]
IV --> BS
LED --> RPT[("Reporting warehouse")]
ADV["Advertiser UI and API"] --> CM[("Campaign DB")]
CM -. "change stream" .-> KIThere are two very different halves. The serving path answers "which ads, in what order, at what price" for every query, under a strict deadline, and is allowed to be approximate about budgets. The money path turns clicks into charges, is allowed to take minutes or hours, and must be exactly right. They share an event stream and the budget service, and nothing else.
Campaign edits land in a relational database and flow out through a change stream that updates the keyword index in every region within a minute or two. Ad servers are stateless apart from caches: they read index shards, call the prediction model, consult local pacing state, run the auction and log the impressions they served.
An inverted index from normalised query terms and phrases to ad groups, with targeting attributes alongside, so geo and device filters run during retrieval rather than after it. Sharded by ad group, fully replicated per region.
Predicts the chance that this user clicks this ad in this slot for this query. A large sparse logistic or neural model trained continuously on impression and click logs.
Holds authoritative spend per campaign, sharded by campaign id, and hands ad servers small spend leases plus a pacing rate so they rarely need to call it.
A tiny redirect service that logs each click durably and then redirects. Downstream, filters drop invalid clicks and an append-only ledger records every billable charge and every credit.
05
Deep dive: ranking, pricing and pacing
Deep dive: ranking, pricing and pacing
From a query to a shortlist
Retrieval has to go from 2 billion keywords to a few hundred plausible ads in a few milliseconds. The query is normalised (lowercased, spelling corrected, synonyms expanded) and looked up in the keyword index under each match type: exact, phrase and broad. Targeting attributes stored with each posting remove ads that cannot show here: wrong country, wrong language, paused, outside schedule, or flagged as out of budget by the local pacing state. A cheap first-stage score, built from historical click rate and bid, trims the survivors to about 300 before the expensive model runs.
Ad rank: bid times expected usefulness
If the highest bid always won, a casino ad would top a query about children's shoes. The auction instead ranks by ad rank = bid x quality, where quality is dominated by the predicted click rate and adjusted for relevance and landing page experience. Multiplying bid by click probability gives expected revenue per impression, so ranking by it maximises revenue and, because irrelevant ads are rarely clicked, it also keeps the page useful. An ad must also clear a reserve threshold of ad rank for its slot, which is why some queries show no ads at all.
What the winner pays
Search ads typically use a generalised second-price rule. Each advertiser pays the smallest amount that would still have kept their position: the ad rank of the ad just below, divided by their own quality, plus a minimum increment. A better ad therefore pays less for the same slot than a worse one, which rewards relevance directly.
A worked case: ad A bids 40 with quality 0.05 (rank 2.0), ad B bids 60 with quality 0.025 (rank 1.5). A wins the top slot despite the lower bid, and pays 1.5 / 0.05 + 0.01, about 30.01 per click. Be precise in an interview: with one slot this is a Vickrey auction and bidding your true value is optimal, but with several slots GSP is not strictly truthful. That is fine in practice, and it is a good detail to know.
Pacing a budget across the day
A campaign with a 25,000 daily budget on popular keywords could spend it all by 9 a.m. if it entered every auction. Advertisers want presence all day, so the system throttles participation. Every minute, the budget service compares actual spend against a target curve shaped like the campaign's expected traffic for the day, and publishes a participation probability: 1.0 when behind, dropping toward 0.2 when ahead. During retrieval the ad server rolls a die per campaign and skips it if the roll is above that probability.
Exact accounting cannot happen on every auction, because a central counter per campaign would see thousands of writes a second for big advertisers. Instead each ad server holds a spend lease: permission to spend, say, 0.5% of the remaining budget before checking in. When its lease runs out it asks for another, and when the campaign is nearly exhausted, leases shrink so the overshoot is bounded by the leases outstanding. Clicks arrive after impressions, so a small overshoot is unavoidable; the platform absorbs it or caps it with a published tolerance.
flowchart LR
CL["Billable clicks"] --> SP["Spend so far per campaign"]
SP --> CMP{"Ahead of target curve?"}
CMP -->|"yes"| DN["Lower participation probability"]
CMP -->|"no"| UP["Raise participation probability"]
DN --> PUB["Publish rate and lease size"]
UP --> PUB
PUB --> AS["Ad servers throttle auctions"]
AS --> CLCounting clicks once, and only the real ones
The click server checks the token's signature and age, writes the event to Kafka, and redirects. The token's id is the deduplication key: a double tap or browser prefetch creates two events with the same id, and the billing consumer keeps the first. Streaming filters then remove clicks that are plainly invalid, such as rapid repeats from one device, known data centre IPs, or impossible timing between impression and click. A slower batch analysis runs hours later over the whole day, finds subtler patterns such as click farms spread across many IPs, and issues credits. The ledger is append-only: a credit is a new negative entry, never an edit.
06
Tempting shortcuts to avoid
Tempting shortcuts to avoid
| Shortcut | Why it hurts | Better |
|---|---|---|
| Highest bid always wins | Irrelevant ads take the top slot, users learn to ignore ads, and click rates fall for everyone. | Rank by bid times predicted usefulness and set a quality floor per slot. |
| Winner pays its own bid on search ads | Advertisers keep lowering bids to find the cheapest winning price, so bids churn and revenue becomes noisy. | Charge the minimum price that holds the position, which removes most of that probing. |
| Check a central budget counter on every auction | Hundreds of thousands of synchronous calls a second land on the busiest campaigns' shards. | Spend leases and a pacing probability, refreshed every minute. |
| Compute the price when the click arrives | The auction context is gone by then, and billing becomes coupled to serving. | Price at auction time and sign it into the click token. |
| Bill raw clicks and refund later on request | Advertisers discover the bot traffic themselves, and trust is gone before the refund arrives. | Filter in the stream before billing, then credit automatically after batch review. |
| Edit ledger rows when correcting charges | Invoices stop matching history, and audits become archaeology. | Append credits and adjustments as new entries. |
07
Decisions and their costs
Decisions and their costs
Stable prices, rewards for relevance, and pricing that is easy to explain on an invoice. It is not perfectly incentive-compatible across several slots, and its revenue depends heavily on well-tuned reserve thresholds.
Standard for search adsSimple and transparent per auction, and what most display exchanges moved to. Buyers then need their own shading algorithms to avoid overpaying, which shifts complexity onto them.
Common in displayNo synchronous budget call per auction, smooth delivery through the day, and bounded overshoot. Spend is only approximately right at any moment and must be reconciled from clicks.
Scales with trafficExact on paper, but it adds a network hop to every auction and creates hot shards for large advertisers. It still cannot be exact, because clicks arrive after the auction.
Cost without the benefitA cheap first stage cuts thousands of candidates to hundreds, and the expensive model only scores those. Some good ads are cut early, so the first stage needs its own monitoring for recall.
Fits the latency budgetBest possible ranking, at several times the compute. It might fit on low-traffic markets, but not at peak global load.
Too expensive at peakObvious fraud is never billed, and subtle fraud is credited within a day. Reports change slightly after they first appear, which needs clear labelling of provisional and final numbers.
Fast and thoroughNumbers never change after they appear, but coordinated click farms that only show up in a day of data slip through and are billed.
Misses organised fraud08
Failure modes
Failure modes
A bad deploy takes the budget service down for ten minutes. Ad servers cannot renew spend leases.
Ad servers keep serving on their current lease and last pacing rate, then stop serving a campaign when its lease is used up. Overspend is bounded by outstanding leases, and campaigns resume automatically when the service returns.A training pipeline bug ships a model that predicts nearly the same click rate for every ad. Rankings collapse to bid order and irrelevant ads rise.
Canary new models on a small slice and compare predicted against observed click rates and revenue per query. Roll back automatically when calibration drifts. Keep the previous model loaded for instant fallback.A consumer restarts after processing a batch but before committing its offset, and replays several thousand clicks.
The ledger write is keyed by click id with a uniqueness constraint, so a replay is a no-op. Exactly-once billing comes from idempotent writes, not from the queue.A slow index shard pushes ad selection past 60 ms. Without a guard, search pages would wait for ads.
The search frontend never waits past its deadline and simply renders without ads. The ad server fans out to shards with hedged requests and runs the auction on whatever answered in time.Thousands of residential IPs click one advertiser's ads at a plausible pace, burning its budget by mid-morning.
Detect concentrated click rates per advertiser against its history, look for shared device and behaviour fingerprints, and credit affected spend. Pace budgets so a morning attack cannot consume the whole day.The change stream lags for an hour. A paused campaign keeps serving and an advertiser's urgent bid cut does not take effect.
Alert on index freshness per region. Push pauses and budget stops through a fast separate channel to ad servers, and do not bill clicks for a campaign after its recorded pause time.09
How to run the interview
How to run the interview
Explain ranking with expected value. Bid times click probability is revenue per impression. Starting there makes quality feel inevitable, not arbitrary.
Work one pricing example out loud. Two ads, two qualities, one price. It shows you understand the formula rather than reciting a name.
Bring up pacing before you are asked. Many candidates forget that budgets need spreading. Probability throttling and leases are the senior answer.
Split serving from money. Approximate and fast on one side, exact and slower on the other, connected by events.
Treat click fraud as billing integrity. Advertisers pay for clicks; charging for bots is charging for nothing. Describe both the stream and batch layers.
Know where display differs. Real-time bidding sends bid requests to outside buyers under a 100 ms budget, which brings first-price auctions and much more traffic.
10
How the design grows
How the design grows
Advertisers buy a keyword for a fixed monthly fee, and a sales team manages the list. No auction, no pacing, no model.
Advertisers bid per click and the highest bid wins. Prices become unstable and irrelevant ads creep in.
Ad rank adds predicted click rate, and prices drop to what holds the position. Users click more and advertisers churn less.
Budgets are spread through the day, the budget service hands out leases, and invalid clicks are filtered in the stream and credited after batch review.
Advertisers set a target cost per conversion and the system bids per auction on their behalf. Display, video and shopping ads join through the same index and auction framework.
Watch and read
Further watching and reading
Try next
Free to read · better with landed
Whiteboard this with landed
landed runs it as a live system design round on the whiteboard and grades your trade-offs.