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

# Claude Code

> Send Claude Code traces to Openlayer over OpenTelemetry, configured for your whole organization through Claude managed settings

<img width="700" style={{ borderRadius: "0.5rem" }} src="https://mintcdn.com/openlayer-docs/uX4thRxLYBNTUYY8/images/integrations/claude_agent_sdk_hero.png?fit=max&auto=format&n=uX4thRxLYBNTUYY8&q=85&s=5a1bda0c754153e85e092a4befc21def" alt="The Claude logo" data-path="images/integrations/claude_agent_sdk_hero.png" />

[Claude Code](https://code.claude.com/docs/en/overview) is Anthropic's agentic coding tool. It
can export [OpenTelemetry](/docs/integrations/opentelemetry) traces for every prompt a developer sends:
the model requests it makes, the tools it runs, and how long each step takes. Point that export at
Openlayer and every Claude Code session in your organization lands in an inference pipeline, with
no SDK to install and no LLM gateway in the request path.

This page configures the export once, in Claude **managed settings**, so it applies to every
developer and individual users can't redirect or turn it off.

<Info>
  This guide covers **client-side trace export from Claude Code**, which works
  on Claude for Teams and Claude for Enterprise. To ingest claude.ai chats and
  Cowork sessions, use the [Claude Compliance](/docs/integrations/claude-compliance)
  integration instead. It reads transcripts from Anthropic's Compliance API and
  requires Claude Enterprise. See [Which Claude surfaces are
  covered](#which-claude-surfaces-are-covered).
</Info>

## Prerequisites

* An Openlayer [API key](/docs/workspace-and-projects/find-your-api-key) and the ID of the inference
  pipeline that should receive the traces.
* A way to deliver Claude Code managed settings to your developers. Either:
  * **Server-managed settings**, from the claude.ai admin console. Requires Claude for Teams or
    Claude for Enterprise and the **Owner** or **Primary Owner** role.
  * **Endpoint-managed settings**, deployed to each device through MDM, an OS policy, or a
    `managed-settings.json` file.
* Claude Code v2.1.251 or later on developer machines. Earlier versions don't fully lock the
  export destination described in [What developers can and can't
  change](#what-developers-can-and-cant-change).

## How Claude Code tracing works

Claude Code tracing is a beta feature and is off by default. Three settings turn it on:

| Variable | Value | Purpose |
| - | - | - |
| `CLAUDE_CODE_ENABLE_TELEMETRY` | `1` | Enables OpenTelemetry in Claude Code. Required for any export |
| `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA` | `1` | Enables span tracing |
| `OTEL_TRACES_EXPORTER` | `otlp` | Sends the spans to an OTLP endpoint |

Each prompt a developer sends starts a `claude_code.interaction` root span. Model calls and tool
calls are recorded as its children, and each tool call has its own children for time spent
waiting on a permission decision and for execution. When Claude spawns a subagent, the
subagent's spans nest under the tool call that started it.

```text theme={null}
claude_code.interaction
├── claude_code.llm_request
└── claude_code.tool
    ├── claude_code.tool.blocked_on_user
    └── claude_code.tool.execution
```

Spans carry the model, token counts, latencies, tool names, and success or failure. Claude Code
redacts prompt text, tool inputs, and tool output by default. The configuration on this page turns
them on, because Openlayer tests evaluate each trace's input and output. See [Privacy and data
handling](#privacy-and-data-handling). Claude's replies are only exported with [detailed
tracing](#capture-claudes-replies-with-detailed-tracing).

## 1. Write the managed settings

Put the following `env` block in your managed settings, replacing the two placeholders:

```json theme={null}
{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1",
    "OTEL_TRACES_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL": "http/protobuf",
    "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "https://api.openlayer.com/v1/otel/v1/traces",
    "OTEL_EXPORTER_OTLP_TRACES_HEADERS": "Authorization=Bearer YOUR_OPENLAYER_API_KEY,x-bt-parent=pipeline_id:YOUR_OPENLAYER_PIPELINE_ID",
    "OTEL_LOG_USER_PROMPTS": "1",
    "OTEL_LOG_TOOL_DETAILS": "1",
    "OTEL_LOG_TOOL_CONTENT": "1"
  }
}
```

* `OTEL_EXPORTER_OTLP_TRACES_*` scopes the endpoint, protocol, and credentials to traces. If your
  organization already exports Claude Code metrics or logs to another collector, that export keeps
  working, and your Openlayer API key is never sent to it.
* The endpoint is the full traces path, because a traces-specific variable doesn't have
  `/v1/traces` appended to it.
* The `x-bt-parent` header chooses the inference pipeline that receives the traces.
* The three `OTEL_LOG_*` values send the prompt, tool inputs, and tool output. Without them, each
  trace's input is empty and its tool calls have no arguments or results, so Openlayer has nothing
  to test. Review [Privacy and data handling](#privacy-and-data-handling) before you deploy them,
  and set them to `0` only if your policies rule out sending content.

<Warning>
  Managed settings reach developers' machines in plain text, so anyone who can
  run Claude Code there can read the API key. Create a dedicated Openlayer API
  key for this export so you can rotate or revoke it on its own. To mint
  short-lived credentials instead, see [Rotate the API
  key](#rotate-the-api-key-with-a-headers-helper).
</Warning>

## 2. Deliver the managed settings

Deliver the block through whichever mechanism you already use to manage Claude Code. By default,
Claude Code reads its policy from **one** managed source, the highest-ranked one present on the
machine. If you already deliver a policy, add the block to that source.

<Tabs>
  <Tab title="Admin console">
    Server-managed settings reach every Claude Code user who signs in to your organization,
    with nothing to install on their devices.

    1. In claude.ai, open [**Admin Settings > Claude Code > Managed
       settings**](https://claude.ai/admin-settings/claude-code).
    2. Add the `env` block to the JSON and save.

    Claude Code fetches the settings at startup and checks for changes every hour. Because the
    block sets an export endpoint, each developer sees an approval dialog that lists the
    variables before Claude Code applies them.

    Server-managed settings don't reach every session. Claude Code skips the fetch when a
    developer's shell exports a `CLAUDE_CODE_USE_*` provider variable, such as
    `CLAUDE_CODE_USE_BEDROCK`, or a custom `ANTHROPIC_BASE_URL`. Cowork sessions never fetch
    them either. Use endpoint-managed settings for those machines.
  </Tab>

  <Tab title="MDM or OS policy">
    Deliver the same keys through your device management tool, such as Jamf, Intune, or Group
    Policy:

    * **macOS**: a configuration profile for the `com.anthropic.claudecode` preference domain,
      with `env` as a dictionary.
    * **Windows**: the JSON document as a `REG_SZ` value named `Settings` under
      `HKLM\SOFTWARE\Policies\ClaudeCode`.

    Claude Code reads the policy at startup and checks for changes every 30 minutes. Anthropic
    publishes starter templates in its [MDM examples
    repository](https://github.com/anthropics/claude-code/tree/main/examples/mdm).
  </Tab>

  <Tab title="managed-settings.json">
    Save the JSON as `managed-settings.json` in the system directory for each operating system:

    | Operating system | Path |
    | - | - |
    | macOS | `/Library/Application Support/ClaudeCode/managed-settings.json` |
    | Linux and WSL | `/etc/claude-code/managed-settings.json` |
    | Windows | `C:\Program Files\ClaudeCode\managed-settings.json` |

    If other teams own parts of your policy, save the block as its own drop-in file, such as
    `managed-settings.d/10-openlayer.json`, next to `managed-settings.json`. Claude Code merges
    every `*.json` file in that directory in alphabetical order.

    Inside WSL, `/etc/claude-code` is writable by the user. To have WSL follow the Windows policy
    instead, set
    [`wslInheritsWindowsSettings`](https://code.claude.com/docs/en/settings-reference#wslinheritswindowssettings)
    in the Windows `HKLM` policy or managed settings file.
  </Tab>
</Tabs>

For how Claude Code ranks and combines these sources, see Anthropic's [managed settings
deployment guide](https://code.claude.com/docs/en/managed-settings).

## 3. Verify the export

1. On a developer's machine, start Claude Code and run `/status`. The `Setting sources` line should
   list `Enterprise managed settings` with the source you used: `(remote)` for the admin console,
   `(plist)` or `(HKLM)` for MDM, and `(file)` or `(drop-ins)` for a managed settings file.
2. If you used the admin console, run `claude doctor` and check the `Managed settings (remote)`
   line. It says whether the settings loaded, the fetch failed, or Claude Code skipped it and why.
3. Send a prompt in Claude Code. Within a few seconds, a trace appears in your Openlayer inference
   pipeline, with the `claude_code.interaction` span at its root.

If no trace arrives, start Claude Code with a debug log, send a prompt, and search the log:

```bash theme={null}
claude --debug-file /tmp/claude-otel.log
grep "3P telemetry" /tmp/claude-otel.log
```

Claude Code logs the result of the first export as a `[3P telemetry] First traces export` line,
followed by the reason when it fails, such as `FAILED (Unauthorized)`. Lines prefixed
`[Anthropic telemetry]` describe Anthropic's own operational telemetry and don't indicate a problem
with this setup.

## What developers can and can't change

Managed settings sit at the top of Claude Code's settings precedence, so no user, project, or
command-line setting overrides them. With the block above in place:

* **The destination is locked.** Because managed settings set the traces endpoint and
  credentials, Claude Code removes any traces endpoint a developer sets in their shell or user
  settings at startup, including `BETA_TRACING_ENDPOINT`, and logs a warning in the debug log.
* **Tracing can't be turned off.** The enable flags and `OTEL_TRACES_EXPORTER` are managed, so a
  developer can't set the exporter to `none` or `console`, or disable telemetry.
* **Repositories can't change it.** Claude Code ignores OpenTelemetry variables in a repository's
  `.claude/settings.json` and `.claude/settings.local.json`.
* **Content capture is yours to set.** A developer can't change the `OTEL_LOG_*` values for their
  own sessions, to send less content or more.

Endpoint-managed settings are only as strong as the device's protection. A developer with local
administrator rights can edit a managed settings file, so prefer MDM delivery, which can redeploy
the policy on a schedule.

## Privacy and data handling

Three variables control the content Claude Code sends. The configuration above sets all three to
`1`, which Openlayer needs to test each trace's input, output, and tool calls:

| Variable | Adds to traces |
| - | - |
| `OTEL_LOG_USER_PROMPTS` | The text of each prompt the developer sends |
| `OTEL_LOG_TOOL_DETAILS` | Tool inputs: Bash commands, file paths, MCP server and tool names, skill names, and subagent types |
| `OTEL_LOG_TOOL_CONTENT` | Tool output, such as the contents of files Claude reads and the output of commands it runs |

<Warning>
  Tool details and tool content routinely include source code, file paths,
  command output, and any secrets that appear in them. With these flags on, that
  data goes to Openlayer for every developer the policy reaches. Confirm that it
  matches your data-handling policies before you deploy the policy, and consider
  [data retention](/docs/workspace-and-projects/data-retention) for the pipeline that
  receives it.
</Warning>

To keep a kind of content out of Openlayer, set its variable to `0`. Openlayer can't test content
it doesn't receive, so a trace without a prompt has no input to evaluate.

Claude Code truncates each content attribute at 60 KB by default. These flags don't add Claude's
replies, which tests need to evaluate the output. Turn on [detailed
tracing](#capture-claudes-replies-with-detailed-tracing) to add them. `OTEL_LOG_ASSISTANT_RESPONSES`
and `OTEL_LOG_RAW_API_BODIES` don't help here: they only affect Claude Code's log events, which
Openlayer doesn't ingest.

## Capture Claude's replies with detailed tracing

Claude Code's detailed beta tracing adds the text of Claude's replies, and the messages and tool
results sent in each model request. Openlayer uses them to show the prompt as each trace's input
and Claude's final reply as its output. Turn it on wherever you can: without a reply, a trace has
no output for tests to evaluate.

Add these variables to the `env` block from [step 1](#1-write-the-managed-settings), and keep
`OTEL_LOG_USER_PROMPTS` set to `1` there:

```json theme={null}
{
  "env": {
    "ENABLE_BETA_TRACING_DETAILED": "1",
    "BETA_TRACING_ENDPOINT": "https://api.openlayer.com/v1/otel"
  }
}
```

* `BETA_TRACING_ENDPOINT` is a base URL. Claude Code appends `/v1/traces` to it and sends traces
  there instead of to `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`. It still sends the
  `OTEL_EXPORTER_OTLP_TRACES_HEADERS` credentials.
* `OTEL_LOG_USER_PROMPTS` gates the prompt and reply text. Without it, detailed traces still arrive,
  but each trace's input and output are empty.
* Detailed tracing doesn't use [`otelHeadersHelper`](#rotate-the-api-key-with-a-headers-helper).
  Set the credentials in `OTEL_EXPORTER_OTLP_TRACES_HEADERS`.
* Claude Code also sends logs to `/v1/logs` under the same base URL. Openlayer doesn't ingest logs,
  so those requests fail and the debug log shows an `OTEL diag error` for each. Traces are
  unaffected.

Each prompt then appears in Openlayer with Claude's reply, the token count and cost, and every
model request and tool call as a step:

<img width="700" style={{ borderRadius: "0.5rem" }} src="https://mintcdn.com/openlayer-docs/exoxJ0qVRp-p2bxd/images/integrations/claude_code_trace.png?fit=max&auto=format&n=exoxJ0qVRp-p2bxd&q=85&s=139e83b4f0a5f68fd467898e78941668" alt="A Claude Code trace in Openlayer, with the span tree, token and cost metrics, the developer's prompt, and Claude's reply" data-path="images/integrations/claude_code_trace.png" />

<Warning>
  With detailed tracing on, `OTEL_LOG_USER_PROMPTS` also sends the tool results
  in each model request, such as the contents of files Claude reads and the
  output of commands it runs. It does so even when `OTEL_LOG_TOOL_CONTENT` is
  `0`. Review the [privacy guidance](#privacy-and-data-handling) above before
  you turn it on.
</Warning>

Detailed tracing is a beta feature. In interactive sessions, it also requires Anthropic to
allowlist your organization. Non-interactive `claude -p` sessions and the Agent SDK don't need
the allowlist. For every attribute it adds, see [Traces
(beta)](https://code.claude.com/docs/en/monitoring-usage#traces-beta) in Anthropic's monitoring
guide.

## Add team and repository context

Each trace carries the developer's session ID, which Openlayer uses to group the traces of one
conversation into a session. When the developer is signed in with a Claude account, Openlayer uses
their email address as the trace's user. Sessions that authenticate with an API key or a cloud
provider, such as Amazon Bedrock, carry an anonymous per-installation ID instead. Claude Code
always sends the email when it's available, whatever the `OTEL_LOG_*` values are.

To tag traces with your own context, such as a team or cost center, and with the repository the
developer is working in, add these variables to the `env` block from [step
1](#1-write-the-managed-settings):

```json theme={null}
{
  "env": {
    "OTEL_RESOURCE_ATTRIBUTES": "department=engineering,team=platform,cost_center=eng-123",
    "OTEL_METRICS_INCLUDE_REPOSITORY": "true",
    "OTEL_METRICS_INCLUDE_VERSION": "true",
    "OTEL_METRICS_INCLUDE_ENTRYPOINT": "true"
  }
}
```

| Variable | Adds to every span |
| - | - |
| `OTEL_RESOURCE_ATTRIBUTES` | Your own `key=value` pairs, comma-separated, with no spaces |
| `OTEL_METRICS_INCLUDE_REPOSITORY` | The repository's URL, owner, name, and provider as `vcs.*` attributes, read from its `origin` remote. Requires Claude Code v2.1.269 or later |
| `OTEL_METRICS_INCLUDE_VERSION` | The Claude Code version, as `app.version` |
| `OTEL_METRICS_INCLUDE_ENTRYPOINT` | How the session was started, such as `cli`, `sdk-py`, or `claude-vscode`, as `app.entrypoint` |

Despite their names, the `OTEL_METRICS_INCLUDE_*` variables add their attributes to trace spans
too.

Openlayer turns each custom key without a dot, such as `department`, into a column you can filter
and group traces by. Keys with a dot, such as `team.id`, and Claude Code's own attributes, such as
`vcs.repository.name` and `app.version`, are stored as nested metadata. You see them on each step
of the trace, but you can't filter by them. So:

* Name custom keys without dots: `team`, not `team.id`.
* Don't reuse the first segment of a dotted attribute. If you set both `team` and `team.id`, the
  nested `team.id` replaces your `team` value. The same applies to Claude Code's own prefixes,
  such as `app`, `user`, `vcs`, and `organization`.

For the full value syntax, including percent-encoding, see [Multi-team organization
support](https://code.claude.com/docs/en/monitoring-usage#multi-team-organization-support) in
Anthropic's monitoring guide.

<Warning>
  Don't set `OTEL_METRICS_INCLUDE_SESSION_ID` to `false`. It removes the session
  ID from every span, so Openlayer can no longer group a conversation's traces
  into a session.
</Warning>

## Which Claude surfaces are covered

The OTLP configuration on this page applies wherever Claude Code reads managed settings:

| Surface | Covered by this guide | Notes |
| - | - | - |
| Claude Code in the terminal | Yes | |
| Claude Code in VS Code and JetBrains | Yes | |
| Claude Desktop, **Code** tab | Yes | Reads the same managed settings as the terminal |
| Claude Code on the web and in cloud sessions | No | Anthropic-hosted sessions don't read device policy |
| Claude Desktop and claude.ai chat | No | Chat doesn't run on Claude Code. Use [Claude Compliance](/docs/integrations/claude-compliance) |
| Cowork | No | Cowork never fetches server-managed settings. Use [Claude Compliance](/docs/integrations/claude-compliance) |

The two integrations differ in plan, direction, and data:

* **Claude Code OTLP export** (this page) works on Claude for Teams and Claude for Enterprise.
  Claude Code pushes traces to Openlayer as each developer works.
* **[Claude Compliance](/docs/integrations/claude-compliance)** requires Claude for Enterprise.
  Openlayer pulls transcripts of claude.ai chats, Cowork sessions, and Claude Code sessions from
  Anthropic's Compliance API on a schedule.

If your machines run the CrowdStrike Falcon sensor,
[CrowdStrike Falcon AIDR](/docs/integrations/crowdstrike-falcon-aidr) also captures Claude Code prompts,
tool calls, and model usage, alongside other AI coding agents, without changing Claude Code's
settings.

## Rotate the API key with a headers helper

To avoid distributing a long-lived API key, point Claude Code at a script that prints the headers
instead. Deploy the script to each machine, then replace `OTEL_EXPORTER_OTLP_TRACES_HEADERS` in
your managed settings with the top-level `otelHeadersHelper` key:

```json theme={null}
{
  "otelHeadersHelper": "/usr/local/bin/openlayer-otel-headers.sh",
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1",
    "OTEL_TRACES_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL": "http/protobuf",
    "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "https://api.openlayer.com/v1/otel/v1/traces",
    "OTEL_LOG_USER_PROMPTS": "1",
    "OTEL_LOG_TOOL_DETAILS": "1",
    "OTEL_LOG_TOOL_CONTENT": "1"
  }
}
```

The script prints a JSON object of headers. Fetch the key from your secrets manager inside it:

```bash theme={null}
#!/bin/bash
echo "{\"Authorization\": \"Bearer $(get-openlayer-key)\", \"x-bt-parent\": \"pipeline_id:YOUR_OPENLAYER_PIPELINE_ID\"}"
```

Claude Code runs the script at startup and every 29 minutes after. If the script fails, Claude
Code exports nothing and reports `otelHeadersHelper failed` in the session and in `/status`.

The helper doesn't apply to [detailed tracing](#capture-claudes-replies-with-detailed-tracing),
which only sends the credentials in `OTEL_EXPORTER_OTLP_TRACES_HEADERS`.

## Troubleshooting

| Symptom | Cause and fix |
| - | - |
| `/status` has no `Enterprise managed settings` line | Claude Code found no managed policy. Check the file path for the operating system, or run `claude doctor` for the admin console fetch outcome |
| `/status` lists a different source than the one you deployed | A higher-ranked managed source is present, and Claude Code ignored yours. `Skipped sources` names it. Add the block to the source that's in effect |
| `claude doctor` says the remote fetch was skipped | The developer's shell exports `CLAUDE_CODE_USE_*` or a custom `ANTHROPIC_BASE_URL`. Deliver the settings through MDM or a managed settings file instead |
| Settings are delivered, but no traces arrive | The developer hasn't accepted the approval dialog for the server-managed settings. Restart Claude Code and accept it |
| The debug log shows `First traces export: FAILED (Unauthorized)` | The API key is wrong or revoked. Check the `Authorization` header |
| Traces arrive in the wrong project | The `x-bt-parent` header names a different pipeline. Check the pipeline ID |
| Traces have no input | `OTEL_LOG_USER_PROMPTS` isn't `1` in managed settings. See [Privacy and data handling](#privacy-and-data-handling) |
| Traces have no output | Claude's replies are only exported with [detailed tracing](#capture-claudes-replies-with-detailed-tracing) and `OTEL_LOG_USER_PROMPTS=1` |
| Traces show an ID instead of the developer's email | The session isn't signed in with a Claude account, for example with an API key or a cloud provider. Only signed-in sessions carry the email |
| A custom attribute isn't a filterable column | Its key has a dot, or shares its first segment with a dotted attribute. See [Add team and repository context](#add-team-and-repository-context) |
| Detailed tracing works with `claude -p` but not interactively | Interactive sessions need Anthropic to allowlist your organization for detailed tracing |
| The debug log shows an `OTEL diag error` for log exports | With detailed tracing, Claude Code also sends logs to `/v1/logs`, which Openlayer doesn't ingest. Traces are unaffected |

For every Claude Code telemetry setting, see Anthropic's [monitoring
guide](https://code.claude.com/docs/en/monitoring-usage).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.