Skip to main content
Bedrock is the widest surface the SDK covers, because Bedrock is really two APIs over dozens of model families with different response shapes. The SDK normalizes all of them. Instrumented calls: In JavaScript the SDK wraps client.send(command) and dispatches on the command constructor: ConverseCommand, ConverseStreamCommand, InvokeModelCommand, InvokeModelWithResponseStreamCommand.

Install

Wrap and call

The wrapper is installed on the boto3 client object itself, so any code holding that client is instrumented. wrap() is idempotent.

InvokeModel

invoke_model needs special handling and gets it. AWS returns the response body as a single-use stream. Reading it to extract usage would leave your code with an exhausted body. The SDK consumes the body once, parses the JSON, extracts usage, then re-wraps the bytes as a fresh StreamingBody. Your code reads response["body"].read() exactly as before.

Response-shape families

InvokeModel has no single usage schema. Each model family reports differently. The SDK dispatches on modelId across seven families, verified against 39 models in eu-west-1: Converse is simpler: three shape families, all handled by one adapter. Standard (inputTokens / outputTokens, 33 models), cache-read-only (Claude Opus 4.7), and full-cache (Claude Sonnet 4.5/4.6, Haiku 4.5, Opus 4.5/4.6).

Streaming

Both streaming methods are instrumented. Usage arrives in the terminal metadata chunk of the event stream, and the SDK emits once the stream is exhausted.

Per-call override

Bedrock’s request shape is validated strictly by AWS, so the override rides on the command object rather than inside the request body.

What gets captured

On Converse, tool_calls counts only Bedrock’s own server-side tool invocations, which is the one number the API reports. Client-side tool calls you execute yourself are not counted — meter those on your own side if you bill on them. The provider property on each event is derived from modelId, so a single Bedrock client produces events tagged anthropic, amazon, meta, mistral, cohere, openai, qwen, google, minimax, nvidia, or zai. That makes provider a useful charge filter when you resell several model families through one Bedrock account.
Combine the provider and model properties with charges with filters to price Nova and Claude differently off the same billable metric.

Pricing

In price mode, Bedrock is priced from the AWS Bedrock Price List Bulk API, parsed per region. Region comes from the model id prefix when present (eu., us.), otherwise from bedrock_default_region / bedrockDefaultRegion, which defaults to us-east-1.
Set your default region. If your model ids carry no region prefix and you leave bedrock_default_region at us-east-1 while calling eu-west-1, you will price against the wrong region’s rates.

Known limits

AWS’s public bulk price data has a gap. It lists Titan, Llama, Mistral, Cohere, and older Claude models, but at time of writing not the current Claude 3.5/3.7/4 models. Bedrock calls for models absent from AWS’s data fall back to token-count events and fire on_error with a PricingUnavailableError. Native Anthropic clients are priced through OpenRouter and unaffected. Legacy Mistral models report no usage at all through InvokeModel. Mistral 7B, Mixtral 8x7B, and Mistral Large 24.02 return no token counts, so the SDK logs a warning and emits nothing — there is nothing to bill on. Use Converse with those models, or a current model, if you need to meter them. Only Converse and InvokeModel are instrumented, in both their streaming and non-streaming forms. Two other billable Bedrock Runtime operations pass through unmetered: start_async_invoke (asynchronous inference) and apply_guardrail. If you use either, build a CanonicalUsage yourself and pass it to sdk.emit().

Next steps

Configuration reference

Every config knob, in both SDKs.

Charges with filters

Price each model family off one billable metric.