Monitoring changedmonitoring-usage
Nearest release: v2.1.309, published 6 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 23 Oct 2026 02:37 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 23 Oct 2026 19:07 UTC.
Upstream edited
Recorded here
Lines+136added
Lines−136removed
From line
37
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits64to this page, all time
The whole hunk
from line 37, old and new numbered
/
from line 37
3737
3838To verify a setup that exports metrics, check your backend for the `claude_code.session.count` metric, which Claude Code emits when a session starts. To verify a logs-only setup, submit a prompt and check for the `claude_code.user_prompt` event.
3939
40If nothing arrives, start Claude Code with `claude --debug-file <path>` and check the log it writes to that path. Claude Code reports failures from the exporters you configure as `[3P telemetry]` errors, where 3P means third-party. Lines prefixed `[Anthropic telemetry]` describe [Anthropic's separate operational telemetry](/docs/en/data-usage.md#telemetry-services) and don't indicate a problem with your setup.
40If nothing arrives, start Claude Code with `claude --debug-file <path>` and check the log it writes to that path. Claude Code reports failures from the exporters you configure as `[3P telemetry]` errors, where 3P means third-party. Lines prefixed `[Anthropic telemetry]` describe [Anthropic's separate operational telemetry](https://code.claude.com/docs/en/data-usage.md#telemetry-services) and don't indicate a problem with your setup.
4141
4242For full configuration options, see the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options).
4343
4444## Administrator configuration
4545
46Administrators can configure OpenTelemetry settings for all users through the [managed settings file](/docs/en/managed-settings.md#delivery-mechanisms). See the [settings precedence](/docs/en/settings.md#settings-precedence) for more information about how settings are applied.
46Administrators can configure OpenTelemetry settings for all users through the [managed settings file](https://code.claude.com/docs/en/managed-settings.md#delivery-mechanisms). See the [settings precedence](https://code.claude.com/docs/en/settings.md#settings-precedence) for more information about how settings are applied.
4747
4848Example managed settings configuration:
4949
from line 60
6060}
6161```
6262
63In the Claude Desktop app, Code tab sessions read these managed settings from the sources that [reach each kind of Desktop session](/docs/en/desktop.md#managed-settings). The OpenTelemetry form for Cowork under **Monitoring** in the admin console's [Data and privacy settings](https://claude.ai/admin-settings/data-privacy-controls) applies to Cowork sessions only, so neither the terminal CLI nor the Code tab exports to a collector you set there.
63In the Claude Desktop app, Code tab sessions read these managed settings from the sources that [reach each kind of Desktop session](https://code.claude.com/docs/en/desktop.md#managed-settings). The OpenTelemetry form for Cowork under **Monitoring** in the admin console's [Data and privacy settings](https://claude.ai/admin-settings/data-privacy-controls) applies to Cowork sessions only, so neither the terminal CLI nor the Code tab exports to a collector you set there.
6464
65Claude Code ignores the [OpenTelemetry exporter variables](/docs/en/settings-reference.md#variables-claude-code-ignores-in-env) in a repository's `.claude/settings.json` and `.claude/settings.local.json`, so a repository can't use them to turn telemetry on, choose where it goes, or capture content. Set them in managed settings, or have each developer set them in their shell or `~/.claude/settings.json`. A repository can still turn a signal off by setting its exporter selector, such as `OTEL_LOGS_EXPORTER`, to `none`, unless managed settings, a `--settings` file, or the environment you start Claude Code from sets that variable.
65Claude Code ignores the [OpenTelemetry exporter variables](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env) in a repository's `.claude/settings.json` and `.claude/settings.local.json`, so a repository can't use them to turn telemetry on, choose where it goes, or capture content. Set them in managed settings, or have each developer set them in their shell or `~/.claude/settings.json`. A repository can still turn a signal off by setting its exporter selector, such as `OTEL_LOGS_EXPORTER`, to `none`, unless managed settings, a `--settings` file, or the environment you start Claude Code from sets that variable.
6666
6767Claude Code doesn't pass `OTEL_*` environment variables to the subprocesses it spawns, including the Bash tool, hooks, MCP servers, and language servers. An OpenTelemetry-instrumented application that you run through the Bash tool doesn't inherit Claude Code's exporter endpoint or headers, so set those variables directly in the command if that application needs to export its own telemetry.
6868
from line 73
7373* **Endpoints**: when you set `OTEL_EXPORTER_OTLP_ENDPOINT`, Claude Code removes every developer-set per-signal endpoint. Developers can't point one signal at a different collector, so you don't need to also set the per-signal endpoint variables in managed settings.
7474* **Protocols**: when you set `OTEL_EXPORTER_OTLP_PROTOCOL`, Claude Code removes every developer-set per-signal protocol.
7575* **Credentials**: when you set `OTEL_EXPORTER_OTLP_HEADERS`, `OTEL_EXPORTER_OTLP_CLIENT_KEY`, or `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE`, Claude Code removes the developer-set per-signal versions of that variable, plus every developer-set endpoint variable, generic or per-signal, since those credentials would otherwise reach a collector the managed settings didn't choose.
76* **Exporter selectors**: `OTEL_METRICS_EXPORTER`, `OTEL_LOGS_EXPORTER`, and the beta `OTEL_TRACES_EXPORTER` follow normal per-key precedence. A developer's setting can still disable a signal or switch it to the console exporter, so set the selectors in managed settings too if you need them locked. Across [admin sources](/docs/en/managed-settings.md#precedence-within-the-managed-tier), `OTEL_LOGS_EXPORTER` follows the [telemetry unit](/docs/en/server-managed-settings.md#per-key-exceptions-across-managed-sources) while the other two selectors merge per key. Requires Claude Code v2.1.223 or later.
76* **Exporter selectors**: `OTEL_METRICS_EXPORTER`, `OTEL_LOGS_EXPORTER`, and the beta `OTEL_TRACES_EXPORTER` follow normal per-key precedence. A developer's setting can still disable a signal or switch it to the console exporter, so set the selectors in managed settings too if you need them locked. Across [admin sources](https://code.claude.com/docs/en/managed-settings.md#precedence-within-the-managed-tier), `OTEL_LOGS_EXPORTER` follows the [telemetry unit](https://code.claude.com/docs/en/server-managed-settings.md#per-key-exceptions-across-managed-sources) while the other two selectors merge per key. Requires Claude Code v2.1.223 or later.
7777* **Beta tracing endpoints**: with [detailed beta tracing](#traces-beta) active, Claude Code exports logs and traces to `BETA_TRACING_ENDPOINT` instead of through the logs and traces exporters. Claude Code therefore removes a developer-set `BETA_TRACING_ENDPOINT` whenever any of these managed settings decides either signal's destination:
7878
7979 * A generic or logs/traces endpoint or credential
80 * An [`otelHeadersHelper`](/docs/en/settings-reference#otelheadershelper)
80 * An [`otelHeadersHelper`](https://code.claude.com/docs/en/settings-reference#otelheadershelper)
8181 * A logs or traces exporter selector set to `none`, `console`, or empty, values that keep the signal off a collector
8282 * `CLAUDE_CODE_ENABLE_TELEMETRY` turned off
8383
from line 89
8989
9090Before v2.1.217, every variable followed per-key settings precedence independently, so a signal-specific endpoint set in user settings or the shell redirected that signal away from the managed collector.
9191
92When the desktop app or a [self-hosted environment](/docs/en/self-hosted-environments) runner launches Claude Code and names an OTLP endpoint in the environment it provides, Claude Code pins the destination the same way: the launcher's telemetry variables remove developer-set variables exactly as managed settings do. Claude Code doesn't remove variables that the launcher itself set. Requires Claude Code v2.1.251 or later.
92When the desktop app or a [self-hosted environment](https://code.claude.com/docs/en/self-hosted-environments) runner launches Claude Code and names an OTLP endpoint in the environment it provides, Claude Code pins the destination the same way: the launcher's telemetry variables remove developer-set variables exactly as managed settings do. Claude Code doesn't remove variables that the launcher itself set. Requires Claude Code v2.1.251 or later.
9393
9494## Configuration details
9595
from line 135
135135
136136| Protocol | Client certificate variables | Trust the collector's CA with |
137137| :- | :- | :- |
138| `http/protobuf`, `http/json` | `CLAUDE_CODE_CLIENT_CERT`, `CLAUDE_CODE_CLIENT_KEY`, and optionally `CLAUDE_CODE_CLIENT_KEY_PASSPHRASE`. See [Network configuration](/docs/en/network-config.md#mtls-authentication) | `NODE_EXTRA_CA_CERTS` |
138| `http/protobuf`, `http/json` | `CLAUDE_CODE_CLIENT_CERT`, `CLAUDE_CODE_CLIENT_KEY`, and optionally `CLAUDE_CODE_CLIENT_KEY_PASSPHRASE`. See [Network configuration](https://code.claude.com/docs/en/network-config.md#mtls-authentication) | `NODE_EXTRA_CA_CERTS` |
139139| `grpc` | `OTEL_EXPORTER_OTLP_CLIENT_KEY` and `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE`, or the per-signal variants such as `OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY` to use a different certificate per signal | `OTEL_EXPORTER_OTLP_CERTIFICATE` |
140140
141141For `grpc`, the OpenTelemetry SDK reads the standard OTLP variables directly, so existing configurations that set the per-signal metrics variables continue to work. On machines with managed settings, Claude Code [may remove developer-set per-signal credentials and endpoints](#how-managed-settings-lock-the-otlp-destination) at startup.
from line 200
200200
201201In Agent SDK and `claude -p` sessions, `claude_code.interaction` itself becomes a child of the caller's span when `TRACEPARENT` is set in the environment.
202202
203When a `PreToolUse` hook [defers a tool call](/docs/en/hooks.md#defer-a-tool-call-for-later), Claude Code saves the trace context of the turn that deferred it. When you resume the session and the tool re-runs, the tool's spans join that earlier turn's trace as children of the turn's `claude_code.interaction` span.
203When a `PreToolUse` hook [defers a tool call](https://code.claude.com/docs/en/hooks.md#defer-a-tool-call-for-later), Claude Code saves the trace context of the turn that deferred it. When you resume the session and the tool re-runs, the tool's spans join that earlier turn's trace as children of the turn's `claude_code.interaction` span.
204204
205205#### Span attributes
206206
from line 227
227227| `query_source_safe` | Bounded form of `query_source`, emitted whether or not detailed beta tracing is active, with values such as `repl_main_thread` or `agent.builtin.general-purpose`. `:` becomes `.` and user-named agents appear as `agent.custom`. Requires Claude Code v2.1.268 or later | |
228228| `agent_id` | Identifier of the subagent or teammate that issued the request. Absent on the main session | |
229229| `parent_agent_id` | Identifier of the agent that spawned this one. Absent for the main session and for agents spawned directly from it | |
230| `workflow.run_id` | Run identifier of the [Workflow](/docs/en/workflows.md) tool run that spawned this agent, prefixed `wf_`. Absent for agents not spawned by a workflow | |
230| `workflow.run_id` | Run identifier of the [Workflow](https://code.claude.com/docs/en/workflows.md) tool run that spawned this agent, prefixed `wf_`. Absent for agents not spawned by a workflow | |
231231| `workflow.name` | Name of the workflow that spawned this agent. User-authored names are replaced with `custom` unless the gate is set | `OTEL_LOG_TOOL_DETAILS` |
232232| `speed` | `fast` or `normal` | |
233| `effort` | [Effort level](/docs/en/model-config.md#adjust-effort-level) applied to the request: `low`, `medium`, `high`, `xhigh`, or `max`. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort. Requires Claude Code v2.1.274 or later | |
233| `effort` | [Effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) applied to the request: `low`, `medium`, `high`, `xhigh`, or `max`. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort. Requires Claude Code v2.1.274 or later | |
234234| `llm_request.context` | `interaction`, `tool`, or `standalone` depending on the parent span | |
235235| `duration_ms` | Wall-clock duration including retries | |
236236| `ttft_ms` | Time to first token in milliseconds | |
from line 285
285285* A call to any tool other than Read, Edit, Write, Bash, WebFetch, WebSearch, and MCP tools
286286* A Read that returns anything other than file text, such as an image, a PDF, or a re-read of a file whose contents haven't changed
287287* An Edit or Write call, unless you also set `OTEL_LOG_TOOL_DETAILS=1`
288* A WebFetch or WebSearch call that Claude Code moved to the background while it ran so that a waiting message could reach Claude. The result that arrives later isn't recorded either. To learn when Claude Code moves a call, see [When Claude Code sends what you queued](/docs/en/interactive-mode.md#when-claude-code-sends-what-you-queued) for the terminal and the [`priority` field](/docs/en/agent-sdk/typescript#sdkusermessage) for Agent SDK sessions
288* A WebFetch or WebSearch call that Claude Code moved to the background while it ran so that a waiting message could reach Claude. The result that arrives later isn't recorded either. To learn when Claude Code moves a call, see [When Claude Code sends what you queued](https://code.claude.com/docs/en/interactive-mode.md#when-claude-code-sends-what-you-queued) for the terminal and the [`priority` field](https://code.claude.com/docs/en/agent-sdk/typescript#sdkusermessage) for Agent SDK sessions
289289
290290The event carries these attributes, each truncated at the content limit (60 KB by default). `Gated by` names the variable an attribute needs on top of `OTEL_LOG_TOOL_CONTENT=1`, and for Edit and Write that variable gates the event itself rather than the attribute.
291291
from line 307
307307| `decision` | `accept`, `reject`, or `cancelled`, where `cancelled` means Claude Code stopped waiting for a permission decision on the tool call and didn't run it | |
308308| `source` | For an `accept` or `reject`, where the decision came from, such as `config`, `hook`, or `user_temporary`, with the meanings given under the [Tool decision event](#tool-decision-event). For a `cancelled`, what ended the wait before any decision was made, such as `user_abort` | |
309309
310A `cancelled` decision with `source` `user_abort` means a message needing immediate delivery interrupted the turn while the permission prompt or [auto mode](/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) check was pending. For example, during an auto mode check, the user had a message queued and [sent it immediately](/docs/en/interactive-mode.md#when-claude-code-sends-what-you-queued).
310A `cancelled` decision with `source` `user_abort` means a message needing immediate delivery interrupted the turn while the permission prompt or [auto mode](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) check was pending. For example, during an auto mode check, the user had a message queued and [sent it immediately](https://code.claude.com/docs/en/interactive-mode.md#when-claude-code-sends-what-you-queued).
311311
312312**`claude_code.tool.execution`**
313313
from line 322
322322
323323**`claude_code.hook`**
324324
325This span appears only when detailed beta tracing is active, which requires `ENABLE_BETA_TRACING_DETAILED=1` and `BETA_TRACING_ENDPOINT`, a pair that also [changes where your logs and traces go](/docs/en/env-vars.md#variables). Set the pair in your shell, user settings, or managed settings; both variables are ignored in [project and local settings](/docs/en/settings-reference.md#variables-claude-code-ignores-in-env). `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA` alone doesn't produce it.
325This span appears only when detailed beta tracing is active, which requires `ENABLE_BETA_TRACING_DETAILED=1` and `BETA_TRACING_ENDPOINT`, a pair that also [changes where your logs and traces go](https://code.claude.com/docs/en/env-vars.md#variables). Set the pair in your shell, user settings, or managed settings; both variables are ignored in [project and local settings](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env). `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA` alone doesn't produce it.
326326
327327In interactive CLI sessions, detailed beta tracing also requires your organization to be allowlisted for the feature. Agent SDK and non-interactive `-p` sessions don't require allowlisting.
328328
from line 350
350350| - | - | - | - |
351351| `new_context` | `claude_code.interaction` | The user prompt | `OTEL_LOG_USER_PROMPTS` |
352352| `new_context` | `claude_code.llm_request` | The new user messages and tool results sent with the request | `OTEL_LOG_USER_PROMPTS` |
353| `system_reminders` | `claude_code.llm_request` | The text of the [system reminders](/docs/en/glossary.md#system-reminder) among the request's new messages | `OTEL_LOG_USER_PROMPTS` |
353| `system_reminders` | `claude_code.llm_request` | The text of the [system reminders](https://code.claude.com/docs/en/glossary.md#system-reminder) among the request's new messages | `OTEL_LOG_USER_PROMPTS` |
354354| `system_prompt_preview` | `claude_code.llm_request` | First 500 characters of the complete system prompt sent with the request | `OTEL_LOG_USER_PROMPTS` |
355355| `user_system_prompt` | `claude_code.llm_request` | Only the system prompt text you provide via the `systemPrompt` SDK option or `--system-prompt` and `--append-system-prompt` flags. Emitted once per session rather than per request | `OTEL_LOG_USER_PROMPTS` |
356356| `response.model_output` | `claude_code.llm_request` | Text of the model's response to the request | `OTEL_LOG_USER_PROMPTS` |
from line 387
387387
388388If the helper fails or prints output that doesn't meet these requirements, exports fail and your telemetry backend receives nothing from the session until the helper works again. Claude Code reports the failure in:
389389
390* A warning notification in interactive sessions, [`otelHeadersHelper failed; telemetry is not being exported`](/docs/en/errors#otelheadershelper-failed), shown once per session when the helper first fails
390* A warning notification in interactive sessions, [`otelHeadersHelper failed; telemetry is not being exported`](https://code.claude.com/docs/en/errors#otelheadershelper-failed), shown once per session when the helper first fails
391391* `/status` output
392* The debug log, when running with [`--debug`](/docs/en/cli-reference#cli-flags) or after running `/debug` in the session
392* The debug log, when running with [`--debug`](https://code.claude.com/docs/en/cli-reference#cli-flags) or after running `/debug` in the session
393393* stderr, in non-interactive sessions started with `-p`
394394
395395#### Refresh behavior
from line 442
442442
443443### Attribute telemetry to Desktop SSH sessions
444444
445To see which remote machine a [Desktop SSH session](/docs/en/desktop.md#ssh-sessions) ran on, name each machine in a custom attribute. Metrics and events don't name the machine a session ran on.
445To see which remote machine a [Desktop SSH session](https://code.claude.com/docs/en/desktop.md#ssh-sessions) ran on, name each machine in a custom attribute. Metrics and events don't name the machine a session ran on.
446446
447On each remote machine, add [`OTEL_RESOURCE_ATTRIBUTES`](#multi-team-organization-support) to the `env` block that turns telemetry on, in the [managed settings file the session reads](/docs/en/desktop.md#managed-settings). Write the name out in each machine's file. Claude Code doesn't expand the value, so `host.name=$(hostname)` arrives as those characters.
447On each remote machine, add [`OTEL_RESOURCE_ATTRIBUTES`](#multi-team-organization-support) to the `env` block that turns telemetry on, in the [managed settings file the session reads](https://code.claude.com/docs/en/desktop.md#managed-settings). Write the name out in each machine's file. Claude Code doesn't expand the value, so `host.name=$(hostname)` arrives as those characters.
448448
449449The following example names the machine `build-7`:
450450
from line 468
468468* **You set it on the computer that runs Desktop**: Desktop doesn't pass a value you set there to the SSH session
469469* **You exported it in a login file**: only login shells read a file such as `/etc/profile`. A value you `export` there reaches Claude Code that you start from a login shell. It doesn't reach a Desktop SSH session, because Desktop doesn't start Claude Code through a login shell.
470470* **A value has a space inside it**: Claude Code then copies none of the keys onto events or datapoints and reports no error. [Take the space out of the value](#multi-team-organization-support).
471* **Something else already sets the variable**: in a session that the desktop app starts, a variable already set in the launch environment [takes precedence over settings files](/docs/en/settings-reference.md#how-env-values-interact-with-your-shell). The [debug log](/docs/en/debug-your-config.md) names each ignored variable. When a third-party Desktop deployment [names an OTLP endpoint](#how-managed-settings-lock-the-otlp-destination) in the environment it provides, that environment carries Desktop's own `OTEL_RESOURCE_ATTRIBUTES`.
471* **Something else already sets the variable**: in a session that the desktop app starts, a variable already set in the launch environment [takes precedence over settings files](https://code.claude.com/docs/en/settings-reference.md#how-env-values-interact-with-your-shell). The [debug log](https://code.claude.com/docs/en/debug-your-config.md) names each ignored variable. When a third-party Desktop deployment [names an OTLP endpoint](#how-managed-settings-lock-the-otlp-destination) in the environment it provides, that environment carries Desktop's own `OTEL_RESOURCE_ATTRIBUTES`.
472472
473473### Example configurations
474474
from line 498
498498export OTEL_METRICS_EXPORTER=prometheus
499499```
500500
501On a [self-hosted environment](/docs/en/self-hosted-environments-reference.md#pass-through-session-child-metrics), the session binds port 9464 only at the runner's default capacity of one. At higher capacity, the runner re-exposes session counters and gauges on its own `/metrics` endpoint instead.
501On a [self-hosted environment](https://code.claude.com/docs/en/self-hosted-environments-reference.md#pass-through-session-child-metrics), the session binds port 9464 only at the runner's default capacity of one. At higher capacity, the runner re-exposes session counters and gauges on its own `/metrics` endpoint instead.
502502
503503To send metrics to multiple exporters:
504504
from line 540
540540
541541## Telemetry from cloud sessions and Claude Tag
542542
543[Cloud sessions](/docs/en/claude-code-on-the-web.md), including [Claude Tag](https://claude.com/docs/claude-tag/overview) channel sessions, run in [cloud environments](/docs/en/cloud-environments.md) rather than on your users' devices, so a managed settings file or shell profile on those devices doesn't configure their telemetry. For sessions in Anthropic-hosted environments, this section covers where to set the telemetry variables, how to make your collector reachable from the environment, and how to tell cloud and Claude Tag sessions apart in the exported data.
543[Cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md), including [Claude Tag](https://claude.com/docs/claude-tag/overview) channel sessions, run in [cloud environments](https://code.claude.com/docs/en/cloud-environments.md) rather than on your users' devices, so a managed settings file or shell profile on those devices doesn't configure their telemetry. For sessions in Anthropic-hosted environments, this section covers where to set the telemetry variables, how to make your collector reachable from the environment, and how to tell cloud and Claude Tag sessions apart in the exported data.
544544
545545To export telemetry from those sessions, set `CLAUDE_CODE_ENABLE_TELEMETRY` and the `OTEL_*` variables, using the same keys as the [administrator configuration](#administrator-configuration) example, in one of two places:
546546
547* **Server-managed settings**: add them to the `env` block of your organization's [server-managed settings](/docs/en/server-managed-settings.md). Claude Code fetches those settings at startup wherever [server-managed settings apply](/docs/en/model-config.md#surface-coverage), which includes your users' machines and cloud sessions other than Claude Tag channel sessions. Claude Tag sessions don't receive your server-managed settings, so this route doesn't configure them.
548* **The environment's variables**: add them to a cloud environment's [environment variables](/docs/en/cloud-environments.md#set-environment-variables) to configure only the sessions that run in that environment. This is the route that reaches Claude Tag sessions.
547* **Server-managed settings**: add them to the `env` block of your organization's [server-managed settings](https://code.claude.com/docs/en/server-managed-settings.md). Claude Code fetches those settings at startup wherever [server-managed settings apply](https://code.claude.com/docs/en/model-config.md#surface-coverage), which includes your users' machines and cloud sessions other than Claude Tag channel sessions. Claude Tag sessions don't receive your server-managed settings, so this route doesn't configure them.
548* **The environment's variables**: add them to a cloud environment's [environment variables](https://code.claude.com/docs/en/cloud-environments.md#set-environment-variables) to configure only the sessions that run in that environment. This is the route that reaches Claude Tag sessions.
549549
550Anyone who uses an environment can read its variables, so don't put a credential there, such as a collector token in `OTEL_EXPORTER_OTLP_HEADERS`. A [network secret](/docs/en/cloud-environments.md#add-network-secrets) on the environment doesn't help either, because Claude Code's own telemetry export is one of the [requests that never get the secret](/docs/en/cloud-environments.md#requests-that-never-get-the-credential). If your collector requires a credential, configure the whole export through server-managed settings instead, because when you set a credential there, [Claude Code removes endpoint variables set outside managed settings](#how-managed-settings-lock-the-otlp-destination).
550Anyone who uses an environment can read its variables, so don't put a credential there, such as a collector token in `OTEL_EXPORTER_OTLP_HEADERS`. A [network secret](https://code.claude.com/docs/en/cloud-environments.md#add-network-secrets) on the environment doesn't help either, because Claude Code's own telemetry export is one of the [requests that never get the secret](https://code.claude.com/docs/en/cloud-environments.md#requests-that-never-get-the-credential). If your collector requires a credential, configure the whole export through server-managed settings instead, because when you set a credential there, [Claude Code removes endpoint variables set outside managed settings](#how-managed-settings-lock-the-otlp-destination).
551551
552552Keep these constraints in mind when you configure telemetry for cloud sessions:
553553
554* **Let sessions reach the collector**: Claude Code sends the export through the session's network, so whether it reaches the host in your `OTEL_EXPORTER_OTLP_ENDPOINT` depends on the environment's [network access level](/docs/en/cloud-environments.md#access-levels). If sessions can't reach the collector's domain at the level you chose, [add the domain to the environment's allowlist](/docs/en/cloud-environments.md#allow-specific-domains), because no server-managed setting adds domains to an environment's network allowlist.
555* **Claude Tag channels use organization-level environments**: channel sessions run in organization-level environments rather than members' personal ones, so make the allowlist and any environment-variable changes on the [shared environment](/docs/en/cloud-environments.md#organization-shared-environments) set as your organization's default or pinned to the channel.
556* **Cowork is configured separately**: Cowork sessions don't receive server-managed settings, as the [surface coverage table](/docs/en/model-config.md#surface-coverage) shows, so the server-managed `env` block doesn't configure their telemetry.
554* **Let sessions reach the collector**: Claude Code sends the export through the session's network, so whether it reaches the host in your `OTEL_EXPORTER_OTLP_ENDPOINT` depends on the environment's [network access level](https://code.claude.com/docs/en/cloud-environments.md#access-levels). If sessions can't reach the collector's domain at the level you chose, [add the domain to the environment's allowlist](https://code.claude.com/docs/en/cloud-environments.md#allow-specific-domains), because no server-managed setting adds domains to an environment's network allowlist.
555* **Claude Tag channels use organization-level environments**: channel sessions run in organization-level environments rather than members' personal ones, so make the allowlist and any environment-variable changes on the [shared environment](https://code.claude.com/docs/en/cloud-environments.md#organization-shared-environments) set as your organization's default or pinned to the channel.
556* **Cowork is configured separately**: Cowork sessions don't receive server-managed settings, as the [surface coverage table](https://code.claude.com/docs/en/model-config.md#surface-coverage) shows, so the server-managed `env` block doesn't configure their telemetry.
557557
558558### Attribute telemetry to cloud sessions
559559
560By default, metrics and events from a cloud session carry the [standard attributes](#standard-attributes), including `session.id`, `ccr.session.id`, and `organization.id`, so you can filter by session or organization without extra configuration. The `ccr.session.id` value is the session's `CLAUDE_CODE_REMOTE_SESSION_ID`. To turn it into the session's transcript URL, see [Link output back to the session](/docs/en/cloud-environments.md#link-output-back-to-the-session).
560By default, metrics and events from a cloud session carry the [standard attributes](#standard-attributes), including `session.id`, `ccr.session.id`, and `organization.id`, so you can filter by session or organization without extra configuration. The `ccr.session.id` value is the session's `CLAUDE_CODE_REMOTE_SESSION_ID`. To turn it into the session's transcript URL, see [Link output back to the session](https://code.claude.com/docs/en/cloud-environments.md#link-output-back-to-the-session).
561561
562562To tell cloud sessions apart, group or filter on `ccr.session.id`, not `session.id`.
563563
from line 564
564564To attribute telemetry in more detail, use these options:
565565
566566* **Identify Claude Tag sessions**: set `OTEL_METRICS_INCLUDE_ENTRYPOINT=true`, as described under [Metrics cardinality control](#metrics-cardinality-control). Metrics then carry `app.entrypoint`, whose value is `claude-in-slack` for Claude Tag sessions.
567* **Add custom attributes**: set [`OTEL_RESOURCE_ATTRIBUTES`](#multi-team-organization-support) in the same place you set the other `OTEL_*` variables for those sessions. If you `export` it in the environment's [setup script](/docs/en/cloud-environments.md#setup-scripts) instead, the value doesn't reach Claude Code: the setup script is a separate Bash script that runs before Claude Code launches, and variables it exports end with it.
567* **Add custom attributes**: set [`OTEL_RESOURCE_ATTRIBUTES`](#multi-team-organization-support) in the same place you set the other `OTEL_*` variables for those sessions. If you `export` it in the environment's [setup script](https://code.claude.com/docs/en/cloud-environments.md#setup-scripts) instead, the value doesn't reach Claude Code: the setup script is a separate Bash script that runs before Claude Code launches, and variables it exports end with it.
568568
569In Claude Tag channel sessions, Claude works as your organization's [shared identity](/docs/en/cloud-environments.md#set-the-environment-a-claude-tag-channel-uses) rather than as any member, so don't rely on the `user.*` attributes to identify who tagged Claude.
569In Claude Tag channel sessions, Claude works as your organization's [shared identity](https://code.claude.com/docs/en/cloud-environments.md#set-the-environment-a-claude-tag-channel-uses) rather than as any member, so don't rely on the `user.*` attributes to identify who tagged Claude.
570570
571571## Available metrics and events
572572
from line 577
577577| Attribute | Description | Controlled By |
578578| - | - | - |
579579| `session.id` | Claude Code's own session ID, which `/clear` replaces | `OTEL_METRICS_INCLUDE_SESSION_ID` (default: true) |
580| `ccr.session.id` | Cloud session identifier, the value of `CLAUDE_CODE_REMOTE_SESSION_ID`, on sessions that run in a [cloud environment](/docs/en/cloud-environments.md) | `OTEL_METRICS_INCLUDE_SESSION_ID` (default: true) |
580| `ccr.session.id` | Cloud session identifier, the value of `CLAUDE_CODE_REMOTE_SESSION_ID`, on sessions that run in a [cloud environment](https://code.claude.com/docs/en/cloud-environments.md) | `OTEL_METRICS_INCLUDE_SESSION_ID` (default: true) |
581581| `app.version` | Current Claude Code version | `OTEL_METRICS_INCLUDE_VERSION` (default: false) |
582582| `app.entrypoint` | How the session was launched, such as `cli`, `sdk-cli`, `sdk-ts`, `sdk-py`, `claude-vscode`, or `claude-in-slack` for Claude Tag sessions | `OTEL_METRICS_INCLUDE_ENTRYPOINT` (default: false) |
583583| `organization.id` | Organization UUID (when authenticated) | Always included when available |
from line 584
584584| `user.account_uuid` | Account UUID (when authenticated) | `OTEL_METRICS_INCLUDE_ACCOUNT_UUID` (default: true) |
585585| `user.account_id` | Account ID in tagged format matching Anthropic admin APIs (when authenticated), such as `user_01BWBeN28...` | `OTEL_METRICS_INCLUDE_ACCOUNT_UUID` (default: true) |
586586| `user.id` | Random anonymous identifier generated on first run and persisted in `~/.claude.json`. It contains no personal information and is not derived from your Claude account. Deleting the file produces a new unrelated value on next run. | Always included |
587| `user.email` | User email address, from your sign-in or, in a [cloud session](/docs/en/claude-code-on-the-web.md), from the session's own credentials | Always included when available |
587| `user.email` | User email address, from your sign-in or, in a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md), from the session's own credentials | Always included when available |
588588| `terminal.type` | Terminal type, such as `iTerm.app`, `vscode`, `cursor`, or `tmux` | Always included when detected |
589589| Keys from `OTEL_RESOURCE_ATTRIBUTES` | Custom attributes you set, such as `department` or `team.id`. See [Multi-team organization support](#multi-team-organization-support) | `OTEL_METRICS_INCLUDE_RESOURCE_ATTRIBUTES` (default: true) |
590590| `vcs.repository.url.full`, `vcs.owner.name`, `vcs.repository.name`, `vcs.provider.name` | The session repository's identity, derived from its `origin` remote. See [Repository attributes](#repository-attributes) | `OTEL_METRICS_INCLUDE_REPOSITORY` (default: false). Requires Claude Code v2.1.269 or later |
591591
592In sessions signed in to a [Claude apps gateway](/docs/en/claude-apps-gateway) through `/login`, the CLI stamps exports with the authenticated identity: `user.id` is the IdP subject, `user.email` is the signed-in email, and `user.groups` carries IdP group membership as a comma-separated string. Each export also carries `identity.source: gateway-oidc`. The gateway identity is applied last, so `user.*` and `identity.*` keys set through `OTEL_RESOURCE_ATTRIBUTES` are ignored on those sessions.
592In sessions signed in to a [Claude apps gateway](https://code.claude.com/docs/en/claude-apps-gateway) through `/login`, the CLI stamps exports with the authenticated identity: `user.id` is the IdP subject, `user.email` is the signed-in email, and `user.groups` carries IdP group membership as a comma-separated string. Each export also carries `identity.source: gateway-oidc`. The gateway identity is applied last, so `user.*` and `identity.*` keys set through `OTEL_RESOURCE_ATTRIBUTES` are ignored on those sessions.
593593
594594> [!NOTE]
595595>
596> Events that Claude Code logs before a developer signs in don't carry the gateway identity. When Claude Code opens a session signed out of the gateway, for example after [the gateway ends the sign-in](/docs/en/errors.md#cloud-gateway-session-expired), the startup events logged before sign-in carry the anonymous `user.id` and no `identity.source`. These include [`managed_settings_resolved`](#managed-settings-resolved-event), [`plugin_loaded`](#plugin-loaded-event), and [`mcp_server_connection`](#mcp-server-connection-event).
596> Events that Claude Code logs before a developer signs in don't carry the gateway identity. When Claude Code opens a session signed out of the gateway, for example after [the gateway ends the sign-in](https://code.claude.com/docs/en/errors.md#cloud-gateway-session-expired), the startup events logged before sign-in carry the anonymous `user.id` and no `identity.source`. These include [`managed_settings_resolved`](#managed-settings-resolved-event), [`plugin_loaded`](#plugin-loaded-event), and [`mcp_server_connection`](#mcp-server-connection-event).
597597
598For the identity attributes on Claude Desktop and Cowork sessions that connect through a gateway, see the [gateway `telemetry` reference](/docs/en/claude-apps-gateway-config#telemetry).
598For the identity attributes on Claude Desktop and Cowork sessions that connect through a gateway, see the [gateway `telemetry` reference](https://code.claude.com/docs/en/claude-apps-gateway-config#telemetry).
599599
600600Events additionally include the following attributes. These are never attached to metrics because they would cause unbounded cardinality:
601601
602602* `prompt.id`: UUID correlating a user prompt with all subsequent events until the next prompt. See [Event correlation attributes](#event-correlation-attributes).
603603* `workspace.host_paths`: host workspace directories selected in the desktop app, as a string array
604* `workflow.run_id`: run identifier, prefixed `wf_`, on the API and tool events emitted by agents that belong to a [Workflow](/docs/en/workflows.md) tool run. Filtering events by one `workflow.run_id` reconstructs that run's API requests and tool results. The identifier covers the agents the workflow script spawns and any agents those spawn in turn, such as skill invocations. It matches the run identifier reported in the Workflow tool result. Absent on all other events.
604* `workflow.run_id`: run identifier, prefixed `wf_`, on the API and tool events emitted by agents that belong to a [Workflow](https://code.claude.com/docs/en/workflows.md) tool run. Filtering events by one `workflow.run_id` reconstructs that run's API requests and tool results. The identifier covers the agents the workflow script spawns and any agents those spawn in turn, such as skill invocations. It matches the run identifier reported in the Workflow tool result. Absent on all other events.
605605* `workflow.name`: name of the workflow, its script's `meta.name`, emitted alongside `workflow.run_id`. Built-in workflow names appear verbatim when the run executes the unmodified built-in script. User-authored names, including edited copies of built-in scripts, are replaced with `custom` unless `OTEL_LOG_TOOL_DETAILS=1` is set.
606606
607607#### Repository attributes
from line 619
619619
620620Values are lowercased, and credentials, query strings, and fragments from the remote URL never appear in them. The attributes are omitted when the session has no `origin` remote, when the remote isn't URL-shaped, or when the only enclosing repository is your home directory.
621621
622To get these attributes from a [cloud session](/docs/en/claude-code-on-the-web.md), set the telemetry variables, including `OTEL_METRICS_INCLUDE_REPOSITORY`, on its [cloud environment](/docs/en/cloud-environments.md#set-environment-variables). Also allow your collector's domain in the environment's [network access](/docs/en/cloud-environments.md#network-access).
622To get these attributes from a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md), set the telemetry variables, including `OTEL_METRICS_INCLUDE_REPOSITORY`, on its [cloud environment](https://code.claude.com/docs/en/cloud-environments.md#set-environment-variables). Also allow your collector's domain in the environment's [network access](https://code.claude.com/docs/en/cloud-environments.md#network-access).
623623
624624A `vcs.*` key you declare in [`OTEL_RESOURCE_ATTRIBUTES`](#multi-team-organization-support) replaces the derived value for that key. If you declare `vcs.repository.url.full`, Claude Code never reads the remote and reports only the keys you declare.
625625
from line 695
695695* `model`: Model identifier (for example, "claude-sonnet-5")
696696* `query_source`: Category of the subsystem that issued the request. One of `"main"`, `"subagent"`, or `"auxiliary"`
697697* `speed`: `"fast"` when the request used fast mode. Absent otherwise
698* `effort`: [Effort level](/docs/en/model-config.md#adjust-effort-level) applied to the request: `"low"`, `"medium"`, `"high"`, `"xhigh"`, or `"max"`. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
698* `effort`: [Effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) applied to the request: `"low"`, `"medium"`, `"high"`, `"xhigh"`, or `"max"`. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
699699* `agent.name`: Subagent type that issued the request. Built-in agent names and agents from official-marketplace plugins appear verbatim. Other user-defined agent names are replaced with `"custom"`. Absent when the request was not issued by a named subagent type.
700700* `skill.name`: Skill active for the request, set by the Skill tool or a `/` command, or inherited by a spawned subagent. Built-in, bundled, user-defined, and official-marketplace plugin skill names appear verbatim. Third-party plugin skill names are replaced with `"third-party"`. Absent when no skill is active.
701701* `plugin.name`: Owning plugin when the active skill or subagent is provided by a plugin. Official-marketplace plugin names appear verbatim. Third-party plugin names are replaced with `"third-party"`. Absent when neither the skill nor the subagent has an owning plugin.
from line 710
710710**Attributes**:
711711
712712* All [standard attributes](#standard-attributes)
713* `type`: (`"input"`, `"output"`, `"cacheRead"`, `"cacheCreation"`). The `"input"` type excludes tokens read from or written to the prompt cache, which are counted under `"cacheRead"` and `"cacheCreation"`. The `"cacheCreation"` type counts cache writes with the five-minute and one-hour [cache lifetimes](/docs/en/prompt-caching.md#cache-lifetime) together.
713* `type`: (`"input"`, `"output"`, `"cacheRead"`, `"cacheCreation"`). The `"input"` type excludes tokens read from or written to the prompt cache, which are counted under `"cacheRead"` and `"cacheCreation"`. The `"cacheCreation"` type counts cache writes with the five-minute and one-hour [cache lifetimes](https://code.claude.com/docs/en/prompt-caching.md#cache-lifetime) together.
714714* `model`: Model identifier (for example, "claude-sonnet-5")
715715* `query_source`: Category of the subsystem that issued the request. One of `"main"`, `"subagent"`, or `"auxiliary"`
716716* `speed`: `"fast"` when the request used fast mode. Absent otherwise
717* `effort`: [Effort level](/docs/en/model-config.md#adjust-effort-level) applied to the request. See [Cost counter](#cost-counter) for details.
717* `effort`: [Effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) applied to the request. See [Cost counter](#cost-counter) for details.
718718* `agent.name`, `skill.name`, `plugin.name`, `marketplace.name`, `mcp_server.name`, `mcp_tool.name`: Skill, plugin, agent, and MCP attribution for the request. See [Cost counter](#cost-counter) for definitions and redaction behavior.
719719
720720#### Code edit tool decision counter
from line 751
751751| `prompt.id` | UUID v4 identifier linking all events produced while processing a single user prompt |
752752| `event.sequence` | 0-based counter for ordering events, counted per Claude Code process rather than per session |
753753| `message.uuid` | UUID of the message as persisted in the session transcript, the `~/.claude/projects/*/*.jsonl` files. Present on `assistant_response`, on `api_response_body`, and on `user_prompt` except for command dispatches, which can produce zero or many messages. On `assistant_response` and `api_response_body`, this is the response's final transcript entry, which the next turn's `parentUuid` chains from. Requires Claude Code v2.1.274 or later on `api_response_body` |
754| `request_id` | Server-assigned ID of the API request, read from the `request-id` response header, such as `req_011...`. On a response with no `request-id` header, as on [Amazon Bedrock](/docs/en/amazon-bedrock.md), the value comes from the `x-amzn-requestid` header instead. Present on `api_request`, `api_error`, `api_refusal`, `assistant_response`, and `api_response_body` when the response carries either header. Matches the same attribute on the `llm_request` trace span. The `x-amzn-requestid` source requires Claude Code v2.1.282 or later |
754| `request_id` | Server-assigned ID of the API request, read from the `request-id` response header, such as `req_011...`. On a response with no `request-id` header, as on [Amazon Bedrock](https://code.claude.com/docs/en/amazon-bedrock.md), the value comes from the `x-amzn-requestid` header instead. Present on `api_request`, `api_error`, `api_refusal`, `assistant_response`, and `api_response_body` when the response carries either header. Matches the same attribute on the `llm_request` trace span. The `x-amzn-requestid` source requires Claude Code v2.1.282 or later |
755755| `client_request_id` | Client-generated UUID sent as the `x-client-request-id` request header. Present on `api_request` and `api_error` on first-party API connections; absent on third-party provider backends and when the request was retried through the non-streaming fallback. Pairs a request with its response and remains available for failures such as timeouts that never produced a server `request_id`. Matches the same attribute on the `llm_request` trace span |
756756
757757To trace all activity triggered by a single prompt, filter your events by a specific `prompt.id` value. This returns the user\_prompt event, any api\_request events, and any tool\_result events that occurred while processing that prompt.
758758
759`event.sequence` starts at 0 each time a Claude Code process starts and counts up for the life of that process. It keeps counting across `/clear`, which assigns a new `session.id`. If you [resume a session without forking](/docs/en/how-claude-code-works.md#resume-or-fork-sessions), the session keeps its `session.id` but takes its `event.sequence` values from the process that resumed it, so within one session a later event can carry a lower value than an earlier one, or repeat one. To order a session's events, sort by `event.timestamp` and use `event.sequence` to order events that share a timestamp.
759`event.sequence` starts at 0 each time a Claude Code process starts and counts up for the life of that process. It keeps counting across `/clear`, which assigns a new `session.id`. If you [resume a session without forking](https://code.claude.com/docs/en/how-claude-code-works.md#resume-or-fork-sessions), the session keeps its `session.id` but takes its `event.sequence` values from the process that resumed it, so within one session a later event can carry a lower value than an earlier one, or repeat one. To order a session's events, sort by `event.timestamp` and use `event.sequence` to order events that share a timestamp.
760760
761For message-level reconstruction, each event class carries a key that matches a field in the session transcript. The transcript entry format is [internal to Claude Code](/docs/en/sessions.md#where-transcripts-are-stored) and changes between versions, so a pipeline that joins on these fields can break on any release; treat the joins as version-specific rather than a stable contract:
761For message-level reconstruction, each event class carries a key that matches a field in the session transcript. The transcript entry format is [internal to Claude Code](https://code.claude.com/docs/en/sessions.md#where-transcripts-are-stored) and changes between versions, so a pipeline that joins on these fields can break on any release; treat the joins as version-specific rather than a stable contract:
762762
763763* `message.uuid` on `user_prompt`, `assistant_response`, and `api_response_body`
764764* `request_id` on the API events, persisted as `requestId` on the transcript's assistant entries
from line 858
858858* `client_request_id`: Client-generated UUID sent as the `x-client-request-id` request header; see the [event correlation attributes](#event-correlation-attributes) table for when it's present
859859* `speed`: `"fast"` or `"normal"`, indicating whether fast mode was active
860860* `query_source`: Subsystem that issued the request, such as `"repl_main_thread"`, `"compact"`, or a subagent name
861* `effort`: [Effort level](/docs/en/model-config.md#adjust-effort-level) applied to the request: `"low"`, `"medium"`, `"high"`, `"xhigh"`, or `"max"`. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
861* `effort`: [Effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) applied to the request: `"low"`, `"medium"`, `"high"`, `"xhigh"`, or `"max"`. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
862862* `agent.name`, `skill.name`, `plugin.name`, `marketplace.name`, `mcp_server.name`, `mcp_tool.name`: Skill, plugin, agent, and MCP attribution for the request. See [Cost counter](#cost-counter) for definitions and redaction behavior.
863863
864864#### API error event
from line 882
882882* `client_request_id`: Client-generated UUID sent as the `x-client-request-id` request header. Available even when a failure such as a timeout or connection error never produced a server `request_id`; see the [event correlation attributes](#event-correlation-attributes) table for when it's present.
883883* `speed`: `"fast"` or `"normal"`, indicating whether fast mode was active
884884* `query_source`: Subsystem that issued the request, such as `"repl_main_thread"`, `"compact"`, or a subagent name
885* `effort`: [Effort level](/docs/en/model-config.md#adjust-effort-level) applied to the request. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
885* `effort`: [Effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) applied to the request. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
886886* `agent.name`, `skill.name`, `plugin.name`, `marketplace.name`, `mcp_server.name`, `mcp_tool.name`: Skill, plugin, agent, and MCP attribution for the request. See [Cost counter](#cost-counter) for definitions and redaction behavior.
887887
888888#### API refusal event
from line 900
900900* `model`: Model identifier from the request
901901* `request_id`: API request ID, such as `"req_011..."`, described under [Event correlation attributes](#event-correlation-attributes).
902902* `query_source`: Subsystem that issued the request, such as `"repl_main_thread"`, `"compact"`, or a subagent name. See [`api_request`](#api-request-event) for definitions.
903* `speed`: Either `"fast"` when [Fast mode](/docs/en/fast-mode.md) is active, or `"normal"`
903* `speed`: Either `"fast"` when [Fast mode](https://code.claude.com/docs/en/fast-mode.md) is active, or `"normal"`
904904* `attempt`: Retry attempt number. The first attempt is `1`.
905* `effort`: [Effort level](/docs/en/model-config.md#adjust-effort-level) applied to the request. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
905* `effort`: [Effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) applied to the request. Absent when Claude Code sends no effort level, for example on a model that doesn't support effort.
906906* `server_fallback_hop`: `true` when the API's server-side model fallback already retried this refusal on a different model, so the user did not see this particular refusal. `false` when the request ended in a refusal. A single turn can emit both a `true` hop event and a later `false` final event when the fallback model also refuses.
907907* `has_category`: `true` when the API response carried a `stop_details.category` of `"cyber"`, `"bio"`, `"frontier_llm"`, or `"reasoning_extraction"`. `false` when the response carried no category or a value outside that set. Absent when `server_fallback_hop` is `true`, because hop blocks don't carry `stop_details`.
908908* `has_explanation`: `true` when the API response carried a `stop_details.explanation`, otherwise `false`. Absent when `server_fallback_hop` is `true`.
from line 987
987987
988988 The `source` value doesn't indicate which of these sources matched. To find which one refused a call, look for the [Safety event](#safety-event) with the same `tool_use_id` and read its `category` and `rule_source` attributes. Some refused calls [have no safety event](#calls-without-a-safety-event).
989989
990 Claude Code also reports `"config"` when the permission prompt request itself fails. For example, that request fails when the Agent SDK's [`canUseTool`](/docs/en/agent-sdk/typescript#canusetool) callback or the [`--permission-prompt-tool`](/docs/en/cli-reference#cli-flags) tool returns an invalid result, or when the input stream closes while the request is pending. Before v2.1.216, Claude Code reported these failures as `"user_reject"`.
990 Claude Code also reports `"config"` when the permission prompt request itself fails. For example, that request fails when the Agent SDK's [`canUseTool`](https://code.claude.com/docs/en/agent-sdk/typescript#canusetool) callback or the [`--permission-prompt-tool`](https://code.claude.com/docs/en/cli-reference#cli-flags) tool returns an invalid result, or when the input stream closes while the request is pending. Before v2.1.216, Claude Code reported these failures as `"user_reject"`.
991991 * `"hook"`: A `PreToolUse` or `PermissionRequest` hook returned the decision.
992992 * `"user_permanent"`: Emitted when the user chose "Yes, and don't ask again for ..." at a permission prompt, which saves an allow rule to their personal settings. In the interactive CLI this is emitted only for that choice itself; later calls that match the saved rule emit `"config"` instead. In Agent SDK or non-interactive `-p` sessions, both the initial choice and later rule matches emit `"user_permanent"`. Treated as an accept.
993993 * `"user_temporary"`: Emitted when the user chose "Yes" at a permission prompt for a one-time approval, or chose an option that grants access for the rest of the session on a file edit or read prompt. In the interactive CLI this is emitted only for the choice itself; later calls allowed by that session-scoped grant emit `"config"` instead. In Agent SDK or non-interactive `-p` sessions, both the choice and later matches emit `"user_temporary"`. Treated as an accept.
994994 * `"user_abort"`: Emitted when the user dismissed the permission prompt without answering. In Agent SDK and non-interactive `-p` sessions, this includes interrupting the turn while a `canUseTool` or `--permission-prompt-tool` permission request is pending; before v2.1.216, Claude Code reported that interrupt as `"user_reject"`. Treated as a reject.
995995 * `"user_reject"`: Emitted when the user chose "No" when prompted. In the interactive CLI this is emitted only for that choice itself; calls that match a deny rule in the user's personal settings emit `"config"` instead. In Agent SDK or non-interactive `-p` sessions, calls that match a deny rule in personal settings emit `"user_reject"`. Treated as a reject.
996* `classifier_verdict`: The auto mode [classifier](/docs/en/permission-modes.md#how-the-classifier-evaluates-actions) verdict for the call, or why Claude Code denied the call when none came. Requires Claude Code v2.1.301 or later
996* `classifier_verdict`: The auto mode [classifier](https://code.claude.com/docs/en/permission-modes.md#how-the-classifier-evaluates-actions) verdict for the call, or why Claude Code denied the call when none came. Requires Claude Code v2.1.301 or later
997997
998998 * `"allow"`: the classifier approved the call
999999 * `"block"`: the classifier blocked the call. A classifier check that fails partway through can also end as `"block"`, so a partial classifier outage can appear as more blocks rather than as `"unavailable"`
1000 * `"no_verdict"`: the check ran but gave [no usable verdict](/docs/en/errors.md#auto-mode-cannot-determine-the-safety-of-an-action), so Claude Code denied the call. The denial doesn't mean the classifier found the call unsafe
1001 * `"unavailable"`: the request to the classifier failed, for example on a rate limit, timeout, or connection error, so Claude Code denied the call. With [server-side classifier review](/docs/en/permission-modes.md#server-side-classifier-review), it also marks a call denied because [the server returned no safety verdict](/docs/en/errors.md#the-server-returned-no-safety-verdict)
1000 * `"no_verdict"`: the check ran but gave [no usable verdict](https://code.claude.com/docs/en/errors.md#auto-mode-cannot-determine-the-safety-of-an-action), so Claude Code denied the call. The denial doesn't mean the classifier found the call unsafe
1001 * `"unavailable"`: the request to the classifier failed, for example on a rate limit, timeout, or connection error, so Claude Code denied the call. With [server-side classifier review](https://code.claude.com/docs/en/permission-modes.md#server-side-classifier-review), it also marks a call denied because [the server returned no safety verdict](https://code.claude.com/docs/en/errors.md#the-server-returned-no-safety-verdict)
10021002
1003 The attribute also appears on plan mode calls when [the classifier reviews commands in plan mode](/docs/en/permission-modes.md#analyze-before-you-edit-with-plan-mode). The attribute is absent in these cases:
1003 The attribute also appears on plan mode calls when [the classifier reviews commands in plan mode](https://code.claude.com/docs/en/permission-modes.md#analyze-before-you-edit-with-plan-mode). The attribute is absent in these cases:
10041004
1005 * An allow or deny [permission rule](/docs/en/permissions.md#manage-permissions) decided the call
1005 * An allow or deny [permission rule](https://code.claude.com/docs/en/permissions.md#manage-permissions) decided the call
10061006 * Claude Code approved the call in auto mode without asking the classifier
1007 * The user answered the prompt Claude Code showed after [repeated blocks](/docs/en/permission-modes.md#repeated-block-thresholds)
1007 * The user answered the prompt Claude Code showed after [repeated blocks](https://code.claude.com/docs/en/permission-modes.md#repeated-block-thresholds)
10081008 * In a `-p` run without `--permission-prompt-tool`, Claude Code denied the call after repeated blocks because there was nobody to answer a prompt. That event reports `decision` as `"reject"` and `source` as `"config"`
1009* `classifier_category` (when `OTEL_LOG_TOOL_DETAILS=1`): The name of the [built-in rule](/docs/en/auto-mode-config.md#inspect-the-defaults-and-your-effective-config) the classifier named when it blocked the call, in lowercase with underscores, such as `"data_exfiltration"` for the Data Exfiltration rule. Requires Claude Code v2.1.301 or later. The attribute is present when both of these hold:
1009* `classifier_category` (when `OTEL_LOG_TOOL_DETAILS=1`): The name of the [built-in rule](https://code.claude.com/docs/en/auto-mode-config.md#inspect-the-defaults-and-your-effective-config) the classifier named when it blocked the call, in lowercase with underscores, such as `"data_exfiltration"` for the Data Exfiltration rule. Requires Claude Code v2.1.301 or later. The attribute is present when both of these hold:
10101010
10111011 * `classifier_verdict` is `"block"`
10121012 * The classifier named exactly one rule, and that rule is a built-in one rather than one you wrote
10131013
1014 Before v2.1.302, the attribute was also absent on any block that [server-side classifier review](/docs/en/permission-modes.md#server-side-classifier-review) decided.
1015* `permission_mode`: [Permission mode](/docs/en/permission-modes.md) active when this call's permission check began: `"default"`, `"plan"`, `"acceptEdits"`, `"bypassPermissions"`, `"dontAsk"`, or `"auto"`. Manual mode appears as `"default"`. A [subagent](/docs/en/sub-agents.md#permission-modes) call reports the subagent's permission mode rather than the session's. Requires Claude Code v2.1.301 or later
1014 Before v2.1.302, the attribute was also absent on any block that [server-side classifier review](https://code.claude.com/docs/en/permission-modes.md#server-side-classifier-review) decided.
1015* `permission_mode`: [Permission mode](https://code.claude.com/docs/en/permission-modes.md) active when this call's permission check began: `"default"`, `"plan"`, `"acceptEdits"`, `"bypassPermissions"`, `"dontAsk"`, or `"auto"`. Manual mode appears as `"default"`. A [subagent](https://code.claude.com/docs/en/sub-agents.md#permission-modes) call reports the subagent's permission mode rather than the session's. Requires Claude Code v2.1.301 or later
10161016* `tool_parameters` (when `OTEL_LOG_TOOL_DETAILS=1`): JSON string containing tool-specific parameters. Same shape as the [Tool result event](#tool-result-event), minus post-execution fields such as `git_commit_id`. Values may differ from `tool_result` for an accepted call if the permission decision rewrites the tool input via `updatedInput`. Use this attribute to see which command was rejected when `decision` is `"reject"`.
10171017 * For `"sdk_host_builtin_mcp"` tools: `mcp_server_name` and `mcp_tool_name` are included even when `OTEL_LOG_TOOL_DETAILS` is off, because the host application defines these names; without them, a rejected call to one of these built-in servers would be unattributable on the default stream. For user-configured MCP servers, the event's `tool_name` is always the literal `"mcp_tool"`, and the server and tool names appear only in `tool_parameters` with the flag on; argument content requires the flag everywhere.
10181018 * For Bash tool: includes `bash_command`, `full_command`, `timeout`, `description`, `dangerouslyDisableSandbox`. The desktop app's workspace bash tool also reports `tool_name` as `Bash`, but includes only `bash_command`, `full_command`, and `timeout`
from line 1024
10241024
10251025#### Safety event
10261026
1027Logged when a check refuses a tool call or requires a permission prompt, except for [calls without a safety event](#calls-without-a-safety-event). Also logged when the [sandbox's network proxy](/docs/en/sandboxing.md#network-isolation) refuses a connection or request, and when a hook blocks a result. Requires Claude Code v2.1.307 or later.
1027Logged when a check refuses a tool call or requires a permission prompt, except for [calls without a safety event](#calls-without-a-safety-event). Also logged when the [sandbox's network proxy](https://code.claude.com/docs/en/sandboxing.md#network-isolation) refuses a connection or request, and when a hook blocks a result. Requires Claude Code v2.1.307 or later.
10281028
10291029The event exports with the other events and has no separate setting. The event's own attributes hold no command text, file paths, host names, or MCP server and tool names. The record also carries the [standard attributes](#standard-attributes) every event has, which can include `workspace.host_paths` and the [repository attributes](#repository-attributes). To see the command or MCP tool behind an event, set `OTEL_LOG_TOOL_DETAILS=1` and read `tool_parameters` on the matching `tool_decision` event.
10301030
from line 1044
10441044* `rule_source`: Settings source of the rule involved, such as `"policySettings"`, `"userSettings"`, `"projectSettings"`, `"localSettings"`, `"flagSettings"`, `"cliArg"`, or `"session"`
10451045* `grant_scope`: `"once"` or `"session"` for a prompt approved without saving a rule to a settings file
10461046* `circuit_breaker`: The built-in safety check, such as `"dangerousRemoval"`, `"outsideReadsBlocked"`, or `"claudeSettingsFile"`
1047* `classifier_category`: With `OTEL_LOG_TOOL_DETAILS=1`, the [built-in rule](/docs/en/auto-mode-config.md#inspect-the-defaults-and-your-effective-config) behind an auto mode block, such as `"data_exfiltration"`
1047* `classifier_category`: With `OTEL_LOG_TOOL_DETAILS=1`, the [built-in rule](https://code.claude.com/docs/en/auto-mode-config.md#inspect-the-defaults-and-your-effective-config) behind an auto mode block, such as `"data_exfiltration"`
10481048* `hook_event`: `"pre_tool_use"` for a `PreToolUse` hook, or `"post_tool_use"`, `"post_tool_use_failure"`, `"stop"`, or `"subagent_stop"` on `"hook_review"` events
1049* `tool_class`: `"bash"` for Bash and [Monitor](/docs/en/tools-reference.md#monitor-tool), `"powershell"`, `"file"` for Read, Edit, Write, NotebookEdit, Glob, and Grep, `"web"` for WebFetch and WebSearch, `"mcp"`, or `"other"`
1049* `tool_class`: `"bash"` for Bash and [Monitor](https://code.claude.com/docs/en/tools-reference.md#monitor-tool), `"powershell"`, `"file"` for Read, Edit, Write, NotebookEdit, Glob, and Grep, `"web"` for WebFetch and WebSearch, `"mcp"`, or `"other"`
10501050* `tool_name`: The tool's name, such as `"Bash"` for a built-in tool, or `"mcp_tool"`, `"skill_tool"`, `"dynamic_tool"`, or `"other_tool"`
10511051* `tool_source`: `"builtin"`, `"mcp"`, or `"sdk_host_builtin_mcp"`, as on [`tool_decision`](#tool-decision-event)
1052* `permission_mode`: The call's [permission mode](/docs/en/permission-modes.md) when checked: `"default"`, `"plan"`, `"acceptEdits"`, `"bypassPermissions"`, `"dontAsk"`, or `"auto"`
1052* `permission_mode`: The call's [permission mode](https://code.claude.com/docs/en/permission-modes.md) when checked: `"default"`, `"plan"`, `"acceptEdits"`, `"bypassPermissions"`, `"dontAsk"`, or `"auto"`
10531053* `tool_use_id`: The call's ID, as on `tool_decision` and `tool_result`
10541054* `sandbox_violation_count`: How many distinct connections or requests from the call's command the sandbox's network proxy refused, `"0"` to `"20"` as a string. Refusals are counted for a sandboxed command that finished in the foreground
1055* `sandbox_enabled`: `"true"` if [sandboxing](/docs/en/sandboxing.md) is on for the session, else `"false"`
1055* `sandbox_enabled`: `"true"` if [sandboxing](https://code.claude.com/docs/en/sandboxing.md) is on for the session, else `"false"`
10561056
10571057These are the event's own attributes when a managed-settings deny rule refuses a Bash command:
10581058
from line 1078
10781078
10791079| Value | Check or outcome | Detail attribute |
10801080| - | - | - |
1081| `"permission_rule"` | A deny or ask [permission rule](/docs/en/permissions.md#manage-permissions) outside managed settings | `rule_source` |
1082| `"managed_policy"` | A deny or ask rule from [managed settings](/docs/en/permissions.md#managed-settings) | `rule_source` |
1083| `"permission_mode"` | [`dontAsk`](/docs/en/permission-modes#allow-only-pre-approved-tools-with-dontask-mode) or [plan](/docs/en/permission-modes.md#analyze-before-you-edit-with-plan-mode) mode, or a prompt with [no category](#prompts-with-no-category) in a session that can't show prompts, as with [`--permission-prompts none`](/docs/en/headless#turn-off-permission-prompts-in-unattended-runs) | `reason_code`, `reason_type` |
1084| `"hook"` | A hook, such as [`PreToolUse`](/docs/en/hooks#pretooluse) or [`PermissionRequest`](/docs/en/hooks#permissionrequest) | `hook_event`, `reason_code` |
1085| `"auto_mode_block"` | The auto mode [classifier](/docs/en/permission-modes.md#how-the-classifier-evaluates-actions) blocked the call | `classifier_category` |
1086| `"auto_mode_no_verdict"` | No usable [classifier verdict](/docs/en/errors.md#auto-mode-cannot-determine-the-safety-of-an-action), such as after a failed request | `reason_code` |
1087| `"safety_check"` | A built-in safety check, such as for Read, Edit, or Write outside your [working directories](/docs/en/permissions.md#working-directories) | `circuit_breaker` |
1081| `"permission_rule"` | A deny or ask [permission rule](https://code.claude.com/docs/en/permissions.md#manage-permissions) outside managed settings | `rule_source` |
1082| `"managed_policy"` | A deny or ask rule from [managed settings](https://code.claude.com/docs/en/permissions.md#managed-settings) | `rule_source` |
1083| `"permission_mode"` | [`dontAsk`](https://code.claude.com/docs/en/permission-modes#allow-only-pre-approved-tools-with-dontask-mode) or [plan](https://code.claude.com/docs/en/permission-modes.md#analyze-before-you-edit-with-plan-mode) mode, or a prompt with [no category](#prompts-with-no-category) in a session that can't show prompts, as with [`--permission-prompts none`](https://code.claude.com/docs/en/headless#turn-off-permission-prompts-in-unattended-runs) | `reason_code`, `reason_type` |
1084| `"hook"` | A hook, such as [`PreToolUse`](https://code.claude.com/docs/en/hooks#pretooluse) or [`PermissionRequest`](https://code.claude.com/docs/en/hooks#permissionrequest) | `hook_event`, `reason_code` |
1085| `"auto_mode_block"` | The auto mode [classifier](https://code.claude.com/docs/en/permission-modes.md#how-the-classifier-evaluates-actions) blocked the call | `classifier_category` |
1086| `"auto_mode_no_verdict"` | No usable [classifier verdict](https://code.claude.com/docs/en/errors.md#auto-mode-cannot-determine-the-safety-of-an-action), such as after a failed request | `reason_code` |
1087| `"safety_check"` | A built-in safety check, such as for Read, Edit, or Write outside your [working directories](https://code.claude.com/docs/en/permissions.md#working-directories) | `circuit_breaker` |
10881088| `"static_analysis"` | How a Bash or Monitor command is written, such as one too complex to analyze | `reason_code` |
1089| `"sandbox_override"` | The prompt to [run a command outside the sandbox](/docs/en/sandboxing.md#the-unsandboxed-retry-escape-hatch) | `reason_code` |
1089| `"sandbox_override"` | The prompt to [run a command outside the sandbox](https://code.claude.com/docs/en/sandboxing.md#the-unsandboxed-retry-escape-hatch) | `reason_code` |
10901090| `"user_rejected"` | Someone declined or dismissed a prompt that had [no category](#prompts-with-no-category) or that only a hook required, or a `canUseTool` callback or `--permission-prompt-tool` tool denied one | `decision_source` |
1091| `"sandbox_network"` | The call ran and the [sandbox's network proxy](/docs/en/sandboxing.md#network-isolation) refused a connection or request | `sandbox_violation_count` |
1091| `"sandbox_network"` | The call ran and the [sandbox's network proxy](https://code.claude.com/docs/en/sandboxing.md#network-isolation) refused a connection or request | `sandbox_violation_count` |
10921092| `"sandbox_other"` | Like `"sandbox_network"`, but no refused target reads as a host name or IP address | `sandbox_violation_count` |
1093| `"hook_review"` | A hook [blocked the call's result](/docs/en/hooks.md#posttooluse-decision-control) or [the end of a turn](/docs/en/hooks.md#stop-decision-control) | `hook_event` |
1093| `"hook_review"` | A hook [blocked the call's result](https://code.claude.com/docs/en/hooks.md#posttooluse-decision-control) or [the end of a turn](https://code.claude.com/docs/en/hooks.md#stop-decision-control) | `hook_event` |
10941094| `"other"` | A refusal no other value describes | `reason_code` |
10951095
10961096To find proxy refusals under any `category`, filter for a `sandbox_violation_count` that is present and isn't `"0"`.
from line 1097
10971097
10981098##### Calls without a safety event
10991099
1100To find calls refused because nobody could answer a [prompt with no category](#prompts-with-no-category), look for [`tool_decision`](#tool-decision-event) events reporting `"reject"` with `source` `"config"` and no safety event sharing their `tool_use_id`. Such refusals happen in a `-p` run with neither [`--permission-prompt-tool`](/docs/en/cli-reference#cli-flags) nor `--permission-prompts none`.
1100To find calls refused because nobody could answer a [prompt with no category](#prompts-with-no-category), look for [`tool_decision`](#tool-decision-event) events reporting `"reject"` with `source` `"config"` and no safety event sharing their `tool_use_id`. Such refusals happen in a `-p` run with neither [`--permission-prompt-tool`](https://code.claude.com/docs/en/cli-reference#cli-flags) nor `--permission-prompts none`.
11011101
11021102Check calls such as these for a `tool_decision` event, since they have no safety event except [`"sandbox_network"`, `"sandbox_other"`, or `"hook_review"` events](#safety-event-categories) sent after they run:
11031103
11041104* A call approved at a prompt with no category
11051105* A call that a `canUseTool` callback or `--permission-prompt-tool` tool approved at a prompt only a `PreToolUse` hook required
1106* An [`AskUserQuestion`](/docs/en/tools-reference#askuserquestion-tool-behavior) or `ExitPlanMode` call, declined or not
1106* An [`AskUserQuestion`](https://code.claude.com/docs/en/tools-reference#askuserquestion-tool-behavior) or `ExitPlanMode` call, declined or not
11071107
11081108##### Prompts with no category
11091109
from line 1125
11251125* `event.sequence`: per-process counter for ordering events, described under [Event correlation attributes](#event-correlation-attributes)
11261126* `from_mode`: The previous permission mode, for example `"default"`, `"plan"`, `"acceptEdits"`, `"auto"`, or `"bypassPermissions"`
11271127* `to_mode`: The new permission mode
1128* `trigger`: What caused the change, for example `"shift_tab"`, `"exit_plan_mode"`, or `"auto_gate_denied"`. Absent for some changes, such as when the SDK sets the permission mode through [`setPermissionMode()`](/docs/en/agent-sdk/typescript#query-object)
1128* `trigger`: What caused the change, for example `"shift_tab"`, `"exit_plan_mode"`, or `"auto_gate_denied"`. Absent for some changes, such as when the SDK sets the permission mode through [`setPermissionMode()`](https://code.claude.com/docs/en/agent-sdk/typescript#query-object)
11291129
11301130#### Auth event
11311131
from line 1218
12181218* `plugin.version`: version from the plugin manifest. Included only when the name is not redacted and the manifest declares a version
12191219* `plugin.scope`: provenance category for the plugin: `"official"`, `"community"`, `"org"`, `"user-local"`, or `"default-bundle"`
12201220* `enabled_via`: how the plugin came to be enabled: `"default-enable"`, `"org-policy"`, `"admin-install"`, `"seed-mount"`, or `"user-install"`. The `"admin-install"` value means the plugin is set to required or auto-install for your organization in [**Organization settings > Plugins & skills**](https://claude.ai/admin-settings/skills?tab=inventory). Before v2.1.246, Claude Code reported these plugins as `"user-install"` or `"seed-mount"`
1221* `plugin_id_hash`: deterministic hash of the plugin name and marketplace, sent only to your configured exporter. Lets you count the distinct third-party plugins loaded across your fleet without recording their names. For [plugins synced from claude.ai](/docs/en/plugins/loading.md#synced-plugins), Claude Code hashes the plugin name with the marketplace name that claude.ai reports for the plugin, or with `synced` otherwise. Before v2.1.246, Claude Code didn't use the marketplace name claude.ai reports in the hash
1222* `has_hooks`: whether the plugin contributes hooks, through [hook configuration](/docs/en/plugins/components.md#hooks) or as a [mod](/docs/en/plugins/mods/overview.md#how-a-mod-works)
1221* `plugin_id_hash`: deterministic hash of the plugin name and marketplace, sent only to your configured exporter. Lets you count the distinct third-party plugins loaded across your fleet without recording their names. For [plugins synced from claude.ai](https://code.claude.com/docs/en/plugins/loading.md#synced-plugins), Claude Code hashes the plugin name with the marketplace name that claude.ai reports for the plugin, or with `synced` otherwise. Before v2.1.246, Claude Code didn't use the marketplace name claude.ai reports in the hash
1222* `has_hooks`: whether the plugin contributes hooks, through [hook configuration](https://code.claude.com/docs/en/plugins/components.md#hooks) or as a [mod](https://code.claude.com/docs/en/plugins/mods/overview.md#how-a-mod-works)
12231223* `has_mcp`: whether the plugin contributes MCP servers
12241224* `host_owned_mcp`: `true` when the SDK host manages this plugin's MCP connections and Claude Code skipped reading the plugin's MCP server configuration, `false` otherwise
12251225* `skill_path_count`: number of skill directories the plugin declares
12261226* `command_path_count`: number of command directories the plugin declares
12271227* `agent_path_count`: number of agent directories the plugin declares
1228* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](/docs/en/cli-reference), `"false"` otherwise. In safe mode this event reports configured inventory only; the plugin's commands, skills, hooks, and MCP servers don't load. Requires Claude Code v2.1.169 or later
1228* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](https://code.claude.com/docs/en/cli-reference), `"false"` otherwise. In safe mode this event reports configured inventory only; the plugin's commands, skills, hooks, and MCP servers don't load. Requires Claude Code v2.1.169 or later
12291229
12301230#### Skill activated event
12311231
from line 1260
12601260* `event.name`: `"at_mention"`
12611261* `event.timestamp`: ISO 8601 timestamp
12621262* `event.sequence`: per-process counter for ordering events, described under [Event correlation attributes](#event-correlation-attributes)
1263* `mention_type`: Type of mention (`"file"`, `"directory"`, `"agent"`, `"mcp_resource"`, `"peer"`). The `"peer"` value means you mentioned [one of your other Claude Code sessions](/docs/en/cross-session-messaging.md). Requires Claude Code v2.1.232 or later
1263* `mention_type`: Type of mention (`"file"`, `"directory"`, `"agent"`, `"mcp_resource"`, `"peer"`). The `"peer"` value means you mentioned [one of your other Claude Code sessions](https://code.claude.com/docs/en/cross-session-messaging.md). Requires Claude Code v2.1.232 or later
12641264* `success`: Whether the mention resolved successfully (`"true"` or `"false"`)
12651265
12661266#### API retries exhausted event
from line 1297
12971297* `hook_event`: hook event type, such as `"PreToolUse"` or `"PostToolUse"`
12981298* `hook_type`: hook implementation type: `"command"`, `"prompt"`, `"mcp_tool"`, `"http"`, or `"agent"`
12991299* `hook_source`: where the hook is defined: `"userSettings"`, `"projectSettings"`, `"localSettings"`, `"flagSettings"`, `"policySettings"`, or `"pluginHook"`
1300* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](/docs/en/cli-reference), `"false"` otherwise. Requires Claude Code v2.1.169 or later
1300* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](https://code.claude.com/docs/en/cli-reference), `"false"` otherwise. Requires Claude Code v2.1.169 or later
13011301* `hook_matcher` (when `OTEL_LOG_TOOL_DETAILS=1`): the matcher string from the hook configuration, when one is set
13021302* `plugin.name` (when `hook_source` is `"pluginHook"`): name of the contributing plugin. For plugins outside the official marketplace and built-in bundle the value is `"third-party"` unless `OTEL_LOG_TOOL_DETAILS=1`
13031303* `plugin_id_hash` (when `hook_source` is `"pluginHook"`): deterministic hash of the plugin name and marketplace, sent only to your configured exporter. Lets you count distinct contributing plugins without recording their names. Claude Code computes it as described under the [plugin loaded event](#plugin-loaded-event)
from line 1319
13191319* `num_hooks`: Number of matching hook commands
13201320* `managed_only`: `"true"` when only managed-policy hooks are permitted
13211321* `hook_source`: `"policySettings"` or `"merged"`
1322* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](/docs/en/cli-reference), `"false"` otherwise. Requires Claude Code v2.1.169 or later
1322* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](https://code.claude.com/docs/en/cli-reference), `"false"` otherwise. Requires Claude Code v2.1.169 or later
13231323* `hook_definitions`: JSON-serialized hook configuration. Included only when both detailed beta tracing and `OTEL_LOG_TOOL_DETAILS=1` are enabled
13241324
13251325#### Hook execution complete event
from line 1346
13461346* `additional_context_chars`: Total characters of `additionalContext` returned by the matching hooks. Requires Claude Code v2.1.280 or later
13471347* `system_message_chars`: Total characters of `systemMessage` returned by the matching hooks. Requires Claude Code v2.1.280 or later
13481348* `initial_user_message_chars`: Total characters of `initialUserMessage` returned by the matching hooks. Requires Claude Code v2.1.280 or later
1349* `num_outputs_persisted`: Number of hook outputs over the [10,000-character cap](/docs/en/hooks.md#json-output) that Claude Code saved to a file. Requires Claude Code v2.1.280 or later
1349* `num_outputs_persisted`: Number of hook outputs over the [10,000-character cap](https://code.claude.com/docs/en/hooks.md#json-output) that Claude Code saved to a file. Requires Claude Code v2.1.280 or later
13501350* `managed_only`: `"true"` when only managed-policy hooks are permitted
13511351* `hook_source`: `"policySettings"` or `"merged"`
1352* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](/docs/en/cli-reference), `"false"` otherwise. Requires Claude Code v2.1.169 or later
1352* `safe_mode`: `"true"` when the session was started with [`--safe-mode`](https://code.claude.com/docs/en/cli-reference), `"false"` otherwise. Requires Claude Code v2.1.169 or later
13531353* `hook_definitions`: JSON-serialized hook configuration. Included only when both detailed beta tracing and `OTEL_LOG_TOOL_DETAILS=1` are enabled
13541354
13551355#### Hook plugin metrics event
from line 1386
13861386* `pre_tokens`: Approximate token count before compaction
13871387* `post_tokens`: Approximate token count after compaction
13881388* `error`: Error message when compaction failed
1389* `precompute_reuse`: Only set when `trigger` is `"manual"` or for an [idle compaction](/docs/en/settings-reference.md#idlecompaction), which reports `trigger` as `"auto"`. Auto-compaction can prepare a summary in the background before the context window fills, and this attribute records whether the compaction reused that prepared summary. `"hit"` means it was reused; `"miss_custom_instructions"`, `"miss_hook"`, and `"miss_not_ready"` give the reason a fresh summary was computed instead
1389* `precompute_reuse`: Only set when `trigger` is `"manual"` or for an [idle compaction](https://code.claude.com/docs/en/settings-reference.md#idlecompaction), which reports `trigger` as `"auto"`. Auto-compaction can prepare a summary in the background before the context window fills, and this attribute records whether the compaction reused that prepared summary. `"hit"` means it was reused; `"miss_custom_instructions"`, `"miss_hook"`, and `"miss_not_ready"` give the reason a fresh summary was computed instead
13901390
13911391#### Subagent completed event
13921392
1393Logged when a [subagent](/docs/en/sub-agents.md) finishes and returns its result to the conversation that started it. Use it to roll up tool use and run time by subagent type; for token or cost rollups, use the [token counter](#token-counter) and [cost counter](#cost-counter) filtered to `query_source` `"subagent"`, since this event's `total_tokens` covers only the final request. The `"subagent"` category also counts requests from agent-based hooks, which emit no subagent event.
1393Logged when a [subagent](https://code.claude.com/docs/en/sub-agents.md) finishes and returns its result to the conversation that started it. Use it to roll up tool use and run time by subagent type; for token or cost rollups, use the [token counter](#token-counter) and [cost counter](#cost-counter) filtered to `query_source` `"subagent"`, since this event's `total_tokens` covers only the final request. The `"subagent"` category also counts requests from agent-based hooks, which emit no subagent event.
13941394
13951395**Event Name**: `claude_code.subagent_completed`
13961396
from line 1403
14031403* `agent_type`: The subagent type. Built-in agent names and agents from official-marketplace plugins appear verbatim; other agent names are replaced with `"custom"` unless `OTEL_LOG_TOOL_DETAILS=1` is set
14041404* `agent.source`: Where the agent definition came from: `built-in`, `plugin`, or the settings source that defined a custom agent, such as `userSettings` or `projectSettings`
14051405* `is_built_in`: Whether the subagent is a built-in agent type
1406* `is_async`: Whether the subagent ran in the [background](/docs/en/sub-agents.md#run-subagents-in-foreground-or-background)
1406* `is_async`: Whether the subagent ran in the [background](https://code.claude.com/docs/en/sub-agents.md#run-subagents-in-foreground-or-background)
14071407* `total_tokens`: The token footprint of the subagent's final API request: that one request's input, cache creation, cache read, and output tokens, roughly the subagent's context size at completion. Not a sum across the run
14081408* `total_tool_uses`: Number of tool calls the subagent made across the whole run
14091409* `duration_ms`: Run time in milliseconds
from line 1414
14141414
14151415#### Feedback survey event
14161416
1417Logged when a session quality survey is shown or answered. See [Session quality surveys](/docs/en/data-usage.md#session-quality-surveys) for what the surveys collect and how to control them.
1417Logged when a session quality survey is shown or answered. See [Session quality surveys](https://code.claude.com/docs/en/data-usage.md#session-quality-surveys) for what the surveys collect and how to control them.
14181418
14191419**Event Name**: `claude_code.feedback_survey`
14201420
from line 1428
14281428* `appearance_id`: Unique ID linking the events emitted for one survey instance
14291429* `survey_type`: Which survey produced the event. `"session"` is the "How is Claude doing?" rating prompt
14301430* `response`: The user's selection on `responded` events
1431* `enabled_via_override`: `true` when [`CLAUDE_CODE_ENABLE_FEEDBACK_SURVEY_FOR_OTEL`](/docs/en/env-vars) is set. Emitted as a Boolean, not a string. Present on `session` survey events. Filter on this attribute to confirm the override is applied across a fleet
1431* `enabled_via_override`: `true` when [`CLAUDE_CODE_ENABLE_FEEDBACK_SURVEY_FOR_OTEL`](https://code.claude.com/docs/en/env-vars) is set. Emitted as a Boolean, not a string. Present on `session` survey events. Filter on this attribute to confirm the override is applied across a fleet
14321432
14331433#### Retention sweep event
14341434
1435Logged once per run of the retention cleanup sweep, which deletes [session transcripts and other application data](/docs/en/claude-directory.md#cleaned-up-automatically) older than the [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays) setting. Claude Code runs the sweep in the background at most once per session, and a run that deletes nothing still emits the event. If Claude Code ran the sweep in any session on the same machine in the last 24 hours, it delays this session's sweep by at least 10 minutes, so a session that exits sooner emits nothing. When you run `claude -p` with `--bare`, Claude Code doesn't run the sweep and emits nothing.
1435Logged once per run of the retention cleanup sweep, which deletes [session transcripts and other application data](https://code.claude.com/docs/en/claude-directory.md#cleaned-up-automatically) older than the [`cleanupPeriodDays`](https://code.claude.com/docs/en/settings-reference#cleanupperioddays) setting. Claude Code runs the sweep in the background at most once per session, and a run that deletes nothing still emits the event. If Claude Code ran the sweep in any session on the same machine in the last 24 hours, it delays this session's sweep by at least 10 minutes, so a session that exits sooner emits nothing. When you run `claude -p` with `--bare`, Claude Code doesn't run the sweep and emits nothing.
14361436
14371437Like every OTel event on this page, it goes only to the telemetry backend you configure. Requires Claude Code v2.1.227 or later.
14381438
1439When Claude Code can't safely determine the retention period, it pauses the sweep and emits the event with `result` set to `"skipped"` and a `skip_reason`. When [managed settings](/docs/en/server-managed-settings.md) set `cleanupPeriodDays`, the managed value pins the retention period and the sweep runs even when a settings file in a lower-priority scope is broken or invalid. When `managed-settings.json` itself can't be read, Claude Code still pauses the sweep unless the [managed tier](/docs/en/managed-settings.md#how-claude-code-combines-managed-sources) supplies `cleanupPeriodDays` from elsewhere, such as server-managed settings or a `managed-settings.d/` drop-in beside the broken file. The deletion counter attributes are present only when `result` is `"complete"`.
1439When Claude Code can't safely determine the retention period, it pauses the sweep and emits the event with `result` set to `"skipped"` and a `skip_reason`. When [managed settings](https://code.claude.com/docs/en/server-managed-settings.md) set `cleanupPeriodDays`, the managed value pins the retention period and the sweep runs even when a settings file in a lower-priority scope is broken or invalid. When `managed-settings.json` itself can't be read, Claude Code still pauses the sweep unless the [managed tier](https://code.claude.com/docs/en/managed-settings.md#how-claude-code-combines-managed-sources) supplies `cleanupPeriodDays` from elsewhere, such as server-managed settings or a `managed-settings.d/` drop-in beside the broken file. The deletion counter attributes are present only when `result` is `"complete"`.
14401440
14411441**Event Name**: `claude_code.retention_sweep`
14421442
from line 1450
14501450* `period_days`: The `cleanupPeriodDays` value from merged settings, in days, or `30` when no source sets it. On skipped events, the value the sweep would have used, computed from the settings sources Claude Code could read
14511451* `used_default`: `"true"` when no readable settings source sets `cleanupPeriodDays`, `"false"` otherwise. On complete events, `"true"` means the 30-day default applied
14521452* `skip_reason`: Why Claude Code paused the sweep. Present only when `result` is `"skipped"`:
1453 * `"user_source_disabled"`: User settings are excluded, for example by the [`--setting-sources`](/docs/en/cli-reference#cli-flags) flag or the SDK's [`settingSources`](/docs/en/agent-sdk/typescript#options) option, and no enabled source provides `cleanupPeriodDays`
1453 * `"user_source_disabled"`: User settings are excluded, for example by the [`--setting-sources`](https://code.claude.com/docs/en/cli-reference#cli-flags) flag or the SDK's [`settingSources`](https://code.claude.com/docs/en/agent-sdk/typescript#options) option, and no enabled source provides `cleanupPeriodDays`
14541454 * `"settings_unknowable"`: A settings file couldn't be read or parsed, so `cleanupPeriodDays` or `desktopSessionCleanupPeriodDays` may be set to a value Claude Code can't see
14551455 * `"settings_invalid_key_set"`: Settings have validation errors and `cleanupPeriodDays` or `desktopSessionCleanupPeriodDays` is explicitly set, so falling back to the default could delete or keep files against that setting
14561456* `transcripts_deleted`: Number of session transcripts, the top-level `~/.claude/projects/*/*.jsonl` files, that the sweep deleted
1457* `transcripts_exempted_desktop`: Number of transcripts past the retention period that the sweep kept under the [Claude Desktop and Cowork rule](/docs/en/claude-directory.md#cleaned-up-automatically). These don't count toward `files_past_cutoff`. Requires Claude Code v2.1.248 or later
1457* `transcripts_exempted_desktop`: Number of transcripts past the retention period that the sweep kept under the [Claude Desktop and Cowork rule](https://code.claude.com/docs/en/claude-directory.md#cleaned-up-automatically). These don't count toward `files_past_cutoff`. Requires Claude Code v2.1.248 or later
14581458* `session_files_deleted`: Number of artifacts the session-files sweep deleted: transcripts plus per-session companion files such as sidecars, recordings, and tool results
14591459* `artifacts_deleted`: Total items the sweep deleted across the data directories it covers, including the session files. Some sweeps count a whole removed directory tree as one item and a few cleanup passes don't contribute to the counter, so treat the value as a floor rather than an exact file count
14601460* `files_retained_fresh`: Files inspected and left in place because they're still within the retention period. Only per-file sweeps count these, so the value is a floor; a nonzero value is the normal steady state
from line 1463
14631463
14641464#### Managed settings resolved event
14651465
1466Logged with the [managed settings](/docs/en/managed-settings.md) a session resolved: once at session start, again when either the managed settings or the [policy helper](/docs/en/managed-settings.md#compute-the-policy-with-a-helper-program)'s state changes during the session, and when Claude Code refuses to start or ends the session for one of the reasons the `error.type` attribute lists.
1466Logged with the [managed settings](https://code.claude.com/docs/en/managed-settings.md) a session resolved: once at session start, again when either the managed settings or the [policy helper](https://code.claude.com/docs/en/managed-settings.md#compute-the-policy-with-a-helper-program)'s state changes during the session, and when Claude Code refuses to start or ends the session for one of the reasons the `error.type` attribute lists.
14671467Use this event to find machines running on an unexpected managed source, machines whose policy helper is failing, and the reason a machine refused to start.
14681468Requires Claude Code v2.1.274 or later.
14691469
from line 1470
14701470By default, the event carries the managed sources and the policy helper's state but not the settings themselves. To add the redacted `managed_settings.settings` attribute and the `managed_settings.resolved_sha256` digest, set `OTEL_LOG_MANAGED_SETTINGS=1`:
14711471
14721472* Set it in the `env` block of managed settings, user settings, or `--settings`, or in the environment you launch Claude Code with. A value in project or local settings doesn't turn it on, because a cloned repository can write them.
1473* Server-managed settings can set it without showing the [security approval dialog](/docs/en/server-managed-settings.md#security-approval-dialogs), because the variable only adds your organization's own redacted policy to an event your organization already receives.
1473* Server-managed settings can set it without showing the [security approval dialog](https://code.claude.com/docs/en/server-managed-settings.md#security-approval-dialogs), because the variable only adds your organization's own redacted policy to an event your organization already receives.
14741474
1475In an interactive session in a folder you haven't [trusted](/docs/en/permissions.md#what-runs-before-you-trust-a-folder), Claude Code doesn't export the refusal event.
1475In an interactive session in a folder you haven't [trusted](https://code.claude.com/docs/en/permissions.md#what-runs-before-you-trust-a-folder), Claude Code doesn't export the refusal event.
14761476
14771477**Event Name**: `claude_code.managed_settings_resolved`
14781478
from line 1484
14841484* `event.sequence`: per-process counter for ordering events, described under [Event correlation attributes](#event-correlation-attributes)
14851485* `managed_settings.trigger`: `"startup"` for the session-start event, `"change"` when the managed settings or the policy helper's state changed later in the session, or `"refused"` when a managed settings policy stopped the session. Claude Code sends a `change` event only when an attribute differs from the last event it sent, and a changed setting value counts even when `OTEL_LOG_MANAGED_SETTINGS` is off
14861486* `error.type`: why Claude Code stopped the session. Present only on `refused` events:
1487 * `"helper_failed"`: a [policy helper run failed](/docs/en/settings-reference.md#helper-failures)
1487 * `"helper_failed"`: a [policy helper run failed](https://code.claude.com/docs/en/settings-reference.md#helper-failures)
14881488 * `"policy_invalid"`: the managed settings contain an error that stops Claude Code from starting, or an admin source failed to load for a reason other than a denied read, so Claude Code can't check organization login or provider enforcement
1489 * `"provider_not_allowed"`: the session would use an API provider, or send a provider's traffic to a host, that the managed [`allowedProviders`](/docs/en/settings-reference#allowedproviders) list doesn't allow. Requires Claude Code v2.1.285 or later
1490 * `"consent_rejected"`: the user rejected the [security approval dialog](/docs/en/server-managed-settings.md#security-approval-dialogs) for server-managed settings
1491 * `"force_refresh_failed"`: the settings fetch that [`forceRemoteSettingsRefresh`](/docs/en/settings-reference#forceremotesettingsrefresh) requires failed
1492 * `"gateway_rejected"`: a [Claude apps gateway](/docs/en/claude-apps-gateway) answered the managed settings load with HTTP 403
1493 * `"version_below_minimum"`: this version of Claude Code is below [`requiredMinimumVersion`](/docs/en/settings-reference#requiredminimumversion) or above [`requiredMaximumVersion`](/docs/en/settings-reference#requiredmaximumversion)
1489 * `"provider_not_allowed"`: the session would use an API provider, or send a provider's traffic to a host, that the managed [`allowedProviders`](https://code.claude.com/docs/en/settings-reference#allowedproviders) list doesn't allow. Requires Claude Code v2.1.285 or later
1490 * `"consent_rejected"`: the user rejected the [security approval dialog](https://code.claude.com/docs/en/server-managed-settings.md#security-approval-dialogs) for server-managed settings
1491 * `"force_refresh_failed"`: the settings fetch that [`forceRemoteSettingsRefresh`](https://code.claude.com/docs/en/settings-reference#forceremotesettingsrefresh) requires failed
1492 * `"gateway_rejected"`: a [Claude apps gateway](https://code.claude.com/docs/en/claude-apps-gateway) answered the managed settings load with HTTP 403
1493 * `"version_below_minimum"`: this version of Claude Code is below [`requiredMinimumVersion`](https://code.claude.com/docs/en/settings-reference#requiredminimumversion) or above [`requiredMaximumVersion`](https://code.claude.com/docs/en/settings-reference#requiredmaximumversion)
14941494 * `"_OTHER"`: the Claude apps gateway managed settings load failed for another reason
1495* `managed_settings.sources`: every managed source that delivers at least one [policy key](/docs/en/managed-settings.md#how-claude-code-combines-managed-sources), highest priority first, including sources whose keys don't take effect under `first-wins`. Values are `"remote"`, `"plist"` or `"hklm"` for the MDM or OS-level policy, `"file"` for managed settings files and drop-ins, `"parent"` when an [embedding host](/docs/en/managed-settings.md#let-an-embedding-host-add-policy) supplies settings, and `"hkcu"` for the [Windows HKCU registry value](/docs/en/managed-settings.md#where-each-mechanism-stores-the-policy) when Claude Code [reads it](/docs/en/managed-settings.md#how-claude-code-combines-managed-sources). A source that carries only control keys, or that Claude Code couldn't read, isn't listed. Emitted as an array of strings, empty when no managed source delivers a policy key
1496* `managed_settings.source_behavior`: the [`managedSourcesBehavior`](/docs/en/settings-reference#managedsourcesbehavior) value Claude Code read, `"first-wins"` or `"merge"`. `"first-wins"` when no source sets the key
1495* `managed_settings.sources`: every managed source that delivers at least one [policy key](https://code.claude.com/docs/en/managed-settings.md#how-claude-code-combines-managed-sources), highest priority first, including sources whose keys don't take effect under `first-wins`. Values are `"remote"`, `"plist"` or `"hklm"` for the MDM or OS-level policy, `"file"` for managed settings files and drop-ins, `"parent"` when an [embedding host](https://code.claude.com/docs/en/managed-settings.md#let-an-embedding-host-add-policy) supplies settings, and `"hkcu"` for the [Windows HKCU registry value](https://code.claude.com/docs/en/managed-settings.md#where-each-mechanism-stores-the-policy) when Claude Code [reads it](https://code.claude.com/docs/en/managed-settings.md#how-claude-code-combines-managed-sources). A source that carries only control keys, or that Claude Code couldn't read, isn't listed. Emitted as an array of strings, empty when no managed source delivers a policy key
1496* `managed_settings.source_behavior`: the [`managedSourcesBehavior`](https://code.claude.com/docs/en/settings-reference#managedsourcesbehavior) value Claude Code read, `"first-wins"` or `"merge"`. `"first-wins"` when no source sets the key
14971497* `managed_settings.helper.state`: state of the policy helper that the selected MDM or file source configures:
14981498 * `"ok"`: the helper's output serves as the managed settings
1499 * `"bad_path"`, `"not_a_file"`, `"exit_nonzero"`, `"timed_out"`, `"oversize"`, `"parse_failed"`, `"envelope_invalid"`, or `"schema_rejected"`: the helper's last run failed. [Helper failures](/docs/en/settings-reference.md#helper-failures) describes the cases
1499 * `"bad_path"`, `"not_a_file"`, `"exit_nonzero"`, `"timed_out"`, `"oversize"`, `"parse_failed"`, `"envelope_invalid"`, or `"schema_rejected"`: the helper's last run failed. [Helper failures](https://code.claude.com/docs/en/settings-reference.md#helper-failures) describes the cases
15001500 * `"none"`: no helper is configured, or the source that configures it isn't an MDM policy or managed settings file
15011501* `managed_settings.helper.applied`: `"output"` while the helper's own output serves as the managed settings, `"none"` when it doesn't
1502* `managed_settings.helper.entry`: `"policyHelper"` when Claude Code selected a [`policyHelper`](/docs/en/settings-reference#policyhelper). Absent when it selected no helper
1503* `managed_settings.helper.path`: the helper's configured [`path`](/docs/en/settings-reference#policyhelper-path). Present whenever Claude Code selected a helper, whether or not `OTEL_LOG_MANAGED_SETTINGS` is set
1502* `managed_settings.helper.entry`: `"policyHelper"` when Claude Code selected a [`policyHelper`](https://code.claude.com/docs/en/settings-reference#policyhelper). Absent when it selected no helper
1503* `managed_settings.helper.path`: the helper's configured [`path`](https://code.claude.com/docs/en/settings-reference#policyhelper-path). Present whenever Claude Code selected a helper, whether or not `OTEL_LOG_MANAGED_SETTINGS` is set
15041504* `managed_settings.resolved_sha256` (when `OTEL_LOG_MANAGED_SETTINGS=1`): SHA-256 of the resolved managed settings before redaction, serialized as JSON with keys sorted recursively and no whitespace. Machines with the same digest run the same policy. Claude Code sends the digest only with the opt-in because a short policy can be recovered by hashing guesses. Absent when no managed settings resolved, and on `refused` events
15051505* `managed_settings.settings` (when `OTEL_LOG_MANAGED_SETTINGS=1`): the names and shape of the resolved managed settings as a JSON string, with the values redacted. Absent on `refused` events. Claude Code builds it from its settings schema:
15061506
from line 1560
15601560
15611561Claude Code retries failed API requests internally and emits a single `claude_code.api_error` event only after it gives up, so the event itself is the terminal signal for that request. Intermediate retry attempts are not logged as separate events.
15621562
1563The `attempt` attribute on the event records the number of attempts. `CLAUDE_CODE_MAX_RETRIES` defaults to 10 and is capped at 15; with [`CLAUDE_CODE_RETRY_WATCHDOG`](/docs/en/env-vars) set, the default is higher and there is no cap.
1563The `attempt` attribute on the event records the number of attempts. `CLAUDE_CODE_MAX_RETRIES` defaults to 10 and is capped at 15; with [`CLAUDE_CODE_RETRY_WATCHDOG`](https://code.claude.com/docs/en/env-vars) set, the default is higher and there is no cap.
15641564
15651565When the request exhausts all retries on a transient error, `attempt` is at most one more than that effective limit: 11 by default.
15661566
from line 1583
15831583
15841584### Map input tokens to OpenTelemetry GenAI semantic conventions
15851585
1586Claude Code exports input token counts as they appear in the API response's usage block, so these values exclude tokens read from or written to the [prompt cache](/docs/en/prompt-caching.md):
1586Claude Code exports input token counts as they appear in the API response's usage block, so these values exclude tokens read from or written to the [prompt cache](https://code.claude.com/docs/en/prompt-caching.md):
15871587
15881588* `input_tokens` on the [`claude_code.llm_request`](#span-attributes) span and the [`api_request`](#api-request-event) event
15891589* The `"input"` type of the [`claude_code.token.usage`](#token-counter) metric
from line 1604
16041604
16051605### Attribute actions to users
16061606
1607The [standard attributes](#standard-attributes) on each event include the authenticated user's identity: `user.email`, `user.account_uuid`, `user.account_id`, and `organization.id` when signed in with a Claude account or, in a [cloud session](/docs/en/claude-code-on-the-web.md), when the session's own credentials carry them, plus `user.id` and the per-session `session.id`. `user.id` is an installation-scoped identifier, except in sessions signed in to a [Claude apps gateway](/docs/en/claude-apps-gateway) through `/login`, where it is the IdP subject from the gateway-issued token.
1607The [standard attributes](#standard-attributes) on each event include the authenticated user's identity: `user.email`, `user.account_uuid`, `user.account_id`, and `organization.id` when signed in with a Claude account or, in a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md), when the session's own credentials carry them, plus `user.id` and the per-session `session.id`. `user.id` is an installation-scoped identifier, except in sessions signed in to a [Claude apps gateway](https://code.claude.com/docs/en/claude-apps-gateway) through `/login`, where it is the IdP subject from the gateway-issued token.
16081608
1609In a session a developer starts, MCP tool calls, Bash commands, and file edits are therefore attributed to that developer. Claude Code doesn't act under a separate service account there; the identity recorded on each event is the developer's own Claude account, or the developer's IdP identity on a [Claude apps gateway](/docs/en/claude-apps-gateway) session. In Claude Tag channel sessions, Claude works as your organization's [shared identity](/docs/en/cloud-environments.md#set-the-environment-a-claude-tag-channel-uses) instead.
1609In a session a developer starts, MCP tool calls, Bash commands, and file edits are therefore attributed to that developer. Claude Code doesn't act under a separate service account there; the identity recorded on each event is the developer's own Claude account, or the developer's IdP identity on a [Claude apps gateway](https://code.claude.com/docs/en/claude-apps-gateway) session. In Claude Tag channel sessions, Claude works as your organization's [shared identity](https://code.claude.com/docs/en/cloud-environments.md#set-the-environment-a-claude-tag-channel-uses) instead.
16101610
16111611When Claude Code authenticates with a direct API key, or against Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry, there is no Claude account in the session and only `user.id` and `session.id` are populated. In these deployments, attach user identity yourself with `OTEL_RESOURCE_ATTRIBUTES`, set per user through the [managed settings](#administrator-configuration) file or a launch wrapper. Claude apps gateway sessions need none of this: see [Standard attributes](#standard-attributes) for the identity their exports carry.
16121612
from line 1654
16541654
16551655### Map egress paths to managed controls and events
16561656
1657The table pairs paths that can carry session content off a machine, plus local retention, with the [managed settings](/docs/en/managed-settings.md) keys that restrict them and the events that record them. For what Claude Code itself sends to Anthropic, such as `/feedback` reports, see [Data usage](/docs/en/data-usage.md). The names link to their reference entries, which give the values and defaults.
1657The table pairs paths that can carry session content off a machine, plus local retention, with the [managed settings](https://code.claude.com/docs/en/managed-settings.md) keys that restrict them and the events that record them. For what Claude Code itself sends to Anthropic, such as `/feedback` reports, see [Data usage](https://code.claude.com/docs/en/data-usage.md). The names link to their reference entries, which give the values and defaults.
16581658
16591659| Path | Managed controls | Events |
16601660| - | - | - |
1661| Bash and PowerShell commands | [`sandbox.enabled`](/docs/en/settings-reference#sandbox-enabled), [`sandbox.failIfUnavailable`](/docs/en/settings-reference#sandbox-failifunavailable), [`sandbox.allowUnsandboxedCommands`](/docs/en/settings-reference#sandbox-allowunsandboxedcommands), [`sandbox.network.allowManagedDomainsOnly`](/docs/en/settings-reference#sandbox-network-allowmanageddomainsonly), [`sandbox.network.allowedDomains`](/docs/en/settings-reference#sandbox-network-alloweddomains) | [`tool_decision`](#tool-decision-event), [`tool_result`](#tool-result-event) |
1662| MCP servers | [`allowedMcpServers`](/docs/en/settings-reference#allowedmcpservers), [`allowManagedMcpServersOnly`](/docs/en/settings-reference#allowmanagedmcpserversonly), [`deniedMcpServers`](/docs/en/settings-reference#deniedmcpservers), [`managed-mcp.json`](/docs/en/managed-mcp) | [`mcp_server_connection`](#mcp-server-connection-event), `tool_decision`, `tool_result` |
1663| Hooks | [`allowManagedHooksOnly`](/docs/en/settings-reference#allowmanagedhooksonly), [`allowedHttpHookUrls`](/docs/en/settings-reference#allowedhttphookurls) | [`hook_registered`](#hook-registered-event), [`hook_execution_start`](#hook-execution-start-event), [`hook_execution_complete`](#hook-execution-complete-event) |
1664| Plugins | [`strictKnownMarketplaces`](/docs/en/settings-reference#strictknownmarketplaces), [`disableSideloadFlags`](/docs/en/settings-reference#disablesideloadflags), [`syncClaudeAiPlugins`](/docs/en/settings-reference#syncclaudeaiplugins), [`syncClaudeAiSkills`](/docs/en/settings-reference#syncclaudeaiskills) | [`plugin_installed`](#plugin-installed-event), [`plugin_loaded`](#plugin-loaded-event) |
1665| [WebFetch](/docs/en/permissions.md#webfetch) | [`permissions.deny`](/docs/en/settings-reference#permissions-deny), [`allowManagedPermissionRulesOnly`](/docs/en/settings-reference#allowmanagedpermissionrulesonly) | `tool_decision`, `tool_result` |
1666| Tools that upload to claude.ai, such as Artifact | `permissions.deny`, [`enableArtifact`](/docs/en/settings-reference#enableartifact) | `tool_decision`, `tool_result` |
1667| Remote Control | [`disableRemoteControl`](/docs/en/settings-reference#disableremotecontrol) | No dedicated event |
1668| Local transcript retention | [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays) | [`retention_sweep`](#retention-sweep-event) |
1661| Bash and PowerShell commands | [`sandbox.enabled`](https://code.claude.com/docs/en/settings-reference#sandbox-enabled), [`sandbox.failIfUnavailable`](https://code.claude.com/docs/en/settings-reference#sandbox-failifunavailable), [`sandbox.allowUnsandboxedCommands`](https://code.claude.com/docs/en/settings-reference#sandbox-allowunsandboxedcommands), [`sandbox.network.allowManagedDomainsOnly`](https://code.claude.com/docs/en/settings-reference#sandbox-network-allowmanageddomainsonly), [`sandbox.network.allowedDomains`](https://code.claude.com/docs/en/settings-reference#sandbox-network-alloweddomains) | [`tool_decision`](#tool-decision-event), [`tool_result`](#tool-result-event) |
1662| MCP servers | [`allowedMcpServers`](https://code.claude.com/docs/en/settings-reference#allowedmcpservers), [`allowManagedMcpServersOnly`](https://code.claude.com/docs/en/settings-reference#allowmanagedmcpserversonly), [`deniedMcpServers`](https://code.claude.com/docs/en/settings-reference#deniedmcpservers), [`managed-mcp.json`](https://code.claude.com/docs/en/managed-mcp) | [`mcp_server_connection`](#mcp-server-connection-event), `tool_decision`, `tool_result` |
1663| Hooks | [`allowManagedHooksOnly`](https://code.claude.com/docs/en/settings-reference#allowmanagedhooksonly), [`allowedHttpHookUrls`](https://code.claude.com/docs/en/settings-reference#allowedhttphookurls) | [`hook_registered`](#hook-registered-event), [`hook_execution_start`](#hook-execution-start-event), [`hook_execution_complete`](#hook-execution-complete-event) |
1664| Plugins | [`strictKnownMarketplaces`](https://code.claude.com/docs/en/settings-reference#strictknownmarketplaces), [`disableSideloadFlags`](https://code.claude.com/docs/en/settings-reference#disablesideloadflags), [`syncClaudeAiPlugins`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiplugins), [`syncClaudeAiSkills`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiskills) | [`plugin_installed`](#plugin-installed-event), [`plugin_loaded`](#plugin-loaded-event) |
1665| [WebFetch](https://code.claude.com/docs/en/permissions.md#webfetch) | [`permissions.deny`](https://code.claude.com/docs/en/settings-reference#permissions-deny), [`allowManagedPermissionRulesOnly`](https://code.claude.com/docs/en/settings-reference#allowmanagedpermissionrulesonly) | `tool_decision`, `tool_result` |
1666| Tools that upload to claude.ai, such as Artifact | `permissions.deny`, [`enableArtifact`](https://code.claude.com/docs/en/settings-reference#enableartifact) | `tool_decision`, `tool_result` |
1667| Remote Control | [`disableRemoteControl`](https://code.claude.com/docs/en/settings-reference#disableremotecontrol) | No dedicated event |
1668| Local transcript retention | [`cleanupPeriodDays`](https://code.claude.com/docs/en/settings-reference#cleanupperioddays) | [`retention_sweep`](#retention-sweep-event) |
16691669
16701670The `allowedHttpHookUrls`, `managed-mcp.json`, and hook event entries need more than the table shows:
16711671
16721672* **`allowedHttpHookUrls`**: entries merge across settings files, so a developer can add to an empty managed list. `allowManagedHooksOnly` decides which hooks run
1673* **`managed-mcp.json`**: to turn MCP off, see [Disable MCP entirely](/docs/en/managed-mcp.md#disable-mcp-entirely). To confirm Claude Code reads the file, see [Validate the configuration](/docs/en/managed-mcp.md#validate-the-configuration)
1673* **`managed-mcp.json`**: to turn MCP off, see [Disable MCP entirely](https://code.claude.com/docs/en/managed-mcp.md#disable-mcp-entirely). To confirm Claude Code reads the file, see [Validate the configuration](https://code.claude.com/docs/en/managed-mcp.md#validate-the-configuration)
16741674* **Hook events**: Claude Code logs `hook_execution_start` and `hook_execution_complete` once per hook event, covering every matching hook. `OTEL_LOG_TOOL_DETAILS=1` on its own doesn't record an HTTP hook's URL. The hook configuration appears only in `hook_definitions`, which also needs detailed beta tracing
16751675
16761676`OTEL_LOG_TOOL_DETAILS=1` adds command strings, server and tool names, and tool input to these events. That detail can contain the same sensitive content as the session itself, so enable it only when your collector is approved to hold that content.
from line 1677
16771677
16781678### Check the retention sweep
16791679
1680To give every machine the same retention period, set [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays) in [managed settings](/docs/en/managed-settings.md). To check that machines run the sweep with that value, collect the [`retention_sweep`](#retention-sweep-event) event. `period_days` and the counters are strings, so cast them to numbers before you compare them.
1680To give every machine the same retention period, set [`cleanupPeriodDays`](https://code.claude.com/docs/en/settings-reference#cleanupperioddays) in [managed settings](https://code.claude.com/docs/en/managed-settings.md). To check that machines run the sweep with that value, collect the [`retention_sweep`](#retention-sweep-event) event. `period_days` and the counters are strings, so cast them to numbers before you compare them.
16811681
16821682| What a machine reports | What it means |
16831683| - | - |
from line 1693
16931693* **A session stays open**: Claude Code runs the sweep at most once per session
16941694* **A session ends early**: a sweep that hasn't finished when the session exits emits nothing, and neither does one that stops on an unexpected error
16951695
1696The sweep doesn't cover every path. [Kept until you delete them](/docs/en/claude-directory.md#kept-until-you-delete-them) lists what stays, and [Clear local data](/docs/en/claude-directory.md#clear-local-data) shows how to remove it.
1696The sweep doesn't cover every path. [Kept until you delete them](https://code.claude.com/docs/en/claude-directory.md#kept-until-you-delete-them) lists what stays, and [Clear local data](https://code.claude.com/docs/en/claude-directory.md#clear-local-data) shows how to remove it.
16971697
16981698### Send events to a SIEM
16991699
from line 1743
17431743
17441744All metrics and events are exported with the following resource attributes:
17451745
1746* `service.name`: `claude-code` for terminal sessions, `claude-code-desktop` for local sessions started from the Code tab in the [Claude Desktop app](/docs/en/desktop.md)
1746* `service.name`: `claude-code` for terminal sessions, `claude-code-desktop` for local sessions started from the Code tab in the [Claude Desktop app](https://code.claude.com/docs/en/desktop.md)
17471747* `service.version`: Current Claude Code version, or the Desktop app version for local Code tab sessions
17481748* `os.type`: Operating system type (for example, `linux`, `darwin`, `windows`)
17491749* `os.version`: Operating system version string
from line 1759
17591759
17601760## Security and privacy
17611761
1762* OpenTelemetry export to your backend is opt-in and requires explicit configuration. For Anthropic's separate operational telemetry and how to disable it, see [Data usage](/docs/en/data-usage.md#telemetry-services)
1762* OpenTelemetry export to your backend is opt-in and requires explicit configuration. For Anthropic's separate operational telemetry and how to disable it, see [Data usage](https://code.claude.com/docs/en/data-usage.md#telemetry-services)
17631763* Raw file contents and code snippets are not included in metrics or events. Trace spans are a separate data path: see the `OTEL_LOG_TOOL_CONTENT` bullet below
17641764* When authenticated via OAuth, `user.email` is included in telemetry attributes, sent only to the OTel endpoint you configure, never to Anthropic. If this is a concern for your organization, work with your telemetry backend to filter or redact this field
17651765* User prompt content is not collected by default. Only prompt length is recorded. To include prompt content, set `OTEL_LOG_USER_PROMPTS=1`. When enabled:
from line 1788
17881788 * The [cost and token counters](#cost-counter) and the `api_request`, `api_error`, and `api_refusal` events carry real agent, skill, plugin, and MCP server and tool names in their attribution attributes
17891789 * The `claude_code.tool` span carries input-derived attributes such as `file_path`. Under detailed beta tracing it also carries a [`tool_input`](#new-context-gates) attribute
17901790* Tool content is not logged in trace spans by default. To include it, set `OTEL_LOG_TOOL_CONTENT=1`. The `claude_code.tool` span then carries a [`tool.output` span event](#tool-output-span-event) with raw file contents, Bash command output, and what MCP tools, WebFetch, and WebSearch return, truncated at the content limit (60 KB by default) per attribute. Results from MCP tools, WebFetch, and WebSearch require Claude Code v2.1.283 or later. Tool content also reaches spans through [`new_context`, whose gate differs per span](#new-context-gates). Configure your telemetry backend to filter or redact these attributes as needed
1791* Raw Anthropic Messages API request and response bodies are not logged by default. To include them, set `OTEL_LOG_RAW_API_BODIES` in your shell, user settings, or managed settings. It's ignored in [project and local settings](/docs/en/settings-reference.md#variables-claude-code-ignores-in-env). The bodies contain the full conversation history, including the system prompt, every prior user and assistant turn, and tool results, so enabling this implies consent to everything the other `OTEL_LOG_*` content flags would reveal. Claude Code always redacts Claude's extended-thinking content from these bodies, regardless of other settings. The value you set determines how Claude Code delivers the bodies:
1791* Raw Anthropic Messages API request and response bodies are not logged by default. To include them, set `OTEL_LOG_RAW_API_BODIES` in your shell, user settings, or managed settings. It's ignored in [project and local settings](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env). The bodies contain the full conversation history, including the system prompt, every prior user and assistant turn, and tool results, so enabling this implies consent to everything the other `OTEL_LOG_*` content flags would reveal. Claude Code always redacts Claude's extended-thinking content from these bodies, regardless of other settings. The value you set determines how Claude Code delivers the bodies:
17921792 * With `=1`, Claude Code emits `api_request_body` and `api_response_body` log events for each API call. The events' `body` attribute carries the JSON-serialized payload, truncated at the content limit (60 KB by default)
17931793 * With `=file:<dir>`, Claude Code writes untruncated bodies to `.request.json` and `.response.json` files under that directory, and the events carry a `body_ref` path instead of the inline body. Ship the directory with a log collector or sidecar rather than through the telemetry stream.
17941794
No line in this hunk matches that.