Engineering

Contextual targeting without cookies: how we rebuilt our context engine

Animated: a bid request arrives carrying only an app ID, with no page URL and no cookie. It reaches the bidder, which makes a single lookup into a shelf of pre-computed verdicts, one card per site or app; the matching card lights up and the bidder answers with what the app is about. Below, more slowly, a context engine reads store listings and pages ahead of time and keeps adding cards to the shelf. Caption: all the reading happens before the auction; the bid does one lookup.

Contextual targeting means placing an ad next to the right content rather than following a person around the internet. We rebuilt ours so that every ad decision knows what a page or app is about — instantly, and without a single piece of personal data. This is what we inherited, what we changed, and why, in plain English.

The problem: context without the page

Contextual targeting promises relevance without tracking people: show the cricket ad next to the cricket story. The textbook version reads the page and classifies it. Our traffic does not cooperate with that version.

When we measured our own bid stream, most requests came from mobile apps, and the large majority carried no page URL at all. An app sends an ID, sometimes a name, and occasionally a few category labels. A system that waits for page text before it can decide anything cannot decide anything for most of our inventory.

Animated bar chart: a long bar for in-app requests, which carry an app ID and no page URL, and a short bar for web requests, which carry a page URL. Inside the long bar a hatched segment shows the minority of in-app requests that also declare a content category. Caption: most requests arrive with no page to read. Proportions illustrative.

What a bid request actually carries, from our own bid stream. Proportions are illustrative; the point is the shape, not the share.

The second constraint is time. An ad auction gives a buyer a few hundredths of a second to answer, and our own share of that is a few thousandths. Nothing that reads a page, and no AI model, can work inside that window. So the real question was never “how do we classify content”. It was: how do we know what a site or app is about before the request arrives, and look it up instantly when it does?

What we learned from the prototype we inherited

We started from a capable prototype: advertisers wrote a “brand blueprint” in plain words — where their brand belongs — a crawler fetched pages, and an AI model judged each page against the blueprint. The product idea was right. Its design made it slow, costly and blind to most of our traffic.

Design problemWhat it causedOur fix
Web pages onlyApps — most of our traffic — were invisibleProfile apps from their store listings: by exact ID where the store offers a lookup, otherwise from the name, with a person confirming the match before it counts
Every blueprint re-read every pageCost grew with pages × blueprintsProfile each page or app once; score many blueprints against the profile
The model saw about a paragraph of each pageJudgements rested on one paragraphOne structured profile per page, from the whole article up to a sensible cap
“Top URLs” had no orderingBusy inventory was skipped at randomRank by real bid requests from our own bid stream
A page fetcher that looked like a browser rather than a crawlerSites could block it, and it isn't how we want to crawlA crawler that says who it is, respects the rules sites publish for crawlers, and paces itself
Results lived outside the auctionMatches could not steer our own bidsAn instant look-up inside the bidder itself
Language, topic and tone came from a separate systemThe product could not stand on its ownThe engine works out language, topic and tone itself

Seven design problems in the prototype, what each one cost, and what replaced it. The prototype and its authors are deliberately not named.

The architecture: understand offline, look up online

The picture at the top of this post is the whole design. The bidder — the part of our system that decides whether to buy an ad — never reads a page or calls an AI model. The context engine does that work ahead of time and leaves a short verdict for every site and app it has seen: what it is about, which standard content categories that maps to, and the keywords the judgement rested on. When a request arrives, the bidder simply looks the verdict up. The dashboard only stores what people ask for and shows what the engine found.

  1. Offline, slowly: the engine ranks sites and apps by how often they actually appear in our bid stream, so the busiest inventory is understood first.
  2. Offline, slowly: each one is profiled once — an app from its store listing, a website from its pages — into a short, structured description and a verdict.
  3. Offline, slowly: where the machine is unsure, the candidate goes to a person for review, and a reviewed decision can never be overwritten by a later automatic run.
  4. Online, instantly: a request arrives with an app ID or a website address; the bidder looks up the verdict and checks it against each campaign's rules. If nothing is known yet, it carries on rather than fail — a slow or empty store can never cost us a bid.

Five design decisions that made it work

  1. Understand offline, look up online. All reading and reasoning happens before the auction; the bidder does one quick look-up per request. It is also the only arrangement in which an AI model can take part at all, because asking a model takes far longer than a bid is allowed to.
  2. Profile once, score many times. Each page or app gets one structured description: a summary, its language, its standard categories, topics, keywords, likely audience and brand-safety risk. A new advertiser blueprint is scored against the cached profiles, so it needs no new crawling. Content costs scale with inventory, not with the number of advertisers.
Animated: before, a grid of four pages across four advertiser blueprints fills with sixteen red dots, one model reading per cell, so cost grows with pages times blueprints. After, each page is read once into a single teal profile and the four blueprints are scored against those profiles with thin lines, no new reading. Caption: content cost scales with inventory, not with the number of advertisers.

The cost shape of the prototype against the rebuild. The grid on the left is what made the prototype expensive; the column on the right is why a new advertiser costs almost nothing to add.

  1. One name for every page and app, shared by every part of the system. A web address can arrive in many spellings, and an app as an ID, a store link or a number. We agreed one standard way of writing each, built it identically in every part of the system, and test them all against the same examples — so no two parts can ever disagree about which page they are talking about.
  2. Speak every taxonomy, think in one. The ad industry has a standard list of content categories — a taxonomy — and it exists in several versions, which different exchanges use. We translate every version into one internal list before any rule runs, with reviewed corrections where the official mapping leaves a sensitive topic unmapped. Without that step, a sensitive topic labelled under a newer version could pass a block written against an older one.
Animated: three labels for the same sensitive topic arrive in three taxonomy versions. Without translation, a block rule written against one version would let the newer label slip past, shown in red. Then a translator converts every version into one internal label before the rule runs, and all three are stopped in teal. Caption: translate first, then judge.

Translate first, then judge. One rule holds across every taxonomy version an exchange sends.

  1. Keep the decision instant. Fetching a campaign's settings from shared storage on every request took tens of milliseconds in our benchmark — most of the time a bid is allowed. Keeping a short-lived copy in memory brought it to well under a millisecond. Translating a category label takes a few billionths of a second.
Shared store tens of ms
In memory < 1 ms
the whole bid decision has to fit inside a few milliseconds

Time to fetch a campaign's settings per request, in our benchmark: reading from shared storage against a copy kept in memory. Shown as a proportion, not a figure; lab results, not production.

Two smaller rules matter as much. A human decision always outranks a machine one, so an automatic run can never overwrite a verdict a person has reviewed. And text from pages is treated strictly as information, never as instructions to the AI model — a page cannot talk its way into a category.

What it gives each side

ForWhat changes
AdvertisersDescribe where your brand belongs in plain words; see which sites and apps match, and why, before spending.
AdvertisersBrand safety that holds across every taxonomy version an exchange sends.
AdvertisersTargeting that works without cookies or device IDs: the context engine looks at the site or app, never the person, and uses no personal data.
Ad opsEvery decision is explainable: a match carries its reasoning, keywords and confidence.
Ad opsDisagree with a result, and the blueprint is refined and re-run on the same inventory.
Ad opsCoverage and lookup pages show what the bidder knows about any site or app.
The businessApps — most of our traffic — are now addressable by context.
The businessLow running cost: content is profiled once and reused by every advertiser.
The businessNo change to auction speed: the decision is still an instant look-up.

Where we are, and what comes next

The pieces inside the bidder are live: category translation, website matching that can't mistake one site for another with a similar name, category checks for in-app inventory, and the in-memory copy of campaign settings. The first product phase — Explore and brand blueprints — is built and tested and is being rolled out now.

  1. Explore and blueprints (rolling out): describe a context, get the matching sites and apps, with the reasoning.
  2. Analysis: scoring whole inventories at once, seeing which topics and keywords appear together, exports, and a record of every judgement.
  3. Planning: reach per blueprint by country, language and category, with trends and recommendations that cite their numbers.
  4. Activation: blueprints used directly as targeting in our own bidder, and shared as audiences with partner exchanges.

We will publish results — match precision against human review, and the effect on campaign outcomes — once each phase has run long enough to measure them honestly. This post claims neither, because neither has been measured yet.

The lesson that travels

Do the expensive thinking before the question is asked. A system that has to understand the world inside the request is slow and blind to anything it can't read in time; a system that understands the world in advance only has to remember. Most of this rebuild was moving work from the moment of the bid to the hours before it.

For what contextual targeting is and why it is having a renaissance, see AI contextual targeting and contextual versus audience targeting. For where the bidder sits in the wider platform, see the architecture post.

A note on numbers

Traffic shares are described in words on purpose — “most”, “the large majority”, “a minority” — and the chart's proportions are illustrative. The timings are from our own benchmarks, not production measurements, and are given as proportions rather than figures. No accuracy or campaign-performance claims are made, because none have been measured yet; they will be published when they have. The prototype we inherited and the company that built it are not named. We do not publish our supply partners' names, our traffic volumes, the categories or keywords behind any specific decision, or any client or advertiser data. The industry content taxonomy referred to is published by IAB Tech Lab, named here only as its publisher. This describes our own platform and is not advice for yours.

Sources

A
AdZoic team
Making ad buying make sense, from Dhaka.
Keep reading

Related reading

Animated: words from an article flow into an AI reader that lights up topic tags and a matching ad clicks into placeTargeting

AI contextual targeting: how machines read a page

The methods (NLP, embeddings, sentiment, multimodal), what the public research says, and the philosophy behind our approach — no cookies needed.

Aug 2026 · 9 min read
Venn diagram: page content on one side, a person on the otherTargeting

Contextual vs. audience targeting — and when to use each

Two ways to reach the right people, no third-party cookies required. Here's how they differ and how to combine them.

Jun 2026 · 5 min read
Animated: ad requests stream through ingress, Go bidder and cache-plus-models layers into a bid decision inside the auction deadlineEngineering

Inside adZoic: the architecture behind millions of ad decisions a day

Our stack, system design, security posture and scaling approach — shared openly, with a diagram and honest numbers.

Aug 2026 · 8 min read

← Back to all posts