Malvertising does not compromise a publisher — it rents them. The creative is served correctly, the page loads correctly, and the reader arrives on a credential-harvesting form wearing your inventory's credibility. The destination domain is the one field in the whole transaction that maps cleanly onto a known-bad lookup.
Nothing is hacked. The supply chain works exactly as designed, and that is precisely what makes the attack economical.
A reader arrives at an article they trust, on a site they have visited for years, over a connection they have no reason to question. An ad slot fills. The creative renders. They click something that looks like a legitimate offer and land on a page that asks them to sign in to an account they genuinely hold. Every hop in that journey performed its function correctly. The publisher served inventory, the exchange matched a bid, the creative loaded from a CDN, the click tracker fired, and the browser followed a redirect. There is no compromised server anywhere in the chain — only a buyer who paid for attention and pointed it somewhere harmful.
The anatomy of a clean-looking incidentThat is what makes malvertising structurally different from most web threats an operations team deals with. It is not an intrusion, it is a purchase. The attacker's cost is measured in CPM rather than in effort, the targeting controls are the same ones legitimate advertisers use, and the delivery infrastructure belongs to companies with strong incentives to keep it fast and reliable. Perimeter thinking does not help here, because there is no perimeter to breach. The only meaningful control point is the decision to accept a buyer and the decision to approve where their creative sends people.
The damage is also asymmetric in a way that matters commercially. The advertiser paying for the placement is anonymous and disposable; the publisher carrying it is neither. When readers complain, they complain about the site they recognise. When a browser vendor or security tool flags the incident, the domain in the report is the publisher's. A network that lets bad demand through does not merely fail a security control, it spends its supply partners' reputation on someone else's fraud, and supply partners have long memories about that.
There is a second-order effect worth naming. Every incident of this kind strengthens the argument for blocking ads entirely, which is an existential cost the whole industry shares. Ad-ops teams generally understand this intuitively; what they often lack is a control that is cheap enough to run on every creative rather than on a sample, and specific enough that it does not generate a queue of ambiguous flags nobody has time to adjudicate. A per-domain known-bad lookup is unusually well suited to that role, because its answer is binary and its cost per answer is a fraction of a cent.
The rest of this page is about where in the pipeline that lookup belongs, what it can and cannot tell you, and how the arithmetic works at the volumes a real network handles. Related material sits in our notes on brand protection and media and publishing, both of which approach the same problem from the other end of the relationship.
Bid requests, creatives, tags and macros differ across every partner you integrate with. A hostname does not.
Almost everything in the programmatic stack is negotiable between partners. Creative formats vary, macro syntax varies, the fields present in a bid request vary by exchange and by protocol version, and the amount of information a reseller passes upstream varies with their appetite for transparency. Amid all of that, one value is consistently present and consistently meaningful: the domain the user ends up on. It is in the advertiser's onboarding record, it is in the creative's click-through URL, it is declared in the bid response, and it is observable at the end of the redirect chain. It is also exactly the shape of input a known-bad domain lookup accepts.
This matters because it lets you build one control that works everywhere instead of six controls that each work in one place. Whether a domain arrived from a self-serve signup form, a manually reviewed insertion order, an affiliate feed or a post-serve crawl, the check is the same call and the answer has the same meaning. The single-domain endpoint strips protocol and path automatically, so passing a full click URL is acceptable, though normalising to a bare host yourself gives you better cache behaviour and a cleaner audit record.
Be deliberate about which hosts you extract, because a creative usually references several. The landing page domain is the obvious one. The click-through URL frequently points at a tracker rather than the landing page. Impression pixels, viewability beacons and third-party verification tags all resolve somewhere. Attackers have historically abused each of these positions, so an extraction routine that only reads the declared landing page is doing perhaps a third of the available work.
Finally, treat subdomains carefully. Verdicts are per-domain, and an attacker who has been granted a subdomain on a shared platform is a different problem from an attacker who registered their own name. Record the exact host you checked alongside the verdict, so that six months later nobody has to guess whether the entry covered the apex, a subdomain, or a path that no longer exists.
The domain the advertiser puts on the record at onboarding and repeats in the bid response. The baseline check, and the one that ties a verdict to a contractual party.
Often a tracker rather than the destination. Check it in its own right, then follow it — the two hosts answer different questions and both belong in the record.
Affiliate trackers, geo-routers and rotators each add a host. Any one of them can be the malicious link in the chain while the endpoints look respectable.
Where the image, video or HTML5 bundle is served from. A creative loading executable script from an unfamiliar host is worth a look on its own merits.
Impression, viewability and conversion tags all resolve to hosts you accepted into the page. They deserve the same scrutiny as the click path.
The corporate domain on the account, the billing contact's email domain and any declared brand sites. Cheap to check once at signup, occasionally decisive.
Four stages, each with a different tolerance for latency and a different consequence for getting it wrong.
The temptation with any new signal is to put it at the front door and declare the problem solved. Advertiser onboarding is a genuine control point, but it is also the stage where an attacker has the most freedom to look respectable: the corporate domain is real, the billing details clear, and the landing page they submit at signup is not the one they intend to run. Onboarding checks catch the careless and establish a record. They do not catch the patient.
Creative approval is where the check earns most of its value, because it is the last moment at which a human decision is already happening and an extra few hundred milliseconds costs nothing. This is where you resolve the click path rather than trusting the declared destination, and where a positive verdict should stop the creative rather than annotate it. It is also where the record you write becomes useful later — the domain, the verdict, the timestamp and the reviewer, all stored against the creative ID.
Post-serve sampling exists because approval is a point-in-time judgement about infrastructure that can change. A creative approved on Monday can point somewhere different by Thursday without any change to the creative itself. Sampling a proportion of real impressions, resolving the destination as a real user's browser would, and checking the final host is the only way to notice that drift. Sample rates are a budget decision, and even a modest one catches sustained abuse quickly because campaigns need volume to be worth running.
Continuous reconciliation against the daily feed is the fourth stage and the cheapest one. Because the database rebuilds every 24 hours and lands at 04:30 UTC, a domain that was clean when you approved it can be catalogued days later. Joining your table of active advertiser domains against the day's feed is a query, not an integration, and it turns "we checked at approval" into "we check every day, forever".
Check the corporate domain, billing email domain and declared brand sites before an account can spend.
Resolve the click path, check every host in it, and block on a positive rather than annotating it.
Re-resolve destinations from real serving conditions at a sampled rate to catch changes after approval.
Join the whole advertiser domain table against each morning's build and its changelog of additions.
Cloaking is not an edge case in this space. It is the default operating assumption of anyone running malvertising at scale.
The mechanic is simple and very old. The server on the other end of the click looks at who is asking — the IP range, the user agent, the referrer, the time of day, whether the request arrives from a datacentre or a residential network, whether a real touch event preceded it — and serves one page to anything that looks like review infrastructure and a different page to everyone else. Your reviewer sees a tidy product landing page. A reader on a phone in the target geography sees a fake account-verification form. Both are telling the truth about what they observed.
This is why the submitted URL is the least interesting field in the record and the final resolved host is the most interesting one. An operator who cloaks has no reason to declare anything but a clean destination, and every reason to make the declared page genuinely benign so that it withstands scrutiny. The value of resolution is that it moves you one step closer to what actually happens, and the value of doing it from varied conditions is that it makes the cloaking decision harder to get right.
Practical advice, in rough order of leverage. Resolve from network paths that do not look like a review farm. Vary user agents and locales to match the campaign's targeting rather than your office. Cap the redirect chain at a sane hop limit and record every host you traverse, not just the last one, because rotators frequently insert a disposable domain in the middle while keeping both ends respectable. Never execute the destination's scripts on a machine that matters, and never let a reviewer open a suspect link on their own workstation — put the verdict in the queue instead, so the temptation does not arise.
Be clear-eyed about the limits of what a domain lookup contributes here. It cannot tell you that a page is cloaking, and it cannot classify a destination it has never seen. What it can do is answer definitively for the hosts that are already catalogued, which is a large and constantly refreshed population, and it can do so for every hop in the chain at a cost low enough that checking all of them is never the expensive part of the operation. Combine it with your own crawl evidence — differing content hashes between review conditions and serving conditions is a strong local signal that no external database can provide.
The final point is organisational rather than technical. Cloaking works because review is a single event and serving is continuous. Any programme that treats approval as the end of the process will be beaten by an operator who is patient enough to wait a week. Continuous reconciliation against a daily-refreshed database is the structural answer, and it is the reason the feed and the API complement each other rather than competing.
Most networks end up running all four. The table is about sequencing and expectations, not about picking a winner.
The comparison worth having is not "which of these is best" but "what does each one actually buy me, and what does it fail to catch". Onboarding is cheap and contractual. Approval is where blocking is legitimate and reversible. Sampling is where drift surfaces. Feed reconciliation is where yesterday's approval gets re-examined against today's intelligence. Each covers a failure the others miss, and the cost of running all four is dominated by whichever one touches the most distinct domains.
The first three rows involve a network call in a process where a few hundred milliseconds is unremarkable. The fourth involves no per-lookup call at all, because you already hold the list. That is the difference that decides architecture at scale: below a certain volume the API is simpler; above it, holding the feed locally and joining in your warehouse is both cheaper and faster.
| Screening point | What it catches | What it misses | Latency budget | Typical mechanism |
|---|---|---|---|---|
| Advertiser onboarding | Accounts opened on infrastructure already catalogued; repeat offenders returning under a new name | Operators who submit a clean domain and switch later | Human-scale — seconds are fine | Single /check per declared domain |
| Creative approval | Known-bad landing pages, trackers and intermediate hops at the moment of review | Destinations that change after approval; freshly registered hosts | Sub-second, inside an existing review step | Resolve chain, then /batch the hosts |
| Post-serve sampling | Drift after approval, geo-targeted swaps, rotator behaviour | Low-volume campaigns that fall below the sample rate | Asynchronous — minutes are acceptable | Sampled crawl feeding /batch |
| Daily feed join | Everything you approved yesterday that became known-bad overnight | Anything not yet in the database at build time | None — a local table join | Feed CSV or JSON loaded into the warehouse |
Ad ops care about what rendered on their pages. Networks and DSPs care about which buyer put it there. The same lookup serves both, on different inputs.
A publisher ad-ops team usually arrives at this problem after a reader complaint, and their question is retrospective and specific: what actually ran on our inventory, and was any of it pointing somewhere harmful. The input they have is a log of destinations observed by their own tag or verification vendor, often thousands of distinct hosts a week across every demand partner they work with. Running that list through the batch endpoint is a straightforward reconciliation job, and it converts an anecdote into a list of partners with names attached, which is the only form in which the conversation with a demand partner ever goes anywhere.
The demand-side view is prospective and contractual. A network, DSP or affiliate platform holds the relationship with the buyer, has a creative approval queue, and can suspend an account. Their input is the set of domains declared and resolved during review, keyed by advertiser. The same verdicts that give the publisher an argument give the network an enforcement basis, and because the underlying database is the same, the two parties are not arguing about whose tool is right — a useful property when money is involved.
Sponsored-content platforms and native widgets sit awkwardly between the two and generally have the hardest job. Their units are embedded directly in editorial layouts, which maximises reader trust, and their inventory is frequently filled by performance advertisers whose creative churn is high. If you run one of these, weight your effort towards approval-time resolution and a high post-serve sample rate, because the credibility you are lending is greater than a banner's and the recovery from a public incident is correspondingly slower.
Affiliate networks add one more wrinkle: the tracker chain is the product. Publishers are paid on clicks that pass through several hosts by design, so a long redirect chain is not itself suspicious and cannot be used as a heuristic. That removes a shortcut other platforms rely on and makes per-hop checking correspondingly more important. Teams running these systems often also read our notes on online marketplaces, where the same "our platform, their content" problem shows up in listings rather than creatives.
Batch the destination hosts your verification logs actually recorded, grouped by demand partner. The output is a per-partner incident list you can take to a QBR rather than a complaint you cannot substantiate.
Check at approval, keyed by advertiser ID, and store the verdict with the creative record. Suspension decisions then rest on dated evidence rather than on a reviewer's recollection.
Disputes between supply and demand partners usually stall on evidence rather than on goodwill. When both sides can point at the same domain, the same phishing/malware category, the same resolves DNS status and the same last_checked date, the argument moves from whether something happened to what to do about it. That is worth more than any single blocked impression. Keeping your own log of what you checked and when — not just what you blocked — is what makes the record usable months later during a chargeback or a partner review. The API documentation lists every response field, and the daily feed ships a changelog of additions and removals that gives the same record a longitudinal dimension.
The break-even between metered lookups and a feed subscription is easy to compute, and it usually arrives sooner than teams expect.
Start with the metered model. Credits are monthly subscription, one credit per domain lookup, billed monthly, and the packages run Starter $59 / 10,000 · Growth $99 / 25,000 · Professional $249 / 100,000 · Business $499 / 250,000 · Enterprise $999 / 750,000 · Enterprise Plus $999/month (Enterprise) / 2,000,000 · Scale $499/month / 5,000,000. The last of those works out to $0.0008 per lookup. Batch requests take up to 100 domains and bill one credit per domain, so batching improves throughput and reduces round trips without changing the price.
Now put a network's volume against it. Suppose you approve 40,000 creatives a month and each one resolves to an average of three distinct hosts across the landing page, the click tracker and one intermediate hop. That is 120,000 lookups before deduplication. In practice a large advertiser runs many creatives against a handful of domains, so distinct-host counts are far lower than creative counts — deduplicating within the month might leave 25,000 to 35,000 genuinely distinct hosts. At the Professional package, 100,000 credits for $249, a month like that costs well under a hundred dollars of credit and you have three months of runway in a single purchase.
Add post-serve sampling and the arithmetic shifts, because sampling generates lookups proportional to impressions rather than to creatives. Sampling one in ten thousand impressions on a billion-impression month is 100,000 resolutions, most of which land on hosts you have already seen. With a cache keyed on hostname and expiring against the 04:30 UTC rebuild, the billable portion collapses again. The rule of thumb worth internalising is that your bill tracks distinct hostnames, never events, and every layer of caching you add is a direct multiplier on that.
Past roughly a few million lookups a year, the calculation changes shape. The Daily Threat Feed is $499 per month, and it delivers the entire database as CSV or JSON with domain,category,dns_status columns plus a daily changelog of what was added and removed. Loaded into a warehouse table, it turns every question into a join against your advertiser domain table — no per-lookup cost, no rate limit, no network dependency in the hot path. The annual plan also includes a historical archive, priority support, custom format options, 100,000 API credits and a dedicated account manager. Enterprise delivery is custom and covers SFTP or S3 drops, STIX/TAXII, custom update frequency, an SLA and on-premise deployment.
The configuration most large networks end up with combines both. The feed lands each morning and is joined against every active advertiser domain, producing a daily list of accounts whose destinations became known-bad overnight. Credits cover the interactive path: a reviewer opening a specific creative, an appeal, a partner escalation, or a host that appeared after the last feed pull. Because both paths read the same database, the verdicts never disagree, which matters a great deal the first time an advertiser disputes one. Compare the packages on the pricing page if you need to size this against your own creative volume.
The configuration most large networks land onCount distinct destination hostnames seen in a representative week, multiply by 52, and add a one-off figure for your historical back catalogue. That number, not your impression count, is what you are buying.
Ten requests per second per API key and 100 domains per batch call. A batch-oriented approval pipeline comfortably fits inside that; an impression-triggered one does not, which is another reason sampling and feed joins are the right shapes for high-volume work.
Blocking an impression is the easy part. Defending the decision when the advertiser has spent five figures is where the record you kept starts to matter.
Every network that suspends accounts eventually meets an advertiser who disputes it, and the dispute is rarely about whether malvertising is bad. It is about whether this particular buyer did this particular thing on this particular date. Vague internal notes lose that argument. A dated record showing the exact hostname checked, the boolean returned, the category of phishing/malware, the DNS status of resolves and the last_checked date wins it, because it is specific, contemporaneous and reproducible.
Teams routinely persist a single boolean and then discover, months later during a payment dispute, that they cannot demonstrate what the system actually saw. Persist the domain, the full response body, the resolution chain that led you to that host, the creative ID, the advertiser ID and the reviewer or job that acted. Storage is negligible; reconstructing the reasoning after the fact is impossible.
Chargebacks add a financial dimension to the same requirement. When a network refunds a publisher or withholds payment from a buyer, the finance team needs an artefact they can attach to the case. A per-domain verdict with a date is exactly that kind of artefact — it is narrow, it is unambiguous, and it does not depend on anybody's judgement about the quality of a landing page. Combine it with your serving logs and you can bound the exposure precisely: these creatives, these placements, these dates.
Two operational details make the record materially stronger. First, log the clean results too. Being able to show that a domain was checked on the fifteenth and was not in the database, and was checked again on the twentieth and was, is what distinguishes a diligent programme from a lucky one, and it is often the difference in an appeal where the advertiser claims they were flagged arbitrarily. Second, keep the daily changelog from the feed. It gives you an independent timeline of when a domain entered the database, which supports the argument that you acted promptly rather than belatedly. Teams that already run a detection stack often route both into threat-intelligence tooling so the ad-side evidence lives beside everything else.
Never let a reviewer confirm a suspicious destination by opening it in a browser on a corporate machine. If a decision genuinely needs a human look, it needs an isolated environment. Putting the domain verdict directly into the review queue removes most of the reasons anyone would be tempted.
Short, concrete answers to the questions that come up before anyone writes code.
No, and you should not want to. An auction completes in low tens of milliseconds end to end, and there is no external network call that fits inside that budget reliably. The correct pattern is to materialise the answer before the auction: screen at creative approval, hold the daily feed locally, and have your bidder consult an in-memory structure. Rate limiting is 10 requests per second per API key, which is a further reminder that this is a control-plane tool rather than a data-plane one.
It means the domain is not in a database of DNS-verified, currently-resolving phishing hosts. That is a genuinely useful negative, and it is not a certificate of good behaviour. Newly registered infrastructure will not be catalogued yet, and a domain can be perfectly benign today and repurposed next week. Treat a clean result as "no known reason to reject", keep your existing review criteria intact, and let the daily feed reconciliation catch what changes after the fact.
Follow it server-side with a hop limit and a timeout, record every host you traverse, and check them all — a batch call takes up to 100 domains, so an entire review run's worth of hops usually fits in a handful of requests. Do not execute page scripts on a machine you care about, and do not rely on the submitted URL, which is the value an operator has the most control over. The final resolved host is the one that matters, but intermediate hosts are frequently the disposable part of the infrastructure and catch rotations early.
Very. Publishers usually have logs of destinations that actually rendered on their inventory, from their own tag or a verification vendor. Extracting distinct hosts from a week of those logs and running them through the batch endpoint produces a list of demand partners with specific incidents attached. That is the artefact that makes a conversation with a partner productive, and it is a few hours of work rather than a project.
Screening helps once the destination is catalogued, and it is the right control for the mechanical half of the problem. The other half — an ad that impersonates a brand while pointing at a domain nobody has reported yet — needs your own trademark and creative-review processes, because a domain-level lookup forms no opinion about the words in the creative or the logo in the image. Run both, and treat a phishing verdict as an escalation rather than the whole programme. Our brand-protection notes cover the other side.
The database rebuilds every 24 hours and the daily build lands at 04:30 UTC. Every domain is DNS-verified through rotating proxy infrastructure and only hosts with an active A record are included, so dead and parked entries fall out rather than accumulating. The /api/v1/stats endpoint reports database size and last update, is open, needs no key and consumes no credits, which makes it a convenient probe for a monitoring check that alerts if a build has not landed.
Start with the API, because you can buy a starter monthly plan and run a batch of your existing advertiser domains the same day, and the result tells you whether the problem is theoretical or already in your inventory. Move to the feed when the metered volume stops being trivial or when you want the checks inside your warehouse rather than over a network. Most large operators end up with both — the feed for the daily join and the bulk work, credits for the interactive and exception paths.
Pick a monthly plan, export the distinct destination domains from a single week of approvals or serving logs, and batch them through the check endpoint. It takes an afternoon, and the result is either reassuring or extremely actionable.