All articles Integration

Edge Bot Detection With a Cloudflare Worker

The cheapest request to defend against is the one that never reaches your origin. A Cloudflare Worker sits in front of your application at every edge location, which makes it the natural place to filter automated traffic before it consumes an application server, a database connection, or a rate-limit budget. Done well, an edge bot gate blocks scrapers and credential-stuffing tools at the door, hands suspicious-but-uncertain traffic a challenge, and passes real users through with latency measured in single-digit milliseconds.

This is also where a self-hostable stack earns its keep. You do not have to send your traffic to a vendor’s cloud to score it — the Worker can run the decision logic itself, consult your own state in Workers KV, and defer only the heaviest verification to your origin. Prynt Edge is built for exactly this shape.

What the edge can see that the origin cannot

A Worker runs at the TLS-terminating edge, so it has access to connection-level signals that are often stripped or normalized by the time a request reaches an origin behind a load balancer.

  • JA4 TLS fingerprint. The JA4 handshake fingerprint characterizes the client’s TLS stack. Automation libraries and scraping toolkits frequently present TLS signatures that do not match the browser they claim to be in their user-agent.
  • HTTP/2 and header ordering. The order and casing of headers, and HTTP/2 settings frames, differ between real browsers and scripted clients.
  • Connection metadata. Cloudflare exposes cf properties — ASN, country, whether the IP is a known bot, datacenter context — without an extra lookup.
  • First-request visibility. The edge sees every request including the first, before any cookie or client-side script has run, which is exactly when a scraper is easiest to catch.

Combined with a client-side signal collected by the SDK, these let the Worker make a strong early decision.

A three-tier decision at the edge

The pattern that scales is a graduated gate, not a binary block. Classify each request into allow, challenge, or block, and keep the expensive work rare.

export default {
  async fetch(request, env) {
    const ja4 = request.cf?.botManagement?.ja4 || headerJA4(request);
    const asn = request.cf?.asn;
    const known = await env.PRYNT_KV.get(`ja4:${ja4}`); // your own reputation

    let score = 0;
    if (known === "bot") score += 60;
    if (isDatacenterASN(asn)) score += 20;
    if (!hasBrowserHeaderShape(request)) score += 25;

    if (score >= 70) return new Response("Forbidden", { status: 403 });
    if (score >= 35) return challenge(request, env);      // proof-of-work
    return fetch(request);                                 // pass to origin
  }
};

The three tiers map to three costs:

TierTriggerResponseCost
AllowClean signalsProxy to originNegligible
ChallengeAmbiguous scoreProof-of-work interstitialPaid by client CPU
BlockHigh-confidence bot403 at edgeNone to origin

The challenge tier is the important one. Rather than a CAPTCHA that frustrates humans, a self-hosted proof-of-work challenge makes the client burn CPU to proceed — invisible to a real browser, expensive at the scale a bot operates. See the Turnstile versus proof-of-work comparison for the trade-off.

Keeping state at the edge with KV

Stateless scoring only goes so far; the strongest edge signals are historical. Workers KV gives you a low-latency, eventually-consistent store the Worker can read on every request and write to asynchronously.

Useful things to keep in KV:

  • JA4 and IP reputation you have accumulated — a fingerprint seen scraping ten sites is scraping yours too.
  • Per-device request velocity for rate limiting by device rather than by IP, which survives proxy rotation.
  • Recently issued challenge tokens so a solved challenge is honored across the fleet without re-solving.

Because KV is eventually consistent, use it for reputation and rate context where a few seconds of propagation lag is acceptable, and keep hard, must-be-exact decisions (like a spent one-time token) at the origin.

Verify at the origin before trusting the decision

An edge decision is fast but the client half of it is, in principle, tamperable. For anything consequential — login, checkout, signup — the origin must independently verify the signed result rather than trust a header the client could forge. This is the server-side verification step, and it is why the edge and origin are complementary, not redundant. The general principle is covered in server-side vs client-side detection.

A clean division of labor:

  • Edge Worker: cheap high-volume filtering, early challenges, reputation lookups, keeping obvious bots off the origin entirely. See the companion nginx auth-request gate for a non-Cloudflare equivalent.
  • Origin: authoritative verification of the sealed result, business-logic risk scoring, and the final allow/deny on sensitive actions.

Frequently asked questions

Why run bot detection in a Worker instead of at the origin?

A Worker runs before the request reaches your servers, so it can block automation at the edge, keep bot traffic off your origin, and add near-zero latency for real users. It also sees TLS and connection signals the origin may not.

Does an edge Worker replace origin-side checks?

No. The edge handles cheap, high-volume filtering and early challenges; the origin still verifies the signed result server-side before trusting a decision on sensitive actions.

Can a Worker compute a full device fingerprint?

The Worker sees network and TLS signals like JA4 and headers, but a full client fingerprint needs browser-side collection. The Worker validates and enriches the client signal rather than replacing it.

An edge Worker turns bot mitigation into a layered system: block the obvious at the door, challenge the uncertain cheaply, and reserve authoritative verification for the origin and the actions that matter. Keeping the decision logic and state in your own Worker and KV means no traffic leaves for a third party — the core reason to self-host fraud detection. Explore the SDKs and docs to wire it up, or read the bot detection pillar for the full picture.

Run it yourself

Prynt is open-source, self-hostable device intelligence — visitor IDs, bot & fraud Smart Signals, and behavioral biometrics you own end to end.

Keep reading