Setting Up a Free Tier Billing Alarm in AWS CloudWatch (Email Alert at $5)
A Free Tier billing alarm in AWS CloudWatch is the fastest way to catch unexpected charges before a surprise invoice arrives at month-end.
TL;DR: Free Tier Billing Alarm Setup Steps
| Step | What to Do | Key Requirement |
|---|---|---|
| 1 | Enable billing alerts in Account Preferences | Must be done in us-east-1; one-time account setting |
| 2 | Create an SNS topic and email subscription | Email must be confirmed before alarm can notify |
| 3 | Create the CloudWatch billing alarm at $5 threshold | Metric only available in us-east-1 |
| 4 | Verify alarm state and confirm SNS subscription | Alarm stays in INSUFFICIENT_DATA until billing data arrives |
Why Free Tier Billing Alarms Exist — and Why Teams Skip Them
AWS Free Tier usage is not automatically capped. When a service exceeds its monthly free allowance, charges accrue silently. CloudWatch billing alarms monitor the EstimatedCharges metric published by AWS Billing and send a notification when a defined threshold is crossed. The alarm does not stop charges — it notifies you so you can act.
In practice, teams setting up a personal or sandbox account skip this step because the console makes it look optional. It is not optional if you care about your credit card.
Think of a billing alarm the way you think of a low-fuel warning light: it does not stop the car, but without it you will not know you are about to stall.
Architecture: How the Billing Alarm Signal Flows
- AWS Billing aggregates estimated charges across all services and publishes the
EstimatedChargesmetric to CloudWatch in theus-east-1region. - CloudWatch Alarm evaluates the metric against your $5 threshold. When the metric value exceeds the threshold, the alarm transitions to
ALARMstate. - SNS Topic receives the state-change notification from CloudWatch.
- Email Subscription on the SNS topic delivers the alert to your inbox.
Step 1: Enable Billing Alerts in Account Preferences
Billing metric data is not published to CloudWatch by default. You must opt in once per AWS account. This setting is global but the metric itself is only available in us-east-1.
— Why this step: Without enabling billing alerts, the EstimatedCharges metric never appears in CloudWatch, and every subsequent step silently produces an alarm with no data.
Navigate to the AWS Billing console → Billing Preferences → check Receive Billing Alerts → save preferences. There is no CLI command to enable this setting; it must be done through the Billing console or via the Billing API. Confirm the setting is saved before proceeding.
Step 2: Create an SNS Topic and Email Subscription for the Free Tier Billing Alarm
CloudWatch alarms notify through Amazon SNS. You need a topic and a confirmed email subscription before the alarm can deliver notifications.
— Why this step: An alarm wired to an unconfirmed SNS subscription will transition to ALARM state correctly but deliver no email — a silent failure that defeats the entire purpose.
You are about to run two commands. The first creates the topic and returns its ARN. Copy that ARN — you need it in Step 3.
# Create the SNS topic (run in us-east-1)
aws sns create-topic \
--name billing-alarm-topic \
--region us-east-1
# Subscribe your email address to the topic
# Replace TOPIC_ARN with the ARN returned above
# Replace you@example.com with your actual address
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:123456789012:billing-alarm-topic \
--protocol email \
--notification-endpoint you@example.com \
--region us-east-1
After running the subscribe command, AWS sends a confirmation email. Open it and click Confirm subscription. The subscription status must show Confirmed before the alarm will deliver notifications. You can verify status with:
aws sns list-subscriptions-by-topic \
--topic-arn arn:aws:sns:us-east-1:123456789012:billing-alarm-topic \
--region us-east-1
Look for "SubscriptionArn" containing a full ARN (not the string PendingConfirmation).
Step 3: Create the CloudWatch Billing Alarm at the $5 Threshold
With billing metrics enabled and SNS confirmed, you can now create the alarm. The EstimatedCharges metric lives in the AWS/Billing namespace and uses the dimension Currency=USD. This metric is only available in us-east-1 regardless of where your resources run.
— Why this step: The metric namespace, dimension name, and region are all fixed by AWS. Using any other region or omitting the Currency dimension results in a metric that returns no data, leaving the alarm permanently in INSUFFICIENT_DATA state.
The engineer's first instinct is often to create this alarm in whatever region their workload runs in. That will not work. Billing metrics are centralized in us-east-1 by design — region of resource deployment is irrelevant here.
aws cloudwatch put-metric-alarm \
--alarm-name "FreeTierBillingAlarm" \
--alarm-description "Alert when estimated charges exceed 5 USD" \
--metric-name EstimatedCharges \
--namespace AWS/Billing \
--statistic Maximum \
--dimensions Name=Currency,Value=USD \
--period 86400 \
--evaluation-periods 1 \
--threshold 5 \
--comparison-operator GreaterThanThreshold \
--alarm-actions arn:aws:sns:us-east-1:123456789012:billing-alarm-topic \
--treat-missing-data notBreaching \
--region us-east-1
Key parameter decisions explained:
- --statistic Maximum: Billing metrics represent cumulative estimated charges.
Maximumcaptures the highest reported value within the period, which reflects the current running total. - --period 86400: AWS updates the
EstimatedChargesmetric several times per day. A 86400-second (24-hour) period is a common and practical evaluation window. - --treat-missing-data notBreaching: Prevents the alarm from firing during periods when no billing data has been published yet (common at the start of a billing cycle).
The threshold is a floating-point value. Setting it to 5 means the alarm triggers when estimated charges exceed $5.00 USD.
Step 4: Verify the Free Tier Billing Alarm State
After creation, the alarm will initially report INSUFFICIENT_DATA. This is expected — CloudWatch has not yet evaluated a full period of billing data. It is not an error.
— Why this step: Confusing INSUFFICIENT_DATA with a misconfiguration causes engineers to delete and recreate the alarm repeatedly, which does not resolve the state and wastes time.
aws cloudwatch describe-alarms \
--alarm-names "FreeTierBillingAlarm" \
--region us-east-1
In the output, check StateValue. Valid states are OK, ALARM, and INSUFFICIENT_DATA. Once AWS publishes billing data for the current period, the alarm will transition to OK (if charges are below $5) or ALARM (if they are not).
- INSUFFICIENT_DATA: Initial state. No billing metric data point has been evaluated yet. Normal at alarm creation.
- OK: Billing metric evaluated; estimated charges are at or below $5.
- ALARM: Estimated charges exceeded $5. SNS notification has been sent.
The alarm does not auto-resolve charges. Once you receive the email, log in to the Billing console to identify which service is generating unexpected spend.
IAM Permissions Required
If you are running these CLI commands as an IAM user or role rather than the root account, the principal needs the following minimum permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSNSTopicManagement",
"Effect": "Allow",
"Action": [
"sns:CreateTopic",
"sns:Subscribe",
"sns:ListSubscriptionsByTopic"
],
"Resource": "arn:aws:sns:us-east-1:123456789012:billing-alarm-topic"
},
{
"Sid": "AllowCloudWatchAlarmManagement",
"Effect": "Allow",
"Action": [
"cloudwatch:PutMetricAlarm",
"cloudwatch:DescribeAlarms"
],
"Resource": "*"
}
]
}
Note: cloudwatch:DescribeAlarms does not support resource-level restrictions and requires "Resource": "*". Enabling billing alerts in the Billing console requires the aws-portal:ModifyBilling permission or root account access, depending on your account configuration.
Common Mistakes That Break Free Tier Billing Alarms
The most frequent failure is creating the alarm in the wrong region. Because EstimatedCharges is only published in us-east-1, an alarm created in eu-west-1 or any other region will remain in INSUFFICIENT_DATA indefinitely with no error message.
The second failure mode is an unconfirmed SNS subscription. The alarm fires correctly, CloudWatch records the state transition, but no email arrives. Engineers then assume the alarm is broken and rebuild it — the subscription confirmation step is the actual fix.
Pricing and service quota limits vary — always check the AWS Free Tier page and the official CloudWatch billing alarm documentation for current details.
Glossary
- EstimatedCharges
- A CloudWatch metric in the
AWS/Billingnamespace representing the estimated total charges for your AWS account in the current billing period. Published inus-east-1only. - SNS Topic
- An Amazon Simple Notification Service endpoint that fans out messages to one or more subscribers. Used here to deliver email notifications from CloudWatch alarm state changes.
- INSUFFICIENT_DATA
- A CloudWatch alarm state indicating that not enough metric data has been collected to evaluate the alarm condition. Expected immediately after alarm creation.
- treat-missing-data
- A CloudWatch alarm parameter controlling how the alarm behaves when no data points exist for the evaluation period.
notBreachingtreats missing data as within threshold. - Billing Alerts (Preference)
- An account-level opt-in setting in the AWS Billing console that enables publication of billing metrics to CloudWatch. Must be enabled before billing alarms can function.
Comments
Post a Comment