# Telemetry and Feedback Anonymous usage data helps improve self-host: which Apps people install, which Setup steps are slow, and where commands fail. Release builds send it to EU PostHog through `https://hog.ajnart.dev`. Development builds and CI send nothing. There is no public dashboard yet; one may come later. ## What it is for The data is used only to see how self-host is used, such as which Apps people install and where Setup and Onboarding break, and to debug failures. Only the maintainers see it. It is never sold, rented or shared with third parties, and never used for advertising. ## What is sent Only these four things. A command that succeeds sends nothing. - **An onboarding summary**, when you approve Onboarding's plan: your Experience level (`new` or `advanced`), the glyph set (`nerd-font` or `simple`), whether you skipped the intro, whether the machine check warned (`ok` or `warn`), how long Onboarding took, and the Catalog App and Recipe IDs and Access choice (`home` or `local`) you picked. Nothing is sent if you quit before approving. - **Errors**, when a command fails or ends incomplete: the command name, duration, Catalog App and Recipe IDs, step IDs, outcomes and durations, and a PostHog `$exception` with the error type, a fixed description, a stable fingerprint, and in-app function names, module-relative files and line numbers. Panics are unhandled exceptions, flushed before the original panic continues. Install approval rejections, Cloudflare plan input errors, a missing Project, a Dashboard closed by a signal and `doctor` findings send nothing. Warning and error steps also send fixed-text OTLP log records with the step and command IDs. These are not App logs, raw error messages or distributed traces. - **Agent App requests.** When an agent is asked for an App that is not in the Catalog, it runs `self-host apps request ""`, which sends the App's name (lowercase, at most 64 characters) and the host of its homepage, never a path or query. A person asks for an App by opening a [GitHub issue](https://github.com/ajnart/self-host/issues) instead. - **Feedback**, only after you see the text and agree (see below). Each event also carries the self-host version, OS and architecture. Events are anonymous: PostHog keeps no person profile and no person properties. GeoIP is disabled; payloads contain no IP addresses or locations. Receiving network infrastructure still sees the source IP. Server-side "Discard client IP data" is a maintainer-controlled setting, not something the CLI verifies. ## Website self-host.fyi (the site, the docs and Docker Compose Maker at `/compose`) sends a few anonymous usage events to the same EU PostHog proxy as the CLI. It sets no cookie and stores nothing in your browser for analytics (Docker Compose Maker keeps only your own settings and selection in local storage), builds no person profile, records no sessions, and sends nothing when your browser asks not to be tracked. It runs only on `self-host.fyi`: a local copy of the site, a preview or the `ghcr.io/ajnart/dcm` image sends nothing. This is separate from the CLI Telemetry above, and `SELF_HOST_NO_TELEMETRY` does not control it. Every page you see sends `$pageview`; a page your browser only prerenders sends it once you open it. PostHog's browser library adds properties to every event: the page URL, referrer and path (query string and fragment removed before sending), browser name and version, OS, device type, viewport and screen size, time zone, language and library version. The request also reaches the proxy with your IP address, as any request does; the site does not rely on a server-side IP setting. The named events carry Catalog or Container ids, counts and fixed values only: | Event | Sent when | Properties | | ----------------------------- | ----------------------------------------------------------- | ----------------------------------- | | `install_command_copied` | you copy the install command on the home or 404 page | `method` (`curl`, `wget`, ...) | | `app_install_copied` | you copy `self-host install ` on an App page | `app` | | `recipe_install_copied` | you copy a Recipe's install command on an App page | `recipe` | | `share_link_copied` | you copy the share link of the home page selection | `count` | | `dcm_mode_changed` | you switch between the self-host and docker compose pages | `mode` (`self-host` or `compose`) | | `dcm_item_selected` | you select a container | `id`, `source` (`self-host`, `dcm`) | | `dcm_item_unselected` | you unselect a container | `id`, `source` | | `dcm_compose_copied` | you copy the Compose file or the `.env` | `count`, `ids`, `file` | | `dcm_compose_downloaded` | you download the Compose file or the `.env` | `count`, `ids`, `file` | | `dcm_share_copied` | you copy the share link of your selection | `count` | | `dcm_selfhost_command_copied` | you copy the `self-host install` command | `count`, `ids` | | `dcm_template_opened` | you open a Template page | `id` | | `dcm_template_copied` | you copy a Template's Compose file or `.env` | `id` | | `dcm_search_opened` | you open the search dialog | none | | `dcm_settings_opened` | you open the settings panel | none | | `dcm_suggest_opened` | you open the Suggest container page | none | | `dcm_suggest_prompt_copied` | you copy the agent prompt on the Suggest container page | none | | `dcm_suggest_issue_opened` | you open the issue template from the Suggest container page | none | `file` is `compose` or `env`. Never sent: what you type, the search query, query strings and fragments, Compose or `.env` content, settings values and the app name and repository you type on the Suggest container page. See [ADR 0013](https://github.com/ajnart/self-host/blob/main/docs/adr/0013-website-analytics.md). ## What is never sent automatically Host names, absolute file paths, typed inputs, secrets, App data, raw error or panic text, IP addresses or locations. Stack files are relative to the Go module, never to the machine where the binary was built or installed. ## There is no stored ID Nothing identifies you or your machine, and nothing is saved. Each run uses a random value held in memory and thrown away when the command ends, so one run cannot be linked to another. ## Notice and controls Onboarding's Welcome step mentions Telemetry and links here, with no button or toggle. Commands print nothing about it, and nothing records that the notice was shown. Usage and logs wait at most 500 ms and are dropped silently if the network is slow, without retries. To turn all Telemetry and Feedback off, set either environment variable: ```sh export SELF_HOST_NO_TELEMETRY=1 ``` or `DO_NOT_TRACK=1`. Set to 1 (or true); any value except empty, 0 or false turns it off. Sending is always off when `CI` is set or the binary is a development build. Tests use fake transports and never send real Telemetry. ## Feedback is deliberate When an agent cannot fix a problem, `self-host feedback --message "…"` can send a report after you see the exact text and agree. `--yes` is only for approval already given in chat. Feedback is the one event carrying approved free text; the agent must remove personal details and the CLI masks known secrets again. `--app ` adds a short Debug report summary, never App logs. Messages from `--message` or stdin are limited to 4096 bytes. Approved Feedback uses the same endpoint, anonymity and off switches, but waits up to five seconds for delivery and reports failure. With Telemetry off it sends nothing, exits 1, and points to [GitHub Issues](https://github.com/ajnart/self-host/issues). ## Technical sources - [PostHog Go library](https://posthog.com/docs/libraries/go). - [PostHog OTLP/HTTP logs endpoint and project-token authentication](https://posthog.com/docs/logs/installation/other). - [PostHog reverse proxies](https://posthog.com/docs/advanced/proxy). Logs use the proxy's documented `/i/v1/logs` path with a bearer project token. Fake-transport tests verify the requests, not live proxy ingestion or server-side IP discard. The key embedded in releases is a public write-only project token, not a personal API key.