Cloudflare Workers

Bot and VPN checks in a Cloudflare Worker

One Worker in front of your site checks each visitor and tells your origin what it found.

Setup

Live in three steps

  1. 1

    Deploy the Worker

    Or use the Deploy button above.

    shell
    git clone https://github.com/ipscanner/ipscanner-cloudflare
    cd ipscanner-cloudflare
    npm install
    npx wrangler deploy
  2. 2

    Add your API key

    shell
    npx wrangler secret put IPSCANNER_API_KEY
  3. 3

    Put it in front of your site

    On a custom domain or workers.dev, set ORIGIN_URL to your backend instead.

    wrangler.jsonc
    "routes": [{
      "pattern": "example.com/*",
      "zone_name": "example.com"
    }]

How it works

What happens on each request

  1. 1

    The Worker reads the visitor's IP, User-Agent and JA4, when Cloudflare provides it.

  2. 2

    Agentscan and IP Detection run in parallel, cached per visitor, and fail open after 1.5 seconds.

  3. 3

    Monitor mode sends verdict headers to your origin. Enforce mode also answers a blocked visitor with a 403.

  4. 4

    Verified crawlers always pass, and X-IPScanner-* headers sent by the client are stripped.

Headers

Headers your origin receives

When a check fails or is skipped, only X-IPScanner-Status is set.

HeaderExample
X-IPScanner-ClassAgentscanhuman
X-IPScanner-ActionAgentscanallow
X-IPScanner-ConfidenceAgentscan0.92
X-IPScanner-Network-ClassIP Detectionresidential_clean
X-IPScanner-AnonymizedBothfalse
X-IPScanner-RiskIP Detection12
X-IPScanner-CountryIP DetectionDE
X-IPScanner-StatusWorkerok

Settings

Settings

Set these in the vars block of wrangler.jsonc.

VariableDefault
MODEmonitor adds headers, enforce also blocksmonitor
CHECK_AGENTRuns Agentscantrue
CHECK_IPRuns IP Detectiontrue
BLOCK_CLASSESAgentscan classes to block in enforce modemalicious_automation
BLOCK_ANONYMIZEDAlso blocks VPN, proxy and Tor in enforce modefalse
TIMEOUT_MSPer call, then the request goes through1500
AGENT_TTLSeconds to cache an Agentscan verdict600
IP_TTLSeconds to cache an IP lookup3600
SKIP_PATHSPath regex that skips the checkStatic assets
ORIGIN_URLBackend to forward to when not on a routeEmpty

Questions

Cloudflare Worker FAQ

One request per enabled check for each uncached visitor, so two with both checks on. Repeat visits within the cache TTL use none.

Start in monitor mode

Watch the headers for a week before you block anything.