NEW ScrapingAnt MCP for Claude Code, Cursor & Windsurf — try it free →
★★★★★ 5.0 on Capterra

Ad Verification API. Verify ads from every country. Not just your office IP.

The data infrastructure under your own ad-verification product. Residential IPs across 100+ countries render the ad your DSP says was bought, headless Chrome captures JS-bid creatives that corporate IPs never see, sticky sessions hold the same exit across a refresh-bound publisher walk.

Residential IPs · 100+ countries · headless Chrome · failed cost 0

# Render a publisher page from a German residential IP — capture the served creative.
$ curl 'https://api.scrapingant.com/v2/general' \
    --data-urlencode 'x-api-key=YOUR_KEY' \
    --data-urlencode 'url=https://publisher.example/article/123' \
    --data-urlencode 'proxy_country=DE' \
    --data-urlencode 'proxy_type=residential' \
    --data-urlencode 'browser=true'
# → fully rendered HTML — extract <img>/iframe creative URLs downstream.
# Capture the served creative in 10 markets — concurrent calls, one credit each.
from concurrent.futures import ThreadPoolExecutor
import requests, hashlib

MARKETS = ["US", "DE", "FR", "BR", "JP",
           "IN", "GB", "AU", "MX", "NL"]

def capture(country):
    r = requests.get("https://api.scrapingant.com/v2/general", params={
        "x-api-key": "YOUR_KEY",
        "url": "https://publisher.example/article/123",
        "proxy_country": country,
        "proxy_type": "residential",
        "browser": "true",
    })
    return country, hashlib.md5(r.text.encode()).hexdigest(), len(r.text)

with ThreadPoolExecutor(max_workers=10) as ex:
    for country, sig, size in ex.map(capture, MARKETS):
        print(country, sig, size)  # diff sig across markets to flag mismatches
// Two markets, same URL — diff the served creatives.
import fetch from 'node-fetch';

async function render(country) {
  const res = await fetch(
    'https://api.scrapingant.com/v2/general?' +
    new URLSearchParams({
      'x-api-key': KEY,
      url: 'https://publisher.example/article/123',
      proxy_country: country,
      proxy_type: 'residential',
      browser: 'true',
    })
  );
  return await res.text();
}

const [de, br] = await Promise.all([render('DE'), render('BR')]);
// extract <img> src+alt from each, diff to flag geo-mismatched creatives.
your-ad-verifier — VERIFY · campaign-2026-q2 · 10 markets 8/10 creatives served correctly · 2 mismatches flagged DE · served JP · served FR · wrong BR · empty — mismatch rows publisher.fr/article/421 served EN creative, expected FR · proxy_country=FR geo-mismatch publisher.br/coluna/77 ad slot empty · creative timed out · proxy_country=BR no-impression publisher.de/wirtschaft/9912 DE creative served at 728×90 · proxy_country=DE match residential render · per-country · one endpoint
publisher.example/article/123 proxy_country=DE · creative: kfz-versicherung-728x90 DE publisher.example/article/123 proxy_country=JP · creative: tokyo-housing-300x250 JP publisher.example/article/123 proxy_country=BR · creative: ecommerce-br-336x280 BR publisher.example/article/123 proxy_country=AU · creative: melb-tourism-320x50 AU one URL · 100+ markets · per-call routing
Per-country rendering, no VPN tooling

Same URL, every country. Different creative each time.

Verifying a campaign means rendering the publisher page from a real viewer in each target market — not the one IP your verification box happens to have. proxy_country=DE hits the publisher from a German residential exit; JP, BR, AU from theirs. Same key, no per-region credential management, no VPN cluster to maintain. Pair with proxy_type=residential on inventory that filters datacenter ranges.

  • 2M+ real residential IPs — country, state, city granularity via the username parameter
  • City-level routing for sub-market campaign QA (DE-Berlin vs DE-Munich)
  • Datacenter pool for inventory that accepts it — flip proxy_type=residential per-call
HTTP fetch no bid ad slot empty JS auction skipped creative invisible browser=true served creative in DOM 728×90 banner advertiser captured extract your ad pipeline JS-bid creatives only render in browser=true
HTTP fetch ≠ rendered ad

Programmatic creatives. Render or miss.

Programmatic inventory routes through a real-time auction: the publisher page ships an empty ad slot, the bidder code negotiates, the winning creative lands in the DOM. A plain-HTTP fetch never triggers the auction — the slot stays blank, the creative goes uncaptured. browser=true spins up headless Chrome inside ScrapingAnt, runs the page just like a viewer, and returns the post-auction DOM. Pair with /v2/extract + extract_properties=ad_units(list: creative_url, advertiser, landing_url) for parser-free JSON rows.

  • Captures JS-bid creatives that plain-HTTP fetches miss entirely
  • Mobile UAs via user_agent — verify mobile-only campaign creatives at full fidelity
  • One flag, one credit pool — no second provider, no separate browser-pool contract
step 1 load slot=top step 2 scroll slot=mid step 3 refresh slot=top step 4 scroll slot=foot step 5 refresh slot=mid session=campaign-2026-q2 · proxy_country=DE 84.41.12.7 same residential exit · all 5 steps refresh rotation captured · one viewer identity
Refresh-bound creatives, coherent capture

Sticky sessions. One viewer, full rotation.

Refresh-bound creatives only rotate if the same viewer sticks around. A publisher's ad rotation logic typically keys on cookies + IP — change either between requests and the publisher starts a fresh frequency-cap window or re-bids from scratch. Append session=<id> to every request and ScrapingAnt pins them to the same residential exit IP. Combine with proxy_country=DE&session=foo to keep the entire publisher walk on one consistent German viewer.

  • Capture the full refresh rotation — slot=top → mid → foot → top — from one consistent viewer identity
  • Per-country session pinning — DE session stays DE, JP session stays JP across the walk
  • Pair with browser=true for full mid-walk JS state (cookies, localStorage, frequency-cap counters)

Six ad-verification workloads teams build on top.

Same API, same credit pool — different ways of slicing the ad-inventory crawl underneath.

Display-ad verification

Render publisher pages from each target market and capture the served creative. browser=true + residential IPs surface the ad your DSP says was bought.

Programmatic creative QA

Capture JS-bid creatives that don't render from corporate IPs. Headless Chrome resolves the auction; the served creative lands in the DOM, ready to extract.

Search-ad SERP capture

Capture paid SERPs from each market with proxy_country=XX. See competitor ads against your brand keywords in DE / JP / BR — pair with the Google search API for parsed rows.

Social-ad placement checks

Capture sponsored posts on social platforms from each market. Sticky sessions + residential IPs keep the feed coherent across a multi-page traversal.

Competitor-ad surveillance

Sweep publisher inventory for creatives from competitor brands; extract creative URLs + landing URLs with /v2/extract into a competitive intel table.

Geo-targeted campaign QA

Validate that a campaign tagged for DE / FR / IT actually appears only in those markets. Pull the same publisher URL from 20 countries; flag accidental over-targeting.

Pricing

Industry leading pricing that scales with your business.

Compare plans side by side. Every tier includes 10,000 free credits to start.
👈Swipe to compare all 5 plans👉
Plans
Enthusiast
100K credits / mo
$19/mo
★ Most Popular
Startup
500K credits / mo
$49/mo
Business
3M credits / mo
$249/mo
Business Pro
8M credits / mo
$599/mo
Custom
10M+ credits / mo
$699+/mo
Monthly API credits 100,000 500,000 3,000,000 8,000,000 10M+
Support channel Email Priority email Priority email Priority email Priority + dedicated
Integration help Docs only Custom code snippets Debug sessions Priority debug sessions Full enterprise onboarding
Expert assistance included included included included
Custom proxy pools included included included
Custom anti-bot avoidances included included included
Dedicated account manager included included included
Start Free Start Free → Start Free Start Free Talk to Sales
Hit your limit mid-month?
Restart your plan instantly — no waiting for the next billing cycle. Credits refresh the moment you pay, so scraping never has to stop.
10,000 free credits every month
No credit card required
Pay only for successful scrapes — failed requests cost 0
Customers

What teams are saying.

From solo developers shipping side projects to enterprise pipelines at Fortune 500s.

★★★★★ 5.0 on Capterra →
★★★★★

“Onboarding and API integration was smooth and clear. Everything works great. The support was excellent.

Illia K.
Android Software Developer
★★★★★

“Great communication with co-founders helped me to get the job done. Great proxy diversity and good price.”

Andrii M.
Senior Software Engineer
★★★★★

“This product helps me to scale and extend my business. The setup is easy and support is really good.”

Dmytro T.
Senior Software Engineer
FAQ

Ad verification API FAQ.

Anything else? Talk to us — we read every email.

What is an ad verification API?

An ad verification API is a managed endpoint that takes URLs (publisher pages, SERPs, social feeds) and returns the rendered ad content as it appeared to a user in a specific market. ScrapingAnt's /v2/general + browser=true + proxy_country=XX + proxy_type=residential returns the DOM with the served creative in place, ready for downstream extraction. The infrastructure layer underneath your own DV / IAS / brand-safety product.

How is this different from DoubleVerify, IAS, or MOAT?

Those are finished ad-verification platforms — they ship a dashboard, SDK integrations with DSPs, an MRC-accredited measurement layer, and a license model. ScrapingAnt is the data infrastructure beneath an ad-verification product. You bring the publisher inventory, the storage, the dashboard; we hand back rendered pages with predictable per-call economics. Teams pick us when they want to embed verification data into a custom product, sweep ad-inventory at higher volume than the boxed tools support, or audit markets the boxed tools index poorly.

Can I capture rendered creatives, not just the HTML?

Yes — pass browser=true and the response is the post-render DOM, so JavaScript-bid creatives that arrive via real-time bidding land in the page exactly as a user would see them. Extract <img>/iframe/video src URLs downstream; or pass extract_properties=ad_units(list: creative_url, advertiser, landing_url) via /v2/extract for parser-free JSON rows.

How many countries do you cover?

100+ residential country pools, with state and city targeting in many markets via the username parameter. The geo-targeting works per request — same key, no per-region credential management. See the residential proxies page for the full list and city-level granularity per country.

Sample cost for 100K verifications per day?

One full headless-render call with residential IP is about 25 credits. 100K daily renders ≈ 2.5M credits/month — fits the Business plan ($249, 3M credits) with headroom. If you skip the browser (raw-HTML verification only), the same 100K/day at ~5 credits each lands on the Startup plan ($49, 500K credits). Failed fetches (anti-bot retries, 4xx, 5xx) cost zero.

Sticky sessions for refresh-bound creatives?

Yes — append session=<id> and the same residential exit IP is used across requests bearing that id. Useful when a publisher refreshes ad slots on scroll or interval and you need to capture the rotation from one consistent viewer. Combine with proxy_country=DE&session=foo to keep the session pinned to one country across the whole walk.

Does it work with mobile user agents?

Yes — pass user_agent=<ua-string> to spoof a mobile profile. Combine with browser=true for full mobile rendering. Useful for verifying mobile-only campaigns or comparing creative size/format across desktop vs mobile inventory.

Talk to us

Building an ad verification product?

Custom volume pricing for million-impression sweeps, dedicated residential pools per market, creative-extract schema design help, or migration help from in-house browser-pool stacks — drop us a line and a real human gets back within a few hours.

“Our clients are pleasantly surprised by the response speed of our team.”

Oleg Kulyk
Founder, ScrapingAnt

A real human replies within a few hours · we don't share your email

Thanks — we'll be in touch shortly.
Something went wrong submitting the form. Please try again or email us directly.

Ready to scrape the web?

10,000 free credits every month. No credit card. Pay only for successful requests.

Sign up in under 30 seconds — no card, no commitment.