> ea.js — Echelon Analytics
Privacy-first, self-hosted web analytics with WebAssembly proof-of-work bot defense.
Drop in a single script tag — clean data, no cookie banners, no bot spam.
Documentation
Why?
Google Analytics used to be my go-to. Then GA4 happened — bloated, confusing, way too heavy, and full of bot spam that distorts your statistics. Using it feels like opening Microsoft Word when all you want is a text editor. So I built my own for afroute.com and ripped it out when implementing Islets Spatial CMS.
Quick Start
cd echelon-analytics deno task dev
<script src="https://your-host/ea.js" data-site="my-site"></script>
That's it. Pageviews, bounces, and sessions tracked automatically.
WASM Proof-of-Work Bot Defense
Analytics tools are plagued by bot traffic that distorts your data. ea.js solves this with a novel approach: every tracker script embeds a runtime-generated WebAssembly module that browsers must solve before pageviews are accepted.
- WASM blob is regenerated from a random seed every 6 hours — each deployment produces unique bytecode
- SipHash-inspired algorithm with randomized constants — bot toolkits can't pre-compute solutions
- Per-minute challenge rotation via HMAC-SHA256
- Invisible to users — solves in <150ms in any modern browser
- Missing or invalid tokens add penalty points to the visitor's bot score (0–100)
- Combined with heuristic scoring, Cloudflare integration, burst detection, and UA blocklists
The result: clean analytics data without CAPTCHAs, JavaScript challenges, or third-party bot detection services. Full bot defense documentation →
How It Works
- 1x1 pixel beacon +
sendBeaconfor events - Cookieless by default — daily-rotating HMAC hash, no cross-day tracking
- No cookie consent banners needed (GDPR/ePrivacy compliant)
- Optional persistent cookies via
data-cookie - SPA-aware — patches
pushState/replaceStatefor automatic route tracking - SQLite with WAL mode — single file, zero config
Tracking Features
- Auto-tracked pageviews, bounces, sessions
- Click, scroll depth, hover, outbound link, and file download tracking
- Core Web Vitals (LCP, CLS, INP) via
data-vitals - Form submission tracking via
data-forms - Custom events:
window.echelon.track("name", { key: "value" }) - UTM campaign tracking with source/medium/content/term breakdown
- A/B experiment tracking with variant allocation and significance testing
Bot Defense
- Heuristic scoring (0–100) — interaction timing, headers, geo, burst detection
- Dynamic WASM proof-of-work — randomized every 6 hours, embedded in tracker
- Cloudflare bot score integration when deployed behind CF
- Known bot UA blocklist (Googlebot, GPTBot, ClaudeBot, curl, etc.)
- AI referrer classification (ChatGPT, Claude, Perplexity, Gemini)
- Per-IP rate limiting on tracking endpoints
Admin Dashboard
- Overview with KPIs, daily trends, top pages, devices, countries, referrers
- Realtime visitor monitoring (10-second polling)
- Bot management — suspicious visitors, exclude/include controls
- A/B experiments — create, manage, view conversion uplift
- UTM campaigns — track and break down by source, medium, content
- Performance metrics — CI/CD benchmark tracking with trends
- REST API for all dashboard data
Auth
- Bearer token (
ECHELON_SECRET) for API access - Username + password login (PBKDF2-SHA256, 600k iterations)
- 24-hour session cookies with CSRF protection
Tech Stack
- Deno + Fresh 2.2.0 (Preact islands)
- SQLite via Deno's built-in
node:sqlite - Preact +
@preact/signals, Tailwind CSS v4 - Vite 7 build pipeline
- Docker-ready (multi-stage, non-root, health check)
Docker
docker build -f confs/Dockerfile -t echelon . docker run -p 1947:1947 -v echelon-data:/app/data echelon