In JavaScript the SDK wraps
client.send(command) and dispatches on the command constructor: ConverseCommand, ConverseStreamCommand, InvokeModelCommand, InvokeModelWithResponseStreamCommand.
Install
Wrap and call
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 terminalmetadata 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.
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.
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 fireon_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.