Follow Discord
Sweep 22 Oct 2026 · 04:32Z Build v2.1.308 527 read Stable v2.1.308 Latest v2.1.308 Next v2.1.308 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · api

api changedmanage-claude/opentelemetry/api

Nearest release: v2.1.300, published 4 hours before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Recorded here
Lines+698added
Lines−0removed
From line — no hunk to open at
First seen 14 Oct 2026 this site's first read of the page
Recorded edits8to this page, all time

## What you need ## 1. Add a destination ### Admin API and CLI ## 2. Choose workspaces for a destination ## 3. Check that spans arrive ## 4. Connect API spans to your own traces ## Next steps ## Delivery and health ## Limits ## Troubleshooting ### Delivery errors

The whole hunk

698 lines, new page
/
lines

A whole new page. There's nothing to diff it against, so here is what it says.

---
title: Use OpenTelemetry with the Claude API
url: https://platform.claude.com/docs/en/manage-claude/opentelemetry/api
description: Add a destination in the Claude Console to send OpenTelemetry traces of your Messages API requests and Managed Agents sessions to your observability platform.
featureMetadata:
  topic:
    title: OpenTelemetry
    url: https://platform.claude.com/docs/en/manage-claude/opentelemetry
  status: beta
  zdr:
    eligibility: eligible
    note: Excludes [Covered Models](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements). Only for features that are themselves ZDR eligible, such as the Messages API. Claude Managed Agents isn't ZDR eligible.
  supportedPlatforms:
    Claude API: beta
    Claude Platform on AWS: beta
  rows:
    - label: Works with
      value: Messages API, Claude Managed Agents
  details:
    - After delivery, the data is held by the service that you chose, outside Anthropic, under that service's retention and access controls.
---

With OpenTelemetry, the Claude API can emit a span for each model request and each tool use that it runs. You can view these spans in your observability platform without changing your code.

The API emits spans for your Messages API requests and Managed Agents sessions. To receive them, add a *destination* in the Claude Console. A destination tells the API your observability platform's OTLP endpoint and how to authenticate with it.

## What you need

* **The admin role** in a Claude Console organization, to add and change destinations. With the developer role, you can view them. If your organization is on Claude Platform on AWS, sign in to the Console through the AWS Console, as [Signing in](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws#signing-in) describes.
* **An OTLP/HTTP endpoint** that accepts protobuf encoding at an HTTPS URL on port 443. If you run your own [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), its OTLP/HTTP receiver listens on port 4318 by default. Configure the receiver to accept HTTPS on port 443, or put a load balancer or reverse proxy in front of the Collector.
* **Credentials for the endpoint**, such as an API key.

## 1. Add a destination

<Info>
  When you add a telemetry destination, Anthropic will send traces of Claude Platform activity in your organization to the third-party provider's OTLP/HTTP endpoint that you specify, in accordance with your provider terms and access controls. After delivery, the data is held by the service that you chose, outside Anthropic, under that service's retention and access controls.
</Info>

1. In the Console, open your organization's [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) and click **Add destination**.

2. Configure the destination:

   | Field                          | What to enter                                                                                                                                                                                                                                                                                                                                                                                                       |
   | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | **Provider**                   | Your observability platform, or **Custom** if it isn't listed. If you choose a listed platform, the Console asks for its details, such as an API key, instead of the **OTLP endpoint URL**, **Request headers**, and **OTLP traces endpoint URL**.                                                                                                                                                                  |
   | **Name**                       | Optional. For example, "Acme's observability platform."                                                                                                                                                                                                                                                                                                                                                             |
   | **OTLP endpoint URL**          | The base HTTPS URL of your observability platform's OTLP/HTTP endpoint, with a hostname, not an IP address. It can have a path prefix, for example `https://gateway.example.com/otlp`. Don't add `/v1/traces`, because the API adds it. If you set an **OTLP traces endpoint URL**, the API uses that URL instead.                                                                                                  |
   | **Request headers**            | The headers that the API sends with each request, for example your observability platform's API key header. Put credentials only in header values. After you save, the Console doesn't show the values again.                                                                                                                                                                                                       |
   | **Content mode**               | **Metadata only** or **Full content**. See [how the content modes differ](https://platform.claude.com/docs/en/manage-claude/opentelemetry#choose-a-content-mode).                                                                                                                                                                                                                                                   |
   | **Workspaces**                 | The workspaces whose spans the destination receives: **All**, **Selected**, or **All except**. See [Choose workspaces for a destination](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#choose-workspaces-for-a-destination).                                                                                                                                                                  |
   | **OTLP traces endpoint URL**   | Optional, under **Advanced settings**. The full URL of your observability platform's traces endpoint, for example `https://gateway.example.com/custom/traces`. Set it when the platform receives traces at a URL other than the OTLP endpoint URL plus `/v1/traces`. It must have the same host as the OTLP endpoint URL.                                                                                           |
   | **Maximum content size in MB** | Optional, under **Advanced settings** when the content mode is **Full content**. The most content that the API sends in each span. The Console fills it in based on the **Provider** you choose. Change it to fit what your observability platform accepts. Leave it empty to send as much as the API allows. See [Content limits](https://platform.claude.com/docs/en/manage-claude/opentelemetry#content-limits). |

3. Click **Add destination** to save.

4. Click **Test** in the destination's **More actions** menu. You will see a message that the test span was delivered to your collector, or how the delivery failed (see [Delivery errors](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-errors)).

5. Check that the `anthropic.test` span arrived in your observability platform.

### Admin API and CLI

You can also add a destination with the [Admin API](https://platform.claude.com/docs/en/manage-claude/admin-api) instead of the Console. Sign in to the CLI as an admin, or use an [Admin API key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys) in `ANTHROPIC_API_KEY`. On Claude Platform on AWS, send the requests to `https://aws-external-anthropic.{region}.api.aws` instead, signed with your AWS credentials as in [Making requests](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws#making-requests). There, your [IAM policy](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions) determines who can manage destinations. A request can include only the workspaces of your AWS account in that Region.

<CodeGroup>
  ```bash CLI
  # Sign in once as an admin, which opens a browser. Leave ANTHROPIC_API_KEY unset, because it overrides the profile.
  ant auth login --profile admin --scope "org:admin"
  ant --profile admin beta:organization:telemetry-destinations create \
    --endpoint-url https://gateway.example.com/otlp \
    --headers '{authorization: "Bearer YOUR_OBSERVABILITY_API_KEY"}' \
    --traces.content-mode metadata_only \
    --workspaces.type all
  ```

  ```bash cURL
  curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/telemetry_destinations" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: telemetry-destinations-2026-08-11" \
    -H "content-type: application/json" \
    -d '{
      "endpoint_url": "https://gateway.example.com/otlp",
      "headers": {"authorization": "Bearer YOUR_OBSERVABILITY_API_KEY"},
      "traces": {"content_mode": "metadata_only"},
      "workspaces": {"type": "all"}
    }'
  ```

  ```python Python
  client = anthropic.Anthropic()

  destination = client.beta.organization.telemetry_destinations.create(
      endpoint_url="https://gateway.example.com/otlp",
      headers={"authorization": "Bearer YOUR_OBSERVABILITY_API_KEY"},
      traces={"content_mode": "metadata_only"},
      workspaces={"type": "all"},
  )

  print(destination.id)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const destination = await client.beta.organization.telemetryDestinations.create({
    endpoint_url: "https://gateway.example.com/otlp",
    headers: { authorization: "Bearer YOUR_OBSERVABILITY_API_KEY" },
    traces: { content_mode: "metadata_only" },
    workspaces: { type: "all" }
  });

  console.log(destination.id);
  ```

  ```csharp C#
  using Anthropic.Models.Beta.Organization.TelemetryDestinations;

  AnthropicClient client = new();

  var destination = await client.Beta.Organization.TelemetryDestinations.Create(
      new()
      {
          EndpointUrl = "https://gateway.example.com/otlp",
          Headers = new Dictionary<string, string>
          {
              ["authorization"] = "Bearer YOUR_OBSERVABILITY_API_KEY",
          },
          Traces = new() { ContentMode = BetaTelemetryDestinationContentMode.MetadataOnly },
          Workspaces = new BetaTelemetryDestinationWorkspacesAllParams(),
      }
  );

  Console.WriteLine(destination.ID);
  ```

  ```go Go
  client := anthropic.NewClient()

  destination, err := client.Beta.Organization.TelemetryDestinations.New(
  	context.Background(),
  	anthropic.BetaOrganizationTelemetryDestinationNewParams{
  		EndpointURL: "https://gateway.example.com/otlp",
  		Headers: map[string]string{
  			"authorization": "Bearer YOUR_OBSERVABILITY_API_KEY",
  		},
  		Traces: anthropic.BetaTelemetryDestinationTracesParams{
  			ContentMode: anthropic.BetaTelemetryDestinationContentModeMetadataOnly,
  		},
  		Workspaces: anthropic.BetaTelemetryDestinationWorkspacesParamsUnion{
  			OfAll: &anthropic.BetaTelemetryDestinationWorkspacesAllParams{},
  		},
  	},
  )
  if err != nil {
  	log.Fatal(err)
  }

  fmt.Println(destination.ID)
  ```

  ```java Java
  import com.anthropic.core.JsonValue;
  import com.anthropic.models.beta.organization.telemetrydestinations.BetaTelemetryDestinationContentMode;
  import com.anthropic.models.beta.organization.telemetrydestinations.BetaTelemetryDestinationTracesParams;
  import com.anthropic.models.beta.organization.telemetrydestinations.BetaTelemetryDestinationWorkspacesAllParams;
  import com.anthropic.models.beta.organization.telemetrydestinations.TelemetryDestinationCreateParams;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      var params = TelemetryDestinationCreateParams.builder()
          .endpointUrl("https://gateway.example.com/otlp")
          .headers(TelemetryDestinationCreateParams.Headers.builder()
              .putAdditionalProperty("authorization", JsonValue.from("Bearer YOUR_OBSERVABILITY_API_KEY"))
              .build())
          .traces(BetaTelemetryDestinationTracesParams.builder()
              .contentMode(BetaTelemetryDestinationContentMode.METADATA_ONLY)
              .build())
          .workspaces(BetaTelemetryDestinationWorkspacesAllParams.builder().build())
          .build();
      var destination = client.beta().organization().telemetryDestinations().create(params);

      IO.println(destination.id());
  }
  ```

  ```php PHP
  $client = new Client();

  $destination = $client->beta->organization->telemetryDestinations->create(
      endpointURL: 'https://gateway.example.com/otlp',
      headers: ['authorization' => 'Bearer YOUR_OBSERVABILITY_API_KEY'],
      traces: ['contentMode' => 'metadata_only'],
      workspaces: ['type' => 'all'],
  );

  echo "{$destination->id}\n";
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  destination = client.beta.organization.telemetry_destinations.create(
    endpoint_url: "https://gateway.example.com/otlp",
    headers: {authorization: "Bearer YOUR_OBSERVABILITY_API_KEY"},
    traces: {content_mode: :metadata_only},
    workspaces: {type: :all}
  )

  puts destination.id
  ```
</CodeGroup>

A create request takes the Console's settings except **Provider**, so enter your observability platform's endpoint URL and headers yourself. Set `traces.max_content_bytes` (csharp, go: `Traces.MaxContentBytes`; java, php: `traces.maxContentBytes`), in bytes, to fit what your observability platform accepts (see [Content limits](https://platform.claude.com/docs/en/manage-claude/opentelemetry#content-limits)). To list, change, or delete destinations, or to add or remove one workspace, use the other methods of the telemetry destinations API.

## 2. Choose workspaces for a destination

A destination receives the spans of the workspaces that it covers. Choose them when you add the destination. For **Workspaces**, select one of the following:

* **All:** Every workspace in the organization, including the [Default Workspace](https://platform.claude.com/docs/en/manage-claude/workspaces#how-workspaces-work) and workspaces created later.
* **Selected:** Only the workspaces that you select.
* **All except:** Like **All**, but without the workspaces that you select.

For **Selected** or **All except**, select the workspaces in the search box that appears under the options. To change a destination's workspaces later, open its **More actions** menu on the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) while the **Workspace** filter shows **All**. Click **Edit**, then choose another **Workspaces** option or change the workspaces in the search box.

If you have the developer role in the organization and the Workspace Admin role in a workspace, you can add that workspace to a **Selected** destination or remove it. Set the **Workspace** filter to that workspace, then open the destination's **More actions** menu. On Claude Platform on AWS, the Console has no Workspace Admin role. There, your [IAM policy](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions) determines who can add a workspace to a destination or remove it.

The API sends spans to every enabled destination that covers the [workspace where the request or session runs](https://platform.claude.com/docs/en/manage-claude/workspaces#api-keys-and-resource-scoping).

## 3. Check that spans arrive

1. In the Console, select a workspace that the destination covers and send a Messages API request in [playground](https://platform.claude.com/playground). You can also send a Messages API request from your application or start a Managed Agents session in that workspace. To start a session, you can follow the steps in [Get started with Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/quickstart).
2. In the Console, on the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations), check that the **Delivery** column shows **Healthy** for the destination. This can take about a minute.
3. In your observability platform, filter on `service.name` = `claude-platform` to find the request's spans.

If the column shows **Failing**, hover over it to see the last error. To find the likely cause, see [Delivery errors](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-errors).

## 4. Connect API spans to your own traces

By default, the API spans for a Messages API request or a Managed Agents session are in their own traces. Connect them to your application's traces, so that they nest under your own spans.

The API reads each request's trace context from the W3C [`traceparent` header](https://www.w3.org/TR/trace-context/). If the sampled flag in the header is off, the API doesn't emit the request's span or the spans under it. Claude Platform on AWS doesn't support this header yet. The spans for requests that you send to it always start their own traces, even when the sampled flag is off.

<Tabs>
  <Tab title="With the Claude SDK">
    To connect the API spans, [set up SDK tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk) in your application and call the SDK from inside one of your own spans. Your span then contains the SDK span, which contains the API span. Send all of these spans to the same observability platform, so that it can show them as one trace. See the example traces of [a Messages API request](https://platform.claude.com/docs/en/manage-claude/opentelemetry#a-messages-api-request) and [a Managed Agents session](https://platform.claude.com/docs/en/manage-claude/opentelemetry#a-managed-agents-session).

    The following example sends a user message to a session inside your own span:

    <CodeGroup exclude="shell">
      ```python Python
      from opentelemetry import trace

      tracer = trace.get_tracer("my-service")

      with tracer.start_as_current_span("summarize_issues"):
          client.beta.sessions.events.send(
              session.id,
              events=[
                  {
                      "type": "user.message",
                      "content": [{"type": "text", "text": "Summarize the open issues"}],
                  },
              ],
          )
      ```

      ```typescript TypeScript
      import { trace } from "@opentelemetry/api";

      const tracer = trace.getTracer("my-service");

      await tracer.startActiveSpan("summarize_issues", async (span) => {
        try {
          await client.beta.sessions.events.send(session.id, {
            events: [
              {
                type: "user.message",
                content: [{ type: "text", text: "Summarize the open issues" }]
              }
            ]
          });
        } finally {
          span.end();
        }
      });
      ```

      ```csharp C#
      using System.Diagnostics;

      // Add this source to your tracer provider, next to com.anthropic.sdk.csharp.
      var source = new ActivitySource("MyService");

      using (source.StartActivity("summarize_issues"))
      {
          // parameters holds a user.message event.
          await client.Beta.Sessions.Events.Send(session.ID, parameters);
      }
      ```

Cut at 300 lines. The page has the rest.

Feedback