A tracker script, an endpoint that writes rows and a dashboard of pages, referrers, countries and devices is a one-sitting build for a personal site, and several open-source projects prove it. What stays behind is bot filtering that improves with many sites, EU hosting you can point a regulator at, and someone else keeping the collector up when a post goes viral. For one site with modest traffic, none of those is a blocker.
Before you buildSimple Analytics Free covers 5 sites with 30 days of history if you accept the badge. For a personal site that may be all you need.
Build me a small web analytics service to replace Simple Analytics. Requirements:
- Node.js 22 + TypeScript: a Fastify server. `npm start` serves the dashboard on
http://localhost:4800 and the collector on port 4801, so only the collector needs a public address.
- Tracker: a script under 2 KB served at /a.js that sends one page view with `navigator.sendBeacon`
to /collect: path, referrer, screen width and UTM parameters. No cookies, no localStorage, no
fingerprinting; it honours Do Not Track and skips localhost. Custom events use the same script:
`sa.event("signup", {plan: "pro"})`, stored with JSON metadata.
- Storage: better-sqlite3 in ./data/stats.db with one row per page view. A visitor is a hash of
IP, user agent and site salted with a secret that rotates daily, so the raw IP is never stored
and the same person can't be followed across days.
- Enrichment at write time: country from a DB-IP lite or GeoLite2 .mmdb file (`maxmind`), browser,
OS and device class from the user agent (`ua-parser-js`), and known bots dropped with `isbot`.
- Dashboard: one page with date presets, unique visitors, page views, top pages, referrers,
countries, devices, UTM campaigns and an events table; clicking a row filters the rest. A site
switcher for several domains, all behind one password in .env.
- Retention: a nightly job rolls rows older than 90 days into daily totals and deletes the raw rows.
- Export: CSV and JSON of raw page views for any date range, and a JSON stats endpoint behind an API key.
- Single user. No accounts, no telemetry, local-first. No outbound calls at runtime; the GeoIP file is a manual download.
- Out of scope: funnels, session replay, heatmaps, email reports, teams.
- README: putting a reverse proxy in front of the collector, adding the script tag, getting the GeoIP
file and backing up with `sqlite3 .backup`.Opens your agent with the prompt filled in, you press enter. Or copy it and paste it into an empty folder.
The first prompt builds the core. Run these one at a time in the same folder to grow it into your own Simple Analytics.
Add a weekly report to the analytics service in this folder. Requirements: - Every Monday at 08:00 in the timezone from .env, email each site's owner address a plain-text summary through nodemailer SMTP: visitors and page views against the previous week, top five pages, top five referrers and top three countries. - A command `stats report <site> --print` shows the same text in the terminal without sending. - Skip sites with no traffic that week. - Update the README with the cron or launchd entry.
Add first-party proxying to the analytics service in this folder. Requirements: - Let the collector answer on a configurable path such as /stats/a.js and /stats/collect on the site's own domain, with a ready-made reverse proxy snippet for Caddy and nginx in the README. - Trust the forwarded IP header only from the proxy addresses listed in .env, so visitors can't spoof their country. - Add a test that a request with a spoofed forwarded header from an untrusted address is ignored.
Add goals and a funnel view to the analytics service in this folder. Requirements: - Define goals in the dashboard: a path match, or a custom event name with optional property filters. Show conversions and conversion rate per goal for the selected dates. - A funnel of up to five steps (paths or events), counting visitors who did the steps in order within 24 hours, with drop-off percentages between steps. - Compute from the stored rows with SQL; add an index and show query timings in the dev log. - Update the README.
Owners want traffic numbers without a cookie banner and without running a server. For $20 a month the data sits in the EU, the dashboard is one page, and nobody has to patch anything or explain a self-hosted database to a client.
Estimate · Free on a machine you already run; about the price of a small VPS otherwise. The build is token usage on your agent plan.
Checked 2026-10-19 against Simple Analytics's docs: 1, 2, 3, 4, 5
| Plan | Monthly | Annual, per month | What you get |
|---|---|---|---|
| Free | $0 | $0 | 1 user, 5 websites, 30 days of history (older data is deleted), Simple Analytics badge required. |
| Self-serve | $20 | $16.67 | From 100k pageviews a month, with a slider up to 2.5M; one-page dashboard, no cookies or consent banner, EU hosting; 1 user included. |
| Enterprise | custom | — | Side-by-side comparison with GA4, campaign comparisons, API and BI access, setup help with proxies and custom domains; starts with a free 30-day proof of concept. |
Free for hobby sites: 1 user, 5 websites, unlimited pageviews under a fair-use policy, 1 month of history and a required badge.
Yes. An AI coding agent such as Claude Code, Codex or Cursor can build a usable personal version in one session with the prompt on this page, running on your own machine.
About $20 a month on the Self-serve, up to 100k pageviews plan, $240 a year (checked 2026-10-19).
Bot and referrer-spam filtering maintained across thousands of sites; Hosting in the Netherlands with a vendor that publishes its compliance position; Ready-made export formats and an API for BI tools; No server to patch, back up or restart; Ingestion that stays up when a post hits the front page. If any of those matter to you, keep paying.
Yes: Plausible Community Edition (open source), Umami (open source), GoatCounter (open source).