> ## Documentation Index
> Fetch the complete documentation index at: https://manifest.build/llm-gateway/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Data and telemetry

> Data saved for the dashboard and anonymous telemetry reported by self-hosted LLM Gateway instances.

Two separate things happen to data as requests flow through the gateway: what your own instance records for the dashboard, and what a self-hosted install reports back to the project. This page covers both.

## What the gateway stores

The gateway always keeps metadata about each request: model, provider, tier, token counts, cost, latency, and an error message. Error text is scrubbed for secrets before it lands, and the request headers the gateway stores drop credentials and IP addresses. The usage and cost views in the dashboard are built from that metadata alone. See [Observability](/llm-gateway/docs/llm-gateway/docs/observability) for what the record looks like in practice.

Message bodies are separate, and optional. With [request logs](/llm-gateway/docs/llm-gateway/docs/request-logs) on for a harness, the gateway also stores the request and response bodies of each provider attempt so you can read them back in the dashboard. New harnesses have it enabled; to make sure a harness records its logs, check its **Settings → Logs**.

A stored body is exactly what went over the wire: every message, system instruction, tool definition and inline image, at full length. The gateway doesn't redact or truncate it, and there is no size limit. Stored bodies are held outside the database, in the object storage your instance is configured for, and deleted on a retention schedule. With logs off for a harness, that harness's prompts and completions stay between you and the provider.

<Note>
  If a harness handles data you'd rather the gateway never hold onto, switch
  **Enable logs** off in its **Settings → Logs** section. Metadata collection
  isn't affected either way.
</Note>

## Anonymous telemetry

Once a day, each self-hosted install sends us a small anonymous report. That's how we know whether anyone's actually using the thing, and which providers are popular enough to deserve more work. It's aggregates, never content: no prompts, no messages, no keys, nothing tied to a user. Fifteen fields total.

<Note>
  This section applies to self-hosted installs only. LLM Gateway Cloud has no
  separate telemetry report — your usage is already in your own dashboard.
</Note>

### What gets sent

| Field                               | Example                                 | Purpose                                                                                                                                                                                       |
| ----------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `schema_version`                    | `1`                                     | So the shape can grow without breaking old clients. Stays `1` for additive changes; bumps on breaking ones                                                                                    |
| `install_id`                        | random UUIDv4                           | Count distinct installs. Generated once on first boot, persisted, never rotated                                                                                                               |
| `manifest_version`                  | `5.47.0`                                | Version adoption across the fleet                                                                                                                                                             |
| `messages_total`                    | `1284`                                  | Daily activity per install. One count per provider attempt, so a request that fell back twice counts three. Requests the gateway blocked count too                                            |
| `messages_by_provider`              | `{"anthropic": 700, "openai": 500}`     | Provider mix. Anything we don't recognize collapses to `"custom"`, so self-hosted provider names and URLs stay local. Activity with no provider, like a blocked request, lands in `"unknown"` |
| `messages_by_tier`                  | `{"default": 900, "simple": 300, ...}`  | Routing tier usage. A tier outside the known set collapses to `"other"`, and activity with no tier lands in `"unknown"`                                                                       |
| `messages_by_auth_type`             | `{"api_key": 1200, "subscription": 84}` | API key, paid subscription or local usage. Anything else collapses to `"other"`, and activity with no auth type lands in `"unknown"`                                                          |
| `tokens_input_total`                | `1_450_000`                             | Volume-weighted signal                                                                                                                                                                        |
| `tokens_output_total`               | `890_000`                               | Same                                                                                                                                                                                          |
| `cost_usd_total` <sup>†</sup>       | `47.83`                                 | Sum of `cost_usd` the gateway computed at routing time, rounded to cents. Lets us see real dollar throughput instead of guessing from token counts. `0` for Ollama-only / free-API installs   |
| `cost_usd_by_provider` <sup>†</sup> | `{"anthropic": 30.50, "openai": 17.33}` | Per-provider split of `cost_usd_total`, rounded to cents. Same `"custom"` collapse rule as `messages_by_provider` — admin-configured BYOK pricing is never keyed by the raw provider name     |
| `agents_total`                      | `4`                                     | Configuration scale                                                                                                                                                                           |
| `agents_by_platform`                | `{"openclaw": 3, "hermes": 1}`          | Which agent clients people use. A harness whose platform is `other` is keyed by its category instead: `personal:other`, `app:other` or `coding:other`                                         |
| `platform`                          | `linux` / `darwin` / `windows`          | OS distribution                                                                                                                                                                               |
| `arch`                              | `x64` / `arm64`                         | Architecture distribution                                                                                                                                                                     |

<sup>†</sup> *Optional. Installs running older gateway versions omit these fields; receivers should feature-detect on presence rather than on `schema_version`. Cost values are derived from the same `input_tokens` / `output_tokens` we already ship, multiplied by the gateway's per-model pricing table — no new data leaves the box, just a rolled-up dollar figure for what's already disclosed.*

### Never sent

Tenant IDs, user IDs, emails, API keys, prompts, message contents, model names, custom provider URLs, OAuth client IDs, hostnames, raw IPs. The ingest takes a SHA-256 of your IP and throws the original away; we keep the hash so we can rate-limit bad actors without knowing where they actually live.

### When

* Once every 24 hours, per install.
* The first report is delayed by a random 0–24h offset, so a fleet of containers rebooted together doesn't all hit the endpoint at the same minute.
* Off by default when `NODE_ENV != production`. Dev machines are never going to accidentally send.
* If the endpoint is down, we log it and try again on the next hourly tick. Your proxy keeps serving requests — the sender never gets in the way.

### Turning it off

Put this in your `.env` (or `docker-compose.yml`) and restart the container:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
MANIFEST_TELEMETRY_DISABLED=1
```

The sender checks the flag before doing anything else. No database read, no DNS lookup, no request leaves the box.

### Sending it somewhere else

If you'd rather run your own fleet dashboard, point `TELEMETRY_ENDPOINT` at a URL you control. Add it to `.env` next to your compose file and restart:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
TELEMETRY_ENDPOINT=https://telemetry.mycompany.internal/v1/report
```

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
docker compose up -d
```

Your collector receives the same payload documented above, and nothing is sent to `telemetry.manifest.build`.

## Related

* [Observability](/llm-gateway/docs/llm-gateway/docs/observability) — what the recorded metadata gets you
* [Environment variables](/llm-gateway/docs/llm-gateway/docs/reference/environment-variables) — `MANIFEST_TELEMETRY_DISABLED` and `TELEMETRY_ENDPOINT` in context
* [Self-hosting with Docker](/llm-gateway/docs/llm-gateway/docs/self-hosted) — where to put these variables
