Claudeのuser_usage_reportでユーザー別トークン使用量を取得する
Enterprise Analytics APIのuser_usage_reportは、席ユーザー起因のトークン数を順位付きで返す。usage_reportとの違いとorder_by、group_byの使い方を示す。
Claude Enterprise Analytics APIの user_usage_report は、期間内のトークン使用量をユーザー1人につき1行で返し、多い順に並べるエンドポイントです。「誰がいちばんトークンを使っているか」を調べるために作られています。ただし数字の母集団は席ユーザーだけで、組織全体の使用量ではありません。この点を押さえないと、usage_report の合計と食い違って戸惑います。
user_usage_reportは席ユーザー起因のトークンだけを返す
呼び出し先は GET /v1/organizations/analytics/user_usage_report です。公式の説明では、含まれるのは席ユーザーに帰属する使用量だけです。APIキーを直接叩いたトラフィックや自動化の分は入りません。
したがって、全ユーザー行の total_tokens を足しても組織の総量にはなりません。組織全体の合計が必要なときは、バケット型の /v1/organizations/analytics/usage_report を使います。
金額を知りたいなら、同じ構造のuser_cost_reportでユーザー別コストを取る方法が別にあります。トークン数と金額は一致しません。モデルやキャッシュの種類で単価が違うためです。トークンの多さで順位を見たいときはこちら、請求への配賦ならコスト側、と使い分けます。
usage_reportとの違い
| 観点 | user_usage_report | usage_report |
|---|---|---|
| 返し方 | user_usage_reportユーザー1人につき1行、order_by の指標で順位付け | usage_report分・時・日のバケットごと、古い順 |
| 母集団 | user_usage_report席ユーザーに帰属する使用量のみ | usage_report組織全体(APIキー直叩き・自動化を含む) |
bucket_width | user_usage_report任意。指定すると行が時間で分割される | usage_report既定は 1d |
limit の単位 | user_usage_report行数(1〜1000、既定20) | usage_report時間バケット数 |
| 主な用途 | user_usage_report利用の多いユーザーの特定 | usage_report推移と総量の把握 |
limit の数え方は注意が必要です。user_usage_report では行数ですが、bucket_width や group_by[] を付けると1人が複数行に分かれます。この場合、limit は「ユーザー × 時間バケット × 次元」の行数を上限にします。20人分を取るつもりで limit=20 と書いても、内訳を付ければ20人は返りません。
利用条件と認証
利用できるのはClaude Enterpriseプランの組織で、read:analytics スコープを持つAPIキーが必要です。このキーは、claude.aiのOrganization settingsにあるAPIのページで公開APIアクセスを有効にしてから、Analytics APIキーとして作ります。
Claude ConsoleのAdmin APIキーとは別物です。Admin APIキーではこのAPIを呼べず、逆も同じです。2種類のAPIの違いはClaude Analytics APIの使い分けにまとめてあります。
プランにも条件があります。使用量とコストのエンドポイントは使用量ベースのEnterpriseプラン向けで、シート課金型のプランでは利用クレジットの分だけが反映されます。シート課金の組織で数字が小さく見えても、APIの不具合とは限りません。
最小のリクエスト
必須のクエリパラメータは starting_at だけです。RFC 3339のタイムゾーン付き日時で指定します。直近365日以内で、かつ2026年1月1日(UTC)以降でなければなりません。ending_at を省くと、現在時刻と starting_at に31日を足した日時の早いほうになります。範囲は最大31日です。
curl "https://api.anthropic.com/v1/organizations/analytics/user_usage_report\
?starting_at=2026-10-01T00:00:00Z\
&ending_at=2026-10-15T00:00:00Z\
&limit=100" \
--header "x-api-key: $ANALYTICS_API_KEY" \
--header "anthropic-version: 2023-06-01"応答は data の配列です。group_by[] も bucket_width も付けなければ、ユーザー1人が1行になります。公式の応答例に沿うと、1行は次のような形です(値は例)。
{
"actor": {
"type": "user_actor",
"user_id": "user_01AbCdEfGhIjKlMnOpQrSt",
"email_address": "jane@example.com",
"name": "Jane Smith",
"deleted": false
},
"cache_creation": {
"ephemeral_1h_input_tokens": 0,
"ephemeral_5m_input_tokens": 0
},
"cache_read_input_tokens": 3200000,
"output_tokens": 891000,
"requests": 128,
"server_tool_use": { "web_search_requests": 10 },
"total_tokens": 5377000,
"uncached_input_tokens": 1284500
}これに加えて、model や product などの次元は、group_by[] に指定したときだけ値が入ります。指定しなければnullです。トップレベルには data_refreshed_at、has_more、next_page、organization_id が付きます。
行の数字をどう読むか
トークンの種類は4つに分かれます。
| フィールド | 中身 |
|---|---|
uncached_input_tokens | 中身キャッシュを使わずに処理した入力トークン |
cache_read_input_tokens | 中身キャッシュから読んだ入力トークン |
cache_creation | 中身キャッシュ作成の入力トークン。5分と1時間で ephemeral_5m_input_tokens / ephemeral_1h_input_tokens に分かれる |
output_tokens | 中身生成された出力トークン |
total_tokens は全トークン種別の合計で、既定の並び順の基準でもあります。つまり、キャッシュ読み取りが多いユーザーは、実際の新規入力が少なくても上位に来ます。「新しく処理させた量」で見たいなら、並び順を uncached_input_tokens か output_tokens に替えます。
requests はAPIリクエスト数です。コード実行のような実行スパンは、リクエストではなくスパン数で数えられ、product がnullの行として現れます。server_tool_use.web_search_requests はウェブ検索の回数です。
この応答には、金額も cost_type / token_type の次元もありません。それらはコスト系エンドポイントの機能です。トークンの種類ごとの内訳は、行の中のフィールドとして最初から横に並んで返ります。
actorで見えるユーザーの状態
actor は常に user_actor 型で、user_id、email_address、name、deleted を持ちます。旧来の email は非推奨で、email_address と同じ値です。
メンバーが組織から外れた場合や、IdP経由でデプロビジョニングされた場合は deleted: true になり、email_address は残ります。アカウント自体が削除されると email_address がnullになり、name は "Deleted User" と返ります。システムが発行するサービスアカウントは email_address がnullで、name にサービス名が入ることがあります。
集計から退職者を外すには、exclude_deleted_users=true を付けます。このとき1ページの行数が limit を下回ることがあるので、has_more と next_page で最後までたどります。
order_byで「何の多さ」で並べるかを選ぶ
order_by で選べる指標は4つで、既定は total_tokens です。order は desc(既定)か asc です。
| 知りたいこと | order_by |
|---|---|
| 全体としていちばん使っている人 | order_bytotal_tokens |
| 新規の入力が多い人 | order_byuncached_input_tokens |
| 出力を多く生成させている人 | order_byoutput_tokens |
| 呼び出し回数が多い人 | order_byrequests |
asc で並べれば、使用量の少ないユーザーから順に見られます。ゼロ使用の席が行として返るかどうかは、このエンドポイントの説明に書かれていません。未使用の席を探すなら、席数を返す活動サマリー系のエンドポイントと突き合わせます。
group_byとフィルターで内訳を出す
ユーザーごとの合計だけでは、何に使ったかが分かりません。group_by[] を付けると、各ユーザーの行が次元ごとに分かれます。指定できるのは9つです。
product、model、context_window、inference_geo、speedrbac_group_id、slack_channel_idclaude_tag_category、claude_tag_user_id
curl -G "https://api.anthropic.com/v1/organizations/analytics/user_usage_report" \
--data-urlencode "starting_at=2026-10-01T00:00:00Z" \
--data-urlencode "group_by[]=product" \
--data-urlencode "group_by[]=model" \
--data-urlencode "order_by=output_tokens" \
--data-urlencode "limit=200" \
--header "x-api-key: $ANALYTICS_API_KEY" \
--header "anthropic-version: 2023-06-01"リスト型のパラメータは、値ごとにパラメータを繰り返すブラケット記法で渡します。絞り込みには products[]、models[]、user_ids[]、rbac_group_ids[]、context_windows[]、inference_geos[]、speeds[] が使えます。products[] の値は chat、chat_cowork_unified、claude-tag、claude_code、claude_design、claude_in_chrome、cowork、office_agent です。
chat_cowork_unified を含む製品別の数字は、利用者が移行するにつれて chat や cowork から動きます。その仕組みはchat_cowork_unifiedに数字が移る仕組みで扱っています。製品で絞るときは、ここを products[] に入れ忘れると、移行済みのユーザーの分が抜けます。
時間で分割する: bucket_width
bucket_width(1d、1h、1m)を指定すると、各行に starting_at と ending_at が入り、1人が時間バケットごとの複数行に分かれます。このとき ending_at は必須です。1m を選ぶと、範囲は最大24時間に制限されます。省略すると、期間全体が1行に集約されます。
上位ユーザーを製品別に集計するスクリプト
内訳付きでは1人が複数行になるので、集計はユーザーごとにまとめ直します。次のスクリプトは、product で分けた応答をユーザー単位にまとめ、製品別の total_tokens を並べます。410(カーソル失効)を受けたら先頭から取り直す処理も入れています。
import os
from collections import defaultdict
import requests
URL = "https://api.anthropic.com/v1/organizations/analytics/user_usage_report"
HEADERS = {
"x-api-key": os.environ["ANALYTICS_API_KEY"],
"anthropic-version": "2023-06-01",
}
PARAMS = {
"starting_at": "2026-10-01T00:00:00Z",
"ending_at": "2026-10-15T00:00:00Z",
"group_by[]": ["product"],
"exclude_deleted_users": "true",
"limit": 1000,
}
def fetch_all():
rows, page, restarts = [], None, 0
while True:
params = dict(PARAMS, **({"page": page} if page else {}))
res = requests.get(URL, headers=HEADERS, params=params)
if res.status_code == 410: # カーソル失効: 先頭から取り直す
restarts += 1
if restarts > 3:
res.raise_for_status()
rows, page = [], None
continue
res.raise_for_status()
body = res.json()
rows += body["data"]
if not body["has_more"]:
return rows
page = body["next_page"]
by_user = defaultdict(lambda: defaultdict(int))
for r in fetch_all():
email = r["actor"]["email_address"] or r["actor"]["user_id"]
by_user[email][r["product"] or "other"] += r["total_tokens"]
top = sorted(by_user.items(), key=lambda kv: sum(kv[1].values()), reverse=True)
for email, products in top[:10]:
print(email, sum(products.values()), dict(products))product がnullの行は、製品に帰属できない使用量です。ここでは other にまとめています。公式の説明にも、帰属できない使用量が other として報告されることがある旨があります。
limit は内訳を含めた行数の上限なので、同じユーザーの行が複数に分かれます。上のように全ページを取得してからユーザー単位で合算します。
組織総額との差を確かめる
ユーザー別の合計が組織の使用量に届かないのは仕様どおりです。差を確かめるには、group_by[] なしの usage_report を同じ期間・同じ bucket_width で取り、その合計からユーザー別の合計を引きます。差は、APIキー直叩きや自動化など、席ユーザーに帰属しない分に当たります。
注意点は、期間の揃え方です。どちらも ending_at を省くと、data_refreshed_at より後の未完了データが末尾に含まれます。2つの数字を比べるなら、両方に同じ ending_at を渡し、その値を前回の data_refreshed_at 以前にします。そうしないと、取得した時刻のずれがそのまま差になります。
つまずきやすい点
- RBACグループで分けると、複数グループに属するユーザーの全使用量が各グループの行に計上される。グループ行の合計は組織総額を超えうる。組織の真の総量は
group_by[]なしの実行で取る claude_tag_user_idはSlackのユーザーIDで、claude.aiのユーザーIDではない。rbac_group_idの次元やrbac_group_ids[]フィルターとは併用できない- 特定のユーザーに帰属しないClaude Tagの利用(監視や、Claudeが自発的に応答した分)は、ユーザー別の行に入らない。ユーザー行の合計がClaude Tag全体より小さくなる
- Claude Tagのダイレクトメッセージの利用は、
claude-tagではなくそのユーザーの製品の下に出る。products[]=claude-tagとclaude_tag_categories[]=dmを併用すると、DMは除外される - カーソルは発行したクエリに結び付く。途中でパラメータを変えると400、データ更新後に失効すると410になる
- Claude CodeをAmazon Bedrock経由で使っている場合、そのClaude Codeの利用はこのAPIに返らない
データの鮮度とレート制限
データは通常4時間ごとに更新されます。応答の data_refreshed_at は、その応答が参照したエクスポートの時刻で、該当期間をカバーするエクスポートがなければnullで data も空です。
値は、遅れて届くイベントや再調整のために改訂されます。改訂は、使用日が属する暦月の終了から約7日後まで続きます。たとえば10月1日の値は、11月7日ごろまで変わりえます。請求と突き合わせる用途では、終了から7日以上たった月だけを対象にします。
レート制限はキー単位ではなく組織単位で、既定ではAnalytics API全体で毎分60リクエストです。ユーザー別に内訳を何度も取り直す実装では、この上限に当たりやすくなります。
まとめ
user_usage_report は、席ユーザーのトークン使用量を順位付きで返します。見たい指標に合わせて order_by を選び、内訳が要るときは group_by[] を足します。内訳付きでは1人が複数行になるため、全ページを取得してユーザー単位で合算するところまでが実装の範囲です。組織全体の量は usage_report、金額はuser_cost_reportと、母集団と単位で分けて使います。権限や画面での見方はClaude Team/Enterpriseの使用量を確認する方法にあります。