Kiro User Activity Dashboard
Introduction
The Kiro User Activity Dashboard provides enterprise visibility into Kiro
The dashboard answers two different questions from two different data sources. How is Kiro being used? comes from the Kiro user activity report: messages, credits, models, and client types, per user per day. What are we paying for, and is it being used? comes from your AWS Cost and Usage Report (CUR): which licences appear on each month’s bill, which of them consumed credits, and what the ones that did not have cost you. Because Kiro allocates and resets plan credits per calendar month, both halves are scoped by a single Billing period control.
Key capabilities include:
-
Licence-level subscription tracking: how many Kiro licences are billed in a month, how many were used, and how many sat idle
-
Idle licence reclaim reporting, with the cost attributable to the months a licence went unused
-
Credit consumption monitoring with tier-based utilization thresholds
-
Per-user and per-account usage breakdown across all Kiro-enabled regions
-
Model-level message tracking (Claude Opus, Sonnet, Haiku, and other models)
-
Subscription tier right-sizing recommendations (upgrade, downgrade, right-sized)
-
Overage detection and at-risk user identification (at or above 75% plan utilization)
-
Under-utilization detection (below 25% of plan), for conversations with team managers rather than direct action
-
New user adoption tracking
The following screenshot shows the Executive Summary tab of the Kiro User Activity Dashboard:
Demo Dashboard
Get more familiar with the Dashboard using the live, interactive demo
dashboard following this
link
The dashboard has five tabs:
-
Executive Summary:
-
Total Kiro Subscriptions, Active Kiro Licences, and Idle Kiro Licences KPIs (from CUR)
-
Total Messages, Credits Used, and Overage Credits KPIs (from the activity report)
-
Active Users by Client Type and Daily Active Users by Client Type
-
Credits by Subscription Tier
-
Messages by Model
-
-
User Engagement:
-
Users by Message Count, and Top 50 Users by Message Count colored by Model
-
User Summary pivot table with per-user monthly utilization and tier recommendations
-
Idle Kiro Licences table, listing reclaim candidates with licence tenure and idle cost
-
-
Credit & Overage Tracking:
-
Users at Risk KPI (at or above 75% plan utilization)
-
Users in Overage KPI
-
Users Below 25% of Plan KPI
-
Daily Credits Used vs Overage
-
Monthly Credits and Overage pivot table
-
-
Model & Client Breakdown:
-
Daily Messages by Model
-
Monthly Messages by Model and Client Type pivot table with user counts
-
-
About:
-
Dashboard version and release information
-
Legal notice
-
All tabs include shared filter controls for Billing period, AWS Account, User, Model, and Client Type.
Important
The Billing period control scopes every widget on every tab, including the subscription KPIs and the Idle Kiro Licences table. Set it to a whole calendar month, and prefer a month that has closed.
Kiro allocates and resets plan credits per calendar month, so a partial window understates plan utilization. It also under-reports subscriptions: Kiro subscription fee lines are dated either on the first of the billing month or spread daily through month end, and CUR delivery lag means the current month’s fee lines may not have arrived yet. A window that ends mid-month can therefore miss a licence’s billing rows entirely, and the licence drops out of the roster instead of being reported. The control defaults to the previous month for this reason, which is the most recent fully delivered bill.
Architecture
The Kiro User Activity module uses a pull-based architecture. A central AWS Lambda function in the Data Collection account reads CSV reports from customer Kiro source buckets on a daily schedule. Customers only need to apply a bucket policy, because no AWS CloudFormation stack is deployed in their accounts.
The following diagram shows the pull-based data collection flow:
-
The Kiro service writes daily CSV user activity reports at 2 AM UTC to each customer’s designated S3 bucket, under the path
kiro/AWSLogs/<account-id>/KiroLogs/user_report/<region>/<year>/<month>/<day>/. -
A Lambda function (scheduled at 3 AM UTC) reconciles each source bucket against the central Data Collection bucket. It lists every Kiro report in the source and every file already imported to the destination. It then pulls only the reports that are missing. For each report it pivots the model-specific columns into normalized rows. It then writes Hive-partitioned output to the central Data Collection bucket, keyed by source account and region:
kiro-user-activity/account_id=<id>/region=<region>/year=<year>/month=<month>/day=<day>/. The destination is the source of truth for what has already been collected. This gives the reconcile both checkpointing (transient failures self-heal on the next run) and backfill (any missing history is filled). It also scales to accounts that manage many source buckets. -
An explicit AWS Glue table partitioned by
account_id,region,year,month, anddaymakes the source account and region first-class query dimensions. This partitioning also prevents cross-account filename collisions. The Lambda registers each partition it writes through the AWS Glue API. Amazon Athena can then query the data without an AWS Glue crawler orMSCK REPAIR TABLE, and newly onboarded accounts and regions become queryable automatically. -
Amazon Quick Suite ingests data from Amazon Athena (through a bounded two-year view over the table) into SPICE (Super-fast, Parallel, In-memory Calculation Engine) and applies calculated fields for utilization metrics, tier recommendations, and overage tracking.
The dashboard uses a second dataset, built from your existing AWS Cost and Usage Report rather than from the Kiro activity report. The activity report only contains users who did something, so it has no way to represent a subscribed-but-idle user. Subscription counts, the active and idle split, and all cost figures therefore come from CUR:
-
An Athena view over your CUR 2.0 table selects Kiro line items (
line_item_product_code = 'Kiro') for the last 18 months, at one row per billing line per subscriber. Subscription fee lines and credit-consumption lines are both retained, because the dashboard needs to distinguish them: the billing operation distinguishes them, not the pricing unit, because the same consumption arrives under two different pricing units. The view also joins the activity report per licence and month, so credit consumption that produces no billing record still registers as activity. It resolves a human-readable email from the same join, falling back to the raw Identity Center user ID for a subscriber who has never generated activity. -
Quick Suite ingests that view into a second SPICE dataset. Both datasets expose a
usage_datecolumn under the same name, which is what allows the single Billing period control to scope both of them at once.
Prerequisites
-
Deploy one or more of the foundational dashboards: CUDOS, Cost Intelligence, or KPI Dashboard. This deployment enables the required Amazon Athena and Amazon Quick Suite resources for this dashboard.
-
Deploy or Update the Data Collection Stack with the Kiro User Activity Data Collection Module enabled (see Step 1).
-
Kiro user activity reporting enabled — Each source account must have Kiro user activity reporting enabled and writing CSV reports to an Amazon S3 bucket. This is configured in each account through the Kiro console.
-
An AWS Cost and Usage Report (CUR 2.0) data export: required by the subscription and cost widgets, which read Kiro line items from CUR rather than from the activity report. The foundational dashboards in step 1 already set this up. If your organization’s Kiro subscriptions are billed in a payer account whose CUR you do not collect, those licences do not appear in the subscription KPIs or the Idle Kiro Licences table, although any activity they generate still appears in the usage widgets.
-
Amazon Quick Suite Enterprise Edition — Required for SPICE datasets and calculated fields.
Note
Unlike most Data Collection modules, the Kiro User Activity module is pull-based and does not require the Management Account Read Permissions stack or a Linked Account StackSet. The central collection Lambda reads directly from the source buckets you specify, and each source account grants access with a bucket policy (see Step 2).
Important
This module currently supports source buckets that are unencrypted or encrypted with Amazon S3-managed keys (SSE-S3). Source buckets encrypted with an AWS KMS key (SSE-KMS) are not supported: the bucket policy in Step 2 grants Amazon S3 read access only, so the collection Lambda cannot decrypt objects protected by a customer-managed KMS key and collection fails.
If your Kiro source buckets use SSE-KMS, either change the bucket’s default encryption to SSE-S3 (or ensure the objects written under kiro/* use SSE-S3), or track KMS support through Feedback and Support.
Deployment
Deployment consists of three steps: enabling the data collection module in the Data Collection Stack, granting read access from each source account, and deploying the Quick Suite dashboard.
Step 1: Enable the Kiro User Activity Module in the Data Collection Stack
The Kiro User Activity module is part of the Data Collection Stack. Enable it when you deploy or update the stack in your Data Collection account.
-
Sign in to your Data Collection account and open the AWS CloudFormation
console. -
Deploy the Data Collection Stack (first-time setup) or Update your existing Data Collection Stack.
-
In the Parameters section, set the following values for the Kiro User Activity Module Configuration:
Parameter Description Example Include Kiro User Activity Data Collection Module
Set to
yesto enable the moduleyesKiro Source Bucket Names (comma-separated)
Comma-separated list of S3 bucket names where Kiro writes user activity reports
my-kiro-bucket-111111111111,my-kiro-bucket-222222222222 -
Complete the stack deployment or update. After the stack reaches
CREATE_COMPLETEorUPDATE_COMPLETE, AWS CloudFormation creates the Kiro collection Lambda function, Amazon EventBridge Scheduler schedule, and AWS Glue table. -
In the AWS CloudFormation Outputs of the nested Kiro module stack, note the LambdaRoleArn value. You use this ARN in each source account’s bucket policy in Step 2.
Note
The collection Lambda runs daily at 3 AM UTC, after Kiro generates its reports at 2 AM UTC. On each run it reconciles every source bucket against what has already been imported and pulls any missing reports, regardless of date. This means the first run backfills all available history, and subsequent runs copy only new or previously-missed reports.
Step 2: Grant Read Access
Apply the following in each source account that produces Kiro user activity reports. Each account must apply a bucket policy granting read access to the collection Lambda role from Step 1. No CloudFormation stack is deployed in the source accounts — a bucket policy is all that is required.
Add the following two statements to the S3 bucket policy on each Kiro source bucket. Access is scoped to the kiro/* prefix so the collection Lambda can read only the Kiro user activity reports, not the rest of the bucket:
{ "Sid": "AllowCIDKiroDataCollectionRead", "Effect": "Allow", "Principal": { "AWS": "<LambdaRoleArn from Step 1 Outputs>" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::<kiro-source-bucket-name>/kiro/*" }, { "Sid": "AllowCIDKiroDataCollectionList", "Effect": "Allow", "Principal": { "AWS": "<LambdaRoleArn from Step 1 Outputs>" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::<kiro-source-bucket-name>", "Condition": { "StringLike": { "s3:prefix": "kiro/*" } } }
Tip
The exact bucket policy statements, pre-populated with your Lambda role ARN, are also provided in the BucketPolicyExample CloudFormation stack output.
Important
When you specify a role ARN as a bucket policy Principal, Amazon S3 stores it internally as the role’s unique ID, not the ARN string. If you tear down and later re-enable the module (or otherwise delete and recreate the Lambda role), the new role has a different unique ID even though the ARN is unchanged. The existing bucket policy then still points at the deleted role, so the Lambda can no longer list or read the source bucket. Collection fails quietly — the run returns total_files_copied: 0, and any per-bucket access failures appear in the errors array of the Lambda response.
If you re-deploy the module, re-apply the bucket policy in each source account so it re-resolves to the new role. Use the current BucketPolicyExample stack output as the source of truth.
Step 3: Test the Lambda Collector
Invoke the Lambda manually to verify data flows correctly:
aws lambda invoke \ --region <region> \ --function-name CID-DC-kiro-user-activity-Lambda \ /tmp/kiro-output.json && cat /tmp/kiro-output.json
Expected response (a successful run returns statusCode: 200; total_files_copied, total_rows_written, and partitions_registered reflect how many reports were missing and therefore imported on this run — a run where everything is already collected returns zeros, which is normal):
{ "statusCode": 200, "total_files_copied": 3, "total_rows_written": 45, "partitions_registered": 3, "errors": [] }
Note
The collector imports only reports that are not already present in the destination. On a first run it backfills everything available; on later runs total_files_copied is often 0 because there is nothing new to copy — this is expected and not an error.
If a first run (or a run against a brand-new source bucket) reports total_files_copied: 0, verify the following:
-
The bucket policy in the source account is applied, and — if you have re-deployed the module — that it points at the current Lambda role (see the IMPORTANT note in Step 2).
-
The Kiro Source Bucket Names parameter is correct.
-
The Kiro service has written reports to the source bucket under the expected
kiro/AWSLogs/<account-id>/KiroLogs/user_report/…path.
The collector reads the source account, region, and date from the S3 object path (kiro/AWSLogs/<account-id>/KiroLogs/user_report/<region>/<year>/<month>/<day>/…) rather than from columns inside the CSV. Reports that do not match this path layout (for example the legacy by_user_analytic report) are skipped.
Step 4: Verify Data in Athena
Run a test query to confirm data is accessible:
SELECT * FROM optimization_data.kiro_user_activity LIMIT 10;
Step 5: Deploy the Quick Suite Dashboard
Example
Step 6: Trigger Initial SPICE Refresh
After deploying the dashboard, trigger a SPICE ingestion to load data:
cid-cmd refresh --dashboard-id kiro-user-activity
Adding New Source Accounts
To start collecting data from additional Kiro-enabled accounts:
-
Update the Data Collection Stack, adding the new bucket name(s) to the Kiro Source Bucket Names parameter.
-
Apply the bucket policy from Step 2: Grant Read Access in the new source account.
-
Invoke the Lambda manually, as described in Step 3: Test the Lambda Collector, to verify the new source is discovered.
You do not need to redeploy the dashboard. New accounts automatically appear as filter values after the next SPICE refresh.
Usage Guide
A typical review runs left to right. Set the Billing period to the month you are reviewing, read the Executive Summary to see whether the licence pool is the right size, use User Engagement to decide what to do about individual licences, and use Credit & Overage Tracking to spot people on the wrong tier. Model & Client Breakdown answers a separate question about which models and clients your developers actually work in.
Example
Note
This tab reports messages, not credits. The Kiro activity report writes a user’s daily credit total on a single one of that user’s model rows rather than splitting it per model, so credits cannot be attributed to an individual model from this data source. Any per-model credit figure would report which row happened to carry the total, not which model spent it.
How licences are counted
One licence is one subscriber within one AWS account, identified by the IAM Identity Center user ID in the CUR line item resource ID, paired with the account that is billed for it.
This matters when the same person is subscribed in more than one account, which happens in organizations that run separate AWS accounts per team or per environment. That person holds two licences, is billed twice, and either licence can go idle and be reclaimed independently of the other. Counting distinct subscribers instead would collapse the two into one and hide the wasted spend, so the subscription KPIs count the pair and a single person can legitimately appear twice in the Idle Kiro Licences table under different accounts.
Grouping only by subscriber has the same effect inside the idle table: if a person works in one account and lets the licence in a second account sit unused, the active account’s last-activity date would mask the abandoned licence. All of the idle calculations are therefore evaluated per account and subscriber together.
Calculated Fields Reference
Activity dataset
Fields derived from the Kiro user activity report, which is one row per user per day per model:
| Field | Logic | Purpose |
|---|---|---|
|
|
|
Date type for time-series, and the column the Billing period control filters on |
|
|
Email if available, cleaned userid otherwise |
Human-readable display |
|
|
Pro=1000, ProPlus=2000, ProMax=5000, Power=10000, Free=50 |
Plan allocation for the tier on that row |
|
|
|
Per-day utilization (not used directly by the pivots; see |
|
|
1 if overage_credits > 0 |
Overage counter |
|
|
|
Efficiency metric |
|
|
1 if new_user = true |
Adoption counter |
|
|
The highest plan allocation the licence held during the calendar month (analysis-level) |
The month’s effective allowance, resolved to a single figure for a licence that changed tier mid-month |
|
|
The tier matching |
The tier label to group by for any monthly figure, so a licence that changed tier mid-month appears once |
|
|
Cumulative monthly credits per user / |
Monthly utilization, the basis for utilization %, at-risk, under-utilization, and tier recommendations |
|
|
Sum of a user’s overage credits over the calendar month (analysis-level) |
Monthly overage total |
|
|
Monthly credits summed, divided by monthly messages summed, per user |
Efficiency metric at monthly grain. Averaging the per-row ratio instead understates it, because the activity report writes a user’s daily credit total on one model row only |
|
|
1 if monthly utilization >= 75%, for a recognized tier |
Risk threshold. Requires a known plan allocation, so an unrecognized tier is excluded rather than silently counted as 0% and dropped from the at-risk count |
|
|
1 if monthly utilization < 25%, for a recognized tier |
Under-utilization threshold. Requires a known plan allocation, so a tier the dashboard does not recognize is excluded rather than reported as unused |
|
|
No known plan allocation gives Unknown Tier; else any monthly overage gives Upgrade Candidate (or Review Overage Settings if already on Power, the top tier); else monthly utilization below 30% on a tier above Pro gives Downgrade Candidate; else Right-Sized |
Tier optimization, evaluated on monthly rather than per-day usage |
Note
tier_key and the tier spellings. The subscription tier is normalized once into a tier_key
column, lowercased with underscores, hyphens and spaces removed, and every comparison matches on
that rather than on the raw Subscription_Tier value.
This is deliberate rather than defensive. Kiro spells the same tier differently depending on where
you read it: the activity report writes PRO_PLUS and PRO_MAX, the CUR line item usage type
uses KiroEnterprise-ProPlus, and the Kiro documentation gives ProPlus and ProMax. Matching
any single spelling means the other two fall through to a zero plan allowance. Normalizing accepts
all of them.
A tier with no known allowance reports Unknown Tier and is excluded from the at-risk and
under-utilization counts, rather than being reported as 0% utilized.
Subscription dataset
Fields derived from CUR, evaluated per account and subscriber together. Except where noted, all of them are scoped to the selected Billing period:
| Field | Logic | Purpose |
|---|---|---|
|
|
|
The unit of licence counting. See How licences are counted |
|
|
Every Kiro charge for the licence in the period, whatever the billing operation |
Defines the roster: a licence with no charge in the month is not on that month’s bill. Deliberately unfiltered, so a charge under an unrecognized billing operation cannot remove the licence from the Total, Active and Idle counts |
|
|
Subscription fee charges only |
The basis for |
|
|
1 if the licence consumed credits in the period, according to the Kiro activity report or a billing record |
Defines active. Credit consumption included in a subscription does not always produce a billing record, so billing alone cannot answer this |
|
|
|
The idle test, and the filter behind the Idle Kiro Licences KPI and table |
|
|
Newest credit-consumption date for the licence, all-time, from the activity report or a billing record |
Last Activity column. Not scoped to the period, so it can show later activity for a licence that was idle during the month under review |
|
|
Oldest fee line date for the licence, all-time |
Licence Since column, and the starting point for a licence that has never consumed credits |
|
|
Subscription cost divided by the number of distinct months billed in the period |
What the licence costs per month, taken from actual charges so tier changes, discounts, and private pricing are all reflected without maintaining a price list |
|
|
Whole calendar months from the last activity to the end of the selected period |
Months Idle column, and the multiplier for Inactivity Cost |
|
|
Months licensed minus months idle |
Months Active column: how long the person used Kiro before going quiet |
|
|
|
Inactivity Cost column: what the idle months have cost, cumulatively rather than for the selected month alone |
Note
Utilization, at-risk, under-utilization, and tier-recommendation logic all evaluate usage over the calendar month, because Kiro plan credits are allocated and reset per calendar month. The subscription and idle fields are scoped to the selected month for the same reason. Set the Billing period control to a full calendar month when reviewing any of these metrics.
Two consequences are worth knowing when reading the idle table:
-
Months Active and Licence Since are bounded by data retention. The subscription view keeps 18 months of CUR, so a licence bought before that shows the oldest date available rather than its true start, and Months Active reads as a minimum rather than an exact tenure. Several licences sharing the same Licence Since date is the signal that you are at that boundary.
-
A licence that was idle in the month under review but has since been used again reports the selected period as its idle span, not the true gap. The figure is a floor, and the Last Activity column shows the later date so the licence is not reclaimed by mistake.
Update
When a new version of the dashboard template is released, update your dashboard by running the following command:
cid-cmd update --dashboard-id kiro-user-activity
Teardown
To remove the Kiro User Activity module:
-
Delete the Quick Suite dashboard and dataset via the Quick Suite console or
cid-cmd delete --dashboard-id kiro-user-activity. -
Update the Data Collection Stack and set Include Kiro User Activity Data Collection Module back to
no. This removes the collection Lambda, EventBridge Scheduler schedule, and Glue table. -
(Optional) Remove the bucket policy statements from source accounts.
-
(Optional) Delete collected data from
s3://<dest-bucket>/kiro-user-activity/.Note
If you migrated from an earlier, replication-based version of this module, the destination bucket might also contain a legacy
s3://<dest-bucket>/kiro/prefix (the raw replication landing zone) and an AWS Glue crawler. These are not used by the current pull-based architecture. After confirming no Glue table still references thekiro/prefix, you can delete that data and remove the crawler.
Authors
-
Darius Seroka, Senior Technical Account Manager
Contributors
-
Yuriy Prykhodko, Principal Technical Account Manager
-
Eric Christensen, Senior Technical Account Manager
Feedback & Support
For feedback and support, see the Feedback and Support guide.
Note
These dashboards and their content: (a) are for informational purposes only, (b) represent current AWS product offerings and practices, which are subject to change without notice, and (c) does not create any commitments or assurances from AWS and its affiliates, suppliers or licensors. AWS content, products or services are provided "as is" without warranties, representations, or conditions of any kind, whether express or implied. The responsibilities and liabilities of AWS to its customers are controlled by AWS agreements, and this document is not part of, nor does it modify, any agreement between AWS and its customers.