Web Analytics With No Dashboard (But There Is a Globe)
Web Analytics With No Dashboard (But There Is a Globe)
I shipped a new product: vigie — cookieless web analytics where the primary user is an agent, not a human staring at charts. There is no dashboard. There is, however, a rotating 3D globe of live traffic that repaints itself while you watch. I'll explain.
The itch
Every product I run needed the same answer: did anyone show up? Google Analytics answers that with a consent banner, a 90-tab dashboard, and a data-sharing arrangement I don't want. The privacy-first alternatives — Plausible, Fathom, Rybbit — are genuinely good, but they all share one assumption: a human logs into a dashboard and looks at charts.
Nobody on my team logs into dashboards. My team is agents. They already write the code, send the email, and file the issues. What they needed was analytics they could query: JSON on stdout, semantic exit codes, an API they can act on. So vigie's contract is the agent-first CLI spec, end to end:
vigie stats overview --site example.com --since 7d
# {"ok":true,"data":{"pageviews":1234,"visitors":410,"bounce_rate_pct":38,...}}
vigie stats referrers --site example.com --country FR
vigie sessions show --sid 15452fd8bee22704 # the full event trail
vigie stats cities --site example.com # geo down to city + coordinates
vigie stats journeys --site example.com # the sankey, as JSON
vigie stats vitals --site example.com # LCP/FCP/CLS/INP/TTFB, p50/75/90
vigie stats errors --site example.com # grouped JS errors
When a human does need to see it
Dashboards aren't useless — they're just not worth running a frontend for 24/7. So in vigie, the dashboard is an artifact: vigie snapshot --publish renders a self-contained HTML report and pushes it to hart, my artifact host. You get a live, shareable, disposable URL. Generated on demand, by an agent, when someone actually asks.
And because analytics deserves one indulgence: vigie snapshot --globe --publish --live renders your traffic as a rotating dot-matrix planet — country markers sized by visitors, green pulses where someone is browsing right now. hart re-pulls the live feed every 60 seconds and the globe repaints itself. Zero JavaScript frameworks, zero external assets: the whole thing is hand-rolled canvas math and an embedded 2° landmask, because hart's CSP forbids everything else. Drag it to pan; it resumes spinning when you let go.
Cookieless by construction
A visitor is sha256(secret + day + site + ip + ua), truncated. The salt rotates daily and the raw IP is never stored, so there is nothing to consent to and nothing to breach. The tracking snippet is ~2 KB and collects pageviews (SPA-aware), custom events, web vitals, and JS errors — country comes free from Cloudflare's edge header, no GeoIP database.
The twist I care about most: agents are users too. vigie track --site api.example.com --name deploy --actor ci records a server-side event with no browser involved. Your cron job's activity is a first-class analytics stream, in the same funnels and sessions as your humans.
Built in a day, and what broke
vigie is written in MFL and compiles to one ~170 KB binary: HTTP ingest, SQLite storage, stats engine, globe renderer, CLI — no Node, no ClickHouse, no Docker. An agent built the whole thing in a day, milestone by verified milestone, and that's the part I find genuinely interesting: dogfooding at this intensity is a bug-finding machine for the language itself. Three compiler issues came out of this one project, including my favorite: MFL string literals were being silently corrupted by C trigraph processing — the globe's JavaScript contained '??', the C toolchain rewrote it to '^', and the only symptom was a browser SyntaxError three layers downstream. Filed, minimal repro and all.
Same-day update: full metric parity
Between publishing this post and the end of the day, the gap list versus the dashboard-first tools went to zero. vigie now captures and aggregates: geo down to region and city (with real coordinates — powered by a MaxMind-DB reader written in pure MFL, reading the CC-BY DB-IP City Lite database, so the globe plots actual cities, not country centroids), user journeys (per-session path transitions and sequences), traffic channels (direct/organic/social/paid, derived from referrer + UTM), OS/browser versions/screens/languages, entry and exit pages, a weekday×hour traffic heatmap, custom-event property aggregation, web vitals percentiles, grouped JS errors, retention cohorts, and identified-user profiles.
And the answer to "where do I see all that" stays true to the thesis, three ways. vigie snapshot --publish renders every metric in one hart-published report — 22 sections, empty ones omitted — regenerated on a timer for sharing and archiving. Here is a fully-populated demo report built from synthetic data (labeled as such), so you can see the complete layout without waiting for my traffic to accumulate.
And yes, in the end there is a dashboard — but on vigie's terms. vigie report --site X prints a private URL where the same full report is rendered live on every request: no frontend server, no JavaScript, period switching (24h/7d/30d) as plain links, gated by a revocable per-site read key — the same key that powers the globe. A dashboard that is stateless HTML served by the analytics binary itself is not a dashboard app; it's a view. That distinction is the whole product.
Open-core, metered like the rest of the stack
The repo is MIT and self-hosting is feature-complete — one binary, bring your own domain. The hosted tier at vigie.intrane.fr adds orgs, scoped tokens, and metering through péage: 10k events/month free, then €1 per 100k, charged to a prepaid wallet — no subscription. When an org runs over quota without a funded wallet, ingest answers a machine-readable HTTP 402 that tells the calling agent exactly how to fund itself. The billing path isn't theoretical: the first over-quota block was charged against a real wallet on the live rail before I wrote this post.
vigie completes a stack where each piece is one small agent-first binary: péage pays, relais receives, portier authenticates — and now vigie watches. Docs at javimosch.github.io/vigie, manual in the binary (vigie guide), and if you visit any of my pages today, you're already a dot on the globe.