POST/api/v1/phishing/urlscan

URLScan.io Analysis

Submit URLs to URLScan.io for full-page rendering, screenshot capture, and threat analysis. Returns verdicts, page metadata, hosting details, and screenshot links.

Credits

3

Per request

Max URLs

5

Per request

Timeout

60s

Polling up to 30s per URL

Plans

All

Free, Starter, Professional, Enterprise

How It Works

StepDescription
1. SubmitEach URL is submitted to URLScan.io with unlisted visibility (your URLs are not publicly exposed)
2. RenderURLScan loads the page in a real browser, capturing screenshots, DOM, network requests, and certificates
3. AnalyzeCommunity and engine verdicts are computed based on page behavior, content, and known threat patterns
4. ReturnResults include verdicts, screenshot links, effective URLs (after redirects), page metadata, and hosting details

Request Body

FieldTypeRequiredDescription
urlsstring[]YesArray of 1-5 URLs to scan. Must use http:// or https:// scheme.

Code Examples

cURL

curl -X POST https://api.dfir-lab.ch/v1/phishing/urlscan \
  -H "Authorization: Bearer sk-dfir-your-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://suspicious-login.com",
      "https://another-url.net"
    ]
  }'

Python

import requests

response = requests.post(
    "https://api.dfir-lab.ch/v1/phishing/urlscan",
    headers={
        "Authorization": "Bearer sk-dfir-your-key-here",
        "Content-Type": "application/json",
    },
    json={
        "urls": [
            "https://suspicious-login.com",
            "https://another-url.net",
        ]
    },
    timeout=90,  # Allow for URLScan polling (up to 60s server-side)
)

data = response.json()
for result in data["data"]["results"]:
    verdict = result["verdicts"]["overall"]
    status = "MALICIOUS" if verdict["malicious"] else "clean"
    print(f"{result['url']}: {status} (score: {verdict['score']})")
    if result["screenshotUrl"]:
        print(f"  Screenshot: {result['screenshotUrl']}")

TypeScript

const response = await fetch(
  "https://api.dfir-lab.ch/v1/phishing/urlscan",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer sk-dfir-your-key-here",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      urls: [
        "https://suspicious-login.com",
        "https://another-url.net",
      ],
    }),
    signal: AbortSignal.timeout(90_000),
  }
);

const { data, meta } = await response.json();

for (const result of data.results) {
  const { overall } = result.verdicts;
  console.log(
    `${result.url}: ${overall.malicious ? "MALICIOUS" : "clean"}`,
    `(score: ${overall.score})`
  );
  if (result.screenshotUrl) {
    console.log(`  Screenshot: ${result.screenshotUrl}`);
  }
}

console.log(`Credits used: ${meta.credits_used}`);

Example Response

{
  "data": {
    "results": [
      {
        "url": "https://suspicious-login.com",
        "uuid": "12345678-abcd-1234-abcd-123456789012",
        "verdicts": {
          "overall": { "score": 75, "malicious": true },
          "engines": [
            { "engine": "community", "result": "malicious" }
          ]
        },
        "screenshotUrl": "https://urlscan.io/screenshots/12345678-abcd.png",
        "pageTitle": "Login - Secure Account",
        "pageIp": "203.0.113.42",
        "pageCountry": "CN",
        "effectiveUrl": "https://suspicious-login.com/phish",
        "error": null
      },
      {
        "url": "https://another-url.net",
        "uuid": "87654321-dcba-4321-dcba-210987654321",
        "verdicts": {
          "overall": { "score": 0, "malicious": false },
          "engines": []
        },
        "screenshotUrl": "https://urlscan.io/screenshots/87654321-dcba.png",
        "pageTitle": "Another URL - Home",
        "pageIp": "198.51.100.10",
        "pageCountry": "US",
        "effectiveUrl": "https://another-url.net",
        "error": null
      }
    ],
    "summary": {
      "total": 2,
      "malicious": 1,
      "screenshotsAvailable": 2
    }
  },
  "meta": {
    "request_id": "req_abc",
    "credits_used": 3,
    "credits_remaining": 97,
    "processing_time_ms": 15000
  }
}

Response Fields

FieldTypeDescription
urlstringThe originally submitted URL
uuidstringURLScan scan ID — use to view full results at urlscan.io/result/{uuid}
verdicts.overall.scorenumberThreat score from 0 (clean) to 100 (malicious)
verdicts.overall.maliciousbooleanWhether the URL is considered malicious
verdicts.enginesarrayIndividual engine verdicts (community, third-party scanners)
screenshotUrlstring | nullDirect link to the rendered page screenshot
pageTitlestring | nullHTML title of the rendered page
pageIpstring | nullIP address hosting the scanned page
pageCountrystring | nullCountry code of the hosting IP
effectiveUrlstring | nullFinal URL after following all redirects
errorstring | nullError message if the scan failed for this URL

URLScan polling may take up to 30 seconds per URL. URLs are scanned sequentially due to URLScan.io rate limits. Set client-side timeouts to at least 90 seconds to account for the 60-second server timeout.

If a scan times out before results are ready, a partial result is returned with the uuid and screenshotUrl fields (the screenshot is usually available shortly after submission).

All scans are submitted with unlisted visibility on URLScan.io. Your submitted URLs will not appear in public search results.

A score of 0 with malicious: false means no threats were detected at the time of scanning. It is not a guarantee of safety.