Show your AWS month-to-date cost on a Stream Deck key, per profile, read from
your local ~/.aws credentials. Two actions:
- Account Cost — one key, one profile: the profile name, the cost so far this month (big), and the month underneath.
- Two Account Costs — one key, two profiles stacked: each profile name over its month-to-date cost.
Example keys — the Account Cost action (left) and Two Account Costs action (right).
Not affiliated with Amazon Web Services.
- Uses your local credentials. The plugin lists the profiles in
~/.aws/credentialsand~/.aws/config(honouringAWS_SHARED_CREDENTIALS_FILE/AWS_CONFIG_FILE) and resolves each selected profile with the AWS SDK's standard chain (fromIni) — so static keys, SSO,credential_process, and assumed roles all work, exactly as the AWS CLI would. - Month-to-date cost. It calls the Cost Explorer API
(
GetCostAndUsage,MONTHLYgranularity,UnblendedCost) for the current UTC month — the same figure the AWS console shows as "Month-to-date cost". Cost Explorer is only reachable in us-east-1, so the plugin always talks to that endpoint (your resources can live anywhere). - Refresh that respects the meter. Each Cost Explorer request is billed at about $0.01, and AWS only updates billing data a few times a day. So the refresh interval is in hours, not seconds — default every 6 hours, selectable from Manual up to Once a day in the property inspector.
- Manual refresh. Press the key to refresh that profile immediately.
- Custom label. Set a Show as name in the property inspector to display
anything you like on the key instead of the raw profile name (e.g.
personal→Prod). Logs still use the real profile name. Leave it blank to show the profile. - Shared fetches, no double billing. Every key shares one per-profile cache: a profile used by several keys (e.g. a single key and one side of a two-account key) is only fetched once per its refresh window — never billed twice for the same window.
- Stays readable when a refresh fails. If a refresh fails, the last good figure stays on the key — dimmed, with a small amber dot, to read as "not live" — instead of flipping to an error. The error screen only shows when there's no figure yet.
| Interval | Requests/day per profile | ≈ Cost/month per profile |
|---|---|---|
| Every hour | 24 | ~$7.20 |
| Every 3 h | 8 | ~$2.40 |
| Every 6 h | 4 | ~$1.20 |
| Every 12 h | 2 | ~$0.60 |
| Once a day | 1 | ~$0.30 |
| Manual | only when you press | ~$0 |
Because billing data only settles a few times a day, every 6 hours is the default sweet spot — more frequent polling mostly just spends money on Cost Explorer without showing you anything new. Press the key any time you want a figure now.
- macOS 12+, Stream Deck 6.5+
- Node.js 20+ (bundled with the Stream Deck app at runtime; 20+ to build)
- An AWS profile in
~/.awswhose credentials can callce:GetCostAndUsage
Minimal IAM policy for the profile:
{
"Version": "2012-10-17",
"Statement": [{ "Effect": "Allow", "Action": "ce:GetCostAndUsage", "Resource": "*" }]
}The key shows a short hint when it can't display a figure:
configure— no profile is selected yet. Open the property inspector and pick one.profile— the selected profile isn't in~/.aws(renamed/removed).creds— the profile has no usable credentials, or AWS rejected them.login— credentials/SSO session expired. Runaws sso login(or refresh keys), then press the key.access— the credentials work but lackce:GetCostAndUsage. Attach the policy above.busy— Cost Explorer rate-limited the request; it backs off and recovers on its own.offline— couldn't reach AWS; recovers once you're back online.
Dimmed key. A dimmed key with an amber dot is showing the last good figure because the most recent refresh failed — press it to retry.
Logs live at
~/Library/Application Support/com.elgato.StreamDeck/Plugins/tphan.awscost.sdPlugin/logs/.
npm install
npm run gen:icons # generate the PNG icons
npm run build # bundle src/ into the .sdPlugin/bin
npx streamdeck link tphan.awscost.sdPlugin # install the dev plugin
npm run watch # rebuild + restart on changenpm run lint type-checks without emitting.
npm run build
npx streamdeck pack tphan.awscost.sdPluginThis produces a .streamDeckPlugin installer.
src/
plugin.ts entrypoint — registers both actions
render.ts SVG → data-URI key images (single, dual, error)
actions/
cost-action.ts shared base: lifecycle + property-inspector profile list
poller.ts shared per-profile scheduler (one fetch per refresh window, backoff, stale)
single-cost.ts the "Account Cost" action
dual-cost.ts the "Two Account Costs" action
aws/
client.ts Cost Explorer month-to-date fetch + error → hint mapping
profiles.ts list profiles from ~/.aws/credentials + ~/.aws/config
format.ts currency + month-label formatting
types.ts settings, reading, and per-profile state types
scripts/gen-icons.mjs generates plugin/action PNGs
tphan.awscost.sdPlugin/ the installed plugin package (manifest, ui, imgs, bin)
- "This month" is the UTC calendar month, matching the Cost Explorer API.
- Costs use
UnblendedCost(the console's default month-to-date metric) in the currency Cost Explorer reports for the account. - Changing a profile's credentials on disk may need a plugin restart
(
npx streamdeck restart tphan.awscost) to be picked up.