Configuration

All environment variables with defaults and descriptions.


Core

VariableDefaultDescription
ECHELON_PORT1947HTTP listen port
ECHELON_DB_PATH./echelon.dbPath to SQLite database file
ECHELON_SECRET(empty)Bearer token for API auth. If unset, PoW tokens won't survive restarts
ECHELON_RETENTION_DAYS90Days to keep raw visitor_views and semantic_events
ECHELON_BOT_RETENTION_DAYS(same as retention)Days to keep raw rows scored as bots (bot_score ≥ 50) or server-ingested. Set lower to reclaim disk sooner

Authentication

VariableDefaultDescription
ECHELON_USERNAME(empty)Username for password-based login
ECHELON_PASSWORD_HASH(empty)PBKDF2 hash (pbkdf2$600000$<salt>$<hash>)

Generate a password hash:

deno eval "import{hashPassword}from'./lib/auth.ts';console.log(await hashPassword('yourpassword'))"

Bot Defense

VariableDefaultDescription
ECHELON_SUSPECT_COUNTRIESCNComma-separated ISO-2 codes that add penalty points
ECHELON_SUSPECT_POINTS30Points added per suspect country match
ECHELON_SITE_SUSPECT_COUNTRIES(empty)Per-site suspect countries: site:CC,CC;site:CC
ECHELON_BOT_DISCARD_THRESHOLD50Scores ≥ this are discarded before storage. 0 = store all (rows scoring 50 or more are still left out of statistics)
ECHELON_BOT_UA_PATTERNS(long list)Comma-separated UA substrings to drop entirely
ECHELON_CHALLENGE_WINDOW_MINUTES10Minutes of past PoW challenges accepted as valid
ECHELON_REQUIRE_ENGAGEMENTfalseAlso treat sessions that never interact (click, key press, tap, form use) as bots: their views and events are raised to the bot threshold 30–180 minutes after they were written and stop counting. Visitors who only read and scroll are removed by this. Leave off unless you want engaged visits only, and do not switch it on in the same deploy as an upgrade (see Upgrading)
ECHELON_BOT_SCORE_WEIGHTS(empty)Per-signal bot score weights, key:points,key:points (0–100 each; 0 turns the signal off; an unknown key or bad value is ignored with a startup warning). Example: linux_desktop:0 for a developer audience, cross_site:0 for sibling sites. Keys: timing_fast, timing_quick, burst, no_accept_language, no_sec_headers, screen, referrer, crawler_feed, ai_crawler_feed, datacenter_ip, win_tablet_mismatch, linux_desktop, cross_site, country_mismatch, cross_continent, global_common_foreign, linux_foreign, stale_android_foreign. See Bot Defense for defaults

Rate Limiting

VariableDefaultDescription
ECHELON_RATE_LIMIT_MAX100Max requests per IP per window
ECHELON_RATE_LIMIT_WINDOW_MS60000Rate limit window in milliseconds

Buffered Writes

VariableDefaultDescription
ECHELON_VIEW_FLUSH_MS15000Flush interval for pageview buffer (ms)
ECHELON_EVENT_FLUSH_MS10000Flush interval for event buffer (ms)
ECHELON_SHUTDOWN_TIMEOUT_MS60000How long shutdown may spend flushing buffers before forcing exit. Keep your container stop grace period longer than this

Network & Proxy

VariableDefaultDescription
ECHELON_TRUST_PROXYfalseTrust X-Forwarded-For / X-Real-IP for client IP
ECHELON_BEHIND_CLOUDFLAREfalseTrust Cloudflare headers (cf-*) for geo and bot data
ECHELON_TRUST_GEO_HEADERSfalseTrust cloudfront-viewer-country / x-country-code
ECHELON_ALLOWED_ORIGINS(empty)Comma-separated domains allowed to load the tracker. Empty = all

Admin UI

VariableDefaultDescription
ECHELON_LIVE_STATS_MINUTES10Time window (minutes) for live stats in the admin nav bar
ECHELON_DISPLAY_TIMEZONEUTCIANA timezone for admin UI timestamps (e.g. Europe/Oslo). Data is stored in UTC.

MCP Server

VariableDefaultDescription
ECHELON_URL(required)Base URL of the Echelon Analytics instance the MCP server queries (e.g. https://ea.islets.app)
ECHELON_SECRET(empty)Bearer token for authenticated instances. Not needed for public mode instances.

Anonymization & Public Mode

VariableDefaultDescription
ECHELON_ANONYMIZE_SITES(empty)Comma-separated site IDs to anonymize before storage. Records for these sites get HMAC-hashed visitor IDs, fictional countries, redacted referrers, and codename UTMs. Session ids come from a list of 50 names that unrelated visits share, so on these sites interaction validation and the engagement gate match by the anonymized visitor id (within 30 minutes) and never by session. See Telemetry
ECHELON_PUBLIC_MODEfalseDisable admin auth requirement. The dashboard is openly accessible without login — ideal for public analytics dashboards

Miscellaneous

VariableDefaultDescription
ECHELON_COOKIE_CONSENTfalseShow consent banner before setting visitor cookie
ECHELON_IGNORED_SITES(empty)Comma-separated site IDs to silently ignore. "smoke-test" always ignored
ECHELON_ALLOWED_SITES(empty)Comma-separated site IDs to accept. Tracking for any other site ID is silently dropped. Empty = all
ECHELON_DEBUGfalseVerbose debug logging (PoW, scoring, events)
ECHELON_TELEMETRY(unset)Override telemetry: true = force on, false = force off, unset = respect admin choice. See Telemetry

🌍 "Did you know you can set per-site suspect countries with ECHELON_SITE_SUSPECT_COUNTRIES? Format: site1:CN,RU;site2:KP for granular bot defense." -🦭

Example .env

# Core
ECHELON_PORT=1947
ECHELON_DB_PATH=./data/echelon.db
ECHELON_SECRET=change-me-to-a-secure-random-string
ECHELON_RETENTION_DAYS=90

# Auth
ECHELON_USERNAME=admin
ECHELON_PASSWORD_HASH=pbkdf2$600000$...

# Network
ECHELON_TRUST_PROXY=true
ECHELON_BEHIND_CLOUDFLARE=true

# Bot defense
ECHELON_SUSPECT_COUNTRIES=CN
ECHELON_SUSPECT_POINTS=30
ECHELON_RATE_LIMIT_MAX=100

# Admin UI
ECHELON_LIVE_STATS_MINUTES=10
ECHELON_DISPLAY_TIMEZONE=Europe/Oslo

# Telemetry (optional — unset = prompt admin on first access)
# ECHELON_TELEMETRY=false

Installation Features API Reference Bot Defense Architecture Data Ownership & Open Access Portable Data MCP Server Telemetry Why ea.js?