{"meta":{"title":"Team-level Copilot usage metrics","intro":"Construct team-level GitHub Copilot usage metrics by joining the daily user-teams report with the daily per-user usage metrics report.","product":"GitHub Copilot","breadcrumbs":[{"href":"/en/copilot","title":"GitHub Copilot"},{"href":"/en/copilot/reference","title":"Reference"},{"href":"/en/copilot/reference/copilot-usage-metrics","title":"Copilot usage metrics"},{"href":"/en/copilot/reference/copilot-usage-metrics/team-level-metrics","title":"Team-level metrics"}],"documentType":"article"},"body":"# Team-level Copilot usage metrics\n\nConstruct team-level GitHub Copilot usage metrics by joining the daily user-teams report with the daily per-user usage metrics report.\n\nThe Copilot usage metrics APIs do not publish a single pre-aggregated team report. Team-level metrics are constructed by joining the **user-teams** report (which lists each user's team memberships for a given day) with the **per-user usage metrics** report (which contains each user's Copilot activity for that day). Aggregating the joined rows by `team_id` produces team-level metrics.\n\nThe same join recipe supports any team-level slice you need: per `(team, day)`, per `(team, day, language)`, per `(team, day, IDE)`, over rolling windows, and so on.\n\n> \\[!NOTE]\n> If you only need a UI-based view of team-level adoption, the impact dashboard's user-team mapping surfaces team-level adoption cohort data natively, without requiring you to build the join described in this article. See [Viewing the Copilot impact dashboard](/en/copilot/how-tos/administer-copilot/view-impact-dashboard). Use the manual join described below when you need raw per-team NDJSON data, such as for custom BI reporting, or team-level metrics beyond adoption cohorts.\n\n## Fetching the reports\n\nThe two reports referenced in this guide are downloaded in two steps. First, call the REST endpoint for the day you want. The endpoint returns time-limited signed URLs from which you can download the report files. Then download the newline-delimited JSON (NDJSON) files those URLs point to. The user-teams and per-user rows are in those NDJSON files; they are not returned inline by the REST endpoint.\n\n| Report                              | Endpoint                                                                                |\n| :---------------------------------- | :-------------------------------------------------------------------------------------- |\n| Organization user-teams             | `GET /orgs/{org}/copilot/metrics/reports/user-teams-1-day?day=YYYY-MM-DD`               |\n| Enterprise user-teams               | `GET /enterprises/{enterprise}/copilot/metrics/reports/user-teams-1-day?day=YYYY-MM-DD` |\n| Organization per-user usage metrics | `GET /orgs/{org}/copilot/metrics/reports/users-1-day?day=YYYY-MM-DD`                    |\n| Enterprise per-user usage metrics   | `GET /enterprises/{enterprise}/copilot/metrics/reports/users-1-day?day=YYYY-MM-DD`      |\n\nEach endpoint returns a response of the form:\n\n```json\n{\n  \"download_links\": [\n    \"https://example.com/copilot-user-teams-report-1.ndjson\"\n  ],\n  \"report_day\": \"2026-05-07\"\n}\n```\n\nDownload the file at each URL within the link's expiration window to retrieve the rows for that report.\n\nFor complete request and response schemas, authentication requirements, and related endpoints, see [REST API endpoints for Copilot usage metrics](/en/rest/copilot/copilot-usage-metrics). For an overview of how individual usage metric fields are defined, see [Data available in Copilot usage metrics](/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics).\n\nFor a multi-day window, call the daily endpoints once per day and aggregate the daily results. See [Building rolling-window team reports](#building-rolling-window-team-reports) below.\n\n## Reports involved\n\nTeam-level metrics come from joining two report families: user-teams reports for team membership, and per-user usage metrics reports for activity.\n\n### User-teams reports\n\nThese reports list each user's team memberships on a given day.\n\n| Report                          | Scope                                                                                      | Key fields                                                           |\n| :------------------------------ | :----------------------------------------------------------------------------------------- | :------------------------------------------------------------------- |\n| `organization_user_teams_1_day` | Organization-team membership for the day. Includes only organization teams.                | `user_id`, `user_login`, `day`, `organization_id`, `team_id`, `slug` |\n| `enterprise_user_teams_1_day`   | Enterprise-team membership for the day. Includes both enterprise teams and business teams. | `user_id`, `user_login`, `day`, `enterprise_id`, `team_id`, `slug`   |\n\nA user belonging to multiple teams on the same day appears in multiple rows—one row per `(user, team)` pair.\n\n> \\[!IMPORTANT]\n> **Teams with fewer than 5 seated Copilot users are excluded from the user-teams reports.**\n>\n> Implications:\n>\n> * A team with fewer than 5 seated users on a given day will not appear in that day's user-teams report, even if its members have Copilot activity. The activity is still in the per-user usage metrics report, but no team row exists in the join result.\n> * A team that crosses the threshold during a multi-day window is present on some days and absent on others. Only the days the team was above the threshold contribute to its totals.\n> * If you sum the team rows back together to compare against an enterprise or organization total, the sum is lower than the entity total. The shortfall is the activity from users who only belong to sub-threshold teams—they have no team row in the join result, so their activity is not represented in any team aggregate.\n\n### Per-user usage metrics reports\n\nThese reports contain each user's Copilot activity for a given day.\n\n| Report                     | Scope                                                                                                                | Key fields                                                                                |\n| :------------------------- | :------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------- |\n| `organization_users_1_day` | One row per `(user_id, day, organization_id)` with the user's Copilot activity within that organization for the day. | `user_id`, `day`, `organization_id`, `enterprise_id`, activity counters, breakdown arrays |\n| `users_1_day`              | One row per `(user_id, day, enterprise_id)` with the user's Copilot activity within that enterprise for the day.     | `user_id`, `day`, `enterprise_id`, activity counters, breakdown arrays                    |\n\nFor the full list of fields available in these reports, see [Data available in Copilot usage metrics](/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics).\n\n> \\[!WARNING]\n> Do not join the rolling 28-day per-user reports (`users_28_day`, `organization_users_28_day`) with the daily user-teams report. The user-teams report reflects team membership on a single day, so joining 28 days of activity against a single-day membership snapshot attributes the full 28 days of activity to whichever teams the user happens to belong to on the join day. This mis-attributes activity to the wrong teams whenever team membership changed during the window. Always join daily activity with daily user-teams, then aggregate to your desired window.\n\n### Entity-level reports\n\nThe entity-level reports (`enterprise_28_day`, `organization_28_day`, `enterprise_1_day`, `organization_1_day`) are pre-aggregated totals for the entire enterprise or organization. They do not carry `user_id` or `team_id`, and cannot be joined with the user-teams report to produce per-team breakdowns. Use them directly when you want enterprise or organization totals; for team-level totals, use the daily user-teams + daily per-user-metrics join described below.\n\n## Example\n\nThis minimal end-to-end example produces one day of organization-team metrics. The sample NDJSON rows below for each input report are like the rows you would find in the file downloaded from one of that report's `download_links` (see [Fetching the reports](#fetching-the-reports) above).\n\nTwo users have Copilot activity on 2026-05-07 in organization `999`:\n\n* **Alice** (`user_id=1001`) belongs to two teams that day: `frontend` (`team_id=42`) and `backend` (`team_id=43`).\n* **Bob** (`user_id=1002`) belongs to `frontend` (`team_id=42`) only.\n\n### Input: `organization_user_teams_1_day`\n\n```json\n{\"user_id\": 1001, \"user_login\": \"alice\", \"day\": \"2026-05-07\", \"organization_id\": \"999\", \"team_id\": 42, \"slug\": \"frontend\"}\n{\"user_id\": 1001, \"user_login\": \"alice\", \"day\": \"2026-05-07\", \"organization_id\": \"999\", \"team_id\": 43, \"slug\": \"backend\"}\n{\"user_id\": 1002, \"user_login\": \"bob\",   \"day\": \"2026-05-07\", \"organization_id\": \"999\", \"team_id\": 42, \"slug\": \"frontend\"}\n```\n\nAlice appears twice—one row per team she belongs to.\n\n### Input: `organization_users_1_day`\n\n```json\n{\"user_id\": 1001, \"user_login\": \"alice\", \"day\": \"2026-05-07\", \"organization_id\": \"999\", \"enterprise_id\": \"13213\",\n \"user_initiated_interaction_count\": 50, \"code_generation_activity_count\": 40, \"code_acceptance_activity_count\": 12,\n \"loc_suggested_to_add_sum\": 200, \"loc_added_sum\": 88, \"used_chat\": true,  \"used_agent\": true,  ...}\n{\"user_id\": 1002, \"user_login\": \"bob\",   \"day\": \"2026-05-07\", \"organization_id\": \"999\", \"enterprise_id\": \"13213\",\n \"user_initiated_interaction_count\": 30, \"code_generation_activity_count\": 25, \"code_acceptance_activity_count\": 7,\n \"loc_suggested_to_add_sum\": 80,  \"loc_added_sum\": 24, \"used_chat\": true,  \"used_agent\": false, ...}\n```\n\nOne row per `(user, day, organization)`. Activity totals are for the day, summed across all surfaces.\n\n### Joined and aggregated result\n\nInner-join the two reports on `(user_id, day, organization_id)`, then group by `team_id` and aggregate. The `active_users` column below is an aggregation output (`COUNT(DISTINCT user_id)`), not a field on the per-user report; the remaining numeric columns are sums of the matching report fields.\n\n| team\\_id | slug     | active\\_users | code\\_acceptance\\_activity\\_count | loc\\_added\\_sum |\n| :------- | :------- | :------------ | :-------------------------------- | :-------------- |\n| 42       | frontend | 2             | 19                                | 112             |\n| 43       | backend  | 1             | 12                                | 88              |\n\nTwo team-day rows, one per team. The `frontend` row aggregates both Alice's and Bob's activity. The `backend` row contains only Alice's activity.\n\nAlice's activity contributes to **both** teams. The 12 and 88 from her row count in `frontend` and again in `backend`. This matches the intent of team-level metrics—each team sees the activity of its members—but summing the two team rows back into a single org total double-counts Alice. For organization totals, query `organization_users_1_day` directly without the user-teams join.\n\n## How to construct team-level metrics\n\nFor any team-level slice, the same four steps apply.\n\n1. **Pick the report pair.**\n\n   * For organization teams, pair `organization_user_teams_1_day` with `organization_users_1_day`. The shared entity id is `organization_id`.\n   * For enterprise and business teams, pair `enterprise_user_teams_1_day` with `users_1_day`. The shared entity id is `enterprise_id`.\n\n2. **Inner-join the two reports** on `(user_id, day, entity_id)`. All three keys must match. The join is one-to-many on the team side—a user on multiple teams matches multiple user-teams rows.\n\n3. **Filter by `day`** to the day you want. Both reports carry the same `day` value.\n\n4. **Group by `team_id`** (and `slug` for the team's display name) and aggregate. Use:\n\n   * `COUNT(DISTINCT user_id)` for distinct-user counts such as active users.\n   * `SUM(...)` for volume counters such as `code_generation_activity_count`, `loc_added_sum`, and `user_initiated_interaction_count`.\n\nThe join is an inner join: a team appears in the result for a given day only if at least one of its members had activity that day. To list teams that had no activity on the day, left-join from the user-teams report and treat null counters as zero.\n\n### Cutting by language, IDE, feature, or model\n\nPer-dimension breakdowns live in array fields on each per-user row (`totals_by_ide`, `totals_by_language_feature`, `totals_by_language_model`, `totals_by_model_feature`). To group by a dimension, expand the relevant array as part of the join, add the dimension columns to your grouping, and aggregate the per-element counters scoped to that dimension. `language` and `ide` live in separate arrays, so a team-level `(language × ide)` cross-tab takes two queries combined in your application.\n\n### Building rolling-window team reports\n\nTo produce a rolling-window team report (for example, a 28-day rollup):\n\n1. Call the daily endpoints for each day in the window.\n2. Join each day's per-user usage metrics report (`organization_users_1_day` or `users_1_day`) with the same day's user-teams report (`organization_user_teams_1_day` or `enterprise_user_teams_1_day`) on `(user_id, day, entity_id)`.\n3. Filter `day` to the window and drop `day` from the grouping.\n\nVolume counters are additive across days; sum them over the window. Distinct-user counts must be evaluated as `COUNT(DISTINCT user_id)` over the joined rows of the full window—they cannot be summed across daily counts.\n\nThe per-day join is what ensures each day's activity is attributed to whichever teams the user was on **that day**. Without it, team membership changes during the window silently mis-attribute activity to the wrong teams.\n\n## Limitations and caveats\n\n* **Users on multiple teams contribute to each team they belong to.** Be careful when combining team rows back into an org or enterprise total—multi-team users will be counted more than once. Use the per-user report directly (without the user-teams join) for org or enterprise totals.\n* **Sub-threshold teams are absent from the user-teams report.** Teams with fewer than 5 seated Copilot users on a given day are excluded, so their activity is not represented in team-level results even though the activity is still in the per-user report.\n* **Distinct-user counts cannot be summed across days.** When rolling up over a multi-day window, evaluate `COUNT(DISTINCT user_id)` over the joined rows for the whole window rather than summing daily counts.\n* **More feature surfaces are tracked.** The volume counters (`code_generation_activity_count`, `code_acceptance_activity_count`, and the `loc_*` counters) aggregate activity across multiple Copilot surfaces—inline IDE completions, chat panel actions, and (for accepted-line counters) Copilot agent edits. For per-counter surface coverage details, see [Data available in Copilot usage metrics](/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics). If you previously consumed similar metrics from a surface that counted only inline IDE completions, expect higher values in these counters and re-baseline rather than diffing across the cutover.\n* **Take advantage of the new dimensions.** Per-IDE, per-feature, per-`(language, feature)`, per-`(language, model)`, and per-`(model, feature)` breakdowns are available on each per-user row, enabling team-level reports that previous team-metric surfaces did not support.\n\n## Next steps\n\n* For the full schema and field reference for the per-user usage metrics report, see [Data available in Copilot usage metrics](/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics).\n* For example JSON payloads from the usage metrics endpoints, see [Example schema for Copilot usage metrics](/en/copilot/reference/copilot-usage-metrics/example-schema).\n* For guidance on reconciling metrics across the dashboard, APIs, and exports, see [Reconciling Copilot usage metrics across dashboards, APIs, and reports](/en/copilot/reference/copilot-usage-metrics/reconciling-usage-metrics)."}