Skip to content

OpenRemedy — privacy notice

Last updated: 2026-05-08

This document is the canonical reference for what data leaves an OpenRemedy installation, why it leaves, and how to stop it from leaving. If anything below disagrees with the source code in openremedy-backend or openremedy-telemetry, the source code is the truth and this document is a bug.

TL;DR

  • Every OpenRemedy install posts a small set of anonymous counters to telemetry.openremedy.io once every 24 hours.
  • The payload contains no personal data: no tenant names, no user emails, no server hostnames, no IPs, no log lines, no API keys.
  • The same install also pulls the latest released version of each OpenRemedy component from the same endpoint, so the dashboard can show an "update available" indicator.
  • Either or both can be turned off with one environment variable.
  • The receiver does not log source IPs at any layer.

What is sent (one POST every 24 hours)

The full payload, fields documented one by one:

{
  "instance_uuid": "1f4b56ca-4ede-4494-aa6e-808870ca673a",
  "version": "v0.1.2",
  "git_sha": "95ef56ad5ea0a1d7d6a67d21348d645cbfd1e7ea",
  "tenant_count": 2,
  "user_count": 5,
  "server_count": 12,
  "agent_count": 4,
  "incidents_30d": 52,
  "executions_30d": 22,
  "incidents_resolved_30d": 50,
  "llm_provider": "deepseek",
  "deployment_age_days": 30,
  "telemetry_seq": 47
}
Field Meaning
instance_uuid Random UUID generated by your install on first proactive boot, persisted in the local telemetry_state table. Has no mapping to any person, organisation, or email. Used only to deduplicate consecutive pings from the same install.
version The OpenRemedy backend version running, e.g. v0.1.2. Or dev for unbuilt local checkouts.
git_sha The 40-character commit SHA the running image was built from, or null for dev builds.
tenant_count Integer. Number of rows in your local tenants table.
user_count Integer. Number of rows in your local users table.
server_count Integer. Number of rows in your local servers table.
agent_count Integer. Number of rows in your local agents table.
incidents_30d Integer. Number of incident rows whose created_at falls in the last 30 days.
executions_30d Integer. Number of execution rows whose created_at falls in the last 30 days.
incidents_resolved_30d Integer. Number of incident rows in resolved status with a non-null resolved_at.
llm_provider One of deepseek, openai, anthropic, kimi, or null. Derived from which API key environment variable is populated.
deployment_age_days Integer. Days since the local telemetry_state.created_at row was first written.
telemetry_seq Integer counter incremented per successful send. Lets us detect dropped pings.

What is not sent

Guaranteed at code level. The payload schema is enforced by the Pydantic model in openremedy-telemetry/src/openremedy_telemetry/schemas.py — any field outside that schema is rejected by the receiver.

  • ❌ Tenant names, slugs, domains, custom labels.
  • ❌ User emails, names, IDs, roles.
  • ❌ Server hostnames, IP addresses, fingerprints, SSH usernames.
  • ❌ Recipe slugs, incident contents, log lines, audit log entries, agent transcripts, sidechain transcripts, evidence bodies.
  • ❌ LLM API keys, encryption keys, JWT secrets, SSH private keys, any other secret.
  • ❌ Cookies, browser fingerprints, User-Agent strings (this is a server-to-server call, not a browser-originated request).
  • ❌ Source IP addresses. The receiver runs uvicorn with --no-access-log, the FastAPI middleware strips Server and X-Powered-By response headers, and the Caddy reverse proxy in front of it has log { output discard } for this vhost. No IP ever lands on disk.

Frequency

The proactive container's TelemetryLoop runs once on startup and then every 24 hours. The HTTP timeout is 10 seconds. Failures retry up to three times with exponential backoff (1s, 4s, 16s). After three consecutive failures, the loop sleeps until the next 24-hour cycle.

If the receiver is rate-limiting your install (HTTP 429), the loop backs off until the next cycle without retrying.

How to turn it off

Two environment variables, both default to false:

Variable Effect
OREMEDY_TELEMETRY_DISABLED=true Suppresses the metrics push (POST /v1/ping). The version-check pull (GET /v1/latest) still runs so the dashboard can still show "update available".
OREMEDY_OFFLINE_MODE=true Overrides everything. Suppresses both the push and the pull. No outbound traffic to telemetry.openremedy.io at all.

Set them in your docker/.env file (openremedy-deployment) and recreate the proactive container:

docker compose -p openremedy --env-file .env up -d --force-recreate proactive

After the next loop tick (or container restart), docker logs openremedy-proactive-1 | grep TelemetryLoop should show the new state in the startup log line.

Right to erasure (GDPR Article 17)

If you have a copy of your instance_uuid (you can read it locally from the telemetry_state table), you can request deletion of all records the receiver holds for that UUID:

# Read your instance_uuid out of your local database
docker compose -p openremedy --env-file .env exec -T postgres \
    psql -U openremedy openremedy -tAc "SELECT instance_uuid FROM telemetry_state"

# Delete it from the receiver
curl -X DELETE https://telemetry.openremedy.io/v1/instances/<paste-uuid-here>

The receiver returns HTTP 204 on success. The row is hard-deleted from the instances table and the rate-limit memory entry is cleared. The endpoint is public and unauthenticated by design — possession of the UUID is the authorisation, since the UUID was generated by your install and shared only by your install.

Retention

The receiver keeps a single most-recent row per instance_uuid. A daily cleanup task removes rows whose last_seen_at is older than 90 days, so an install that is decommissioned will fall out of the receiver naturally without needing a deletion request.

Lawful basis

The lawful basis under GDPR Article 6(1)(f) is legitimate interest: maintaining a B2B infrastructure product responsibly, where knowing how many self-hosters exist and on which versions is necessary to schedule support, security backports, and end-of-life notices.

The fields collected are pseudonymous (random UUID), aggregated counts, and version strings — they cannot be used to identify a natural person. Even taken together with everything an attacker could reasonably obtain, they cannot be re-identified to a real-world operator without information the receiver does not have (and does not log).

If your jurisdiction requires opt-in rather than opt-out collection even for non-personal aggregate data, set OREMEDY_TELEMETRY_DISABLED=true and we will not be offended.

Source code

Everything described here is open to inspection:

Contact

Questions, complaints, requests for further detail: albertof@barrahome.org with subject prefix [OpenRemedy Privacy].


This notice will be versioned alongside the project. Material changes to what is collected will be reflected here at least one minor release before they take effect, and the file's git history is the audit trail.