Search
CLD Tutorial

AWS Cost Explorer Setup: Track AI Spend in 13 Steps [2026]

Yusuf Demir
Yusuf DemirCloud & Software Reporter
23 min read
AWS Cost Explorer Setup: Track AI Spend in 13 Steps [2026]

AWS Cost Explorer just became a lot more useful for the one line item nobody can forecast anymore: AI spend. Amazon rolled out a free FinOps Agent on Bedrock in June 2026 and wired Amazon Q directly into Cost Explorer, so engineers can type a plain English question like “why did my Bedrock bill jump last week” and get an answer instead of a spreadsheet. Google followed with a FinOps Explainability Agent and Spend Caps for Vertex AI and AI Studio. Both moves point at the same problem: cloud bills built around inference calls and GPU hours move faster than the humans watching them.

The sections below cover through setting up AWS Cost Explorer from a cold start, tagging AI workloads so they show up correctly, wiring in budgets and anomaly detection, exporting billing data to the new FOCUS 1.4 spec, and building a working Python tracker that pulls cost data through the Cost Explorer API and posts alerts to Slack. By the end you will have a repeatable AI spend monitoring pipeline running on a schedule, not a one time dashboard screenshot.

The timing matters. Flexera’s 2025 State of the Cloud report found that “84% of organizations identify managing cloud spend as a top cloud challenge”. A separate Flexera figure from the same report put average budget overruns at around 17%, found that 59% of organizations now run dedicated cost optimization teams, and estimated that roughly 27% of infrastructure and platform cloud spend goes to waste. The FinOps Foundation’s 2025 State of FinOps report adds the AI specific piece: “63% of respondents report that their organizations manage AI spending, up from 31% the previous year”. That is a doubling in twelve months, and it is exactly why Cost Explorer, Budgets, and Cost Anomaly Detection now treat Bedrock and SageMaker as first class citizens instead of afterthoughts.

Google · Preferred Sources

Don't miss new tech stories on Google

Add TrendinTech once in the Google app and our stories appear in your news suggestions.

Add Now

Why AI Workloads Break Traditional Cost Monitoring

Regular cloud cost monitoring was built around fairly predictable shapes. An EC2 fleet grows or shrinks with traffic, an RDS instance bills a flat hourly rate, and month over month changes usually trace back to a deploy, a traffic spike, or someone forgetting to shut down a test environment. AI workloads do not follow that pattern. A single fine tuning run on SageMaker can burn through more GPU hours in six hours than a web server racks up in a month, and a Bedrock integration that gets linked to a popular feature can see its token volume triple overnight with zero code changes on your end, just because more users started hitting that one endpoint.

That volatility is exactly why Amazon rebuilt parts of Cost Explorer around AI use cases instead of treating Bedrock and SageMaker like any other line item. Inference pricing is usage based down to the token, training jobs bill by the second across potentially dozens of GPU instances at once, and a lot of that spend originates from application code that a finance team has never seen and would not recognize if they did. Static monthly reports miss these swings entirely, which is the gap this tutorial closes with daily granularity, tag based attribution, and automated anomaly checks instead of a once a month spreadsheet review.

There is also an organizational angle here. When 63% of organizations now manage AI spending as its own category, according to the FinOps Foundation, that usually means a new stakeholder, typically an ML platform lead or a product engineering manager, is suddenly expected to answer for a cost center that used to roll up quietly inside general cloud infrastructure. Tagging and dashboards are not just technical hygiene at that point. They are what lets that person answer a hard question in a budget meeting without digging through raw CSV exports first.

What You Need Before You Start

You do not need an enterprise support plan or a dedicated FinOps team to follow this guide. You do need an AWS account with billing access, a terminal, and roughly 90 minutes. The table below lists everything used in this walkthrough along with the versions confirmed working as of October 2026.

RequirementVersion or TierNotes
AWS accountStandard or Organizations payer accountBilling console access, Cost Explorer is free to enable
IAM user or roleAdmin or scoped FinOps policyNeeds ce:*, budgets:*, cur:* permissions, covered in Step 1
AWS CLILatest v2 releaseInstall or update with the official AWS installer
Python3.11 or newerUsed for the boto3 tracker script
boto3Latest release via pipRun pip install upgrade boto3 before Step 9
S3 bucketAny region matching your billing preferenceDestination for the Cost and Usage Report export
Slack workspaceOptional, incoming webhook enabledUsed for the alerting step, skip if you prefer email only

One thing to decide up front. this guide assumes you are tracking spend inside a single payer account, with AI workloads running through Amazon Bedrock, SageMaker, or EC2 GPU instances. If you run workloads across multiple linked accounts, the same steps apply. You will just add LINKED_ACCOUNT as a grouping dimension in a few places, which gets called out when it comes up.

Step 1: Lock Down IAM Permissions for Cost Explorer and Budgets

Cost Explorer, Budgets, and Cost and Usage Reports each have their own IAM actions, and the default AWS managed policies are either too broad or missing pieces entirely. Create a scoped policy before touching the console so you are not debugging AccessDenied errors later in the tutorial.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CostExplorerRead",
      "Effect": "Allow",
      "Action": [
        "ce:GetCostAndUsage",
        "ce:GetCostForecast",
        "ce:GetDimensionValues",
        "ce:GetTags",
        "ce:GetAnomalies",
        "ce:CreateAnomalyMonitor",
        "ce:CreateAnomalySubscription",
        "ce:UpdateCostAllocationTagsStatus",
        "ce:ListCostAllocationTags"
      ],
      "Resource": "*"
    },
    {
      "Sid": "BudgetsManage",
      "Effect": "Allow",
      "Action": [
        "budgets:ViewBudget",
        "budgets:ModifyBudget"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CurReportAccess",
      "Effect": "Allow",
      "Action": [
        "cur:PutReportDefinition",
        "cur:DescribeReportDefinitions"
      ],
      "Resource": "*"
    }
  ]
}

Attach this policy to the IAM user or role you will use for the rest of the tutorial. If you are running the boto3 script in Step 9 from a Lambda function or EC2 instance later, attach the same policy to that execution role instead of hardcoding long lived credentials.

Step 2: Turn On Cost Explorer and Set Your Baseline View

Log into the Billing and Cost Management console and open Cost Explorer from the left navigation. New accounts need to enable it once, after which data appears within about 24 hours. Set the date range to the last 3 months and group by Service so you get a baseline view of where money is already going before you start slicing by AI workload.

This baseline matters more than people expect. You cannot tell Cost Explorer to alert you when Bedrock costs look weird until you know what normal Bedrock spend looks like for your account. Spend five minutes here looking at daily granularity instead of monthly, since AI inference costs tend to spike around specific events like a product launch or a batch job, and monthly granularity smooths those spikes into noise.

Step 3: Activate Cost Allocation Tags for AI Workloads

Tags are the single biggest lever for accurate AI cost attribution, and they are also the step most teams skip, then regret. Cost allocation tags only apply going forward from the moment you activate them. They do not retroactively tag historical usage. Tag your Bedrock model invocations, SageMaker training jobs, and GPU EC2 instances with keys like team, project, and model-name before you need the breakdown, not after.

# Tag a SageMaker training job at creation time
aws sagemaker create-training-job \
  --training-job-name ai-spend-demo-job \
  --tags Key=team,Value=ml-platform Key=project,Value=finops-tutorial Key=model-name,Value=llama-finetune

# Activate the tags as cost allocation tags so they appear in Cost Explorer
aws ce update-cost-allocation-tags-status \
  --cost-allocation-tags-status TagKey=team,Status=Active TagKey=project,Status=Active TagKey=model-name,Status=Active

After activation, give it up to 24 hours before the tags show up as groupable dimensions in Cost Explorer. If you manage multiple AWS accounts through Organizations, activate these same tag keys from the management account so they propagate to every linked account.

Step 4: Ask Amazon Q Natural Language Cost Questions

Amazon embedded Amazon Q directly into Cost Explorer, which changes the workflow from clicking through filters to just asking. Open the Cost Explorer dashboard, find the Q prompt box near the top, and try a question like “why did my RDS costs spike last month” or “what is driving my Bedrock spend this week.” Amazon Q responds with a plain language explanation and usually surfaces the specific service, region, or linked account behind the change.

This is genuinely faster than manual filtering for anomaly triage, but treat it as a first pass, not a final answer. Amazon Q is reading the same underlying Cost Explorer data you are, so if your tags are not activated yet, its explanations will be less specific. Cross check anything budget critical against the raw grouped data in Step 5 before you report a number upward.

Using the Free Bedrock FinOps Agent for Deeper Cost Investigations

Amazon Q inside Cost Explorer is the quick-question tool. The Bedrock FinOps Agent, which Amazon launched for free in June 2026, is built for a longer conversation about a specific cost problem. Where Q answers a single question and moves on, the FinOps Agent keeps context across a back and forth session, so you can start with “what is my total Bedrock spend this month” and follow up with “break that down by model” and then “which of those models had the biggest week over week increase” without restating the scope each time.

Access it from the Bedrock console under the agents section, or through the same Cost Explorer entry point as Amazon Q depending on how your account’s console navigation is configured. The agent pulls from the same underlying Cost Explorer and Cost and Usage Report data as everything else So it benefits directly from the tagging work in Step 3. An untagged account gets vague, service level answers. A properly tagged account gets specific, project level answers, because the agent can only explain the attribution data that actually exists.

A useful way to use the FinOps Agent alongside the Python tracker from Step 10 is to treat the script as your quantitative first pass and the agent as your qualitative follow up. When the tracker flags a project jumping 62% day over day, take that exact finding into the FinOps Agent and ask it to explain the likely driver. In practice that often surfaces something the raw numbers alone do not, like a specific model version change or a batch job that ran twice because of a retry loop.

Step 5: Group and Filter Costs by Service, Tag, and Account

With tags live, build the view you will actually use day to day. In the console, group by Tag instead of Service, select the project key, and filter down to just Bedrock and SageMaker as services. Save this as a report so you are not rebuilding the filter stack every morning.

The same query works from the CLI, which matters once you move to automation in Step 9.

aws ce get-cost-and-usage \
  --time-period Start=2026-10-01,End=2026-10-19 \
  --granularity DAILY \
  --metrics "UnblendedCost" \
  --group-by Type=DIMENSION,Key=SERVICE Type=TAG,Key=project \
  --filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon Bedrock","Amazon SageMaker"]}}'

If you run across multiple linked accounts, add Type=DIMENSION,Key=LINKED_ACCOUNT to the group by list so a single spike does not get buried inside a consolidated total.

Step 6: Set Up AWS Budgets and Alerts for Bedrock and SageMaker

Cost Explorer tells you what already happened. AWS Budgets tells you before you blow past a number you care about. Create a cost budget scoped to your AI services with an alert at 80% of the monthly threshold and a second one at 100%, so you get a warning before the hard stop rather than finding out at close of month.

aws budgets create-budget \
  --account-id 123456789012 \
  --budget '{
    "BudgetName": "ai-services-monthly",
    "BudgetLimit": {"Amount": "5000", "Unit": "USD"},
    "BudgetType": "COST",
    "TimeUnit": "MONTHLY",
    "CostFilters": {"Service": ["Amazon Bedrock", "Amazon SageMaker"]}
  }' \
  --notifications-with-subscribers '[
    {
      "Notification": {"NotificationType": "ACTUAL", "ComparisonOperator": "GREATER_THAN", "Threshold": 80},
      "Subscribers": [{"SubscriptionType": "EMAIL", "Address": "[email protected]"}]
    }
  ]'

Replace the account ID and email address with your own, and confirm the SNS or email subscription when AWS sends the confirmation message. Budgets will not fire a single alert until that subscription is confirmed, which trips up a lot of first time setups.

Budgets alone only tells you when you have already crossed a line. Pair it with the Cost Forecast API to see where you are headed before the month closes, which is especially useful for a training job or a Bedrock integration that is still ramping up.

aws ce get-cost-forecast \
  --time-period Start=2026-10-20,End=2026-11-01 \
  --metric UNBLENDED_COST \
  --granularity DAILY \
  --filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon Bedrock","Amazon SageMaker"]}}'

Run this once a week alongside your budget check. If the forecasted total for the rest of the month already exceeds the remaining headroom in your budget, that is your cue to investigate before the automated alert even fires.

Step 7: Turn On Cost Anomaly Detection

Budgets catch threshold breaches. Cost Anomaly Detection catches the shape of spend changing even when you are still under budget, which is exactly what an AI workload runaway looks like in the first 48 hours. Create a monitor scoped to your AI services, then attach a subscription so you get notified the moment the model behind Anomaly Detection flags something outside the expected range.

aws ce create-anomaly-monitor \
  --anomaly-monitor '{
    "MonitorName": "bedrock-sagemaker-monitor",
    "MonitorType": "DIMENSIONAL",
    "MonitorDimension": "SERVICE"
  }'

aws ce create-anomaly-subscription \
  --anomaly-subscription '{
    "SubscriptionName": "ai-anomaly-alerts",
    "Threshold": 50,
    "Frequency": "DAILY",
    "MonitorArnList": ["arn:aws:ce::123456789012:anomalymonitor/REPLACE_WITH_MONITOR_ARN"],
    "Subscribers": [{"Address": "[email protected]", "Type": "EMAIL"}]
  }'

Grab the monitor ARN from the output of the first command before running the second. The threshold value is in dollars of estimated impact, not a percentage, so tune it to something meaningfully above your normal day to day noise for a workload this size.

Step 8: Export Billing Data With CUR 2.0 and the FOCUS 1.4 Spec

Cost Explorer is great for one account. The moment you run workloads across AWS, Azure, and Google Cloud, you need billing data in a shared format, which is exactly what the FinOps Foundation’s FOCUS specification solves. FOCUS 1.4, ratified June 4, 2026, standardizes cloud billing columns across providers and improves visibility into Kubernetes costs, though it still does not automatically allocate shared node costs down to individual namespaces or workloads, so you will still lean on tags for that layer. The next version, FOCUS 1.5, is on a roadmap targeting December 2026 with native AI token and unit economics tracking built in.

Set up a Cost and Usage Report export in FOCUS compatible format so you have this data ready once FOCUS 1.5 lands.

aws cur put-report-definition \
  --report-definition '{
    "ReportName": "focus-billing-export",
    "TimeUnit": "DAILY",
    "Format": "textORcsv",
    "Compression": "GZIP",
    "AdditionalSchemaElements": ["RESOURCES"],
    "S3Bucket": "your-cur-export-bucket",
    "S3Prefix": "focus-exports",
    "S3Region": "us-east-1",
    "ReportVersioning": "OVERWRITE_REPORT"
  }'

Your S3 bucket needs a policy granting the AWS billing reports service principal permission to write objects, or the export will silently fail to land. That specific failure mode is common enough to get its own entry in the troubleshooting section below.

Step 9: Pull Cost Data Programmatically With Boto3

Everything so far lives in the console or one off CLI calls. To build something repeatable, you need the Cost Explorer API wrapped in a script you control. Install boto3, configure your credentials through the AWS CLI, and confirm you can pull the same grouped data from Step 5 through Python.

import boto3
from datetime import date, timedelta

client = boto3.client("ce", region_name="us-east-1")

end = date.today()
start = end - timedelta(days=14)

response = client.get_cost_and_usage(
    TimePeriod={"Start": start.isoformat(), "End": end.isoformat()},
    Granularity="DAILY",
    Metrics=["UnblendedCost"],
    Filter={"Dimensions": {"Key": "SERVICE", "Values": ["Amazon Bedrock", "Amazon SageMaker"]}},
    GroupBy=[{"Type": "TAG", "Key": "project"}],
)

for day in response["ResultsByTime"]:
    print(day["TimePeriod"]["Start"], day["Groups"])

Note that the Cost Explorer API is a global endpoint that only accepts requests from us-east-1, regardless of which region your workloads actually run in. That single detail causes more EndpointConnectionError reports than almost anything else in this workflow.

Step 10: Build the Complete AI Spend Tracker Project

Here is the full working project. a script that pulls 14 days of Bedrock and SageMaker spend grouped by project tag, flags any project whose spend jumped more than a set threshold day over day, and prints a clean summary you can pipe into a log, a file, or the Slack webhook from Step 11. Save this as ai_spend_tracker.py.

import boto3
import json
from datetime import date, timedelta

ANOMALY_THRESHOLD_PERCENT = 40
CE = boto3.client("ce", region_name="us-east-1")


def fetch_daily_costs(days_back=14):
    end = date.today()
    start = end - timedelta(days=days_back)
    response = CE.get_cost_and_usage(
        TimePeriod={"Start": start.isoformat(), "End": end.isoformat()},
        Granularity="DAILY",
        Metrics=["UnblendedCost"],
        Filter={
            "Dimensions": {
                "Key": "SERVICE",
                "Values": ["Amazon Bedrock", "Amazon SageMaker"],
            }
        },
        GroupBy=[{"Type": "TAG", "Key": "project"}],
    )
    return response["ResultsByTime"]


def flatten_by_project(results):
    by_project = {}
    for day in results:
        day_date = day["TimePeriod"]["Start"]
        for group in day["Groups"]:
            project = group["Keys"][0].split("$")[-1] or "untagged"
            amount = float(group["Metrics"]["UnblendedCost"]["Amount"])
            by_project.setdefault(project, []).append((day_date, amount))
    return by_project


def detect_anomalies(by_project):
    flagged = []
    for project, series in by_project.items():
        series.sort(key=lambda x: x[0])
        if len(series) < 2:
            continue
        yesterday, today = series[-2][1], series[-1][1]
        if yesterday == 0:
            continue
        change_pct = ((today - yesterday) / yesterday) * 100
        if change_pct >= ANOMALY_THRESHOLD_PERCENT:
            flagged.append(
                {
                    "project": project,
                    "yesterday": round(yesterday, 2),
                    "today": round(today, 2),
                    "change_pct": round(change_pct, 1),
                }
            )
    return flagged


def main():
    results = fetch_daily_costs()
    by_project = flatten_by_project(results)
    flagged = detect_anomalies(by_project)

    print(f"Checked {len(by_project)} tagged projects across Bedrock and SageMaker.")
    if not flagged:
        print("No anomalies above the threshold today.")
        return

    for item in flagged:
        print(
            f"ALERT: {item['project']} jumped {item['change_pct']}% "
            f"(${item['yesterday']} -> ${item['today']})"
        )
    with open("ai_spend_alerts.json", "w") as f:
        json.dump(flagged, f, indent=2)


if __name__ == "__main__":
    main()

Run it with python ai_spend_tracker.py. On a clean account with no tagged spend yet, it will print zero checked projects, which is expected until Step 3’s tags have been live for a few days and accumulated real usage data.

It is worth walking through what each function actually does, since the logic is simple on purpose and you will likely extend it. fetch_daily_costs does nothing more than the CLI call from Step 5, wrapped in boto3 so it can run unattended. flatten_by_project takes the nested response structure Cost Explorer returns, which groups by day first and tag second, and inverts it into a dictionary keyed by project with a time series of dates and dollar amounts. That inversion matters because comparing yesterday to today for a single project is awkward when the data is organized day first, and trivial once it is organized project first.

detect_anomalies is intentionally simple, a single day over day percentage comparison against a fixed threshold, rather than a statistical model. That is a deliberate tradeoff for a first version. It catches obvious spikes with code anyone on the team can read in thirty seconds, at the cost of missing slower, multi day creep that a more sophisticated model like AWS’s own Cost Anomaly Detection from Step 7 would catch instead. Running both side by side, this lightweight script for fast same day visibility and the native anomaly detector for pattern based detection, covers more ground than either alone. main just ties the pieces together and decides what to do with a flagged result, which is where the Slack integration from Step 11 plugs in.

A natural extension once this is running reliably is to swap the fixed 40% threshold for a rolling average baseline, so a project that always moves by 35% between a Friday and a Monday does not generate a false alert every single week. That is a small change to detect_anomalies, comparing against a trailing seven day average instead of just yesterday, and it is usually the first improvement teams make after running the tracker for about a month.

Output Example

Here is what a healthy run looks like once tagged data has accumulated, including one flagged project.

Checked 6 tagged projects across Bedrock and SageMaker.
ALERT: finops-tutorial jumped 62.3% ($41.20 -> $66.86)

The script also writes ai_spend_alerts.json with the same data in a structured format, which feeds directly into the Slack step next.

Step 11: Wire Up Slack Alerts and Automate the Schedule

A tracker that only prints to a terminal is a tracker nobody checks. Add a Slack webhook post so flagged projects land in a channel your team actually reads.

import requests

SLACK_WEBHOOK_URL = "https://hooks.slack.com/services/REPLACE/WITH/YOUR_WEBHOOK"


def send_slack_alert(flagged):
    if not flagged:
        return
    lines = [
        f"- {item['project']}: {item['change_pct']}% increase "
        f"(${item['yesterday']} -> ${item['today']})"
        for item in flagged
    ]
    payload = {"text": "AI spend anomaly detected:\n" + "\n".join(lines)}
    requests.post(SLACK_WEBHOOK_URL, json=payload, timeout=10)

Call send_slack_alert(flagged) at the end of main() in the tracker script, then schedule the whole thing to run once a day with cron.

# Run every morning at 8 AM
0 8 * * * /usr/bin/python3 /opt/finops/ai_spend_tracker.py >> /var/log/ai_spend_tracker.log 2>&1

If you would rather not manage a cron server, the same script runs fine inside a scheduled AWS Lambda function triggered by EventBridge, using the IAM role from Step 1 instead of local credentials.

Numbers in a Slack message are good for alerts, but trend lines are better for weekly reviews. Feed the same by_project dictionary from Step 10 into matplotlib for a quick line chart, or route it into Amazon QuickSight if you want something your finance team can open without touching Python. Either way, keep the chart scoped to the tagged project dimension, not raw service totals, so a reviewer can see which team or model is driving a trend rather than just a rising total.

Teams running Google Cloud alongside AWS can mirror this same view inside Google’s FinOps Hub, which now pulls in GKE workload recommendations directly, giving you a comparable per workload breakdown without building a custom exporter for that side of the stack.

A minimal matplotlib chart takes about ten lines once by_project is populated, and it is worth keeping in the same script rather than a separate notebook so the chart always reflects the same run that generated your Slack alert.

import matplotlib.pyplot as plt

def plot_trend(by_project, output_path="ai_spend_trend.png"):
    plt.figure(figsize=(10, 5))
    for project, series in by_project.items():
        series.sort(key=lambda x: x[0])
        dates = [d for d, _ in series]
        amounts = [a for _, a in series]
        plt.plot(dates, amounts, marker="o", label=project)
    plt.xticks(rotation=45, ha="right")
    plt.ylabel("Daily cost (USD)")
    plt.title("Bedrock and SageMaker spend by project")
    plt.legend(loc="upper left", fontsize=8)
    plt.tight_layout()
    plt.savefig(output_path)

Call plot_trend(by_project) right after flatten_by_project runs in Step 10, and you get a saved PNG alongside the JSON alert file every time the tracker runs, which is handy for pasting straight into a weekly review doc without rebuilding the chart from scratch.

Step 13: Validate, Test, and Review Your Setup

Before you call this done, run through a short validation pass. Confirm Cost Explorer shows data under the new tag groupings, confirm the Budgets email subscription shows as confirmed rather than pending, confirm the anomaly monitor has a valid ARN attached to its subscription, and confirm the CUR export has landed at least one file in S3. Each of these is a common silent failure point covered in the troubleshooting section below, and catching them now is far cheaper than discovering a gap during an actual cost spike.

Common Pitfalls When Setting Up AWS Cost Explorer for AI Workloads

Most of the mistakes teams make here are not exotic. They are small sequencing errors, like flipping a switch in the wrong order or assuming a feature works the way a similar one does elsewhere in AWS. Catching these early saves a lot of confused Slack threads later when a number does not match what someone expected.

  • Tagging resources after they are already running. Cost allocation tags only apply to usage recorded after activation. Retroactive tagging does not backfill historical Cost Explorer data.
  • Treating Cost Explorer as real time. Data typically lags by roughly 24 hours. Do not build an alert workflow that assumes same hour visibility into spend.
  • Forgetting the us-east-1 requirement. The Cost Explorer API only responds from the global us-east-1 endpoint, regardless of workload region, which breaks scripts hardcoded to another region.
  • Ignoring Savings Plans and Reserved Instance amortization. Amortized discounts can make a service look cheaper or more expensive than the raw on demand rate, skewing per project comparisons if you are not using UnblendedCost consistently.
  • Setting anomaly thresholds too low. A $5 threshold on a workload that naturally swings by $20 a day generates alert fatigue fast, and the team starts ignoring the channel entirely.
  • Leaving budget notification subscriptions unconfirmed. AWS Budgets will not deliver a single alert until the SNS or email subscription confirmation is accepted.
  • Mixing CUR 2.0 schema versions across exports. Switching report format mid month creates gaps that make month over month FOCUS comparisons unreliable.

Troubleshooting AWS Cost Explorer and FinOps Tooling

When something in this pipeline does not behave the way the tutorial describes, the cause is almost always one of the nine issues below. Work through the table top to bottom before assuming you have hit an edge case AWS has not documented, since in practice these nine cover the overwhelming majority of support threads on this topic.

SymptomLikely CauseFix
AccessDeniedException on get_cost_and_usageIAM policy missing ce:GetCostAndUsageAttach the policy from Step 1 to the calling user or role
Cost Explorer shows no data for new tagsTags activated less than 24 hours agoWait a full day, then re check the grouping dimension list
Budget alert never arrivesSNS or email subscription not confirmedCheck inbox or SNS console for a pending confirmation link
CUR file never appears in S3Bucket policy does not grant the billing reports service principal accessAdd a bucket policy allowing billingreports.amazonaws.com to PutObject
boto3 throws ThrottlingExceptionScript polling the Cost Explorer API too frequentlyAdd exponential backoff and cache results for at least an hour
Amazon Q gives a vague cost explanationUnderlying cost allocation tags are not yet activeConfirm tags from Step 3 are active before relying on Q’s breakdown
Anomaly monitor never triggersThreshold set far above normal daily varianceLower the dollar threshold closer to your real daily baseline
FOCUS export missing expected columnsReport definition still on an older CUR schemaRecreate the report definition with CUR 2.0 and FOCUS compatible settings
EndpointConnectionError calling the ce clientboto3 client created with a region other than us-east-1Force region_name us-east-1 when instantiating the ce client

Advanced Tips for Multi-Cloud FinOps in 2026

Once the basic tracker is running, a few upgrades pay off quickly. First, mirror the Spend Caps idea Google is piloting for Vertex AI and AI Studio by adding a hard circuit breaker to your own tracker. if a project’s daily spend crosses a defined ceiling, have the script disable the IAM role tied to that workload rather than just sending an alert nobody reads in time. Second, watch the FOCUS 1.5 roadmap closely, since native AI token and unit economics tracking targeted for December 2026 will let you compare cost per million tokens across AWS, Azure, and Google Cloud without writing custom normalization logic.

Third, keep an eye on where the industry is pointed. Cost tooling across every major provider is shifting from static dashboards toward autonomous agents that investigate anomalies on their own, echoing the direction AWS’s own October 2026 serverless release notes describe. That shift is not optional background noise. Gartner’s forecast, covered by TechTarget’s cloud computing desk, warns that up to 80% of neoclouds could stop operating independently by 2030 because projected AI infrastructure costs are outpacing projected revenue. Teams that build cost visibility into their AI workflow now, rather than bolting it on after a surprise invoice, are the ones who will not be caught flat footed by that kind of market correction.

Finally, if your organization already uses Kubernetes for part of the AI stack, remember that FOCUS 1.4 improves billing visibility at the cluster level but still will not automatically split shared node costs across namespaces. Combine it with the per pod tagging discipline from Step 3, applied to your cluster workloads, to avoid a blind spot right where GPU backed inference pods usually run.

How This Maps to Azure and Google Cloud

If your organization is not purely AWS, the good news is that every provider has converged on a similar shape for this problem, even though the console names differ. Azure Cost Management and Billing covers the same ground as Cost Explorer and Budgets combined, with cost allocation tags, budget alerts, and an anomaly detection feature of its own. Google Cloud’s equivalent is spread across Cloud Billing reports, Budgets and alerts, and the newer FinOps Hub, which as mentioned earlier now folds in GKE workload recommendations and is getting its own Explainability Agent and Spend Caps feature for Vertex AI and AI Studio.

The practical takeaway for a multi cloud AI team is to build the tagging discipline from Step 3 identically across all three providers using the same key names, like team, project, and model-name, so that when you do export everything through FOCUS 1.4, the rows line up without a translation layer. Trying to reconcile cost-center on one cloud with CostCenter on another after the fact is a painful cleanup job that a five minute naming convention decision avoids entirely.

AWS Cost Tooling at a Glance

With five different tools covered It helps to see them side by side.

ToolBest ForData LagCost
Cost ExplorerExploring and visualizing historical spendAbout 24 hoursFree
AWS BudgetsThreshold based alerts before overspendNear real time against latest Cost Explorer dataFirst two budgets free, then a small per budget fee
Cost Anomaly DetectionCatching unusual spend patterns automaticallyDaily evaluationFree
Cost and Usage Report 2.0 / FOCUSMulti cloud billing normalization and deep exportsDaily or hourly export depending on configurationFree, standard S3 storage charges apply
Bedrock FinOps AgentConversational cost analysis for Bedrock and connected AI servicesBased on underlying Cost Explorer data refreshFree

Frequently Asked Questions

Does AWS Cost Explorer cost anything to use?
No. Cost Explorer itself is free. You only pay for the resources it reports on, plus any S3 storage used by Cost and Usage Report exports.

How current is the data inside Cost Explorer?
Expect roughly a 24 hour lag between when a resource runs and when its cost shows up. Treat Cost Explorer as a next day view, not a live meter.

Can Amazon Q inside Cost Explorer replace manual cost analysis entirely?
Not yet. It is a strong first pass for explaining anomalies in plain language, but it reads the same underlying data your scripts do, so critical numbers should still be cross checked against a grouped query like the one in Step 5.

Why does my tagged spend show as untagged in Cost Explorer?
Either the tag was applied after the resource started running, or the cost allocation tag has not finished activating yet. Both situations resolve within about 24 hours of correctly tagging a new resource.

What is the difference between CUR 2.0 and the FOCUS specification?
CUR 2.0 is AWS’s own detailed billing export format. FOCUS is a vendor neutral specification, now at version 1.4, designed so the same billing schema works across AWS, Azure, and Google Cloud for multi cloud reporting.

Do I need Cost Anomaly Detection if I already set up Budgets?
Yes, they catch different failure modes. Budgets alert on crossing a fixed threshold you defined in advance. Anomaly Detection flags unusual patterns even while you are still comfortably under budget.

Will this tutorial’s Python script work for multi account AWS Organizations setups?
Yes, with one change. Add LINKED_ACCOUNT to the GroupBy list in the boto3 calls from Step 9 and Step 10 so costs from each account are broken out instead of consolidated into a single total.

How do I track AI spend across AWS and Google Cloud in one place?
Export both sides using FOCUS compatible billing formats, since the shared schema lets you load both exports into one table or dashboard without writing custom normalization code for each provider.

Related Coverage

Yusuf Demir

Yusuf Demir

Cloud & Software Reporter

Yusuf Demir is the Cloud & Software Reporter at TrendinTech, where he covers cloud infrastructure, enterprise platforms, developer tools and the digital transformation of businesses in the UK and the United States. He is most interested in the gap between vendor roadmaps and the systems engineers actually run, and in what the cloud bill looks like once the free credits expire.

All stories by Yusuf Demir (392)

Related Articles