OpenTelemetry Export Wire Reference
OpenTelemetry Export is in beta, as is the companion setup page. This wire surface may change before general availability.
Companion to OpenTelemetry Export. Full wire surface: every metric, log event, attribute, enum, and presence rule.
The surface is additive. Tolerate unknown attributes, events, and enum values. Renames and removals get explicit notice.
Transport and scope
- OTLP/HTTP binary protobuf (
application/x-protobuf),POST - Endpoints:
<base>/v1/metricsand<base>/v1/logs - Scope:
cursor.telemetry/0.1.0
Resource attributes
One resource per (team, user, surface, entrypoint, surface version) grouping.
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
service.name | string | Always | Constant cursor |
service.version | string | Optional | Client version when source is desktop/CLI; usually absent on cloud_agent / bugbot |
cursor.team.id | int | Always | Your team id |
cursor.surface | string | Always | unspecified | desktop | cli | cloud_agent | bugbot |
cursor.entrypoint | string | Always | unspecified | desktop | cli | web | mobile | sdk_ts | sdk_py | api | automation | github_pr |
cursor.user.id | int | Optional | Opaque team-scoped user id when the source has one. Often absent on cloud agent. Do not require presence. |
Families
Family ids match the toggles in Team Settings. All default on for a new destination.
| Family id | Signals | Covers |
|---|---|---|
model_usage | metrics + logs | token.usage, cost.usage; api.request, api.error, api.correction |
tool_calls | metrics | tool.calls |
skills_hooks_plugins | logs | skill.activated, hook.execution_complete, plugin.installed |
cloud_agents | logs | cloud_agent.pull_request, cloud_agent.setup, cloud_agent.artifact |
Metrics
All metrics are monotonic delta sums. Metric datapoints carry no correlation IDs; those appear on logs only.
Consume metrics as sums of deltas per series. A series is the resource, the metric name, and the exact datapoint attribute set. Windows for the same series can overlap across flushes.
cursor.token.usage
Unit {token}. Family model_usage.
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.token.type | string | Always | input | output | cache_read | cache_creation |
cursor.model.name | string | Optional | Requested public model after routed-intent collapse (auto: to Auto, thinking: to Thinking, pro: to Pro, premium: to Premium; else pass-through). Absent on bugbot or when the source had no model. |
cursor.api.status | string | Optional | success | errored | aborted |
cursor.api.billable | bool | Optional |
cursor.tool.calls
Unit {call}. Family tool_calls. Value 1 per completed tool call.
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.tool.kind | string | Always | builtin | mcp |
cursor.tool.name | string | Always | Builtin id (e.g. read, shell) or customer MCP tool name (open) |
cursor.tool.status | string | Always | success | failure | aborted (MCP never reports aborted) |
cursor.mcp.server.name | string | MCP only | Customer-defined server display name (open) |
cursor.cost.usage
Unit USD (double). Family model_usage. Best-effort estimated cost at event time, not an invoice. Subject to cursor.api.correction. For BYOK, this is the Cursor Token Rate only, not provider spend.
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.model.name | string | Optional | Same collapse rules as token.usage |
Log events
Severities: INFO=9, WARN=13, ERROR=17.
Common log attributes
| Attribute | Type | Presence | Notes |
|---|---|---|---|
cursor.event.id | string | Always | Dedupe key. Opaque. Deterministic across retries, worker restarts, and Cursor Kafka replay. Prefix customer-telemetry:v1:... is stable; treat the whole string as opaque. |
cursor.source_event.id | string | Always | Opaque internal source identity. Several signals may share one value. |
cursor.request.id | string | Optional | On api.request, api.error, skill.activated, hook.execution_complete, plugin.installed. Never on api.correction or cloud_agent.*. |
cursor.conversation.id | string | Optional | IDE/CLI: composer UUID. Cloud agent: customer-visible bc-... agent id. Join key for session reconstruction across api, skill/hook, and cloud_agent logs. |
cursor.usage_event.id | string | Optional | api.request / api.error / api.correction only. Request-grain key against Cursor usage and billing exports. |
cursor.api.request
INFO, body api_request. Family model_usage.
| Attribute | Type | Presence | Notes |
|---|---|---|---|
cursor.api.request.input_tokens | int | Always | |
cursor.api.request.output_tokens | int | Always | |
cursor.api.request.cache_read_tokens | int | Always | |
cursor.api.request.cache_creation_tokens | int | Always | |
cursor.model.name | string | Optional | |
cursor.api.billable | bool | Optional |
cursor.api.error
ERROR, body api_error. Family model_usage. No raw error messages. Low-cardinality kind and status attributes are planned; don't depend on them yet.
| Attribute | Type | Presence | Notes |
|---|---|---|---|
cursor.model.name | string | Optional | |
cursor.api.billable | bool | Optional |
cursor.api.correction
WARN, body api_correction_<kind>. Family model_usage. Billing finalization: the usage event was retroactively not billed. Join on cursor.usage_event.id and drop the whole group for billing. Deliberately carries no cursor.model.name.
| Attribute | Type | Presence | Values |
|---|---|---|---|
cursor.api.correction.kind | string | Always | not_billed_errored | not_billed_aborted_before_timeout |
cursor.skill.activated
INFO, body skill_activated. Family skills_hooks_plugins.
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.skill.name | string | Always | Customer-authored (open) |
cursor.skill.trigger | string | Always | agent_read | manually_attached | skill_name_in_prompt |
cursor.skill.source | string | Always | unspecified | workspace | user | builtin | plugin | claude |
cursor.plugin.name | string | Optional | When the skill came from a plugin |
cursor.hook.execution_complete
INFO (ERROR for failed / timeout), body hook_execution_complete. Family skills_hooks_plugins.
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.hook.name | string | Always | Customer-configured (open) |
cursor.hook.type | string | Always | pre_tool_use | post_tool_use | post_tool_use_failure | before_submit_prompt | after_agent_response | after_agent_thought | stop | subagent_start | subagent_stop |
cursor.hook.outcome | string | Always | success | blocked | failed | timeout |
cursor.hook.duration_ms | int | Always | |
cursor.plugin.name | string | Optional | When the hook came from a plugin |
cursor.plugin.installed
INFO, body plugin_installed. Family skills_hooks_plugins. No conversation.id (install is not conversation-scoped).
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.plugin.name | string | Always | Open |
cursor.plugin.scope | string | Always | unspecified | public | private_marketplace |
cursor.cloud_agent.pull_request
INFO (opened) / WARN (creation_failed), body cloud_agent_pull_request_<kind>. Family cloud_agents. conversation.id = bc-....
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.cloud_agent.pull_request.kind | string | Always | opened | creation_failed |
cursor.cloud_agent.pull_request.number | int | opened only | |
cursor.cloud_agent.pull_request.draft | bool | opened only |
creation_failed is live. opened may be sparse while the producer rolls out.
cursor.cloud_agent.setup
INFO (started / completed) / ERROR (failed), body cloud_agent_setup_<kind>. Family cloud_agents. conversation.id = bc-....
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.cloud_agent.setup.kind | string | Always | started | completed | failed |
cursor.cloud_agent.setup.duration_ms | int | Terminal kinds when present | completed / failed |
cursor.cloud_agent.setup.reason | string | failed only | Open vocabulary (e.g. install_command_failed) |
cursor.cloud_agent.artifact
INFO, body cloud_agent_artifact_created. Family cloud_agents. conversation.id = bc-....
| Attribute | Type | Presence | Values / notes |
|---|---|---|---|
cursor.cloud_agent.artifact.file_name | string | Always | Open |
cursor.cloud_agent.artifact.content_type | string | Optional | MIME |
Identity and joins
- Dedupe logs on
cursor.event.id. - Session reconstruction: group logs by
cursor.conversation.id(composer UUID orbc-...). - Billing reconcile grain:
cursor.usage_event.idacrossapi.request/api.error/api.correction. - Metrics do not carry these ids. Use
api.requestlogs for per-conversation token totals.
See Joining sessions on the setup page for recipes.
Delivery semantics
- Logs are at-least-once. Transient failures recover automatically for about 7 days; dedupe on
event.id. Terminal rejections (persistent 4xx, bad payloads) are not replayed. - Metrics are at-most-once. Failed metric requests are not retried or replayed.
- No ordering guarantee. Corrections can arrive after the requests they amend; order by record timestamp.
- OTLP partial success is honored. Rejected items are not re-sent.
- No backfill from before destination activation. Source retention upstream of export is also about 7 days (separate from the delivery retry window).