Amazon Bedrock's model invocation logging captures a rich record for every call on the bedrock-runtime endpoint: timestamps, model IDs, token counts, the caller's IAM identity, and the full request and response bodies. Almost every field is populated by Bedrock itself. Exactly one is yours: requestMetadata, a set of caller-supplied key-value tags you attach to an inference call, which Bedrock preserves in the invocation log record.
That single field is the hook for per-call cost and usage attribution. IAM identity alone often is not enough — many architectures funnel all Claude traffic through one service role, so identity.arn tells you "the chatbot backend called," not "the refunds team's summarization feature called." Request metadata carries the application-level context that IAM cannot: team, feature, tenant, environment, experiment arm.
Attaching the tags
The field rides along on bedrock-runtime inference calls (this is the legacy surface — Converse/InvokeModel via boto3, not the AnthropicBedrockMantle Messages API client). A Converse call with attribution tags looks like this:
import boto3
client = boto3.client("bedrock-runtime", region_name="us-east-1")
resp = client.converse(
modelId="anthropic.claude-haiku-4-5-20251001-v1:0",
messages=[{"role": "user", "content": [{"text": "Summarize this ticket..."}]}],
requestMetadata={
"team": "support-tools",
"feature": "ticket-summary",
"env": "prod",
},
)
Bedrock writes these keys and values into the log record's requestMetadata field verbatim, alongside input.inputTokenCount and output.outputTokenCount. Two prerequisites: model invocation logging must be enabled (it is off by default), and if you want to query in near-real time, CloudWatch Logs should be among the destinations.
Querying by tag in CloudWatch Logs Insights
AWS documents a Logs Insights pattern that groups token usage by identity.arn to break usage down per IAM principal without any request metadata. The same shape works against your own tags — for example, a per-team token rollup (illustrative; adjust field paths to your records):
fields requestMetadata.team as team,
input.inputTokenCount as in_tok,
output.outputTokenCount as out_tok
| stats sum(in_tok), sum(out_tok) by team
Swap team for feature or env, add a filter clause for one model ID, or group by both tag and modelId to build a chargeback matrix. Because token counts are right there in the record, you can multiply by list prices in a downstream spreadsheet or FinOps tool without touching billing exports. For S3-destination logs, the same aggregation runs in Athena over the gzipped JSON batch files.
Design rules for a tag scheme that survives contact with finance
- Standardize keys centrally.
team,Team, andteam_nameare three different fields to a query engine. Publish a small allowed-key list and enforce it in your shared client wrapper. - Low cardinality wins. Tags like
request_uuidadd nothing (the record already hasrequestId) and make aggregations useless. Tag with the dimensions you will actually bill or alert on. - Never put sensitive values in metadata. Tags land in invocation logs readable by anyone with log access — and on the current bedrock-mantle surface, AWS explicitly warns that customer-supplied metadata on
CreateInferencecalls is logged verbatim in CloudTrail: no secrets, credentials, or sensitive values. Treat metadata as public-within-your-org. - Fall back to
identity.arn. Untagged calls still attribute to a principal. If each team uses its own role, IAM-level grouping is your safety net for code that predates the tag scheme.
Where this pattern does not reach
Two boundaries to keep in mind. First, invocation logging — and therefore this whole pattern — covers only the bedrock-runtime endpoint; calls on the current bedrock-mantle surface are not captured. On that surface, per-project attribution comes instead from the Project dimension in the AWS/BedrockMantle CloudWatch namespace (see the namespace guide). Second, requestMetadata is an observability feature, not a billing one — it never appears on your AWS invoice. For invoice-level splits, pair it with cost allocation tags and a broader tagging strategy; requestMetadata fills in the per-call, per-feature resolution those coarser tools lack.
Where to go next
See the full ModelInvocationLog schema walkthrough for every field in the record, or logging for FinOps for turning these queries into a chargeback process.