GitHub Copilot Usage Metrics API: A Practical Guide

GitHub retired its Copilot Billing Preview app on August 4, 2026, and replaced one tidy preview with two control planes: billing settings for money, and the GitHub Copilot usage metrics API for behavior. That is extra plumbing. It is also better data: per-user app sessions, prompts, requests, tokens, code activity, and adoption signals in reports you can automate.

This guide pulls a rolling 28-day user report for a GitHub organization, downloads every NDJSON partition, and turns the new Copilot app fields into a readable table. It also covers the part dashboards tend to bury: a prompt count is evidence of prompting, not proof of productivity.

What replaced the Billing Preview app

GitHub’s retirement notice directs administrators to the main billing experience. The AI usage page handles credits, exports, budgets, cost centers, and usage-pool allocation. Use that side when the question is “What did Copilot cost?” or “Who can spend more?”

The usage metrics API answers a different set of questions: Who used Copilot? Which surfaces, models, and languages were active? How many prompts became requests? How much code activity was recorded? That separation is healthy. Anyone who has compared the products in our coding-assistant workflow guide knows that price and usage rarely describe the same thing.

Do not reconcile an invoice from these activity fields. The per-user report includes ai_credits_used, but GitHub describes it as consumption analysis rather than an invoicing total. Finance gets the billing data; engineering gets the telemetry. Mixing them produces a dashboard with impressive decimals and the wrong answer.

Prerequisites for the GitHub Copilot usage metrics API

For the organization-level walkthrough, you need an authorized organization owner or custom role, Copilot usage metrics enabled, curl, and jq. The official REST reference supports fine-grained personal access tokens, GitHub App user tokens, and GitHub App installation tokens with Organization Copilot metrics: read.

Store the credential in GITHUB_TOKEN; do not paste it into a script or commit it beside the report. For durable automation, a GitHub App is easier to rotate and audit than somebody’s personal token. This is ordinary least privilege, the unglamorous layer that keeps an AI coding-agent security checklist from becoming decorative wall art.

  • Enable the Copilot usage metrics policy for the organization.
  • Grant only read access to Organization Copilot metrics.
  • Set GITHUB_TOKEN in your shell or secret manager.
  • Replace YOUR_ORG with the organization slug, not its display name.

Choose the scope before choosing the endpoint. Organization reports are convenient for a team that owns its own reporting; enterprise reports provide cross-organization rollups and require enterprise-level permissions. Both offer daily and rolling 28-day variants, plus separate aggregate, per-user, repository, and user-to-team reports. Begin with per-user data only if you genuinely need it. An aggregate report answers many adoption questions with less workforce telemetry attached.

Pull a 28-day per-user Copilot report

Request the report envelope

The endpoint does not return the report itself. It returns a date range and one or more limited-lifetime download URLs. Start by saving that envelope:

: "${GITHUB_TOKEN:?Set GITHUB_TOKEN first}"
report_org="YOUR_ORG"
report_api="https://api.github.com/orgs/${report_org}/copilot/metrics/reports/users-28-day/latest"

curl -fsSL \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer ${GITHUB_TOKEN}" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  "${report_api}" > copilot-report.json

jq '{
  report_start_day,
  report_end_day,
  partitions: (.download_links | length)
}' copilot-report.json

A 403 usually points to the policy, role, or token permission. A 404 often means the organization slug or resource scope is wrong. Check the response before debugging jq; the JSON parser did not revoke your enterprise permissions, however ambitious it may look.

Download every NDJSON partition

Do not assume download_links[0] is the whole report. GitHub can partition exports, so iterate over every URL and combine the records. Fetch them soon after creating the envelope because signed links expire:

: > copilot-users.ndjson

jq -r '.download_links[]' copilot-report.json |
while IFS= read -r report_url; do
  curl -fsSL "${report_url}" >> copilot-users.ndjson
  printf '\n' >> copilot-users.ndjson
done

jq -s 'length' copilot-users.ndjson

If a signed URL fails after the envelope worked, request a fresh envelope rather than retrying an expired address forever. For a scheduled pipeline, save the report dates and ingestion time alongside the raw file. “Latest” is convenient for humans; explicit lineage is kinder to the person investigating why Tuesday changed on Friday.

Parse the new Copilot app metrics

The current metrics schema adds used_copilot_app and a nested totals_by_copilot_app object. That object carries sessions, requests, prompts, input tokens, output tokens, and average tokens per request. It is omitted when a user has no app activity, so optional access is not optional in practice.

jq -s -r '
  ["user","app","sessions","requests","prompts",
   "prompt_tokens","output_tokens","credits","loc_added"],
  (.[] | [
    .user_login,
    (.used_copilot_app // false),
    (.totals_by_copilot_app.session_count // 0),
    (.totals_by_copilot_app.request_count // 0),
    (.totals_by_copilot_app.prompt_count // 0),
    (.totals_by_copilot_app.token_usage.prompt_tokens_sum // 0),
    (.totals_by_copilot_app.token_usage.output_tokens_sum // 0),
    (.ai_credits_used // 0),
    (.loc_added_sum // 0)
  ]) | @tsv
' copilot-users.ndjson > copilot-users.tsv

prompt_count records user-issued prompts, commands, or queries. request_count also includes automated agentic follow-up calls, so requests can exceed prompts without anybody secretly typing at superhuman speed. The ratio can reveal how agent-heavy a workflow is. It cannot tell you whether those calls produced good code.

FieldUseful interpretationDo not call it
session_countDistinct app sessionsDays saved
prompt_countUser-issued commandsProblems solved
request_countPrompts plus agent follow-upsDeveloper effort
token_usageModel workloadCode quality
loc_added_sumRecorded lines addedBusiness value

That final column is not pedantry. A refactor can delete thousands of lines and improve a system; generated boilerplate can add thousands and create a maintenance invoice for next quarter. Preserve the raw counters, then name derived metrics according to what they actually calculate. “App requests per active user” is defensible. “Engineering acceleration score” is a costume.

Copilot app activity also enters the broader feature, model, language, code-generation, acceptance, and lines-of-code rollups under the copilot_app feature value. Use the nested object for app-specific engagement and the rollups when comparing the app with IDE chat, completions, CLI, or agents.

Unstructured Copilot activity flowing through an API into a structured metrics grid

Verify the dashboard before trusting it

GitHub’s current data-freshness guidance allows two full UTC days after a reporting day closes. Treat newer records as provisional. A daily job should reload that trailing window so late telemetry corrects the history instead of manufacturing a recurring end-of-chart slump.

Coverage also depends on client settings and versions. A developer who disables IDE telemetry may still appear in top-level active-user counts through server-side signals while feature, language, model, and lines-of-code arrays stay empty. Unknown values are valid records, not database lint. Keep them, monitor their share, and investigate upgrades when it rises.

Dashboard comparisons need matching windows as well. GitHub’s interface uses rolling periods, while daily API records expose day-by-day activity and NDJSON exports freeze whatever telemetry existed when they were created. Record report_start_day, report_end_day, and ingestion time. When a chart disagrees with the interface, check window boundaries and data freshness before opening a severity-one incident against arithmetic.

  • Label the latest two full UTC days provisional and reload them.
  • Track the share of users with populated dimensional data.
  • Compare matching daily or 28-day windows.
  • Backfill recent partitions before publishing trend changes.

Measure adoption without productivity theater

GitHub calls its lines-of-code metrics directional. That is the correct level of humility. Sessions, prompts, accepted blocks, tokens, and added lines measure activity. They do not measure correctness, maintainability, avoided incidents, or whether a developer spent the afternoon deleting the morning’s AI output.

Start with a modest scorecard: telemetry coverage, active app users, prompts per active user, request-to-prompt ratio, and adoption trend. Pair it with independently measured delivery and quality outcomes. Our analysis of why AI coding benchmarks fail in production applies here too: a precise counter can still measure the wrong target.

Per-user reports also deserve an explicit governance rule. Decide who can see them, how long raw records live, and which decisions the data may inform. Adoption support and capacity planning are reasonable uses. Quietly ranking employees by prompt volume is not analysis; it is surveillance with a tab-separated output file. If a team-level aggregate answers the question, collect the aggregate.

The unresolved question is whether organizations will use this granularity to improve adoption or flatten it into another developer leaderboard. The best Copilot dashboard knows the difference between observing work and judging it. Its first test arrives two full UTC days after every report date: if the numbers cannot revise when GitHub expects the data to be available, the dashboard is measuring pipeline timing and calling it team behavior.

Get the Daily Pulse

Sharp analysis on what's actually moving in AI. No hype, no filler, no weekly digest.

Get the Daily Pulse

Sharp AI analysis, daily. Two minutes, every morning.

Get the Daily PulseTwo minutes, every morning