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

# Anthropic

> Track Anthropic SDK calls from Python or TypeScript

## Language support

| Setup option    |   Python  | TypeScript |
| --------------- | :-------: | :--------: |
| Agnost AI skill |     ✓     |      ✓     |
| Agnost AI SDK   |     ✓     |      ✓     |
| OpenTelemetry   | Automatic |   Manual   |

## Choose a setup method

| Method              | Use it when                                                                    |
| ------------------- | ------------------------------------------------------------------------------ |
| **Agnost AI skill** | You want your coding agent to inspect the app, make the change, and verify it. |
| **Agnost AI SDK**   | You want explicit control over the interaction boundaries and fields.          |
| **OpenTelemetry**   | The framework already emits useful spans or you operate an OTel pipeline.      |

Start with one method for a call path. Combining SDK tracking with framework
OpenTelemetry on the same call can create duplicate interactions.

## Recommended: Agnost AI skill

<Note>
  **Recommended.** Choose this path when you want your coding agent to inspect the
  project, select a supported transport, make the smallest instrumentation change,
  send a test event, and verify that it reached Agnost AI.
</Note>

Install the skill once in your coding-agent environment:

```bash theme={null}
npx skills add AgnostAI/skills --skill agnost-ai
```

Run the framework-specific prompt below from the application root. Review the
resulting diff before deploying it.

```text theme={null}
Use the agnost-ai skill to add Agnost AI analytics to this Anthropic application.
Org ID: your-org-id
Instrument the real messages.create() path and verify one fresh interaction.
```

## Manual setup: Agnost AI SDK

<CodeGroup>
  ```bash Python theme={null}
  pip install agnost
  ```

  ```bash TypeScript theme={null}
  npm install agnostai
  ```
</CodeGroup>

<CodeGroup>
  ```python Python theme={null}
  import agnost
  from anthropic import Anthropic

  agnost.init("your-org-id")
  client = Anthropic()
  interaction = agnost.begin(user_id="u-42", agent_name="anthropic-support", input=prompt)
  try:
      response = client.messages.create(model="claude-sonnet-4-5", max_tokens=512,
                                        messages=[{"role": "user", "content": prompt}])
      interaction.end(output="".join(block.text for block in response.content if block.type == "text"))
  except Exception as exc:
      interaction.end(output=str(exc), success=False)
      raise
  finally:
      agnost.shutdown()
  ```

  ```typescript TypeScript theme={null}
  import Anthropic from '@anthropic-ai/sdk';
  import * as agnost from 'agnostai';

  agnost.init('your-org-id');
  const client = new Anthropic();
  const interaction = agnost.begin({
    userId: 'u-42',
    agentName: 'anthropic-support',
    input: prompt,
  });

  try {
    const response = await client.messages.create({
      model: 'claude-sonnet-4-5',
      max_tokens: 512,
      messages: [{ role: 'user', content: prompt }],
    });
    const output = response.content
      .filter((block) => block.type === 'text')
      .map((block) => block.text)
      .join('');
    interaction.end(output);
  } catch (error) {
    interaction.end(String(error), false);
    throw error;
  } finally {
    await agnost.shutdown();
  }
  ```
</CodeGroup>

## Manual setup: OpenTelemetry

### Python: automatic instrumentation

### Install

```bash theme={null}
pip install anthropic openinference-instrumentation-anthropic \
            opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
```

### Setup

```python theme={null}
import os
from anthropic import Anthropic
from openinference.instrumentation.anthropic import AnthropicInstrumentor
from openinference.instrumentation import using_attributes
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://otel.agnost.ai"
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = "X-Agnost-Org-ID=<your-org-id>"

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(provider)
AnthropicInstrumentor().instrument(tracer_provider=provider)

client = Anthropic()
with using_attributes(session_id="sess-123", user_id="u-42"):
    client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hi"}],
    )
```

Tool-use blocks are unpacked. You get `llm.input_messages.*`, `llm.output_messages.*`, `tool.name`, `tool.parameters`, and `llm.token_count.{prompt,completion}`.

### Alternative

The Traceloop alternative (`opentelemetry-instrumentation-anthropic`) emits `gen_ai.*` and `traceloop.*`: also recognized by Agnost AI.

### Verify

Run one `client.messages.create` call, then open **Events** in Agnost AI. Confirm message and tool-use attributes appear as expected.

### Troubleshooting

* Confirm `AnthropicInstrumentor().instrument(...)` runs before Anthropic calls.
* Confirm `OTEL_EXPORTER_OTLP_HEADERS` contains `X-Agnost-Org-ID=<your-org-id>`.
* Confirm `using_attributes` wraps the call you want grouped.

### References

* [Enable OpenTelemetry export](https://github.com/Arize-ai/openinference/tree/main/python/instrumentation/openinference-instrumentation-anthropic)
* [Add custom metadata](https://arize.com/docs/phoenix/tracing/how-to-tracing/add-metadata/customize-spans)

### TypeScript: manual instrumentation

Install the OpenTelemetry packages alongside your existing Anthropic SDK:

```bash theme={null}
npm install @opentelemetry/api @opentelemetry/sdk-node \
  @opentelemetry/exporter-trace-otlp-proto
```

Start OpenTelemetry before creating the Anthropic client, then wrap the call you
want to track:

```typescript theme={null}
import Anthropic from '@anthropic-ai/sdk';
import { SpanStatusCode, trace } from '@opentelemetry/api';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'https://otel.agnost.ai/v1/traces',
    headers: { 'X-Agnost-Org-ID': process.env.AGNOST_ORG_ID! },
  }),
});
await sdk.start();

const client = new Anthropic();
const tracer = trace.getTracer('anthropic-app');

const response = await tracer.startActiveSpan('anthropic.messages.create', async (span) => {
  span.setAttribute('gen_ai.operation.name', 'chat');
  span.setAttribute('gen_ai.provider.name', 'anthropic');
  span.setAttribute('gen_ai.request.model', 'claude-sonnet-4-5');
  span.setAttribute('gen_ai.conversation.id', 'conversation-123');
  span.setAttribute('user.id', 'user-42');
  span.setAttribute('input.value', prompt);

  try {
    const message = await client.messages.create({
      model: 'claude-sonnet-4-5',
      max_tokens: 512,
      messages: [{ role: 'user', content: prompt }],
    });
    const output = message.content
      .filter((block) => block.type === 'text')
      .map((block) => block.text)
      .join('');
    span.setAttribute('output.value', output);
    return message;
  } catch (error) {
    span.recordException(error as Error);
    span.setStatus({ code: SpanStatusCode.ERROR });
    throw error;
  } finally {
    span.end();
  }
});

await sdk.shutdown();
```

Run one message call, then open **Events** in Agnost AI and confirm the input,
output, model, user, and conversation fields are present.

## Next steps

* [Conversations](/using-conversations): review the complete Anthropic interaction.
* [Events](/using-events): inspect the SDK or OpenTelemetry records.
* [Intents](/using-intents): organize production conversations by what users wanted.
