Anti-Malware — entry 013 of 15

URLScan.io

Verified Jul 2026

urlscan.io submits URLs to a real, sandboxed browser and publishes the resulting screenshot, DOM, requested domains, and detected technologies, plus a searchable archive of past scans, all as JSON. A live unauthenticated GET against its search endpoint succeeded immediately (returning IP-scoped X-Rate-Limit headers), and a follow-up OPTIONS preflight returned Access-Control-Allow-Origin: *, resolving cors to yes and confirming HTTPS; submitting new scans instead requires an API-Key header. Public scanning is free within per-minute/hour/day rate limits, with a paid urlscan Pro tier for vetted researchers needing deeper private search.

urlscan.io scans a URL in a real sandboxed browser and stores the result: a screenshot, the page's DOM, every domain it contacted, and the technologies it found. Most of the API needs an API key. One part does not: the search endpoint. A live GET this run against /search/ returned real results with no credential sent.

url-scanningthreat-intelligencesandboxsecurityapi-key
AuthenticationAPI KeySign up with the provider to obtain credentials.
HTTPSSupportedTraffic is encrypted in transit.
CORSEnabledCallable directly from browser JavaScript.
PricingFreemiumA usable free tier exists, with paid plans for more volume.
FormatsJSONResponses can be requested as JSON.

GreatAPIs Score

Score61out of 100
Authentication15/25API key required
Pricing17/20Freemium tier available
Docs0/20No docs or spec available
Formats9/15Single response format
Freshness20/20Verified within 6 months

Embed this badge

Scored 61 on greatapis.com
<a href="https://greatapis.com/api/urlscan-io/"><img src="https://greatapis.com/badge/urlscan-io.svg" alt="Scored 61 on greatapis.com"></a>

Auth quickstart

  1. Search needs no key. GET /search/?q=<query> works with no api-key header. A live call this run returned HTTP 200 with real scan results.
  2. Submitting a new scan needs a key. A live POST /scan/ this run with no key returned HTTP 401: No API key supplied. Please supply a valid API key in the "api-key" HTTP header.
  3. Reading a single scan result by UUID also needs a key, even for a public scan. A live GET /result/<uuid>/ this run returned HTTP 403: You're not logged in!
  4. Get a free API key by creating an account at urlscan.io, then send it as an api-key header on /scan/ and /result/ calls.
Stored keyNo key stored

Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.

Keyless search for past scans of a domain

GEThttps://urlscan.io/api/v1/search/?q=page.domain:github.com&size=2

200 application/json; charset=utf-8

{"results":[{"task":{"visibility":"public","method":"api","domain":"github.com","time":"2026-08-22T08:11:33.895Z","uuid":"01a02886-515a-7018-bfb9-79a4ab620ebd","url":"https://github.com/2dust/v2rayN"},"stats":{"uniqIPs":5,"uniqCountries":2,"requests":172},"page":{"country":"DE","server":"github.com","ip":"140.82.121.4","status":"200"},"result":"https://urlscan.io/api/v1/result/01a02886-515a-7018-bfb9-79a4ab620ebd/","screenshot":"https://urlscan.io/screenshots/01a02886-515a-7018-bfb9-79a4ab620ebd.png"}],"total":10000,"took":50,"has_more":true}

The q field name matters. A live query with q=domain:github.com this run returned unrelated hosts, and q=page.domain:github.com returned real github.com results. urlscan does not reject an unknown field name; it just ignores it and returns the wrong rows.

Developer reference

Rate limit

30 requests/minute, 100/hour, 500/day for the "search" action -- default anonymous/IP-scoped tier (public submission scan: 30/min, 250/hour, 2,500/day; private scan: 5/min, 25/hour, 25/day) -- per urlscan.io/user/quotas/

Gotchas & limits

  • Search is the only keyless part of this API. A live GET /result/<uuid>/ this run, even for a public scan, returned HTTP 403 {"warning": "You're not logged in!"}. Use the result and screenshot URLs from a search hit directly in a browser instead of calling /result/ from a script with no key.
  • The unauthenticated tier is rate-limited by IP, not by key. A live search call this run returned x-rate-limit-limit: 30 and x-rate-limit-window: minute, plus x-rate-limit-concurrency-limit: 10 for how many requests can run at once.
  • CORS is wide open. A live OPTIONS preflight against /search/ this run returned HTTP 200 with access-control-allow-origin: *, so a browser page can call search directly with no server proxy.
  • total is a ceiling, not a result count. Three separate high-volume queries this run (page.domain:github.com, domain:github.com, page.domain:google.com) each returned total: 10000, and a query with no matches returned total: 0. Treat 10000 as "at least this many" and page with has_more instead of trusting total as a real total.