elastic / elastic/integrations
[New Integration] Cursor Analytics & Code Tracking API's
- Dominant language
- Handlebars
- Stars
- 333
- Forks
- 647
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 225
Description
The data, field mapping, text etc was written by me, AI was only used to convert it to markdown.
The only open questions are:
1. For datastream 5, since the metrics are split up into so many small API's I currently added them under a single datastream, calling all API's in a single CEL interval, this could easily be changed into many smaller datastreams on request.
2. Event.category and event.type for each datastream is just a wild guess because there is nothing that really fits, any other suggestions on existing fields are welcome.
3. Handling CEL state cursor for datastream 5, which polls daily and uses full days in their endDate filter
All the datastreams includes all relevant details like field and ECS mapping, manifest.yml fields, pagination usage etc **(not AI generated)**.
> Addition to #17525 — adding datastreams for the [Code Tracking API](https://cursor.com/docs/account/teams/ai-code-tracking-api) and [Analytics API](https://cursor.com/docs/account/teams/analytics-api).
All APIs use **Basic Auth** with the API key as the username and empty password (for some reason..)
---
## Datastreams Overview
| # | Datastream | API Endpoint Base | Schedule |
|---|-----------|-------------------|----------|
| 1 | `code_tracking_commits` | `/analytics/ai-code/commits` | Daily |
| 2 | `code_change_metrics` | `/analytics/ai-code/changes` | Daily |
| 3 | `leaderboard` | `/analytics/team/leaderboard` | Daily |
| 4 | `bugbot` | `/analytics/team/bugbot` | Daily |
| 5 | `metrics` | Multiple `/analytics/team/*` endpoints | Daily |
---
## Datastream 1 — `code_tracking_commits`
### Request
```
GET https://api.cursor.com/analytics/ai-code/commits?startDate={initial_interval/cursor.timestamp}&endDate=now&page=1&pageSize={page_size}
Authorization: Basic
```
**Pagination:** Ceiling division of `totalCount / pageSize`, or paginate until `items` is empty.
**Cursor:** Use `interval` as the `startDate` parameter after initial_interval run, or "now + 1d". (Supports both 2025-01-15 and 2025-01-15T00:00:00Z)
### Configuration
Expand
| Parameter | Type | Default | Notes |
|-----------|------|---------|-------|
| `interval` | schedule | 1d | Run once per day |
| `initial_interval` | duration | 7 days | Max lookback per API rules |
| `api_key` | secret | — | Basic Auth username |
| `page_size` | number | 100 | Optional |
### Response Example
Expand
```json
{
"items": [
{
"commitHash": "a1b2c3d4",
"userId": "user_3k9x8q...",
"userEmail": "developer@company.com",
"repoName": "company/repo",
"branchName": "main",
"isPrimaryBranch": true,
"totalLinesAdded": 120,
"totalLinesDeleted": 30,
"tabLinesAdded": 50,
"tabLinesDeleted": 10,
"composerLinesAdded": 40,
"composerLinesDeleted": 5,
"nonAiLinesAdded": 30,
"nonAiLinesDeleted": 15,
"message": "Refactor: extract analytics client",
"commitTs": "2025-07-30T14:12:03.000Z",
"createdAt": "2025-07-30T14:12:30.000Z"
}
],
"totalCount": 42,
"page": 1,
"pageSize": 100
}
```
### ECS Field Mapping
Expand
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"code_changes_metrics"` |
| — | — | `event.category` = `["file"]` |
| — | — | `event.type` = `["info"]` |
| `commitTs` | date | `@timestamp` |
| `createdAt` | date | `event.created` |
| `userId` | string | `user.id` |
| `userEmail` | string | `user.name` |
| `message` | string | `message` |
| `commitHash` | string | `cursor.code_tracking_commits.commit_hash` |
| `repoName` | string | `cursor.code_tracking_commits.repo_name` |
| `branchName` | string | `cursor.code_tracking_commits.branch_name` |
| `isPrimaryBranch` | boolean | `cursor.code_tracking_commits.is_primary_branch` |
| `totalLinesAdded` | int | `cursor.code_tracking_commits.total_lines_added` |
| `totalLinesDeleted` | int | `cursor.code_tracking_commits.total_lines_deleted` |
| `tabLinesAdded` | int | `cursor.code_tracking_commits.tab_lines_added` |
| `tabLinesDeleted` | int | `cursor.code_tracking_commits.tab_lines_deleted` |
| `composerLinesAdded` | int | `cursor.code_tracking_commits.composer_lines_added` |
| `composerLinesDeleted` | int | `cursor.code_tracking_commits.composer_lines_deleted` |
| `nonAiLinesAdded` | int | `cursor.code_tracking_commits.non_ai_lines_added` |
| `nonAiLinesDeleted` | int | `cursor.code_tracking_commits.non_ai_lines_deleted` |
---
## Datastream 2 — `code_change_metrics`
### Request
```
GET https://api.cursor.com/analytics/ai-code/changes?startDate={initial_interval/cursor.interval}&endDate=now&page=1&pageSize={page_size}
Authorization: Basic
```
**Pagination:** Ceiling division of `totalCount / pageSize`, or paginate until `items` is empty.
**Cursor:** Use `interval` as the `startDate` parameter after initial_interval run, or "now + 1d". (Supports both 2025-01-15 and 2025-01-15T00:00:00Z)
### Configuration
Expand
| Parameter | Type | Default | Notes |
|-----------|------|---------|-------|
| `interval` | schedule | daily | 1d lookback |
| `initial_interval` | duration | 7 days | Max lookback per API rules |
| `api_key` | secret | — | Basic Auth username |
| `page_size` | number | 200 | Optional |
### Response Example
Expand
```json
{
"items": [
{
"changeId": "749356201",
"userId": "user_3k9x8q...",
"userEmail": "developer@company.com",
"source": "COMPOSER",
"model": null,
"totalLinesAdded": 18,
"totalLinesDeleted": 4,
"createdAt": "2025-07-30T15:10:12.000Z",
"metadata": [
{
"fileName": "src/analytics/report.ts",
"fileExtension": "ts",
"linesAdded": 12,
"linesDeleted": 3
},
{
"fileName": "src/analytics/ui.tsx",
"fileExtension": "tsx",
"linesAdded": 6,
"linesDeleted": 1
}
]
}
],
"totalCount": 128,
"page": 1,
"pageSize": 200
}
```
### ECS Field Mapping
> **Note:** The `metadata` array should be flattened — one document per `metadata` entry.
Expand
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"code_changes"` |
| — | — | `event.category` = `["file"]` |
| — | — | `event.type` = `["change", "info"]` |
| `createdAt` | date | `@timestamp` |
| `changeId` | string | `event.id` |
| `userId` | string | `user.id` |
| `userEmail` | string | `user.name` |
| `source` | string | `cursor.code_change_metrics.source` |
| `model` | string | `cursor.code_change_metrics.model` |
| `totalLinesAdded` | int | `cursor.code_change_metrics.total_lines_added` |
| `totalLinesDeleted` | int | `cursor.code_change_metrics.total_lines_deleted` |
| `metadata[].fileName` | string | `file.name` |
| `metadata[].fileExtension` | string | `file.extension` |
| `metadata[].linesAdded` | int | `cursor.code_change_metrics.lines_added` |
| `metadata[].linesDeleted` | int | `cursor.code_change_metrics.lines_deleted` |
---
## Datastream 3 — `leaderboard`
### Request
```
GET https://api.cursor.com/analytics/team/leaderboard?startDate={initial_interval/cursor.params.endDate}&endDate=now&page=1&pageSize={page_size}
Authorization: Basic
```
**Pagination:** Use `pagination.hasNextPage` / `pagination.totalPages` from the response.
**Cursor:** Use `cursor.params.endDate` as the `startDate` parameter after initial_interval run. (Supports shortcuts like `1d`, `7d`, `30d`, `90d`,etc.)
### Configuration
Expand
| Parameter | Type | Default | Notes |
|-----------|------|---------|-------|
| `interval` | schedule | 1d | 1d lookback |
| `initial_interval` | duration | 7 days | Max lookback per API rules |
| `api_key` | secret | — | Basic Auth username |
| `page_size` | number | 200 | Optional |
### Response Example
Expand
```json
{
"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
},
{
"email": "bob@example.com",
"user_id": "user_def789",
"profile_picture_url": "https://example.com/avatars/bob.jpg",
"total_accepts": 796,
"total_lines_accepted": 2090,
"total_lines_suggested": 7689,
"line_acceptance_ratio": 0.2718168812589414,
"accept_ratio": 0.2731256599787746,
"rank": 2
}
],
"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
},
{
"email": "bob@example.com",
"user_id": "user_def789",
"profile_picture_url": "https://example.com/avatars/bob.jpg",
"total_accepts": 843,
"total_lines_accepted": 61709,
"total_lines_suggested": 51092,
"line_acceptance_ratio": 1.2077924536684573,
"rank": 2
}
],
"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
}
}
```
### Processing Note
The `data` object should be split on each root key (e.g. `tab_leaderboard`, `agent_leaderboard`). Each child `.data` array entry becomes its own document, with a custom field indicating the leaderboard type. The leaderboard type is reflected in `event.action`.
### ECS Field Mapping
Expand
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"leaderboard_tab"` \| `"leaderboard_agent"` (per leaderboard type) |
| — | — | `event.category` = `["session"]` |
| — | — | `event.type` = `["info"]` |
| `email` | string | `user.name` |
| `user_id` | string | `user.id` |
| `profile_picture_url` | string | `event.reference` |
| `total_accepts` | int | `cursor.leaderboard.total_accepts` |
| `total_lines_accepted` | int | `cursor.leaderboard.total_lines_accepted` |
| `total_lines_suggested` | int | `cursor.leaderboard.total_lines_suggested` |
| `line_acceptance_ratio` | float | `cursor.leaderboard.line_acceptance_ratio` |
| `accept_ratio` | float | `cursor.leaderboard.accept_ratio` |
| `rank` | int | `cursor.leaderboard.rank` |
---
## Datastream 4 — `bugbot`
### Request
```
# With optional repo and PR state filters:
GET https://api.cursor.com/analytics/team/bugbot?repo=github.com/acme/app&prState=merged&startDate={initial_interval/cursor.params.endDate}&endDate=now&page=1&pageSize={page_size}
# Without repo filter:
GET https://api.cursor.com/analytics/team/bugbot?startDate={initial_interval/cursor.params.endDate}&endDate=now&page=1&pageSize={page_size}
Authorization: Basic
```
**Pagination:** Use `pagination.hasNextPage` / `pagination.totalPages` from the response.
**Cursor:** Use `cursor.params.endDate` as the `startDate` parameter after initial_interval run. (Supports both 2025-01-15 and 2025-01-15T00:00:00Z)
### Configuration
Expand
| Parameter | Type | Default | Notes |
|-----------|------|---------|-------|
| `interval` | schedule | daily | 1d lookback |
| `initial_interval` | duration | 7 days | Max lookback per API rules |
| `api_key` | secret | — | Basic Auth username |
| `repository` | text | — | Optional. Filter by repo, e.g. `github.com/acme/app` |
| `pr_state` | text | `merged` | Allowed values: `merged`, `all` |
| `page_size` | number | 100 | Optional |
### Response Example
Expand
```json
{
"data": [
{
"repo": "github.com/acme/app",
"pr_number": 42,
"timestamp": "2025-01-21T00:00:00.000Z",
"reviews": 3,
"issues": {
"total": 5,
"by_severity": {
"high": 1,
"medium": 2,
"low": 2
}
},
"issues_resolved": {
"total": 2,
"by_severity": {
"high": 1,
"medium": 1,
"low": 0
}
}
}
],
"pagination": {
"page": 1,
"pageSize": 100,
"totalItems": 1,
"totalPages": 1,
"hasNextPage": false,
"hasPreviousPage": false
}
}
```
### ECS Field Mapping
Expand
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"bugbot"` |
| — | — | `event.category` = `["session"]` |
| — | — | `event.type` = `["info"]` |
| `timestamp` | date | `@timestamp` |
| `repo` | string | `cursor.bugbot.repo` |
| `pr_number` | int | `cursor.bugbot.pr_number` |
| `reviews` | int | `cursor.bugbot.reviews` |
| `issues.total` | int | `cursor.bugbot.issues.total` |
| `issues.by_severity.high` | int | `cursor.bugbot.issues.high` |
| `issues.by_severity.medium` | int | `cursor.bugbot.issues.medium` |
| `issues.by_severity.low` | int | `cursor.bugbot.issues.low` |
| `issues_resolved.total` | int | `cursor.bugbot.issues_resolved.total` |
| `issues_resolved.by_severity.high` | int | `cursor.bugbot.issues_resolved.high` |
| `issues_resolved.by_severity.medium` | int | `cursor.bugbot.issues_resolved.medium` |
| `issues_resolved.by_severity.low` | int | `cursor.bugbot.issues_resolved.low` |
---
## Datastream 5 — `metrics`
> All small aggregated team metrics are collected under a single datastream, differentiated by `event.action`. These endpoints return daily aggregates and do not support pagination.
### Endpoints
| `event.action` | Endpoint |
|---|---|
| `agent_edits_metrics` | `GET /analytics/team/agent-edits` |
| `agent_tabs_metrics` | `GET /analytics/team/tabs` |
| `agent_dau_metrics` | `GET /analytics/team/dau` |
| `agent_client_versions_metrics` | `GET /analytics/team/client-versions` |
| `agent_top_file_extensions_metrics` | `GET /analytics/team/top-file-extensions` |
| `agent_mcp_metrics` | `GET /analytics/team/mcp` |
| `agent_commands_metrics` | `GET /analytics/team/commands` |
| `agent_plans_metrics` | `GET /analytics/team/plans` |
| `agent_ask_mode_metrics` | `GET /analytics/team/ask-mode` |
All endpoints accept `?startDate={initial_interval/cursor.params.endDate}&endDate=now` and use `Authorization: Basic `.
**Pagination:** No pagination provided, aggregates per day.
**Cursor:** Use `cursor.params.endDate` as the `startDate` parameter after initial_interval run. (Supports both 2025-01-15 and 2025-01-15T00:00:00Z)
**NOTE:** An issue with the cursor is that if we run the interval for "now -1d" at the start of a day, we might end up with missing a day?
### Configuration
Expand
| Parameter | Type | Default | Notes |
|-----------|------|---------|-------|
| `interval` | schedule | daily | 1d lookback |
| `initial_interval` | duration | 7 days | Max lookback per API rules |
| `api_key` | secret | — | Basic Auth username |
---
### 5a — Agent Edits (`agent_edits_metrics`)
Response Example
```json
{
"data": [
{
"event_date": "2025-01-15",
"total_suggested_diffs": 145,
"total_accepted_diffs": 98,
"total_rejected_diffs": 47,
"total_green_lines_accepted": 820,
"total_red_lines_accepted": 160,
"total_green_lines_rejected": 210,
"total_red_lines_rejected": 60,
"total_green_lines_suggested": 1030,
"total_red_lines_suggested": 220,
"total_lines_suggested": 1250,
"total_lines_accepted": 980
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_edits_metrics"` |
| — | — | `event.category` = `["host"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `total_suggested_diffs` | int | `cursor.metrics.total_suggested_diffs` |
| `total_accepted_diffs` | int | `cursor.metrics.total_accepted_diffs` |
| `total_rejected_diffs` | int | `cursor.metrics.total_rejected_diffs` |
| `total_green_lines_accepted` | int | `cursor.metrics.total_green_lines_accepted` |
| `total_red_lines_accepted` | int | `cursor.metrics.total_red_lines_accepted` |
| `total_green_lines_rejected` | int | `cursor.metrics.total_green_lines_rejected` |
| `total_red_lines_rejected` | int | `cursor.metrics.total_red_lines_rejected` |
| `total_green_lines_suggested` | int | `cursor.metrics.total_green_lines_suggested` |
| `total_red_lines_suggested` | int | `cursor.metrics.total_red_lines_suggested` |
| `total_lines_suggested` | int | `cursor.metrics.total_lines_suggested` |
| `total_lines_accepted` | int | `cursor.metrics.total_lines_accepted` |
---
### 5b — Tabs (`agent_tabs_metrics`)
Same field structure as Agent Edits. `event.action` = `"agent_tabs_metrics"`.
Response Example
```json
{
"data": [
{
"event_date": "2025-01-15",
"total_suggestions": 5420,
"total_accepts": 3210,
"total_rejects": 2210,
"total_green_lines_accepted": 4120,
"total_red_lines_accepted": 2000,
"total_green_lines_rejected": 1480,
"total_red_lines_rejected": 730,
"total_green_lines_suggested": 5600,
"total_red_lines_suggested": 2740,
"total_lines_suggested": 8340,
"total_lines_accepted": 6120
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_tabs_metrics"` |
| — | — | `event.category` = `["host"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `total_suggestions` | int | `cursor.metrics.total_suggestions` |
| `total_accepts` | int | `cursor.metrics.total_accepts` |
| `total_rejects` | int | `cursor.metrics.total_rejects` |
| `total_green_lines_accepted` | int | `cursor.metrics.total_green_lines_accepted` |
| `total_red_lines_accepted` | int | `cursor.metrics.total_red_lines_accepted` |
| `total_green_lines_rejected` | int | `cursor.metrics.total_green_lines_rejected` |
| `total_red_lines_rejected` | int | `cursor.metrics.total_red_lines_rejected` |
| `total_green_lines_suggested` | int | `cursor.metrics.total_green_lines_suggested` |
| `total_red_lines_suggested` | int | `cursor.metrics.total_red_lines_suggested` |
| `total_lines_suggested` | int | `cursor.metrics.total_lines_suggested` |
| `total_lines_accepted` | int | `cursor.metrics.total_lines_accepted` |
---
### 5c — DAU (`agent_dau_metrics`)
Response Example
```json
{
"data": [
{
"date": "2025-01-15",
"dau": 42,
"cli_dau": 5,
"cloud_agent_dau": 37,
"bugbot_dau": 10
}
]
}
```
> **Note:** This endpoint uses `date` instead of `event_date` as the timestamp field.
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_dau_metrics"` |
| — | — | `event.category` = `["host"]` |
| — | — | `event.type` = `["info"]` |
| `date` | date | `@timestamp` (time set to `00:00:00`) |
| `dau` | int | `cursor.metrics.dau` |
| `cli_dau` | int | `cursor.metrics.cli_dau` |
| `cloud_agent_dau` | int | `cursor.metrics.cloud_agent_dau` |
| `bugbot_dau` | int | `cursor.metrics.bugbot_dau` |
---
### 5d — Client Versions (`agent_client_versions_metrics`)
Response Example
```json
{
"data": [
{
"event_date": "2025-01-01",
"client_version": "0.42.3",
"user_count": 35,
"percentage": 0.833
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_client_versions_metrics"` |
| — | — | `event.category` = `["host"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `client_version` | string | `cursor.metrics.client_version` |
| `user_count` | int | `cursor.metrics.user_count` |
| `percentage` | float | `cursor.metrics.percentage` |
---
### 5e — Top File Extensions (`agent_top_file_extensions_metrics`)
Response Example
```json
{
"data": [
{
"event_date": "2025-01-15",
"file_extension": "tsx",
"total_files": 156,
"total_accepts": 98,
"total_rejects": 45,
"total_lines_suggested": 3230,
"total_lines_accepted": 2340,
"total_lines_rejected": 890
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_top_file_extensions_metrics"` |
| — | — | `event.category` = `["file"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `file_extension` | string | `file.extension` |
| `total_files` | int | `cursor.metrics.total_files` |
| `total_accepts` | int | `cursor.metrics.total_accepts` |
| `total_rejects` | int | `cursor.metrics.total_rejects` |
| `total_lines_suggested` | int | `cursor.metrics.total_lines_suggested` |
| `total_lines_accepted` | int | `cursor.metrics.total_lines_accepted` |
| `total_lines_rejected` | int | `cursor.metrics.total_lines_rejected` |
---
### 5f — MCP (`agent_mcp_metrics`)
Response Example
```json
{
"data": [
{
"event_date": "2025-01-15",
"tool_name": "read_file",
"mcp_server_name": "filesystem",
"usage": 245
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_mcp_metrics"` |
| — | — | `event.category` = `["process"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `tool_name` | string | `cursor.metrics.tool_name` |
| `mcp_server_name` | string | `cursor.metrics.mcp_server_name` |
| `usage` | int | `cursor.metrics.usage` |
---
### 5g — Commands (`agent_commands_metrics`)
Response Example
```json
{
"data": [
{
"event_date": "2025-01-15",
"command_name": "explain",
"usage": 89
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_commands_metrics"` |
| — | — | `event.category` = `["process"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `command_name` | string | `cursor.metrics.command_name` |
| `usage` | int | `cursor.metrics.usage` |
---
### 5h — Plans (`agent_plans_metrics`)
Response Example
```json
{
"data": [
{
"event_date": "2025-01-15",
"model": "claude-sonnet-4.5",
"usage": 156
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_plans_metrics"` |
| — | — | `event.category` = `["process"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `model` | string | `cursor.metrics.model` |
| `usage` | int | `cursor.metrics.usage` |
---
### 5i — Ask Mode (`agent_ask_mode_metrics`)
Response Example
```json
{
"data": [
{
"event_date": "2025-01-15",
"model": "claude-sonnet-4.5",
"usage": 203
}
]
}
```
ECS Field Mapping
| Source Field | Type | ECS / Target Field |
|---|---|---|
| — | — | `event.action` = `"agent_ask_mode_metrics"` |
| — | — | `event.category` = `["process"]` |
| — | — | `event.type` = `["info"]` |
| `event_date` | date | `@timestamp` (time set to `00:00:00`) |
| `model` | string | `cursor.metrics.model` |
| `usage` | int | `cursor.metrics.usage` |
---
## Dashboards and Visualizations
### Dashboard 1 — AI Code Impact
> Primary datastreams: `code_tracking_commits`, `code_change_metrics`
High-level view of how much code AI is generating, where, and how it compares to human-written code.
| # | Visualization | Type | Fields Used | Filters / Notes |
|---|---|---|---|---|
| 1 | AI vs Non-AI Lines Over Time | Line chart | `@timestamp`, `cursor.code_tracking_commits.tab_lines_added`, `cursor.code_tracking_commits.composer_lines_added`, `cursor.code_tracking_commits.non_ai_lines_added` | Stacked lines; one series per source. Filter `cursor.code_tracking_commits.is_primary_branch: true` to focus on main branches |
| 2 | AI Code Proportion | Donut | `cursor.code_tracking_commits.tab_lines_added`, `cursor.code_tracking_commits.composer_lines_added`, `cursor.code_tracking_commits.non_ai_lines_added` | Three slices: Tab, Composer, Non-AI. Sum over selected time range |
| 3 | Top Repositories by AI Lines | Horizontal bar | `cursor.code_tracking_commits.repo_name`, sum of `cursor.code_tracking_commits.total_lines_added` | Top N repos. Optionally filter `cursor.code_tracking_commits.is_primary_branch: true` |
| 4 | Code Changes by Source | Donut | `cursor.code_change_metrics.source` (count) | One slice per source value (COMPOSER, TAB, etc.) |
| 5 | Top File Extensions by Lines Changed | Horizontal bar | `file.extension`, sum of `cursor.code_change_metrics.lines_added` | From `code_change_metrics`; top N extensions |
| 6 | Recent Commits | Table | `@timestamp`, `user.name`, `cursor.code_tracking_commits.repo_name`, `cursor.code_tracking_commits.branch_name`, `cursor.code_tracking_commits.total_lines_added`, `cursor.code_tracking_commits.total_lines_deleted`, `message` | Sorted by `@timestamp` desc; paginated |
| 7 | Total AI Lines Added | Metric tile | Sum of `cursor.code_tracking_commits.tab_lines_added` + `cursor.code_tracking_commits.composer_lines_added` | Single number over selected range |
| 8 | Total Commits | Metric tile | Count of `code_tracking_commits` documents | — |
---
### Dashboard 2 — Developer Leaderboard
> Primary datastream: `leaderboard`
Rankings and acceptance metrics per developer across Tab and Agent leaderboards.
| # | Visualization | Type | Fields Used | Filters / Notes |
|---|---|---|---|---|
| 1 | Tab Leaderboard | Table | `cursor.leaderboard.rank`, `user.name`, `cursor.leaderboard.total_accepts`, `cursor.leaderboard.total_lines_accepted`, `cursor.leaderboard.total_lines_suggested`, `cursor.leaderboard.accept_ratio`, `cursor.leaderboard.line_acceptance_ratio` | Filter `event.action: "leaderboard_tab"`. Sort by `cursor.leaderboard.rank` asc |
| 2 | Agent Leaderboard | Table | Same fields as above (except `accept_ratio` which is absent for agent) | Filter `event.action: "leaderboard_agent"`. Sort by `cursor.leaderboard.rank` asc |
| 3 | Top Developers by Accepts | Horizontal bar | `user.name`, `cursor.leaderboard.total_accepts` | Filter by leaderboard type via `event.action`. Top N |
| 4 | Team Acceptance Ratio Distribution | Histogram | `cursor.leaderboard.line_acceptance_ratio` | Bucket developers by acceptance ratio to show distribution |
| 5 | Total Team Accepts | Metric tile | Sum of `cursor.leaderboard.total_accepts` | Filter by `event.action` to choose Tab or Agent |
| 6 | Avg Line Acceptance Ratio | Metric tile | Avg of `cursor.leaderboard.line_acceptance_ratio` | — |
---
### Dashboard 3 — Team Usage & Adoption
> Primary datastream: `metrics` (sub-endpoints 5a–5i)
Aggregate team-level usage trends including DAU, suggestions, client versions, and model/tool usage.
| # | Visualization | Type | Fields Used | Filters / Notes |
|---|---|---|---|---|
| 1 | Daily Active Users Over Time | Line chart | `@timestamp`, `cursor.metrics.dau`, `cursor.metrics.cli_dau`, `cursor.metrics.cloud_agent_dau`, `cursor.metrics.bugbot_dau` | Filter `event.action: "agent_dau_metrics"`. Stacked or multi-line |
| 2 | Suggestions vs Accepts vs Rejects | Stacked area | `@timestamp`, `cursor.metrics.total_accepts`, `cursor.metrics.total_rejects` | Filter `event.action: "agent_tabs_metrics"` |
| 3 | Agent Edit Acceptance Rate Over Time | Line chart | `@timestamp`, computed ratio of `cursor.metrics.total_accepted_diffs` / `cursor.metrics.total_suggested_diffs` | Filter `event.action: "agent_edits_metrics"` |
| 4 | Client Version Distribution | Donut | `cursor.metrics.client_version`, `cursor.metrics.user_count` | Filter `event.action: "agent_client_versions_metrics"`. Latest `@timestamp` only for point-in-time view |
| 5 | Top File Extensions | Horizontal bar | `file.extension`, `cursor.metrics.total_lines_accepted` | Filter `event.action: "agent_top_file_extensions_metrics"` |
| 6 | MCP Tool Usage | Horizontal bar | `cursor.metrics.tool_name`, `cursor.metrics.mcp_server_name`, `cursor.metrics.usage` | Filter `event.action: "agent_mcp_metrics"`. Group by server + tool |
| 7 | Command Usage | Horizontal bar | `cursor.metrics.command_name`, `cursor.metrics.usage` | Filter `event.action: "agent_commands_metrics"` |
| 8 | Model Usage — Plans vs Ask Mode | Stacked bar | `cursor.metrics.model`, `cursor.metrics.usage` | Side-by-side or stacked; filter `event.action` = `"agent_plans_metrics"` or `"agent_ask_mode_metrics"` |
| 9 | Lines Suggested vs Accepted (Tabs) | Metric tiles (pair) | `cursor.metrics.total_lines_suggested`, `cursor.metrics.total_lines_accepted` | Filter `event.action: "agent_tabs_metrics"` |
| 10 | Total DAU (Latest) | Metric tile | `cursor.metrics.dau` | Filter `event.action: "agent_dau_metrics"`, latest `@timestamp` |
---
### Dashboard 4 — BugBot Code Review
> Primary datastream: `bugbot`
PR review activity, issues found, severity breakdown, and resolution rates.
| # | Visualization | Type | Fields Used | Filters / Notes |
|---|---|---|---|---|
| 1 | Issues Found Over Time | Line chart | `@timestamp`, `cursor.bugbot.issues.total` | — |
| 2 | Issues by Severity | Stacked bar | `@timestamp`, `cursor.bugbot.issues.high`, `cursor.bugbot.issues.medium`, `cursor.bugbot.issues.low` | One color per severity |
| 3 | Found vs Resolved | Grouped bar | `cursor.bugbot.issues.total`, `cursor.bugbot.issues_resolved.total` | Paired bars per time bucket |
| 4 | Severity Distribution (All Time) | Donut | Sum of `cursor.bugbot.issues.high`, `.medium`, `.low` | Three slices |
| 5 | Resolution Rate | Metric tile | Computed `cursor.bugbot.issues_resolved.total` / `cursor.bugbot.issues.total` | Percentage display |
| 6 | PR Review Detail | Table | `@timestamp`, `cursor.bugbot.repo`, `cursor.bugbot.pr_number`, `cursor.bugbot.reviews`, `cursor.bugbot.issues.total`, `cursor.bugbot.issues_resolved.total` | Sorted by `@timestamp` desc. Optional filter by `cursor.bugbot.repo` |
| 7 | Top Repos by Issues Found | Horizontal bar | `cursor.bugbot.repo`, sum of `cursor.bugbot.issues.total` | Top N repos |
| 8 | Reviews Per PR Over Time | Line chart | `@timestamp`, avg of `cursor.bugbot.reviews` | Shows review activity trend |
Contributor guide
Assessment
This issue has not been assessed yet.