# cms-edit telemetry (Axiom)

Hosted cms-edit deployments can emit aggregate usage telemetry to [Axiom](https://axiom.co). Events contain command names, outcomes, and durations only — no user ids, emails, slugs, entry ids, or error messages.

## Enable on Vercel

Set on each cms-edit host project (`se-website-2026-cms-edit-host`, `pedestal-cms-edit`, `headwater-cms-edit`, dev `cms-edit-host`):

| Variable | Value |
|----------|-------|
| `CMS_EDIT_TELEMETRY` | `1` |
| `AXIOM_TOKEN` | Axiom ingest token (sensitive) |
| `AXIOM_DATASET` | `cms-edit` |
| `AXIOM_DOMAIN` | Optional; default `api.axiom.co` |
| `CMS_EDIT_PROJECT_KEY` | Already required — used as `project_key` for aggregation |

Opt out: `CMS_EDIT_TELEMETRY=0`.

## Event schema

Each event is one JSON object:

| Field | Description |
|-------|-------------|
| `event_id` | UUID for deduplication |
| `timestamp` | ISO 8601 completion time |
| `command` | e.g. `open`, `save`, `oauth` |
| `subcommand` | Optional, e.g. `replace`, `link-contentful` |
| `outcome` | `success`, `error`, or `exit` |
| `exit_code` | When `outcome` is `exit` |
| `error_name` | Error class or stable reason code (never message text) |
| `duration_ms` | Wall-clock duration |
| `cms_edit_version` | Package version |
| `mode` | `hosted-mcp` on Vercel, `cli` locally |
| `project_key` | From `CMS_EDIT_PROJECT_KEY` |
| `node_version` | Node runtime |
| `platform` | `process.platform` |

OAuth events emit `command: oauth` with route-specific `subcommand` values:

| `subcommand` | When |
|--------------|------|
| `link-contentful` | Contentful sign-in link step (failures only today) |
| `authorization-code` | Initial MCP connect via `/oauth/token` (`authorization_code` grant) |
| `refresh-token` | Silent token refresh via `/oauth/token` (`refresh_token` grant) |

`error_name` uses stable reason codes only — never token values, user ids, or emails. Examples: `invalid_contentful_token`, `space_access_denied`, `invalid_refresh_token`, `refresh_client_mismatch`, `invalid_authorization_code`.

## Local development

With `CMS_EDIT_TELEMETRY=1` and no Axiom env vars, events append to `~/.contentful-cms/telemetry.log` as NDJSON.

## Example Axiom queries

**Commands per project (last 24h):**

```apl
['cms-edit']
| where _time > ago(24h)
| summarize count() by project_key, command, outcome
| order by count_ desc
```

**OAuth failures by reason:**

```apl
['cms-edit']
| where command == "oauth" and outcome == "error"
| summarize count() by project_key, error_name
```

**Token refresh health (success vs failure):**

```apl
['cms-edit']
| where command == "oauth" and subcommand == "refresh-token"
| summarize count() by project_key, outcome
| order by count_ desc
```

**p95 duration by command:**

```apl
['cms-edit']
| where outcome == "success"
| summarize percentile(duration_ms, 95) by project_key, command
```

## Flow

MCP request → `runCmsEditArgs` → Commander hooks record outcome → `flush()` POSTs buffered events to `https://{AXIOM_DOMAIN}/v1/datasets/{AXIOM_DATASET}/ingest` before the HTTP response returns. OAuth `link-contentful` failures record and flush in the route handler.

After adding or changing `AXIOM_*` env vars on Vercel, **redeploy** — serverless only reads env at deploy time.