---
title: "Anti-bot check — website scraping difficulty"
method: POST
path: "/diagnostics/antibot-check"
tags: ["Web"]
---

# Anti-bot check — website scraping difficulty

`POST /diagnostics/antibot-check`

## Request

- Base URL: `https://api.crawlora.net/api/v1`
- URL: `https://api.crawlora.net/api/v1/diagnostics/antibot-check`
- Auth: API key in header `x-api-key`

Probes a URL across escalating transports (direct HTTP → browser-impersonation → headless/stealth browsers) and returns an empirical scraping-difficulty assessment for that exact URL: a 0–10 `difficulty_score` and `difficulty_band` (`easy`, `medium`, `hard`, `very_hard`, `blocked`, `unknown`), whether it is `scrapeable`, the detected anti-bot `protections` (Cloudflare, DataDome, Akamai, PerimeterX, Kasada, Imperva, AWS WAF and more — each with a `kind` and `confidence`), the lightest transport that worked, and a `recommended_profile`. Difficulty is per-URL, not per-site — a homepage may be open while deep pages are bot-managed. Intended for authorized public-data scraping planning.

## Headers

- `x-api-key` string, required

## Request body

- DiagnosticsAntibotCheckRequest
  - `fast` boolean: Fast (default true) escalates cheapest-transport-first and returns at the first tier that retrieves the page, so an unprotected page never spins up a browser. Set false for an exhaustive multi-run sweep across every backend.
  - `url` string, required: URL is the absolute http/https target to assess.

## Response `200`

OK

- DiagnosticsAntibotCheckResponseDoc
  - `code` integer
  - `data` AntibotVerdict
    - `auth_required` boolean
    - `block_detail` string
    - `block_reason` string: BlockReason is WHY the representative request was blocked (or "ok"): ok | bot_challenge | captcha_required | rate_limited | ip_blocked | geo_blocked | auth_required | payment_required | service_unavailable | forbidden | other | unreachable. Different reasons call for different fixes (rotate IPs vs run a browser vs log in), so they are surfaced distinctly.
    - `captcha_types` string[]: CaptchaTypes lists the distinct CAPTCHA types detected (e.g. recaptcha_v3, turnstile) for easy aggregation.
    - `coverage` string: Coverage is `full` when every transport tier ran, or `partial` when some were skipped (e.g. browser sidecars unconfigured in this environment), in which case a "blocked" verdict may understate what a browser could do.
    - `custom_vm` boolean: CustomVM / VMVendor are set when any detected protection is the proprietary closed-VM class (Kasada / F5 Shape / TikTok).
    - `detection_confidence_score` integer: ConfidenceScore is the strongest detection's numeric confidence (0-100), or 0 when nothing was detected (confidence describes a detection, not a negative).
    - `difficulty_band` 'easy' | 'medium' | 'hard' | 'very_hard' | 'blocked' | 'unknown'
    - `difficulty_score` integer: 0 (trivial) .. 10 (blocked)
    - `easiest_working_transport` string
    - `enforcement` string: Enforcement separates a managed vendor actively challenging/blocking us from one merely sitting in front as passive CDN/edge: open | passive_edge | active_challenge | active_block.
    - `gated_layers` string[]: GatedLayers names the anti-bot detection layers that block a plain client, derived empirically from which probe tiers were rejected: `tls` (a plain HTTP client's TLS/header fingerprint was rejected, but browser-impersonation or a browser got through), `js` (HTTP transports failed; JavaScript rendering / a real browser was required), `behavior` (a plain headless browser was also rejected; an anti-detect/stealth browser was needed).
    - `notes` string[]
    - `protections` AntibotProtection[]
      - `captcha_mode` string
      - `captcha_type` string: CaptchaType / CaptchaMode sub-classify a kind=captcha detection (e.g. recaptcha_v3 / score, turnstile / managed).
      - `confidence` string: low | medium | high
      - `confidence_score` integer: ConfidenceScore is the numeric (0-100) additive confidence over this detection's own evidence (Wappalyzer-style); Confidence is its bucketed label.
      - `custom_vm` boolean: CustomVM marks the proprietary signed-payload / closed-VM class (Kasada, F5 Shape, TikTok) whose anti-bot is a closed in-browser bytecode VM rather than generic transport detection; VMVendor names it.
      - `evidence` string[]
      - `kind` string: waf | bot_management | captcha | challenge | access_control | rate_limit
      - `vendor` string
      - `vm_vendor` string
    - `recommended_approach` string
    - `recommended_profile` string
    - `retry_after` string
    - `scrapeable` boolean
    - `signals` AntibotSignals
      - `attempts_passed` integer
      - `attempts_run` integer
      - `attempts_skipped` integer
      - `block_markers` string[]
      - `blocked_status` boolean
      - `captcha_detected` boolean
      - `challenge_detected` boolean
      - `js_render_likely` boolean
      - `rate_limited` boolean
    - `summary` string
    - `url` string
    - `vm_vendor` string
  - `msg` string

## Other responses

- `400`: Invalid or missing URL
- `429`: Rate limit exceeded
- `503`: Probe failed (transport/browser error or blocked target)

---

[API](https://skmtc.dev/crawlora/apis/crawlora-api.md) · [All operations](https://skmtc.dev/crawlora/apis/crawlora-api/llms.txt) · [OpenAPI document](https://skmtc.dev/crawlora/apis/crawlora-api/revisions/afac9b012a27?raw)
