GitHub Enterprise seat/billing metrics exporter for Prometheus.
The exporter collects aggregate enterprise billing/seat metrics and maps them to:
github_enterprise_license_seats_used{enterprise,feature}github_enterprise_license_seats_total{enterprise,feature}(when available)github_enterprise_license_seats_available{enterprise,feature}(when available)github_exporter_last_scrape_timestamp_seconds
Runtime uses githubkit + githubkit-schemas[ghec-2026-03-10] typed clients and one canonical endpoint per supported enterprise feature:
ghec(required):
/enterprises/{enterprise}/consumed-licensescopilot(required):
/enterprises/{enterprise}/copilot/billing/seats?per_page=1advanced_security(required):
/enterprises/{enterprise}/settings/billing/advanced-security
If a required feature endpoint is unavailable or unauthorized, the scrape fails immediately (HTTP 500 on /metrics).
- Token identity must have enterprise-level access (typically enterprise owner or billing manager-equivalent access).
- Classic PAT: include at least
read:enterprise. - Fine-grained PAT or GitHub App token: grant equivalent read access to enterprise billing/administration APIs used above.
All runtime options are available as CLI flags and environment variables:
--enterprise/GITHUB_ENTERPRISE(required)--token/GITHUB_TOKEN(required)--api-url/GITHUB_API_URL(default:https://api.github.com)--listen-address/EXPORTER_LISTEN_ADDRESS(default:0.0.0.0)--port/EXPORTER_PORT(default:9736)--timeout-seconds/EXPORTER_TIMEOUT_SECONDS(default:15)--once/EXPORTER_ONCE(default:false)--log-level/LOG_LEVEL(default:INFO)
Run a single scrape to stdout:
EXPORTER_ONCE=true GITHUB_ENTERPRISE=<enterprise> GITHUB_TOKEN=<token> uv run github-exporterRun HTTP exporter endpoint for Prometheus:
GITHUB_ENTERPRISE=<enterprise> GITHUB_TOKEN=<token> uv run github-exporterHTTP endpoints exposed by this exporter:
GET /metrics- Prometheus metricsGET /healthz- health responseokGET /- health responseok
When testing with gh in Copilot workflows, return only minimal fields so personal data is not unnecessarily returned to the LLM context.
Examples (aggregate values only):
export ENTERPRISE=<enterprise>
gh api "/enterprises/$ENTERPRISE/consumed-licenses" \
--jq '{consumed:.total_seats_consumed,total:(.total_seats // .total_seats_purchased)}'gh api "/enterprises/$ENTERPRISE/copilot/billing/seats?per_page=1" \
--jq '{used:(.total_seats // .active_this_cycle // .total_active_users // .total_active_seats // .seats_in_use), seats_returned:(.seats|length)}'If a verification query returns records, explicitly cap and narrow fields:
gh api graphql -f query='
query($enterprise:String!) {
enterprise(slug:$enterprise) {
organizations(first: 1) { totalCount nodes { login } }
}
}' -F enterprise="$ENTERPRISE"- Exporter behavior already minimizes transfer by querying summary billing endpoints (not paginated user lists).
- For manual troubleshooting, prefer minimal projection (
--jq) and strict limits (first: 1,per_page=1) where applicable. - Use sensible Prometheus scrape intervals for billing metrics (typically minutes, not seconds).
The included Dockerfile follows uv's Docker guidance with dependency-layer caching and uses a versioned uv image tag pinned by SHA256.
See the Dockerfile for the current pinned reference.
Build:
docker build -t github-exporter:local .Run:
docker run --rm \
-e GITHUB_ENTERPRISE=<enterprise> \
-e GITHUB_TOKEN=<token> \
github-exporter:localRun the Create GitHub Release
workflow from the repository's default branch
and use the version in pyproject.toml. It publishes the built container
image to GHCR with that release tag only.
The workflow creates a draft and publishes it as an immutable GitHub release for the verified image.
Install dependencies:
uv sync --lockedRun lint checks and formatting:
uv run ruff check .
uv run ruff format .Run type checking:
uv run ty check