# Privacy & telemetry

The canonical version of this lives at
[fregata.app/privacy](https://fregata.app/privacy). This page is
the engineer's-eye-view: what's actually in the request bodies,
how to read the code, and how to turn it off.

## What leaves the Mac

**Three categories**, that's it.

### 1. License activation (one-time)

Sent when you click **Activate** in the activation window.

```http
POST /v1/activate
{
  "license_key":   "frgt_XXXX-XXXX-XXXX-XXXX",
  "email":         "<your-license-email>",
  "machine_id":    "<sha256 of IOPlatformUUID>",
  "hostname_hint": "Home Mac mini",
  "app_version":   "0.17.1"
}
```

`machine_id` is a one-way hash. The original `IOPlatformUUID`
never leaves the machine; only its SHA-256 digest does, used
solely to bind the license to this Mac.

`hostname_hint` is whatever you typed into the optional
"This Mac" field on the activation screen. It's a display label
only — the
[license-management page](https://fregata.app/manage-license)
uses it to show "this license is on `<your label>`" instead of
an opaque ID, so you can tell your own activations apart if
you have more than one Mac. Fregata sets it once at activation
and never updates it on subsequent heartbeats; leave it blank
if you don't want to provide one.

### 2. License heartbeat (every ~6 hours)

Sent in the background to keep the token fresh and confirm the
license is still valid.

```http
POST /v1/heartbeat
{
  "token":       "<current license token>",
  "app_version": "0.17.1",
  "telemetry": {                       // optional
    "app_version": "0.17.1",
    "os_version": "macOS 26.5",
    "mac_model": "MacBookPro18,1",
    "arch": "arm64",
    "cpu_cores": 10,
    "ram_gb_bucket": "16",
    "camera_count": 4,
    "detector_type": "coreml",
    "uptime_hours": 72,
    "crash_count_since_last": 0,
    "soc_name":            "Apple M4 Pro",
    "detector_compute":    "ane",            // your config.yml's inference_backend ("ane" or "gpu")
    "recent_inference_ms": 1,                // detector latency
    // Crash signature — present ONLY on a beat after a crash, and anonymous:
    "crash_kind":   "native",                // "native" | "python" | "unknown"
    "crash_signal": "SIGSEGV",               // OS signal, for native crashes
    "crash_label":  "Python",                // faulting binary OR exception type
    "crash_frame":  "frigate.record.maintainer.run:142",  // app-relative frame
    "crash_sig":    "a3f1c0de9b2e4471"       // 16-hex grouping hash
  }
}
```

**None of the telemetry fields are personally identifiable.**
Privacy is a core product principle at Fregata, not a footnote.
The fields above are hardware and runtime properties only — the
Mac model, the Apple SoC name (e.g. "Apple M4 Pro"), OS version,
CPU/RAM bucket, the *count* of cameras (never their names, URLs,
credentials, or contents), the detector backend type, the
detector compute target you picked in your config (`ane` or
`gpu`), the most recent inference time in milliseconds, uptime,
and a crash counter. After a crash, we also include an anonymous
crash *signature* — which process crashed, the OS signal (e.g.
`SIGSEGV`), the error type, and an app-relative code frame (e.g.
`frigate.record.maintainer.run:142`). It carries **no** log text,
file paths, exception messages, or credentials, and rides the same
opt-out as the rest of telemetry. The same class of data is visible in the
**About this Mac** window on any Mac. None of it ties back to
a person.

The server replies with a refreshed token and stores nothing
about the request body except the telemetry fields above (when
present).

### 3. Update manifest fetch (daily)

Anonymous, unauthenticated.

```http
GET /v1/manifest
```

Returns the latest version, its DMG hash, the minimum license
expiry that version requires, and an Ed25519 signature. No
identifiers in the request, no body. This is how the **Update
available** menu item gets populated.

## What does *not* leave the Mac

- **Camera URLs, names, or credentials.** Never.
- **Recordings, snapshots, event clips.** Never.
- **Detection events, zones, classes.** Never.
- **Your IP address.** We never log or store your IP address.
- **Your Mac's hostname.** We never read it. The only "hostname"
  the server sees is whatever you typed into the optional
  "This Mac" field at activation (the `hostname_hint` above).
- **Your email**, beyond what you typed at activation. (For
  GenAI / Frigate+ integrations you'd configure with your own API
  keys, those calls go directly from the Mac to the chosen
  provider — see the
  [Frigate GenAI docs](https://docs.frigate.video/configuration/genai).)
- **Crash dumps, system logs, ffmpeg logs**, or anything else
  Frigate writes locally. (After a crash we send an anonymous
  *signature* — process, OS signal, error type, app-relative
  frame — but never the dump itself or any log text, path,
  message, or credential. See the heartbeat section above.)

There is no Sentry, no Mixpanel, no DataDog, no third-party analytics SDK
of any kind in the app.

## How to disable telemetry

Set `FREGATA_TELEMETRY_DISABLED=1` in **Settings → Environment
Variables** in the menu-bar tray. Restart Frigate.

After that, heartbeat requests omit the entire `telemetry` block.
No telemetry is sent and nothing is saved by our server.

You can verify by tailing the Frigate log on the next heartbeat
(a few minutes after startup and roughly every six hours later) — the log line says
`heartbeat sent (telemetry: off)`. The `off` confirms the env var
was picked up.

## How to disable heartbeats entirely

You can't, while staying activated. The heartbeat is also the
license-validity check; turning it off would strand the app in a
permanent grace state, which is precisely the failure mode the
grace was designed for.

The closest thing to "no network calls at all" is to put the Mac
on a network with no internet. Fregata happily runs in that mode
indefinitely while the app stays up; only *restarts* past 7 days
of offline time need a network round-trip to reactivate. See
[Running offline](/getting-started/activation/#running-offline).

## What about the manifest fetch?

It's anonymous and signed. Disabling it loses the **Update
available** menu item but doesn't affect anything else. There's no
runtime toggle today; if you really want it gone, you can block
the licensing host at the network level — Fregata will treat the
failed fetch as "no update available" and move on.

## Data retention on our side

Per the [privacy policy](https://fregata.app/privacy):

- Telemetry rows are kept for 24 months in our database, then deleted.
- Activation rows (license ↔ machine binding) are kept while the
  binding is active and for 12 months after a release / refund.
- Stripe handles all card details; we receive only the email,
  Stripe transaction ID, and status.

For deletion requests, reply to your license email. Honoured
within 30 days, less the data we're required to retain for tax
/ refund compliance.

:::note
Telemetry is **on by default** (opt-out) — you can turn it off
anytime with the env var above. We keep it on because the few
aggregate metrics it provides — Mac model distribution, average
camera count, detector-tier histogram, and now crash *signatures*
so we can fix stability bugs we can't reproduce — genuinely change
how we triage. If you'd rather opt out, the env var above is the
whole story; there's no nag, no counter, no degraded feature set.
:::
