---
title: "Centralized Claude Code OTel collection"
canonical_url: "https://docs.getdx.com/claude-code-otel-centralized-collection/"
md_url: "https://docs.getdx.com/claude-code-otel-centralized-collection.md"
last_updated: "2026-07-17"
---

# Centralized Claude Code OTel collection
Centralized collection routes Claude Code telemetry through a customer-managed OpenTelemetry (OTel) collector or gateway before forwarding it to DX. Use this architecture to keep the DX ingest token off developer workstations and apply enterprise authentication and identity controls at a central point.

> **Note**: Create a [Claude Code (OTel) connection](https://docs.getdx.com/connectors/claude-code-otel/) before using this guide. The connection provides your customer-specific DX endpoint and ingest token.

## Centralized collection use cases

- **Keep DX credentials centralized.** Store the DX ingest token in one customer-managed gateway instead of distributing the same credential across developer machines.
- **Send telemetry to multiple destinations.** Point Claude Code at one gateway, then fan out the unchanged telemetry to DX and other OTLP destinations.

## Before you begin

- **Customer-managed endpoint** that accepts OTLP HTTP/JSON metrics and logs from Claude Code clients.
- **Per-user or per-device authentication** between each client and the customer-managed endpoint.
- **Corporate identity mapping** that maps the authenticated principal to a verified email address.

## Centralized collection flow



1. Claude Code sends its native OTLP HTTP/JSON telemetry to the customer-managed collector or gateway. The workstation does not store the DX ingest token.
1. The collector authenticates each user or device with a unique credential and maps that principal to a corporate identity.
1. The collector removes untrusted identity values and adds the verified `user.email` to the forwarded telemetry.
1. The collector forwards the metrics and logs to DX without changing their structure. It adds the DX ingest token to the `Authorization` header.

The client-to-collector authentication method is customer controlled. DX does not prescribe how to implement it.

The DX ingest token authenticates the connection, not an individual developer. DX trusts the identity attributes in the forwarded payload, so the collector must prevent client-supplied values from overriding the verified identity. Remove or overwrite `user.email`, `user`, `user.account_id`, and `user.id` at the resource, data-point, and log-record levels before forwarding.



## Forward telemetry to DX

DX accepts OTLP HTTP/JSON. It does not accept OTLP over gRPC or protobuf for this connector.

- Send metrics to `POST /api/otel/v1/metrics`.
- Send logs to `POST /api/otel/v1/logs`.
- Set `Content-Type: application/json`.
- Set `Authorization: Bearer <DX ingest token>`.
- Send metrics with delta temporality: `aggregationTemporality: 1`.
- Preserve the native Claude Code payload on the DX-bound copy. Do not aggregate it or apply transformations intended for another observability destination.

Use the host from the `OTEL_EXPORTER_OTLP_ENDPOINT` value generated on the Claude Code (OTel) connection page.

### Metrics request

This minimal request records one Claude Code session for a verified user:

```http
POST /api/otel/v1/metrics HTTP/1.1
Host: <your-datacloud-host>
Authorization: Bearer <DX ingest token>
Content-Type: application/json

{
  "resourceMetrics": [
    {
      "resource": {
        "attributes": [
          {
            "key": "user.email",
            "value": { "stringValue": "developer@example.com" }
          }
        ]
      },
      "scopeMetrics": [
        {
          "metrics": [
            {
              "name": "claude_code.session.count",
              "sum": {
                "aggregationTemporality": 1,
                "isMonotonic": true,
                "dataPoints": [
                  {
                    "timeUnixNano": "1784145600000000000",
                    "asInt": "1"
                  }
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
```

All supported metrics use `sum.dataPoints`. Put metric-specific attributes on each data point.

- `claude_code.session.count` — No required attributes. The value is the session count.
- `claude_code.lines_of_code.count` — Set `type` to `added` or `removed`. The value is the line count.
- `claude_code.commit.count` — No required attributes. The value is the commit count.
- `claude_code.pull_request.count` — No required attributes. The value is the pull request count.
- `claude_code.token.usage` — Set `model` and set `type` to `input`, `output`, `cacheRead`, or `cacheCreation`. The value is the token count.
- `claude_code.cost.usage` — Set `model`. The value is the cost in USD.
- `claude_code.code_edit_tool.decision` — Set `tool_name` to `Edit`, `MultiEdit`, `Write`, or `NotebookEdit`, and set `decision` to `accept` or `reject`. The value is the decision count.

Include `timeUnixNano` and either `asInt` or `asDouble` on each data point. If the timestamp is absent, DX uses the request receipt date. If the value is absent, DX records zero.

### Logs request

Logs are required only for [skill usage tracking](https://docs.getdx.com/connectors/claude-code-otel/#optional-skill-usage-tracking). This minimal request records one skill activation:

```http
POST /api/otel/v1/logs HTTP/1.1
Host: <your-datacloud-host>
Authorization: Bearer <DX ingest token>
Content-Type: application/json

{
  "resourceLogs": [
    {
      "resource": {
        "attributes": [
          {
            "key": "user.email",
            "value": { "stringValue": "developer@example.com" }
          }
        ]
      },
      "scopeLogs": [
        {
          "logRecords": [
            {
              "timeUnixNano": "1784145600000000000",
              "body": { "stringValue": "claude_code.tool_result" },
              "attributes": [
                {
                  "key": "tool_name",
                  "value": { "stringValue": "Skill" }
                },
                {
                  "key": "tool_parameters",
                  "value": {
                    "stringValue": "{\"skill_name\":\"review-pr\"}"
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

DX also accepts the skill name in `tool_input` instead of `tool_parameters`, and as `skill` instead of `skill_name`.

### Identity attributes

DX uses `user.email` as the preferred identity. It also recognizes `user` as an email and uses `user.account_id` or `user.id` when an email is unavailable. `user.name`, `organization.id`, and `terminal.type` are optional.

Identity attributes can appear on the resource or individual data point or log record. Record-level attributes take precedence, so the collector must remove or overwrite untrusted identity attributes at every level.

If the gateway relies on identity attributes from Claude Code, add `OTEL_RESOURCE_ATTRIBUTES` under `env` in the managed or local Claude Code settings:

```json
{
  "env": {
    "OTEL_RESOURCE_ATTRIBUTES": "user.email=alice@example.com,user.name=Alice%20Smith"
  }
}
```

Encode spaces as `%20`. If the gateway derives identity from its client authentication, omit these client-side identity attributes and add the verified values at the gateway instead.

> **Note**: Keep custom resource attributes to the minimum needed by the gateway. Claude Code repeats them across metric data points, so directory fields such as `user.department` or `user.title` can significantly increase payload size. DX does not use those fields for metric aggregation.

## Validate the connection

Send telemetry for one user before rolling out the configuration:

- `200` confirms that DX received the request for asynchronous processing. It does not confirm that every field passed semantic validation.
- `401` indicates a missing or invalid ingest token, or that no active Claude Code (OTel) connection exists.
- `415` indicates that `Content-Type` is not `application/json`.
- `422` indicates invalid JSON or a malformed gzip body.
- If DX returns `200` but no data appears, confirm that the payload includes an identity, uses delta temporality, and preserves the native Claude Code structure.

## Next steps

After validating one user, distribute the customer-managed endpoint through Claude Code managed settings, MDM, or your configuration management system. Keep the DX ingest token only in the collector or gateway; when the token changes, update it there rather than on each workstation.
---

## Sitemap

[Overview of all docs pages](/llms.txt)
