Self-hosted web analytics with a Go backend and React dashboard. Built for low-resource hosts, with Go's small memory footprint and single-binary deployment keeping it lightweight. Supports SQLite or PostgreSQL.
- Privacy-first: no analytics cookies, daily visitor ID rotation
- Bot filtering: excludes crawlers, scrapers, monitoring bots.
- Lightweight: runtime consumes around ~15MB of RAM on AMD processor.
- SQLite and PostgreSQL supported.
- Dashboard: GraphQL API with React UI deployed as a static assets.
- Custom events: allowlisted event names and fields. Prevents spamming your database with unnecessary data.
services:
lovely-eye:
image: ghcr.io/revotale/lovely-eye:latest
ports:
- "8080:8080"
environment:
- JWT_SECRET=your-secret-key-min-32-chars
# Dashboard auth uses cookies and requires HTTPS (serve behind a reverse proxy)
# Default is true; you can disable it to serve over HTTP.
# Tracking is cookieless; this setting only affects dashboard auth.
- SECURE_COOKIES=true
# Optional: enable country stats with a MaxMind license key (auto-downloads to /data)
- GEOIP_MAXMIND_LICENSE_KEY=your-maxmind-license-key
volumes:
- lovely-eye-data:/app/data
# Optional: mount /data once for both SQLite and GeoIP
- ./data:/data
restart: unless-stopped
volumes:
lovely-eye-data:services:
lovely-eye:
image: ghcr.io/revotale/lovely-eye:latest
ports:
- "${PORT:-8080}:8080"
environment:
- DB_DRIVER=postgres
- DB_DSN=postgres://${POSTGRES_USER:-lovely}:${POSTGRES_PASSWORD:-lovely}@lovely-eye-db:5432/${POSTGRES_DB:-lovely_eye}?sslmode=disable
- JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required}
# Dashboard auth uses cookies and requires HTTPS (serve behind a reverse proxy)
# Default is true; you can disable it to serve over HTTP.
# Tracking is cookieless; this setting only affects dashboard auth.
- SECURE_COOKIES=true
- INITIAL_ADMIN_PASSWORD=${INITIAL_ADMIN_PASSWORD}
- INITIAL_ADMIN_USERNAME=${INITIAL_ADMIN_USERNAME}
depends_on:
lovely-eye-db:
condition: service_healthy
networks:
- lovely-eye-net
restart: unless-stopped
lovely-eye-db:
image: postgres:18.1-alpine
environment:
- POSTGRES_USER=${POSTGRES_USER:-lovely}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-lovely}
- POSTGRES_DB=${POSTGRES_DB:-lovely_eye}
volumes:
- lovely-eye-data:/var/lib/postgresql
networks:
- lovely-eye-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-lovely} -d ${POSTGRES_DB:-lovely_eye}"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
lovely-eye-data:
networks:
lovely-eye-net:
Requires Go 1.25+.
cd server
go run ./cmd/serverServer starts at http://localhost:8080. The first registered user becomes admin. SQLite by default.
After you started your containers:
- login into dashboard.
- Create "Site" and enter domain you want to track.
- Open your "Site". You will find the "Settings" button in right top corner. Click it and scroll to the "Tracking Code" section.
- Copy the tracking code and install into your website via
javascriptorhtml.
| Variable | Default | Description |
|---|---|---|
SERVER_HOST |
0.0.0.0 |
Server bind address |
SERVER_PORT |
8080 |
Server port |
DB_DRIVER |
sqlite |
sqlite or postgres |
DB_DSN |
file:data/lovely_eye.db?cache=shared&mode=rwc |
Database connection string |
JWT_SECRET |
(random) | JWT signing key (min 32 chars, required for production) |
SECURE_COOKIES |
true |
Use secure cookies (requires HTTPS). Set to false for local dev |
ALLOW_REGISTRATION |
false |
Allow new user registration after first user |
GEOIP_DB_PATH |
/data/GeoLite2-Country.mmdb |
Path to GeoLite2-Country.mmdb for country stats |
GEOIP_DOWNLOAD_URL |
https://download.db-ip.com/free/dbip-country-lite.mmdb.gz |
Default GeoIP download URL (mmdb, gz, or tar.gz) |
GEOIP_MAXMIND_LICENSE_KEY |
- | MaxMind license key for GeoLite2 auto-download |
Country tracking downloads the GeoIP database on demand when at least one site enables it. If the download fails, the dashboard will show the error in site settings.
<script>
window.lovelyEye?.track('error', {
message: 'Checkout failed',
code: 'PAYMENT_DECLINED',
});
</script>Events must be allowlisted in site settings. Unknown event names or fields are ignored.
- ANALYTICS.md - tracking mechanics
- PRIVACY.md - privacy handling
JWT tokens in HttpOnly cookies with SameSite settings:
- HttpOnly: prevents JavaScript access (XSS protection)
- Secure: HTTPS only in production
- SameSite=Strict (production) or Lax (development): prevents CSRF
Copyright 2025 RevoTale
Licensed under AGPL-3.0.
