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

# Amazon Bedrock

> Capture Anthropic models on Bedrock automatically with the Python SDK, or send other Bedrock traffic to Moda through manual capture or the HTTP API.

Moda captures Anthropic models on Amazon Bedrock automatically in Python when you call them through the `AnthropicBedrock` client from the `anthropic` package. Calls made through `boto3` (`invoke_model`, `converse`) and all Bedrock calls from Node.js are not auto-instrumented — use manual capture, the HTTP API, or OpenTelemetry for those paths.

## Support matrix

| Path | Support |
| - | - |
| Python — `AnthropicBedrock` client (`anthropic` package) | Supported: auto-instrumented by `moda-ai` |
| Python — `boto3` (`invoke_model`, `converse`) | Not auto-instrumented: use the [HTTP API](/ingestion/http-api) or [OpenTelemetry](/ingestion/opentelemetry) |
| Node.js — any Bedrock client | Not auto-instrumented: use `Moda.withLLMCall`, the [HTTP API](/ingestion/http-api), or [OpenTelemetry](/ingestion/opentelemetry) |

## Python: AnthropicBedrock client

### Prerequisites

* Python 3.10 or later
* The `moda-ai` and `anthropic` packages
* AWS credentials with Bedrock model access (environment variables, shared credentials file, or an IAM role)
* A Moda API key, created at **Settings → Ingestion keys** (see [Authentication](/administration/authentication))

<Steps>
  <Step title="Install the packages">
    ```bash theme={"dark"}
    pip install moda-ai anthropic
    ```
  </Step>

  <Step title="Initialize Moda before creating the client">
    `moda.init()` is synchronous. Call it before you construct the `AnthropicBedrock` client.

    ```python app.py theme={"dark"}
    import os

    import moda
    from anthropic import AnthropicBedrock

    moda.init(os.environ["MODA_API_KEY"])

    client = AnthropicBedrock(aws_region="us-east-1")

    moda.conversation_id = "session_8f2a"
    moda.user_id = "user_1042"

    response = client.messages.create(
        model="us.anthropic.claude-sonnet-4-20250514-v1:0",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}],
    )
    print(response.content[0].text)

    moda.flush()
    ```

    The examples on this page use a US cross-region inference profile ID; substitute the model or inference-profile ID that is enabled for your AWS account and region.

    Streaming through `client.messages.stream(...)` and async clients are captured the same way.
  </Step>

  <Step title="Verify in the dashboard">
    Open **Traces** in the [dashboard](https://moda.dev/dashboard). Within minutes you should see a trace with ID `session_8f2a` containing the user message and the assistant response, with the model name and token counts attached.
  </Step>
</Steps>

## boto3 and Node.js

The Moda SDKs do not auto-instrument `boto3` or any Node.js Bedrock client. Pick one of the following.

### Node.js: manual capture with `Moda.withLLMCall`

If you already use the Moda SDK for Node.js, wrap the Bedrock call and report the request and response yourself:

```typescript app.ts theme={"dark"}
import { Moda } from 'moda-ai';
import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime';

await Moda.init(process.env.MODA_API_KEY!);

const bedrock = new BedrockRuntimeClient({ region: 'us-east-1' });
const model = 'us.anthropic.claude-sonnet-4-20250514-v1:0';

const reply = await Moda.withLLMCall({ vendor: 'bedrock', type: 'chat' }, async ({ span }) => {
  span.reportRequest({
    model,
    messages: [{ role: 'user', content: 'Hello!' }],
    conversationId: 'session_8f2a',
    userId: 'user_1042',
  });

  const response = await bedrock.send(new ConverseCommand({
    modelId: model,
    messages: [{ role: 'user', content: [{ text: 'Hello!' }] }],
  }));

  const text = response.output?.message?.content?.[0]?.text ?? '';
  span.reportResponse({
    usage: {
      input_tokens: response.usage?.inputTokens,
      output_tokens: response.usage?.outputTokens,
    },
    completions: [{ role: 'assistant', content: text }],
  });
  return text;
});

console.log(reply);
await Moda.flush();
```

Errors thrown inside the callback propagate to your code after the span is recorded. See [the Node.js SDK page](/ingestion/node) for the full `withLLMCall` reference.

### Any language: HTTP API

Make the Bedrock call as usual, then post the messages to `POST /v1/ingest`:

<CodeGroup>
  ```python bedrock_ingest.py theme={"dark"}
  import os

  import boto3
  import requests

  bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
  user_message = "Hello!"

  response = bedrock.converse(
      modelId="us.anthropic.claude-sonnet-4-20250514-v1:0",
      messages=[{"role": "user", "content": [{"text": user_message}]}],
  )
  assistant_message = response["output"]["message"]["content"][0]["text"]
  usage = response.get("usage", {})

  resp = requests.post(
      "https://moda-ingest.modas.workers.dev/v1/ingest",
      headers={
          "Authorization": f"Bearer {os.environ['MODA_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={
          "events": [
              {
                  "conversation_id": "session_8f2a",
                  "user_id": "user_1042",
                  "role": "user",
                  "message": user_message,
              },
              {
                  "conversation_id": "session_8f2a",
                  "user_id": "user_1042",
                  "role": "assistant",
                  "message": assistant_message,
                  "model": "us.anthropic.claude-sonnet-4-20250514-v1:0",
                  "provider": "bedrock",
                  "input_tokens": usage.get("inputTokens"),
                  "output_tokens": usage.get("outputTokens"),
              },
          ]
      },
      timeout=10,
  )
  print(resp.json())
  ```

  ```typescript bedrock-ingest.ts theme={"dark"}
  import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime';

  const bedrock = new BedrockRuntimeClient({ region: 'us-east-1' });
  const userMessage = 'Hello!';

  const response = await bedrock.send(new ConverseCommand({
    modelId: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
    messages: [{ role: 'user', content: [{ text: userMessage }] }],
  }));
  const assistantMessage = response.output?.message?.content?.[0]?.text ?? '';

  const res = await fetch('https://moda-ingest.modas.workers.dev/v1/ingest', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.MODA_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      events: [
        {
          conversation_id: 'session_8f2a',
          user_id: 'user_1042',
          role: 'user',
          message: userMessage,
        },
        {
          conversation_id: 'session_8f2a',
          user_id: 'user_1042',
          role: 'assistant',
          message: assistantMessage,
          model: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
          provider: 'bedrock',
          input_tokens: response.usage?.inputTokens,
          output_tokens: response.usage?.outputTokens,
        },
      ],
    }),
  });
  console.log(await res.json());
  ```
</CodeGroup>

A successful request returns:

```json theme={"dark"}
{ "success": true, "count": 2, "requestId": "5b2f8a3e-1c9d-4e7a-9f0b-2d6c8e4a1b3f" }
```

The full event schema and limits are on the [HTTP API page](/ingestion/http-api).

### OpenTelemetry

If your service already exports OpenTelemetry spans, point them at Moda's OTLP endpoint and add GenAI attributes to your Bedrock spans — see [OpenTelemetry](/ingestion/opentelemetry).

<Note>
  In Python, `moda.init()` also activates the `opentelemetry-instrumentation-bedrock` package for `boto3` when both are installed. That package is third-party and is not bundled with `moda-ai`; install it separately if you want to try this path.
</Note>

## Troubleshooting

| Symptom | Fix |
| - | - |
| `boto3` calls do not appear | Expected — `boto3` is not auto-instrumented. Use manual capture, the HTTP API, or OpenTelemetry as shown above. |
| Node.js Bedrock calls do not appear | Expected — the Node.js SDK has no Bedrock instrumentation. Use `Moda.withLLMCall` or the HTTP API. |
| `AnthropicBedrock` calls do not appear (Python) | Call `moda.init()` before constructing the client, and `moda.flush()` before the process exits. |
| Token counts missing on HTTP API events | `/v1/ingest` only stores tokens you send. Pass `input_tokens` and `output_tokens` from the Bedrock response `usage` object. |

## Next steps

* [Moda SDK for Python](/ingestion/python) — init options, context APIs, and flush semantics.
* [HTTP API](/ingestion/http-api) — full event schema, limits, and error envelope.
* [OpenTelemetry](/ingestion/opentelemetry) — send OTLP spans from an existing tracing setup.
* [Anthropic](/ingestion/providers/anthropic) — auto-instrumentation for the Anthropic API outside Bedrock.


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