9.7 KiB
Umami Analytics – Operations & Integration Guide
This document explains how we run our self‑hosted Umami analytics at https://analytics.degelas.be, how to integrate new sites/domains, and how to define custom events, goals, and reports. It is written so another server/agent can reproduce the setup.
1. Architecture overview
- Umami app: Docker container
umami, imageghcr.io/umami-software/umami:postgresql-latest. - Database: Docker container
umami-db, imagepostgres:16-alpine. - Reverse proxy: Existing Nginx proxy stack in
fullstack_degelas(containerdegelas_nginx). - Public URL:
https://analytics.degelas.be(served bydegelas_nginx, proxied toumamiby container name). - TLS: Single Let’s Encrypt certificate for
degelas.bethat now includes:degelas.be,www.degelas.be,glenn.degelas.be,maite.degelas.be,analytics.degelas.be.
All analytics script tags on our sites point to https://analytics.degelas.be/script.js.
2. Umami stack (docker-compose)
Location: solar_trading_engine/umami-docker-compose.yml
Key points:
- Creates
umami-db(Postgres) andumami(Umami server). - Uses an
.envfile (umami.env) for DB credentials and secrets. - Attaches
umamito both:- A private network
umami-net(for DB), - The shared external network
fullstack_degelas_proxyso Nginx can reach it by container nameumami.
- A private network
To (re)start the stack on a server:
cd /root/solar_trading_engine
docker compose --env-file umami.env -f umami-docker-compose.yml up -d
Check containers:
docker compose -f umami-docker-compose.yml ps
3. Environment configuration (umami.env)
Location: solar_trading_engine/umami.env (not committed; umami.env.example is the template).
Required values:
UMAMI_DB_NAME,UMAMI_DB_USER,UMAMI_DB_PASSWORD- Strong password; used by
umami-dbandumami.
- Strong password; used by
UMAMI_APP_SECRET- Random secret, generated with:
openssl rand -hex 32
UMAMI_WEBSITE_URL- Canonical analytics URL, e.g.
https://analytics.degelas.be.
- Canonical analytics URL, e.g.
On a new server:
- Copy
umami.env.example→umami.env. - Fill in strong values for the password and secret.
- Set
UMAMI_WEBSITE_URLto the correct domain.
4. Nginx proxy integration (analytics.degelas.be)
The global proxy stack lives in fullstack_degelas/ with docker-compose.yml and Nginx config under nginx/.
4.1 Networks
fullstack_degelascreates an external Docker networkfullstack_degelas_proxy.- Our
degelas(solar trading) stack andmaitestack join this network. umamialso joins this network to allow:degelas_nginx→proxy_pass http://umami:3000;
4.2 Nginx vhost for analytics
Location: fullstack_degelas/nginx/conf.d/analytics.degelas.be.conf
Behavior:
- Listens on 80/443 for
analytics.degelas.be. - Serves ACME challenges via
/var/www/certbot. - Redirects HTTP → HTTPS.
- On HTTPS, proxies to
http://umami:3000using the shared Docker network.
After changing Nginx configuration:
cd /root/fullstack_degelas
docker compose up -d # ensure nginx + certbot are running
docker compose exec nginx nginx -s reload
5. Certificates (Let’s Encrypt)
The fullstack_degelas stack runs a certbot container that:
- Stores certs under
/etc/letsencrypt. - Uses the webroot
/var/www/certbotfor HTTP-01 challenges. - Has a single certificate
degelas.bethat includes:degelas.be,www.degelas.be,glenn.degelas.be,maite.degelas.be,analytics.degelas.be.
To inspect certificates:
cd /root/fullstack_degelas
docker compose exec certbot certbot certificates
To add an extra domain (e.g. analytics.degelas.be) without changing others:
docker compose exec certbot certbot certonly \
--webroot -w /var/www/certbot \
--expand \
-d degelas.be \
-d www.degelas.be \
-d glenn.degelas.be \
-d maite.degelas.be \
-d analytics.degelas.be
Then reload Nginx:
docker compose exec nginx nginx -s reload
If you reproduce this on another server, adjust the -d list to match the domains you want on the shared cert.
6. Frontend integration (tracking script)
For degelas.be we inject the Umami script in solar_trading_engine/frontend/index.html:
<script
async
src="https://analytics.degelas.be/script.js"
data-website-id="c7ba71c0-4bac-48d3-a8e3-7fdc92a6e4ba"
data-domains="degelas.be"
></script>
Key fields:
src: always points to the Umami instance,https://analytics.degelas.be/script.js.data-website-id: UUID for the specific website in Umami (per-site).data-domains: comma-separated list of hostnames this Umami site should accept, e.g.degelas.beordegelas.be,www.degelas.be.
For new domains:
- In Umami, create a new website for that domain.
- Copy its Website ID.
- On that domain’s frontend, add a script tag pointing to
https://analytics.degelas.be/script.jswith the new website ID and correctdata-domains.
Example for example.com:
<script
async
src="https://analytics.degelas.be/script.js"
data-website-id="NEW-WEBSITE-ID-FROM-UMAMI"
data-domains="example.com"
></script>
You can also use one website ID for multiple domains by listing them all in data-domains and in the Umami UI.
7. Custom events from the frontend
We added a small helper in solar_trading_engine/frontend/src/umami.ts:
- It exposes a safe
trackEventfunction that callswindow.umami.track(...)when available. - It fails silently if Umami is disabled or not loaded, so analytics never breaks the app.
Usage in React code:
import { trackEvent as trackUmamiEvent } from './umami'
// Example: when user runs a trading simulation
trackUmamiEvent('trading_sim_run', {
country: 'BE',
plan: 'battery',
})
// Example: when user visits a special page (in addition to normal pageview)
trackUmamiEvent('view_log_page', { section: 'activity' })
Notes:
- The event name is the first argument (string).
- The optional second argument is a key–value object (string/number/boolean) and appears in Umami as event properties.
8. Goals in Umami
Goals are configured in the Umami UI, not in code.
For each website:
- Open Umami → Settings → Websites → [website] → Goals.
- Click Add goal and choose:
- Event goal: triggered by a custom event name, e.g.
signup_completed,trading_sim_run. - Pageview goal: triggered when a specific URL or path is viewed, e.g.
/contact/success.
- Event goal: triggered by a custom event name, e.g.
- Save.
From that point:
- Every time code calls
trackUmamiEvent('signup_completed', {...}), the corresponding goal increments. - For pageview goals, any visit to the configured path increments the goal.
9. Reports & dashboards
Umami’s built-in UI allows:
- Filtering by date range, country, referrer, event name, etc.
- Viewing:
- Pages: top URLs and their metrics.
- Events: your custom events and their counts.
- Goals: conversion counts and rates.
Workflow for useful reports:
- Decide on key events/goals, e.g.:
signup_started,signup_completedtrading_sim_runbattery_config_saved
- Implement them in code using
trackUmamiEvent. - Define goals in Umami based on those events or URLs.
- In the Events/Goals views, filter by:
- Country (e.g. Belgium vs. others),
- Referrer (e.g.
google,maite.degelas.be), - Device, etc.
- Use Umami’s “save view” or dashboard features (depending on version) to keep common filters.
10. Geo stats (country/region/city)
We keep GeoIP lookups local to preserve privacy and avoid external dependencies.
On the server (see umami-geoip.md for more detail):
- Download a local GeoIP database (e.g. MaxMind GeoLite2-City).
- Mount it into the Umami container (e.g.
/geoip/GeoLite2-City.mmdb). - Configure Umami (via environment or config, depending on version) to use that file.
Once enabled, Umami’s UI shows breakdowns by:
- Country, and optionally region/city, in the standard views.
11. Email / SMTP (optional, but recommended)
Umami can send:
- User invites,
- Password reset emails,
- (Depending on version) scheduled reports.
Configuration is described in umami-smtp-and-testing.md. In summary:
- Choose an SMTP provider (Postmark, Mailgun, SES, etc.).
- Add SMTP environment variables to
umami.env, for example:UMAMI_SMTP_HOST,UMAMI_SMTP_PORT,UMAMI_SMTP_USERNAME,UMAMI_SMTP_PASSWORD,UMAMI_EMAIL_FROM.
- Wire them into the
umamiservice inumami-docker-compose.yml. - Restart the
umamicontainer. - Test:
- Invite a test user,
- Trigger password reset,
- Check inbox + spam + email headers for SPF/DKIM/DMARC.
12. Adding a new domain/site – checklist
Assuming another server or site wants to use the existing Umami instance:
-
DNS: point the new site’s domain to its own web server as usual (no change needed for analytics).
-
Ensure the new site is allowed:
- In Umami, either:
- Create a new website with that domain, or
- Add the domain to an existing site’s allowed domains.
- In Umami, either:
-
Script tag:
- Add a script tag to the new site’s HTML:
<script async src="https://analytics.degelas.be/script.js" data-website-id="WEBSITE_ID_FOR_THIS_SITE" data-domains="new-domain.com" ></script> -
Custom events (optional):
- Implement
window.umami.track(...)or use a helper similar tofrontend/src/umami.tsto send custom events.
- Implement
-
Goals & reports:
- Define goals in the Umami UI for this site.
- Build and save reports as needed.
No changes are required to the Umami server stack for additional sites; it is multi-tenant by design as long as each site has a Website ID and uses the correct script tag.