Self-hosting
Umami Cloud
Enable optional Umami Cloud statistics from the admin panel, with same-origin proxying and reader privacy controls.
An instance admin can connect Umami Cloud from Admin → Instance → Umami Cloud. The integration starts disabled and is independent of the built-in writer dashboard. Statistics are viewed in Umami Cloud, not in Omicron’s dashboard.
Connect a website
- Add a website in Umami Cloud for your instance’s public domain. Copy its website ID or tracking snippet.
- Sign in to Omicron with an admin account. Open
/admin?tab=settingsand find the Umami Cloud section in the Instance tab. Moderators cannot change these settings. - Paste the value into Website ID or tracking code. A website ID is a UUID,
such as
94db1cb1-74f4-4a40-ad6c-962362670409. - Turn on Enable Umami Cloud, then select Save Umami settings. Changing the switch alone does not save it.
- After a successful save, the field contains the extracted website ID and the panel reports Umami Cloud enabled. Open a public article in a browser without a privacy opt-out and check the website’s statistics in Umami Cloud.
Only the website ID and enabled state are saved. Pasted markup is not executed or kept, and any script URL in it is ignored. No Umami password or API key is needed; the website ID is public, not a secret.
The settings persist in the instance database. Saving does not require a restart, environment variables, Caddy edits, or a Content Security Policy exception. This integration supports Umami Cloud, not a self-hosted Umami server or an arbitrary analytics provider.
Same-origin proxying
Both browser requests stay on your Omicron instance’s origin:
| Browser request | Fixed upstream |
|---|---|
GET /api/site/script.js |
https://cloud.umami.is/script.js |
POST /api/site/api/send |
https://gateway.umami.is/api/send |
Omicron sets the script’s data-host-url to its local proxy, so collection
does not fall back to a direct browser request to the Cloud gateway. This
implements Umami’s proxy approach to ad blockers.
It can avoid third-party domain blocklists; it cannot guarantee that every
extension or blocking rule permits the tracker.
The backend keeps the script in memory for one hour, sharing concurrent
fetches. Cloud requests have a five-second timeout. Browser-facing responses
use Cache-Control: no-store; collection responses are not cached. Visitor
cookies and authorization credentials are not forwarded to Cloud. Collection
does forward the visitor IP and User-Agent, plus Umami’s session-cache header
when present.
What is measured
Omicron sends pageviews after a successful page navigation, including client-side navigation without a full reload. A change to only the query string or fragment does not produce another pageview for the current page.
| Included pages | Excluded pages and activity |
|---|---|
| Home, profiles, published articles | Sign-in, registration, account recovery, and setup |
| Tag pages | Admin, settings, search, dashboards, and notifications |
| About, contact, privacy, status | Editors, drafts, scheduled posts, and all reading-list pages |
| Error pages, custom events, identification, performance, replays |
Page URLs contain only the path: queries and fragments are removed. Referrers from this instance retain only allowed public paths; private paths are omitted. External referrers are reduced to their origin, with no path, query, or fragment. No reader account ID is supplied, and the integration sets no analytics cookies. These pageviews do not change the writer dashboard’s view counts.
Do Not Track and Global Privacy Control are checked in the browser and
on incoming collection requests. A browser with a truthy
localStorage['umami.disabled'] value also opts out. Visiting without JavaScript
does not generate Umami pageviews. A proxy or tracker failure does not prevent
reading the site.
While enabled, /privacy includes an Optional website statistics disclosure,
even if you have supplied a custom privacy policy. This disclosure does not
replace your responsibility to maintain an appropriate policy.
On omicron.blog, the disclosure names Umami Cloud’s Europe region. That region
wording is currently hard-coded in the frontend rather than read from the
website settings. If your Umami Cloud website uses a different region, update
apps/frontend/src/routes/privacy/+page.svelte to match before enabling the
integration.
Disable or remove
- Pause collection: turn off Enable Umami Cloud and select Save Umami settings. The saved website ID remains available for later use.
- Remove the configuration: leave the switch off, clear the website field, and save. An empty ID cannot be saved with the switch enabled.
The backend stops forwarding pageviews when disabled and no longer serves the tracker. Neither action deletes historical statistics held by Umami Cloud; manage those in Cloud separately. Built-in writer analytics are unaffected.
Troubleshooting
- Invalid website ID: use the website’s UUID, not an account or team ID.
A snippet must contain exactly one quoted
data-website-idattribute. - No pageviews: confirm the settings were saved and the Cloud website matches your domain. Use a public page, check DNT/GPC and the browser’s local opt-out, and inspect extension blocking. Private pages are intentionally absent.
- Proxy unavailable: a
502from the script or collection route means the Cloud request failed. Check outbound HTTPS access tocloud.umami.isandgateway.umami.is; do not add a second direct tracking snippet. - Rate limited: collection has a fixed 60 requests per minute per IP
budget, in addition to the general API-write budget. A request over the limit
gets
429withRetry-After; see Rate limits.
For scripted configuration and the proxy route map, see Admin API and HTTP API.
Found a mistake?Edit this page on GitHub.