Privacy-first, feather-light website analytics.
Kite is a simple, self-hosted web analytics tool. Add one line of code to any website and get clean, respectful traffic insights — with zero cookies, zero third parties, and full data ownership.
- Extremely lightweight — Tracking script is ~800 bytes
- No cookies — Uses
localStoragefor sessions only - Visitor insights — Records IP address + approximate city/country for each pageview
- Works everywhere — Static sites, SPAs, Next.js, WordPress, you name it
- Beautiful dashboard — Real-time pageviews, referrers, top pages, and visitors
- Self-hosted — Your data lives in a single SQLite file (
analytics.db) - SPA support — Automatically tracks client-side navigation
- Optional uptime monitoring — Built-in active checks for sites with a domain (no extra code on your sites)
git clone https://github.com/yourusername/kite-analytics.git
cd kite-analytics
npm install
npm run devOpen http://localhost:3000.
- Create a new site in the dashboard
- Copy the snippet:
<script src="https://yourdomain.com/analytics.js" data-site="YOUR_SITE_ID"></script>- Paste it into the
<head>of any website.
That's it. Visits will start appearing immediately.
- The script sends pageviews via
navigator.sendBeacon(with fetch fallback) - Sessions are stored locally in the visitor's browser
- All data is written to a local SQLite database on your server
- No data ever leaves your infrastructure
Kite can also monitor the availability of your sites (separate from analytics tracking).
- When you add a site with a domain, Kite will periodically send simple HTTP checks (HEAD/GET) to that domain from your server.
- No code is required on the monitored website — this is active/synthetic monitoring.
- Results (status, latency, uptime %) appear on the main dashboard and on each site's page.
- History is stored in the same
analytics.db.
The monitor is a small standalone script. It must be running for uptime data to be collected.
# One-time check (great for testing)
npx tsx scripts/uptime-monitor.ts --once
# Continuous monitoring (every 5 minutes by default)
npx tsx scripts/uptime-monitor.tsRecommended ways to keep it running in production:
- PM2:
pm2 start npx --name kite-uptime -- tsx scripts/uptime-monitor.ts - systemd / Docker sidecar / Railway "worker" process
- External cron calling the protected endpoint:
*/5 * * * * curl -s "https://your-kite.example.com/api/uptime/check?token=YOUR_SECRET" >/dev/null
Set UPTIME_INTERVAL_SECONDS=300 (or any value) and UPTIME_CHECK_SECRET (for the HTTP trigger) in your environment if needed.
Uptime data older than 90 days is automatically pruned.
Kite collects the following per pageview:
- Raw IP address (for display in Recent Pageviews)
- Approximate location (city + country via GeoIP lookup at ingestion time)
- Referrer, path, user agent (truncated), and session id (localStorage-based)
Other notes:
- No cookies are set
- The script respects the
Do Not Trackheader - IP + location data lives only in your
analytics.db— nothing is sent to third parties - Unique visitor counts still use a salted hash of the IP (not the raw value)
If you prefer stricter privacy, you can fork and remove the IP/location storage in app/api/track/route.ts.
- Next.js 16 (App Router)
- TypeScript + Tailwind
- SQLite (via
better-sqlite3) - Recharts for visualizations
app/
├── api/
│ ├── track/ # Event ingestion endpoint
│ ├── sites/ # Site CRUD
│ └── stats/[id]/ # Analytics queries
├── sites/[id]/ # Per-site dashboard
└── page.tsx # Sites overview
public/
└── analytics.js # The embeddable tracking script
lib/db.ts # Database layer
lib/uptime.ts # Uptime check logic
scripts/uptime-monitor.ts # Background monitor daemon
Kite works great on:
- Vercel (with persistent storage or external DB)
- Railway
- Fly.io
- Any VPS (just run
npm run build && npm start)
Note: The default SQLite database is file-based. For production with multiple replicas, consider switching to Postgres or using a volume for analytics.db.
| Variable | Description | Default |
|---|---|---|
IP_SALT |
Salt used when hashing visitor IPs | analytics-salt-change-me |
ADMIN_USERNAME |
Username for dashboard login | (required for login) |
ADMIN_PASSWORD |
Password for dashboard login | (required for login) |
AUTH_SECRET |
Secret used to sign login sessions (use a long random string) | change-this... |
Important: To enable the login screen, set ADMIN_USERNAME and ADMIN_PASSWORD in your environment. Without them, the login system will show an error.
Contributions are welcome! Please open an issue or pull request.
MIT
Built with care for people who want to understand their traffic without invading their visitors' privacy.
