ADR 06: Self-hosted Umami for analytics
One analytics instance for the whole fleet.
Status: adopted (2026-07-15), standing workflow
Context
Every client site needs analytics without per-site SaaS fees or cookie banners.
Decision
Self-hosted Umami at analytics.backpackops.com. Every finished or ported site is registered there and carries the tracking script. This is a standing workflow: a site is not “done” until tracked. Credentials live in UMAMI_USERNAME and UMAMI_PASSWORD env vars only.
Mechanics
- Registration is idempotent: check
GET /api/websites?query=<domain>for an exact domain match before creating. - Static sites get the script injected into every page’s head (exports have no shared includes). porter/umami.py does this idempotently.
- Next.js sites use an env-gated next/script with NEXT_PUBLIC_UMAMI_WEBSITE_ID and NEXT_PUBLIC_UMAMI_SRC.
- The console resolves a site’s Umami entry by reading data-website-id off the live page, which stays correct before DNS cutovers when the registered domain (target apex) differs from the current Vercel alias.