API / get-leaderboard-via-analytics-api

API

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 totalUsers exceeds pageSize — 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.