
Get the team leaderboard with the Analytics API
Pull Tab and Agent usage rankings with GET https://api.cursor.com/analytics/team/leaderboard. Official reference: Analytics API → Leaderboard.
Authenticate with Basic auth (API key as username, empty password). Create keys at Cursor Dashboard → API Keys. Most Analytics endpoints need scope admin:*. Availability: Enterprise only. Team-level rate limit: 100 requests per minute per team.
Without a users filter the response ranks members by AI usage (default ranking uses combined lines accepted). With users, matching members keep their actual team-wide rank (a user who ranks #45 overall still returns rank: 45). The payload includes separate tab_leaderboard and agent_leaderboard lists plus pagination for large teams.
Query parameters
| Parameter | Rules |
|---|---|
startDate |
Optional. Default: 7 days ago. Prefer YYYY-MM-DD, or shortcuts now / today / yesterday / Nd (e.g. 14d). Max range 30 days. Time is ignored (day-level UTC). |
endDate |
Optional. Default: today. Same formats as startDate. |
page |
Optional. 1-indexed. Default: 1. |
pageSize |
Optional. Users per page. Default: 10, max: 500. |
users |
Optional. Comma-separated emails and/or public user ids (user_…). Mix formats in one request. |
Omit both dates for the last 7 days (simplest path for HTTP caching). Prefer day shortcuts or YYYY-MM-DD over ISO timestamps so ETag cache hits stay stable.
Request
curl -X GET "https://api.cursor.com/analytics/team/leaderboard" \
-u YOUR_API_KEY:
Second page with a custom page size:
curl -X GET "https://api.cursor.com/analytics/team/leaderboard?page=2&pageSize=20" \
-u YOUR_API_KEY:
Filter to specific users (team-wide ranks preserved):
curl -X GET "https://api.cursor.com/analytics/team/leaderboard?users=alice@example.com,bob@example.com" \
-u YOUR_API_KEY:
Example response:
{
"data": {
"tab_leaderboard": {
"data": [
{
"email": "alice@example.com",
"user_id": "user_abc123",
"profile_picture_url": "https://example.com/avatars/alice.jpg",
"total_accepts": 1334,
"total_lines_accepted": 3455,
"total_lines_suggested": 15307,
"line_acceptance_ratio": 0.2256519892590384,
"accept_ratio": 0.2330827067669173,
"rank": 1
}
],
"total_users": 142
},
"agent_leaderboard": {
"data": [
{
"email": "alice@example.com",
"user_id": "user_abc123",
"profile_picture_url": "https://example.com/avatars/alice.jpg",
"total_accepts": 914,
"total_lines_accepted": 65947,
"total_lines_suggested": 201467,
"line_acceptance_ratio": 0.3273465219182842,
"rank": 1
}
],
"total_users": 142
}
},
"pagination": {
"page": 1,
"pageSize": 10,
"totalUsers": 142,
"totalPages": 15,
"hasNextPage": true,
"hasPreviousPage": false
},
"params": {
"metric": "leaderboard",
"teamId": 12345,
"startDate": "2025-01-01",
"endDate": "2025-01-31",
"page": 1,
"pageSize": 10
}
}
Response fields
| Field | Type | Meaning |
|---|---|---|
data.tab_leaderboard.data[] |
array | Tab autocomplete ranking rows |
data.agent_leaderboard.data[] |
array | Agent edits ranking rows |
email / user_id |
string | Member identity |
profile_picture_url |
string | Avatar URL when present |
total_accepts |
number | Accept count for that surface |
total_lines_accepted / total_lines_suggested |
number | Line totals |
line_acceptance_ratio |
number | Accepted lines ÷ suggested lines |
accept_ratio |
number | Present on Tab rows (accept rate) |
rank |
number | Team-wide rank (kept when filtering by users) |
*.total_users |
number | Users in that leaderboard slice |
pagination.* |
object | page, pageSize, totalUsers, totalPages, hasNextPage, hasPreviousPage |
params.metric |
string | Echoes leaderboard |
Caching
Store the response ETag and send it back as If-None-Match on the next poll. Unchanged data returns 304 Not Modified with no body; 304s do not count against the rate limit. Analytics endpoints use Cache-Control: public, max-age=900 (15 minutes). See API Overview → Caching.
Pitfalls
- Expecting filtered ranks to renumber 1…N — filtered users keep their team-wide
rank. - Requesting more than 30 days — the Analytics date range caps at 30 days.
- Sending timestamps with clock times — time is ignored, and varying times break ETag cache hits.
- Polling without
If-None-Match— burns the 100/min team budget on identical payloads. - Ignoring pagination when
totalUsersexceedspageSize— default page size is only 10.
Sibling how-tos in this batch: Get Bugbot analytics, Get Bugbot review analytics, Get by-user metrics. Related: Get agent edits, Get Tab usage.