Know what the creative does before it hits your exchange.

Adscan renders real adm in a headless browser, records redirects, runs an NSFW classifier, and gives you a blocklist you can pull into your own stack.

Built for ops and engineering teams running RTB—not a consumer ad product.

Queue a scan
# POST /api/scan — async job, poll job id
curl -s -X POST "$API_BASE/api/scan" \
  -H "Content-Type: application/json" \
  -d '{
    "dsp": "your_dsp",
    "creative_id": "cr_123",
    "adm": "<div>...</div>",
    "w": 300, "h": 250
  }'

What you get

Same pipeline your traffic would hit—without waiting for a user complaint to learn the tag was trash.

Redirect truth

Follow what the markup actually does, including chained hops. Known bad URL patterns can short-circuit without a full render.

Visual + scores

Optional screenshots (stored efficiently) and classifier output so reviewers and machines both have signal.

Blocklist in your bidder

Export JSON or hit a per-creative check endpoint. Wire it into pre-bid or your own policies.

Dashboard + keys

Team accounts, scan history, and optional API keys when you want the edge locked down.

Typical flow

Three steps from “new tag” to “blocked in prod.”

Submit creative

Your bidder or a sidecar posts markup and metadata. Whitelist skips trusted DSPs; duplicates can short-circuit.

Queue renders and classifies

Headless browser work runs in a worker pool. Results land in Postgres with timestamps you can audit.

Act on the result

Pull detail over HTTP, export the blocklist bundle, or let auto-blocklist rules push bad IDs for you.

HTTP API

Everything runs under /api. Machine-readable route list: GET /api. Health checks stay on /api/health.

  • POST /api/scan — enqueue
  • GET /api/scan/:jobId — poll
  • GET /api/creative/:id — latest result
  • GET /api/blocklist/export — bundle
  • GET /api/blocklist/check — single lookup

The admin UI on dash.adscan.plus shows curl samples with the right host and optional API key headers.

Integration page →