
Amazon Bedrock Cost Attribution: A Prescriptive Guide
Picking the right mix of cost tracking approaches is often the hardest part of scaling Amazon Bedrock. This guide shows which approach fits your team's requirements, whether that's per-application cost, per-user and per-team cost, per-request granularity, or hard enforcement, and which anti-patterns to avoid
Amazon Bedrock gives you several ways to track and cap cost: application inference profiles, projects, IAM principal attribution, per-request metadata, and a gateway in front of all of it. Teams tend to arrive with the same question: which of these do we actually need, in what order, and do we need all of them? That depends on the outcome you're after. Putting per-team cost on the invoice is a different problem from counting tokens per developer, and both are different from stopping a runaway job before the money is gone.This guide takes a prescriptive, scenario-driven approach. Rather than explaining every feature in isolation, we start with the default recommendation that works for 80% of organizations, then show you how to escalate as your requirements grow — and which anti-patterns to avoid along the way.
Start Here: Choose by the Question You're Answering
Cost tracking on Amazon Bedrock is a layered model, not a single choice. Start with attribution to understand how your users and teams consume Bedrock, then use those patterns to introduce controls and progressive friction that encourage the right behavior. Add each new layer only when a requirement calls for it. The first table below maps goals to layers, and the second shows combinations that typically suit different kinds of organizations.By the question you're answering
if your goal is ... | Layer | Section |
|---|---|---|
Per-application or per-workload cost | Foundation | Application Inference Profiles (bedrock-runtime) or Projects (bedrock-mantle) |
Per-user or per-team cost on your bill | Layer 2 | IAM Principal Attribution |
Per-prompt token usage, sliced by any dimension | Layer 3 | Request Metadata Tagging + model invocation logs |
Actively stop or throttle spend before it happens | Layer 4 | Custom Gateway |
By the organization you are
Scenario | Recommended Stack |
|---|---|
Small team, just getting started | 1 AIP per team + IAM principal attribution + CloudWatch alarms on spend |
Multi-team, need chargeback | AIPs per team/app + IAM principal attribution + per-request metadata for operational detail |
Claude Code / developer rollout (100+) | LLM gateway (LiteLLM or custom, with per-key budgets) + IAM session tags + per-request metadata + model invocation logs |
Multi-tenant SaaS | LLM gateway (off-the-shelf or custom) + per-request metadata for tenant-level tracking + AIPs for aggregate billing per tenant tier |
| |
For most organizations, the Foundation layer alone answers the question. Each section below states the requirement it solves, the approach, the limitations you'll hit, and when to escalate to the next layer.
Foundation — Per-Application Cost Buckets: Application Inference Profiles or Projects
Most cost questions come down to which application or team is spending the money. Bedrock answers that on the invoice itself: you create a cost bucket, tag it, and the spend shows up in Cost Explorer and CUR 2.0 under that tag, with no log pipeline to run and no cost estimation on your side. That is why it comes first. There are two mechanisms, and which one applies depends on the endpoint you call:
On
bedrock-runtime (InvokeModel, Converse) → Use Application Inference Profiles . Create a profile per application/team, attach cost allocation tags, swap the model ARN for the profile ARN. Tagged costs appear in Cost Explorer and CUR 2.0 natively. As documented in Track, allocate, and manage your generative AI cost and usage with Amazon Bedrock , SCPs can mandate that all traffic flows through tagged profiles. The multi-tenant cost management pattern shows how to add graduated CloudWatch alarm levels on top.On
bedrock-mantle (Responses, Chat Completions, Anthropic Messages) → Use Projects . A single project spans all models — no per-model profile needed. Pass the project ID as a header and tagged costs flow to billing. Up to 1,000 projects per account. This is the natural fit for Claude Code deployments and teams using OpenAI-compatible SDKs.The practical trade-off is resource count: application inference profiles are model-specific, so the number you manage grows with every model you use, whereas a single project on
bedrock-mantle can span many models at once. If you're on bedrock-runtime , profiles are your only option; if you're on bedrock-mantle and want one construct across models, projects are the simpler choice.Limitations: Both methods produce aggregated cost per day per usage-type — no per-request rows. Neither provides enforcement (no "stop at a set limit"). AIPs don't scale to thousands of individual developer profiles. Projects don't cover
bedrock-runtime features (Agents, Knowledge Bases, Guardrails).Recommended when: You need cost allocation by team AND application for finance/chargeback, your teams are disciplined, and you don't yet need hard spending caps.
Layer 2 — Per-User & Per-Team Cost: IAM Principal Attribution
Once you have per-application cost buckets, the next question is usually "but which user or team inside that application is driving the cost?" Amazon Bedrock answers it for free: it automatically records the IAM principal — user or role — for every inference call on
bedrock-runtime , and that identity flows into AWS Cost Explorer and CUR 2.0 with no application changes: no profiles to create, no headers to pass, no metadata to attach.To add dimensional context such as team, department, or cost center, tag your IAM users and roles with standard AWS tags and activate them as cost allocation tags in the Billing console. Tagged data becomes available in billing the following day.
Where many developers share a single gateway role, session tags applied during
AssumeRole preserve per-user identity through that role. The pattern is to assume the role per user, cache the resulting credentials for the session lifetime, and carry the user identity as a session tag, a RoleSessionName , or both.Limitations: Tagged data appears in billing roughly 24 hours later, and cost allocation tags must be activated in the management account. CUR files grow, since each principal adds a row per usage-type. Most importantly, this layer provides visibility only — it cannot enforce budgets or throttle expensive calls.
Recommended when: You have mature IAM governance, you trust developers with direct model access, and your primary need is after-the-fact chargeback and reporting rather than active control.
Layer 3 — Per-Request Granularity: Request Metadata Tagging
The billing-level approaches (IAM attribution, AIPs, Projects) all aggregate to daily totals. If you need to know "how many tokens did developer X use on experiment Y at 2:30pm on Tuesday?" — you need per-request metadata tagging .This works by attaching key-value tags to each individual inference call. The tags land in your model invocation logs (S3 or CloudWatch Logs), not in CUR. You then query the logs with CloudWatch Logs Insights to produce per-user, per-model token totals:
fields requestMetadata.user as user, modelId, input.inputTokenCount as inTokens, output.outputTokenCount as outTokens| stats sum(inTokens) as totalInput, sum(outTokens) as totalOutput, count() as calls by user, modelIdRequest-level attribution is supported on InvokeModel, InvokeModelWithResponseStream, Converse, and ConverseStream. The multi-tenant cost tracking blog demonstrates how passing tenant-specific identifiers transforms standard invocation logs into rich analytical datasets.
Keep billing tags stable and low-cardinality (team, environment, application), reserve high-cardinality values (session ID, trace ID, experiment ID) for request metadata, and set that metadata in a single shared layer all traffic passes through rather than relying on individual developers. See the best practices guidance for detail.
Limitations: This data never touches billing reports — you must convert token counts to cost yourself, and that figure is only an estimate: it does not reflect discounts, commitments, batch pricing, or provisioned throughput. Application code must be modified. There's no enforcement. You need Model Invocation Logging enabled (additional S3/CloudWatch cost) and an analytics pipeline (Athena/QuickSight) to make the data useful.
Recommended when: You need operational analytics — A/B experiment attribution, per-developer tracking for coaching, multi-tenant SaaS metering — and you're combining it with a billing-level method for finance.
Layer 4 — Hard Enforcement: LLM Gateway (Off-the-Shelf or Custom)
Everything so far is attribution-only; none of it can stop a runaway workload before the spend happens. Hard enforcement — denying a request before it reaches Bedrock — requires a gateway, and the first decision is buy vs. build.
Buy / adopt (start here for most teams). A purpose-built gateway like LiteLLM already provides virtual keys per user/team, hard budget caps, rate limiting, and per-key spend tracking in front of Amazon Bedrock, giving you enforcement in days rather than weeks. None of that depends on the wire format your clients speak: LiteLLM exposes OpenAI-compatible routes, Anthropic's
/v1/messages , and pass-through routes that keep native Bedrock request shapes, and the same budgets and keys apply across all of them. Kong AI Gateway does the same from an API-gateway angle, adding cost-based budget caps per consumer group, semantic caching, and prompt compression — see Unlock advanced AI control with Kong AI Gateway and Amazon Bedrock .
If your rollout is specifically Claude Code and Claude Desktop, the Claude apps gateway for AWS is the purpose-built option: a self-hosted container that authenticates developers against your IdP instead of putting AWS credentials on their machines, routes all inference to Bedrock through a single IAM role, and reports per-user usage — the AWS reference deployment ships an admin console for per-user spend limits and model access.The one caveat across all of them: they typically call Bedrock through a single service role, so use session tags /
RoleSessionName to preserve per-user identity in native billing.Build. When you need deeper AWS-native integration, you don't have to start from an empty Lambda. AgentCore Gateway inference provider targets give you a managed enforcement point in front of Bedrock (or any provider endpoint): you declare which models are reachable — including glob patterns such as
anthropic.claude-opus-* — set per-model token limits, rewrite request paths, and hold the upstream credential in the gateway instead of on the client. On top of that you can layer rate limits per caller, target, or tool , which reject over-quota requests with a 429. Where you need budget logic those managed controls don't express — cumulative month-to-date spend per team, for instance — build a serverless proxy (API Gateway + Lambda + DynamoDB) that checks each request against per-user/per-team budgets and returns 429 when exceeded. Rather than reinvent it, start from the published references: Guidance for Tracking and Managing Costs on Amazon Bedrock , the Multi-Tenant Generative AI Gateway , the proactive cost management series ( Part 1 / Part 2 ), and Dynatrace's AI gateway architecture .Either way, use SCPs to deny direct Bedrock access outside the gateway role, making it the only call path — and the single place where per-request metadata is stamped automatically. Beyond budgets, a gateway is also where model gating, loop protection for agentic tool-use, and cache-aware cost accounting live.
Limitations: A gateway adds latency, is a single point of failure (its outage blocks all AI access), needs careful streaming design, and doesn't feed CUR natively. If it re-assumes an IAM role per user, cache those credentials for the session lifetime — calling
sts:AssumeRole per request will exceed STS quotas under load.Recommended when: You're rolling out Bedrock to 100–1,000+ developers (especially Claude Code), you've had or fear a runaway spend incident, or compliance requires provable budget controls.
Decision Flowchart

Anti-Patterns
1. Creating 1,000 Application Inference Profiles for per-developer tracking.
AIPs are designed for team/application granularity, not individual developer attribution. If you need per-developer visibility, IAM principal attribution gives it to you automatically — or use per-request metadata for per-call detail. Don't create an AIP explosion that hits service quotas and becomes an admin nightmare.
2. Using per-request metadata as your billing source of truth.
Request metadata lives in invocation logs, not in CUR. The FAQ is explicit : "the computed figure is an estimate — it does not reflect discounts, commitments, batch pricing, free tier, or provisioned throughput." Use native billing methods (IAM attribution, AIPs, Projects) for finance-grade cost allocation. Use metadata for operational analytics only.
3. Relying on developer discipline for tagging.
The best practices documentation warns: "Per-call tagging mechanisms (request metadata, session tags) are opt-in. Bedrock does not reject calls that omit them." For billing-level attribution, you can enforce tagging across the organization with Service Control Policies that deny any invocation not made through a tagged Application Inference Profile Enforce Amazon Bedrock Usage Through Tagged Application Inference Profiles Using SCPs. These SCPs block bad requests but don't fix them, so developers still have to react to the denied call and correct it. For per-request metadata, which SCPs can't enforce, stamp tags automatically in a shared client wrapper or LLM gateway.
4. Putting high-cardinality values in cost allocation tags.
Session IDs, timestamps, or conversation IDs as resource/principal tags create a cardinality explosion in CUR and Cost Explorer. These values belong in request metadata (which lands in logs, not billing). Keep cost allocation tags stable and low-cardinality: team, environment, application, cost center.
Authors
- Muhammad Zain Akram - AWS Solutions Architect - https://www.linkedin.com/in/muhammad-zain-akram/
- Rahul Kulkarni - AWS Specialist AI Solutions Architect - https://www.linkedin.com/in/rahul-kulkarni-awsrk/
- Yago Tobio Souto - AWS Solutions Architect - https://www.linkedin.com/in/yago-tobio-souto/
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article