Telemetry
The anonymous heartbeat a Noite install sends once a day — what it contains, where it goes, how to see the exact payload, and how to turn it off.
Noite installs send one anonymous heartbeat a day, so the maintainers can tell how many installs run which release and roughly how they are used. It is on by default and opt-out: the payload is counts, versions and closed buckets, nothing identifies you or your users, and turning it off is one setting.
The runner sends it directly to PostHog’s HTTP capture API. There is no PostHog SDK, no cookie and no browser tracking — the request comes from the container, not from a visitor’s browser. This is separate from the per-app telemetry Noite collects for you: logs, traces, metrics and errors live in your own bucket and never leave it (Storage).
What is sent
One event per install per day, instance_heartbeat, built by the runner from its own database. These are all its properties:
| Property | Example | Meaning |
|---|---|---|
version |
0.1.0-alpha.3 |
Release version baked into the image (dev for a source build) |
celld_version |
0.6.1 |
celld version the image ships (unknown if unset) |
arch |
x86_64 |
CPU architecture |
tenancy |
multi |
multi or single (Tenancy) |
storage |
bundled |
bundled for the bundled RustFS, external for your own bucket |
apps |
4 |
Total apps |
apps_running |
3 |
Apps desired running and awake |
apps_sleeping |
1 |
Apps asleep (Limits) |
deploys_24h |
7 |
Deploy rows created in the last 24 hours |
deploys_failed_24h |
1 |
Of those, failed |
users |
2-5 |
Bucket of the account count: 1, 2-5, 6-20, 21+, or unknown when the control worker cannot be reached |
install_age_days |
12 |
Whole days since the install was first created |
uptime_hours |
813 |
Whole hours since the runner started |
What is never sent
No domains or hostnames. No app names or slugs, no bucket names or endpoints. No account names, email addresses or sign-in data. No IP addresses or geolocation. No request paths, logs, source or deploy output. No environment values, and nothing about the visitors to your apps. The payload is fixed — every field is a count, a version or a closed bucket, and there is no field that carries free-form text.
The install id
distinct_id is a random UUID v4, generated on the install’s first boot. It lives in the runner’s database (instance_setting, key install_id), which is snapshotted into your bucket, so it survives container recreation, upgrades and a restore from the bucket — one install stays one install. It is not derived from your domain, server or account, and a fresh install starts a new one.
Where it goes
POST https://eu.i.posthog.com/i/v0/e/ — PostHog’s EU Cloud — under the project key compiled into the image (write-only, safe to be public). The event sets $geoip_disable: true and $process_person_profile: false, so PostHog does not geolocate the request or keep a person profile for it. A send has a 10-second timeout; a failure is logged at most once and retried at the next check. Telemetry never blocks or fails a deploy, a request or a boot.
How often
The first attempt is ten minutes after the runner starts, then it checks hourly and sends when the last successful send was at least 24 hours ago. That time is stored as telemetry_last_sent_at. Turning telemetry off stops sends immediately.
See the exact payload
Instance admins have two ways to see exactly what the next send would post.
On /account, the Admin section has an Anonymous usage telemetry row whose Show the exact payload disclosure renders the JSON the next heartbeat would post (with the API key omitted from the display).
The same body comes from the runner, using the RUNNER_TOKEN from /opt/noite/.env:
cd /opt/noite
RUNNER_TOKEN=$(grep '^RUNNER_TOKEN=' .env | cut -d= -f2-)
docker compose exec -T noite curl -s \
-H "Authorization: Bearer $RUNNER_TOKEN" \
http://127.0.0.1:8080/v1/admin/telemetry | jq .preview
GET /v1/admin/telemetry returns the effective enabled state, the stored setting, whether the setting is locked and why, lastSentAt, the installId, and preview — the exact JSON body, API key included. The UI hides the key; the raw API does not.
Turning it off
| Way | How |
|---|---|
| Admin checkbox | On /account, under Admin → Anonymous usage telemetry, clear Share anonymous instance telemetry. Applies immediately. |
| Environment variable | NOITE_TELEMETRY=0 in /opt/noite/.env, then cd /opt/noite && docker compose up -d. false and off work too. The installer also accepts NOITE_TELEMETRY and writes it to .env. |
| Do Not Track | DO_NOT_TRACK=1 disables it — any non-empty value other than 0. |
| Local domains | An install whose base domain is localhost, *.localhost, *.local, *.test, *.internal or an IP literal never reports. That covers the dev stack and the e2e lanes (which also set NOITE_TELEMETRY=0). An <ip>.sslip.io install is a public domain and does report — the installer’s no-DNS default still counts. |
When an environment variable or a local domain applies, the setting is locked: the checkbox is disabled and reads Disabled by NOITE_TELEMETRY=0, Disabled by DO_NOT_TRACK or Disabled by local domain, and the runner will not send even if the stored preference is on. Removing the override restores the stored preference.
Nothing is sent about the opt-out itself: turning telemetry off is not an event.