Skip to main content
Claude Code reports every session over OpenTelemetry. The LangWatch command line tool connects that report to your workspace, so you can read the cost of each session, the tool call tree of each turn, and the prompt and the response behind both. There are two ways to set it up:
  • langwatch claude starts Claude Code and sets up the connection on the first run. Use it on a machine you work on.
  • langwatch instrument claude writes the same setup and exits. Use it on a server, or when the telemetry must go to a team project.

Before you start

  • Install Claude Code.
  • Install the LangWatch command line tool: npm install -g langwatch
  • Create an account at app.langwatch.ai, or run your own instance with npx @langwatch/server.

Run Claude Code through the wrapper

The first run asks one question: LangWatch remembers the answer, so later runs do not ask again. Everything else is unchanged: langwatch claude accepts the same flags, the same subcommands and the same keyboard shortcuts as claude, and it returns the same exit code.
A virtual key is created the first time you choose the gateway, not at login. If you always keep your own subscription, LangWatch never creates one for you.

Set up a machine without starting Claude Code

langwatch instrument claude writes the connection into ~/.claude/settings.json and exits. A plain claude run on that machine then sends its telemetry to LangWatch. This is the setup for a server that holds many agents, for a machine image, or for a configuration management run.

Choose where the telemetry goes

Pass one scope flag, and one only.

Send the telemetry to a team project

This creates an ingest key for this device and holds Claude Code to that project. LangWatch creates one key per device and never replaces the key of another device, so many machines can report to one project at the same time. You need a login and the traces:create permission on the project. See Roles and permissions. The wrapper accepts the same flags. This pins the project and then starts Claude Code:
--project and --personal are LangWatch flags. LangWatch removes them from the command line before Claude Code reads it, so they never reach the agent.

Set up a machine that never logs in

--key takes an ingest key (ik-lw-…). It needs no login and contacts no server, which makes it the option for a shared machine, a build agent, or a base image.
The command reads the same value from the LANGWATCH_INGEST_KEY environment variable:
For a self-hosted instance, add its address:
To get an ingest key without the command line tool, install an ingestion template for the tool in the dashboard: the setup drawer mints one for you. See Ingestion templates.

Move a tool back to your personal workspace

This removes the project pin and writes the personal connection again.

Remove the setup

This deletes every connection the command line tool wrote, for every tool.

What you get in LangWatch

Open your personal page at /me, or open the project you pinned Claude Code to.
  • Sessions: one row per Claude Code session, with the context it carried, how often it compacted, how long it worked, and the pull requests it drove.
  • Traces: one trace per turn, with the tool call tree, the latency of each step, and each subagent on its own branch.
  • Cost: the amount per session and per turn, the model of each turn, and the split between tokens written to the prompt cache and tokens read back from it.
  • Content: the prompt of each turn, the input and the output of each tool call, and the response of the model.
Your agent can read all of this back. See Explore your usage with your own agent.

Attribute sessions to pull requests

LangWatch joins a session to a pull request through the repository and branch the session reports. The session reports the directory it is working in, read at the start of the session and again after every turn. Two rules follow from how Claude Code tracks that directory:
  • A cd inside the Bash tool does not move the session. The session still reports the directory it was launched in.
  • A native switch with the EnterWorktree tool does move the session. From then on it reports the repository and branch of the worktree it entered.
So to get a session attributed to the pull request it works on, either start Claude Code inside a checkout of that branch, or have the session switch natively:
  1. Create a worktree for the branch: git -C <repo> fetch origin <branch> && git -C <repo> worktree add .claude/worktrees/<name> <branch>
  2. Ask the session to call the EnterWorktree tool with that worktree’s path.
A long-lived session that picks up several pull requests should switch this way each time it moves to the next one. Work done from a directory outside any checkout, for example reviewing with gh commands from a home directory, attaches to no repository and no pull request, and its token cost cannot be attributed. The per pull request rollup is available over the API as Get pull request coding agent usage.

Content and privacy

The setup that langwatch claude and langwatch instrument claude write turns on the four Claude Code content flags, because the content is what makes a trace worth reading: Remove the flags from ~/.claude/settings.json to keep only the usage numbers: tokens, cost, model, latency, the tool call tree and the subagent tree stay, and the content stops. langwatch claude and langwatch instrument claude set OTEL_LOG_RAW_API_BODIES, which already carries the assistant’s response text along with the rest of the request and response body. If you want the response text on its own, without the full body, add OTEL_LOG_ASSISTANT_RESPONSES yourself: the wrapper does not set it for you. Claude Code shortens each inline body at 60 kilobytes. CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH raises that limit. Claude Code always removes extended thinking from the bodies, so LangWatch never receives it.

Troubleshooting

Restart Claude Code. It reads ~/.claude/settings.json at start, so a session that was already open when you ran langwatch instrument claude keeps its old configuration.Then run langwatch instrument claude again and read what it prints. It names the file it wrote and the destination the telemetry goes to.
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA is missing. It is the flag that turns spans on, and OTEL_TRACES_EXPORTER does nothing without it. Cost and tokens still arrive, so the session appears, but LangWatch has no structure to attach them to and every subagent folds into the main session.
OTEL_LOG_USER_PROMPTS is missing. Claude Code removes the prompt text from its user_prompt event by default.
Both OTEL_LOG_RAW_API_BODIES and OTEL_LOG_ASSISTANT_RESPONSES are missing. Claude Code reports the response text of the assistant on its api_response_body event (needs OTEL_LOG_RAW_API_BODIES=1, and carries the full request and response JSON) or on its lighter assistant_response event (needs OTEL_LOG_ASSISTANT_RESPONSES=1, and carries only the response text). Both are off by default. Set OTEL_LOG_ASSISTANT_RESPONSES=1 if you want the response without the rest of the body.Claude Code docs describe OTEL_LOG_ASSISTANT_RESPONSES as falling back to the value of OTEL_LOG_USER_PROMPTS. Don’t rely on that fallback: set it explicitly.Claude Code also reports api_response_body and assistant_response for work that is not a conversation, such as an autosuggestion or a session title. LangWatch filters those out, so a title never becomes the output of a trace.
Run langwatch instrument claude --project <id-or-slug> to move it to a team project, or langwatch instrument claude --personal to move it back to your own.
Check that the key is live and that the header reads Authorization=Bearer <key>. An ingest key can write traces and nothing else, so a key that works for ingestion still fails on other endpoints.On a machine with a login, run langwatch login --device again to refresh the session.
The model name on the span does not match an entry in the LangWatch cost catalog. Read gen_ai.request.model on the span. Current names such as claude-sonnet-4-6, claude-opus-4-7 and claude-haiku-4-5 match; older aliases return no cost.
For more failure modes see CLI debug.

Manual OpenTelemetry setup

Use this when you cannot install the LangWatch command line tool. The block below mirrors the variables langwatch instrument claude writes for you, plus the optional OTEL_LOG_ASSISTANT_RESPONSES flag, which the wrapper does not set. Drop that line if you only want what the wrapper gives you.

Environment variables

The header takes an ingest key (ik-lw-…), which can create traces and nothing else. Keep a full project API key (sk-lw-…) out of the configuration of a coding agent: it can read and change your project data, and a coding agent has no use for that. For a self-hosted instance, replace the endpoint with the address of your instance followed by /api/otel. Claude Code appends /v1/traces, /v1/logs and /v1/metrics on its own. Never write the per-signal path yourself.
The five OTEL_LOG_* flags put your session content in LangWatch. Read Content and privacy before you use them where the content matters.

Settings file

Claude Code reads the same variables from the env block of ~/.claude/settings.json, which survives a new terminal:
To wire a single repository instead of the whole machine, put the block in .claude/settings.json in the repository and keep the key and the content flags in a gitignored .claude/settings.local.json. See Per-repository telemetry.

Managed settings for a fleet

An administrator can apply the same block to every machine through the managed settings file:
  • macOS: /Library/Application Support/ClaudeCode/managed-settings.json
  • Linux and Windows Subsystem for Linux: /etc/claude-code/managed-settings.json
  • Windows: C:\ProgramData\ClaudeCode\managed-settings.json
Variables in the managed settings file take precedence and a user cannot override them. Distribute the file with your device management system.

Team attribution

Add your own labels to every trace with OTEL_RESOURCE_ATTRIBUTES:
OTEL_RESOURCE_ATTRIBUTES follows the W3C Baggage specification. Write comma-separated key=value pairs. Values cannot contain a space, a double quote, a comma, a semicolon or a backslash. Percent-encode any other character outside that range.

Headers from a script

An enterprise that issues short-lived tokens can produce the headers at start time. Add this to .claude/settings.json:
The script writes a JSON object of string headers to standard output:
Claude Code reads the headers at start only, so a token that expires mid-session is not refreshed. For frequent refresh, send the telemetry to an OpenTelemetry Collector and let the collector refresh its own headers.
Last modified on August 22, 2026