> Bot Defense

Multi-layered bot detection: PoW challenges, heuristic scoring, and Cloudflare integration.


Overview

Every incoming request is scored from 0 (definitely human) to 100 (definitely bot). Views and events with bot_score ≥ 50 are excluded from daily rollups. Known bot User-Agents are dropped entirely before scoring.

Known Bot UA Filter

Requests matching any pattern in ECHELON_BOT_UA_PATTERNS are dropped before scoring. Default list includes:

Bot Scoring Factors

SignalConditionPoints
CF verified botCloudflare confirms known bot UA+15
CF bot score ≤ 2Very confident bot+50
CF bot score 3–29Likely automated+30
CF bot score 30–50Uncertain+10
Interaction < 850msBeacon fired too fast+20
Interaction 850–1000msSuspiciously fast+8
Suspect countryIP in ECHELON_SUSPECT_COUNTRIES+30 (configurable)
Per-site suspect countryIP in ECHELON_SITE_SUSPECT_COUNTRIES+30 (stacks with global)
Burst detection> 15 requests in 5-minute window+25
Missing Accept-LanguageNo header present+10
Missing Sec-CH-UA + Sec-Fetch-SiteBoth headers absent+10
Unrealistic screenWidth/height ≤ 0 or > 10000+10
No referrer + deep pathDirect visit to path with ≥ 2 segments+5
PoW token missingNo proof-of-work token sent+15
PoW token invalidToken fails verification+25

Score is capped at 100.

Proof-of-Work System

Every request for /ea.js embeds a WebAssembly blob and a challenge string. The browser must solve the challenge before sending beacons.

How It Works

Server Verification

The server tries all combinations of:

Returns "valid", "missing", or "invalid" — each adding different penalty points.

Burst Detection

Rate Limiting

Tracking endpoints (/b.gif, /e) are rate-limited per IP:

Cloudflare Integration

Set ECHELON_BEHIND_CLOUDFLARE=true to enable:

Referrer Classification

Incoming referrers are classified into categories:

TypeDomains
aiperplexity.ai, chat.openai.com, chatgpt.com, claude.ai, you.com, phind.com, copilot.microsoft.com, gemini.google.com, poe.com
searchGoogle (22 TLDs), bing.com, yahoo.com, duckduckgo.com, yandex.com/ru, ecosia.org
socialfacebook.com, twitter.com, x.com, reddit.com, linkedin.com, instagram.com, t.co
direct_or_unknownEverything else

Manual Exclusion

Via the admin dashboard or API, you can manually exclude specific visitor IDs from rollups:

# Exclude
POST /api/bots/exclude
{ "visitor_id": "abc123", "label": "Known bot" }

# Re-include
DELETE /api/bots/exclude/abc123

Discard Threshold

Set ECHELON_BOT_DISCARD_THRESHOLD to a score (e.g., 80) to discard high-score requests before they're even stored. Default is 0 (store all, filter at rollup time).


Installation Features API Reference Configuration Architecture