NanoAnalytics
Own Your Data
Lightweight, self-hosted web analytics.
One line of JS. No cookies. No GDPR banner.
Your data. Your server. Always.
Google Analytics tracks your visitors. NanoAnalytics doesn't.
Every time you paste a Google Analytics tag, you hand your visitors' data to a third party — and slap a GDPR banner on your site. That's the deal. NanoAnalytics changes it: you host it, you own the data, and your visitors get no banner because there are no cookies and no personal data stored.
The trade-off? You lose the Google ecosystem. What you gain: complete data control, a clean privacy policy, a sub-400-byte tracking beacon, and a full OpenAPI REST API that works with Claude, GPT, and any data tool you already use.
Everything You Need. Nothing You Don't.
Analytics without the bloat, the trackers, or the monthly bill.
Sub-400-Byte Beacon
The tracking script is tiny — smaller than a thumbnail image. Tracks pageviews, referrers, browser,
screen width, language, and country from IP. SPA-ready with history.pushState support.
No Cookies, No Banner
Sessions are stored in sessionStorage — not cookies, not localStorage.
No personal data. No cross-site tracking. GDPR-compliant without lifting a finger.
SQLite — No Infra Overhead
One database file. No Postgres, no Redis, no managed DB cost. At 1,000 daily visitors the database grows ~90 MB per year. At 10k daily: ~900 MB. Simple, predictable, cheap.
15 API Endpoints
Pageviews, top pages, referrers, devices, countries, browsers, OS, screen widths, entry/exit pages, peak hours, bounce rates, session duration, real-time active visitors. Bearer token auth. Everything documented.
AI-Ready via MCP
OpenAPI 3.1 spec at /openapi.json. Swagger UI at /docs.
Plug your analytics directly into Claude Desktop, Cursor, Windsurf, or any GPT Action. Ask your data questions in plain English.
Live Visitor Map
Dashboard includes a real-time world map with active visitors by country, refreshing every 30 seconds. GeoIP lookups are done offline — no external API calls, no latency, no cost.
One Line to Track Everything
Paste this before </body>. That's it.
<script async src="https://your-instance.railway.app/a.js"></script>
Non-blocking. Zero impact on your page load score.
Works across all your domains from a single instance.
Hooks into history.pushState for client-side routing.
Deploy in Minutes
Three ways to self-host. All of them straightforward.
One-Click Cloud Deploy (Recommended)
Deploy to Railway, Render, or Fly.io with a single click. The platform provisions the instance,
sets your API_TOKEN, and you're live. No CLI, no config files.
Docker Compose — VPS or Local
Clone, set your token, start. A named volume handles persistence automatically. Works on any Linux VPS (Hetzner, DigitalOcean, Linode) or your local machine.
git clone https://github.com/callmefredcom/NanoAnalytics
cd NanoAnalytics
echo "API_TOKEN=your-secret-token" > .env
docker compose up -d
Running on port 8000. Data persisted in a named Docker volume. That's it.
pip Install — Embed in Any Python Project
Install as a package and run alongside your existing Flask app or as a standalone service.
pip install nano-analytics
export API_TOKEN=your-secret-token
export DB_PATH=/data/analytics.db
gunicorn "nano_analytics:create_app()" --bind 0.0.0.0:8000
AI-Ready from Day One
Your analytics data is queryable by any AI agent, workflow tool, or REST client.
OpenAPI 3.1 Spec
Machine-readable spec at /openapi.json. Swagger UI at /docs.
Every endpoint is documented: parameters, response schemas, auth requirements.
MCP Server Support
Connect to Claude Desktop, Cursor, or Windsurf via the OpenAPI MCP server. Ask questions like "what were my top pages yesterday?" and get live data back.
Telegram & Discord Bots
Optional bot scripts included. Deploy alongside your instance and query stats from your phone:
/stats, /pages, /active, /countries, and more.
n8n, Make, LangChain
Any tool that can make a Bearer-token HTTP request can read your analytics. Build automated reports, Slack summaries, or AI-driven dashboards without vendor lock-in.
Example API call — top pages, last 7 days:
curl https://your-instance.railway.app/api/pages \
-H "Authorization: Bearer your-secret-token" \
-G -d "start=$(date -d '7 days ago' +%s)" \
-d "end=$(date +%s)" \
-d "limit=10"
The Stack
Simple by design. Readable by anyone.
Backend
- Flask 3.1+ — WSGI server, clean route definitions, Gunicorn for production
- SQLite with WAL mode — concurrent reads, no database server, one file
- geoip2fast — offline country lookup from IP. No external API calls
- No ORM — direct SQL, one table, zero magic. You can read every query in 5 minutes
Frontend & Infra
- Chart.js 4 — timeseries, bar charts, doughnut charts for device/browser breakdowns
- Leaflet.js — real-time world map of active visitors by country
- Swagger UI 5 — interactive API explorer for every endpoint
- Alpine Docker image — Python 3.12, minimal footprint, platform-agnostic
The entire database is one table. Seriously.
CREATE TABLE hits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ts INTEGER NOT NULL, -- Unix timestamp
site TEXT NOT NULL, -- Domain
path TEXT NOT NULL, -- Page path
ref TEXT, -- Referrer
ua TEXT, -- User-Agent string
lang TEXT, -- Browser language
w INTEGER, -- Screen width
session TEXT, -- sessionStorage ID
country TEXT -- ISO country code (offline GeoIP)
);
Why We Built It
Infra cost at <1k daily visitors
Railway free tier or $5/mo VPS
Analytics endpoints
All documented. All queryable by AI.
Tracking beacon size
Async, non-blocking, invisible to Lighthouse
NanoAnalytics is Flask Vibe, applied.
It's what a Flask + SQLite app looks like when you resist the urge to over-engineer. One table. One beacon. One token. Full analytics. No surprise bills. This site runs it. So do several others.
Ready to Own Your Analytics?
Open source. MIT license. Deploy once, track forever.