Skip to content

Repository files navigation

Vision

Self-hosted, cookie-free web analytics. Drop a 3.7 KB unminified script on a site, watch pageviews, visitors, referrers and goals in a SvelteKit dashboard you own.

Visitors are identified by a random ID in localStorage, not a cookie, and no IP address is ever stored — country comes from Cloudflare's CF-IPCountry header when it is present.

Live at vision.facile.studio.

What it does

  • Collects pageviews through a tracking pixel, so ad blockers and sendBeacon restrictions do not silently kill ingestion
  • Records referrers, UTM parameters, browser, OS, device, language, screen width and Navigation-Timing performance numbers
  • Counts live visitors from a 30-second heartbeat with a 60-second expiry window
  • Streams new pageviews to the dashboard over server-sent events
  • Tracks custom events and conversion goals, matched on event name or page path
  • Groups sites into workspaces with member roles, and shares any dashboard read-only via a public token link
  • Exports a date range as JSON or CSV, and issues scoped vis_ro / vis_rw API keys
  • Posts periodic HMAC-signed traffic reports to a webhook

Stack

Layer Tech
API Go 1.24, Chi v5, GORM, PostgreSQL 16, tronc v0.3.0
Client SvelteKit 2 (Svelte 5 runes), Tailwind CSS 4, shadcn-svelte, LayerChart, TopoJSON world map
Auth Bearer session tokens, argon2id passwords, optional OIDC, vis_* API keys
Deploy Docker Compose, three containers: database, API, SvelteKit server

Quick start

cp .env.example .env
docker compose up -d --build

Then open http://localhost:3000. The SvelteKit container is the only one you talk to; it proxies /api/* to the Go API on its own network.

Local development

mise run install
cd apps/api    && go run .        # :4000
cd apps/client && bun run dev     # :5173, proxies to API_URL

Tracking a site

Add the site in the dashboard, then put this on the pages you want measured:

<script defer src="https://vision.facile.studio/s.js"></script>

The script derives its collection endpoint from its own src, so self-hosting under another hostname needs no configuration. window.vision.track(name, props) sends a custom event.

Configuration

Variable What it does
DATABASE_URL Postgres connection string
PORT API listen port, 4000 by default
DOMAIN Dashboard origin. It is the only allowed CORS origin on the API
STORAGE_DIR Where uploaded avatars live
API_URL Client container only: where the SvelteKit proxy forwards /api/*
OIDC_ISSUER Set it to turn on SSO; three more OIDC_* variables become required
SSO_ONLY Disables local email/password auth

Full reference: docs/configuration.md.

Structure

apps/
  api/       Go backend — modules/ (auth, sites, events, analytics, goals,
             apikeys, workspaces, webhooks), internal/ (env, middleware,
             siteaccess, database), schemas/ (GORM), tracker/ (stale, see docs)
  client/    SvelteKit server — hooks.server.ts is the API proxy,
             static/s.js is the tracker actually served to browsers
docs/        Architecture, configuration, development, deployment, API
scripts/     check.sh, the repository quality gate

Documentation

Doc What's in it
Architecture Request flow, ingestion, data model, auth
Configuration Every environment variable and default
Development Local setup, tests, the quality gate
Deployment Compose topology and why Vision is not one container
API HTTP endpoints and payloads

Part of the Facile Suite — self-hosted tools for creative studios and freelancers. One login, zero cloud dependency.

About

Web visit tracking for Facile client projects

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages