Ad fraud is not usually discovered. It is reported, by the same systems that are being defrauded, and by then the budget is spent. The structural problem is that the platforms and networks serving your ads are also the source of the numbers you use to judge them, so anything that goes wrong inside that loop is invisible from inside it.
Independent detection means checking what actually happens when a real user in a real place loads the page, and doing it continuously rather than in a quarterly audit. Here is what that involves in practice.
What you are looking for
Fraud takes several shapes, and each leaves a different signature, which matters because your detection has to be looking for the right thing.
Domain spoofing misrepresents where the ad ran, so an impression billed against a premium publisher actually served on a low-quality site. The signature is a mismatch between the reported placement and the page your own check found.
Ad stacking and pixel stuffing hide multiple ads on top of one another, or render them in a space too small to see, so impressions are counted for ads no human could have viewed. The signature is geometric: an element with real dimensions in the reporting and effectively none on the page.
Geographic misrepresentation bills traffic as coming from a market it did not come from, which matters when you paid a premium for that market. The signature only appears if you check from inside the market.
Invalid traffic is machine-generated impressions and clicks dressed as human. The signature is behavioural and statistical rather than visible in any single check.
Creative and landing-page issues sit alongside outright fraud: the wrong creative, an expired offer, a broken landing page, or a competitor’s ad in an exclusivity slot. Not fraud in the legal sense, but the same money wasted, and detected by the same mechanism.
Why detection requires real vantage points
The core mechanic is simple to state. Ad delivery is targeted, so what serves depends on who appears to be asking: their country and city, their device, their language, and often their apparent history. To see what a user in São Paulo on a phone sees, the request has to look like it came from that person.
That is why datacenter traffic cannot do this job. Ad platforms and fraud operators both treat known hosting ranges differently, so a check from a cloud region may be served a clean, generic version of the page while the fraud continues for real users, or be blocked outright. The result is a verification system that reports everything is fine.
Residential exits make each check look like an ordinary visitor from the market being checked, which is the entire basis for ad verification proxies as a category. The address selection matters as much as the geography, since a flagged or datacenter-adjacent address gets a different experience, per what IP reputation is and spotting datacenter IPs sold as residential.
Coverage across markets
If you buy in many countries, you have to check in many countries, and the honest constraint is that coverage is per market rather than global. A network spanning 195 countries makes that a configuration question, and the practical work is deciding where to sample and how often, since checking everywhere continuously is neither necessary nor affordable.
A reasonable allocation weights three things: spend, so the markets taking most of the budget get most of the checks; risk, so markets or partners with a history of discrepancies get more; and change, so new campaigns and new placements are sampled heavily at launch and then tapered. Where a campaign is city-targeted, the check has to be too, per city-level targeting, and availability varies by market in ways worth knowing before you promise global coverage, per country availability.
What “real time” actually means here
Real time in this context is not sub-second. It means the loop closes fast enough that you can stop the spend before it matters, which for most programmes is minutes to a couple of hours rather than the next monthly report.
Four things determine whether you hit that.
Sampling frequency, which is the dominant factor. Continuous sampling across a rotating set of placements beats an exhaustive sweep once a day, because it bounds how long a problem can run undetected.
Detection latency, meaning how quickly a check completes and is evaluated. Residential requests are slower than datacenter ones, so budget for that and keep the checks lean, per reducing latency.
Evaluation, which should be automatic. A screenshot nobody looks at is not detection. Comparison against expectations has to run in code.
The action. Detection that ends in a dashboard is monitoring; detection that pauses a placement or opens a ticket is a control. Decide in advance which findings trigger which response.
Building the loop
The shape is the same regardless of scale.
Start from an expectation, since you cannot detect a discrepancy without one. For each placement you should know the domain it is supposed to run on, the creative that should render, the market it is targeted to, and the landing page it should reach.
Then check from the market, capturing enough evidence to act on: the resolved page, the ad element and its actual rendered dimensions, the creative, the landing URL after redirects, and a screenshot. Evidence matters because the output of this system is often a conversation with a partner about money, and a claim without a capture is an opinion.
def check_placement(placement, country, city=None):
ctx = browser_context(country=country, city=city) # residential exit
page = ctx.new_page()
page.goto(placement["url"], wait_until="networkidle")
ad = page.query_selector(placement["selector"])
box = ad.bounding_box() if ad else None
return {
"found": ad is not None,
"visible": bool(box and box["width"] > 1 and box["height"] > 1),
"dimensions": box,
"creative": ad.get_attribute("src") if ad else None,
"final_url": page.url,
"screenshot": page.screenshot(),
"market": {"country": country, "city": city},
"checked_at": now(),
}
Then compare against the expectation and classify: ad absent, ad present but effectively invisible, wrong creative, wrong domain, wrong market, or landing page broken. Each maps to a different response, and the classification is what makes the alerting actionable rather than noisy.
Finally, watch your own collection health, because a market that quietly stopped returning results looks exactly like a market with no problems. That distinction is the difference between a verification system and a false sense of security, and it is the discipline in monitoring proxy health at scale.
Keeping it honest
Two constraints worth being explicit about.
This is measurement, not interference. Verification means observing what is served, not clicking ads to test them, generating impressions, or anything that would itself distort delivery or spend. Pace politely so your checks are a rounding error against real traffic rather than a load on the publishers you are verifying.
And treat findings as evidence to be reviewed rather than verdicts. A missing ad can be a legitimately unfilled slot, a geographic mismatch can be a targeting change nobody told you about, and a wrong creative can be a flight that rotated. The value is in the pattern and the capture, which is what makes the partner conversation productive.
The bottom line
You cannot detect ad fraud from inside the system reporting it, so detection means independent checks from real user vantage points in the markets you buy. Know what each fraud type looks like, because the check has to be looking for the right signature: a domain mismatch, an element with no real dimensions, a market that does not match, a creative that should not be there. Sample continuously and weight coverage by spend, risk and recency rather than trying to check everything. Capture evidence, because the output is usually a conversation about money. Automate the comparison and attach an action to each classification, and monitor your own collection so a silent market is not mistaken for a clean one.
The vantage points are the part that cannot be improvised: ad verification proxies put each check in the market it belongs to, running on residential proxies with country and city targeting and per-GB pricing that suits a continuous sampling programme.