Cursor
Port's Cursor integration allows you to ingest Cursor usage metrics into your software catalog using the Ocean Custom Integration framework.
Supported metricsโ
The Cursor integration can ingest usage metrics into Port. Available metrics depend on your Cursor subscription tier:
Available for all Cursor teams:
cursor_usage_record- Organization-level daily usage metrics from/teams/daily-usage-data.
Requires Cursor Enterprise subscription:
cursor_commit_record- Individual commits with AI assistance breakdown from/analytics/ai-code/commits.cursor_ai_code_change_record- Daily AI-generated code changes from/analytics/ai-code/changes.
The Cursor API documentation provides details on available endpoints. Analytics APIs (commit tracking and code changes) are only available for Cursor Enterprise teams. Standard Cursor teams can access usage metrics endpoints only.
Prerequisitesโ
To use this integration, you need:
- A Cursor API token with appropriate permissions to access usage metrics.
- The token should have read access to organization or team usage data.
Installationโ
Choose one of the following installation methods to deploy the Ocean Custom Integration:
- Helm
- Docker
Prerequisites
To install the integration, you need a Kubernetes cluster that the integration's container chart will be deployed to.
Please make sure that you have kubectl and helm installed on your machine, and that your kubectl CLI is connected to the Kubernetes cluster where you plan to install the integration.
If you are having trouble installing this integration, please refer to these troubleshooting steps.
Installation
- Add Port's Helm repo and install the Ocean Custom Integration:
Remember to replace the placeholders for YOUR_PORT_CLIENT_ID, YOUR_PORT_CLIENT_SECRET, and YOUR_CURSOR_API_KEY.
helm repo add --force-update port-labs https://port-labs.github.io/helm-charts
helm upgrade --install my-ocean-cursor-integration port-labs/port-ocean \
--set port.clientId="YOUR_PORT_CLIENT_ID" \
--set port.clientSecret="YOUR_PORT_CLIENT_SECRET" \
--set port.baseUrl="https://api.getport.io" \
--set initializePortResources=true \
--set scheduledResyncInterval=120 \
--set integration.identifier="my-ocean-cursor-integration" \
--set integration.type="custom" \
--set integration.eventListener.type="POLLING" \
--set integration.config.baseUrl="https://api.cursor.com" \
--set integration.config.authType="basic" \
--set integration.config.paginationType="none" \
--set integration.secrets.username="YOUR_CURSOR_API_KEY" \
--set integration.secrets.password=""
The port_region, port.baseUrl, portBaseUrl, port_base_url and OCEAN__PORT__BASE_URL parameters are used to select which instance of Port API will be used.
Port exposes two API instances, one for the EU region of Port, and one for the US region of Port.
- If you use the EU region of Port (https://app.port.io), your API URL is
https://api.port.io. - If you use the US region of Port (https://app.us.port.io), your API URL is
https://api.us.port.io.
Configuration parameters
This table summarizes the available parameters for the installation.
| Parameter | Description | Example | Required |
|---|---|---|---|
port.clientId | Your Port client id | โ | |
port.clientSecret | Your Port client secret | โ | |
port.baseUrl | Your Port API URL - https://api.getport.io for EU, https://api.us.getport.io for US | โ | |
integration.config.baseUrl | The base URL of the Cursor API instance | https://api.cursor.com | โ |
integration.config.authType | The authentication type for the API (use basic for Cursor) | basic | โ |
integration.secrets.username | Your Cursor API key (used as username in Basic Auth) | key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | โ |
integration.secrets.password | Password for Basic Auth (empty string for Cursor API) | "" | โ |
integration.config.paginationType | How your API handles pagination (offset, page, cursor, or none) | none | โ |
integration.eventListener.type | The event listener type. Read more about event listeners | POLLING | โ |
integration.type | The integration type (must be custom for Ocean Custom Integration) | custom | โ |
integration.identifier | Unique identifier for the integration instance | my-ocean-cursor-integration | โ |
scheduledResyncInterval | The number of minutes between each resync. When not set the integration will resync for each event listener resync event. Read more about scheduledResyncInterval | 120 | โ |
initializePortResources | Default true, When set to true the integration will create default blueprints and the port App config Mapping. Read more about initializePortResources | true | โ |
sendRawDataExamples | Enable sending raw data examples from the third party API to port for testing and managing the integration mapping. Default is true | true | โ |
For advanced configuration such as proxies or self-signed certificates, click here.
To run the integration using Docker for a one-time sync:
Remember to replace the placeholders for YOUR_PORT_CLIENT_ID, YOUR_PORT_CLIENT_SECRET, and YOUR_CURSOR_API_KEY.
docker run -i --rm --platform=linux/amd64 \
-e OCEAN__EVENT_LISTENER='{"type":"ONCE"}' \
-e OCEAN__INITIALIZE_PORT_RESOURCES=true \
-e OCEAN__SEND_RAW_DATA_EXAMPLES=true \
-e OCEAN__INTEGRATION__CONFIG__BASE_URL="https://api.cursor.com" \
-e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="basic" \
-e OCEAN__INTEGRATION__CONFIG__PAGINATION_TYPE="none" \
-e OCEAN__INTEGRATION__SECRETS__USERNAME="YOUR_CURSOR_API_KEY" \
-e OCEAN__INTEGRATION__SECRETS__PASSWORD="" \
-e OCEAN__PORT__CLIENT_ID="YOUR_PORT_CLIENT_ID" \
-e OCEAN__PORT__CLIENT_SECRET="YOUR_PORT_CLIENT_SECRET" \
-e OCEAN__PORT__BASE_URL="https://api.getport.io" \
ghcr.io/port-labs/port-ocean-custom:latest
The port_region, port.baseUrl, portBaseUrl, port_base_url and OCEAN__PORT__BASE_URL parameters are used to select which instance of Port API will be used.
Port exposes two API instances, one for the EU region of Port, and one for the US region of Port.
- If you use the EU region of Port (https://app.port.io), your API URL is
https://api.port.io. - If you use the US region of Port (https://app.us.port.io), your API URL is
https://api.us.port.io.
For advanced configuration such as proxies or self-signed certificates, click here.
Set up data modelโ
Before the integration can sync data, you need to create the required blueprints in Port. These blueprints define the data model for your Cursor metrics.
To create the blueprints:
-
Go to your Builder page.
-
Click on the
+ Blueprintbutton. -
Copy and paste each blueprint JSON from the sections below.
Cursor Usage Record Blueprint (Click to expand)
Organization-level daily usage metrics:
{
"identifier": "cursor_usage_record",
"description": "A daily summary record of Cursor usage for an organization (UTC)",
"title": "Cursor Usage Record",
"icon": "Cursor",
"schema": {
"properties": {
"record_date": {
"type": "string",
"format": "date-time",
"title": "Record Date (UTC)"
},
"org": {
"type": "string",
"title": "Organization"
},
"total_accepts": {
"type": "number",
"title": "Total Accepts"
},
"total_rejects": {
"type": "number",
"title": "Total Rejects"
},
"total_tabs_shown": {
"type": "number",
"title": "Total Tabs Shown"
},
"total_tabs_accepted": {
"type": "number",
"title": "Total Tabs Accepted"
},
"total_lines_added": {
"type": "number",
"title": "Total Lines Added"
},
"total_lines_deleted": {
"type": "number",
"title": "Total Lines Deleted"
},
"accepted_lines_added": {
"type": "number",
"title": "Accepted Lines Added"
},
"accepted_lines_deleted": {
"type": "number",
"title": "Accepted Lines Deleted"
},
"composer_requests": {
"type": "number",
"title": "Composer Requests"
},
"chat_requests": {
"type": "number",
"title": "Chat Requests"
},
"agent_requests": {
"type": "number",
"title": "Agent Requests"
},
"subscription_included_reqs": {
"type": "number",
"title": "Subscription Included Requests"
},
"api_key_reqs": {
"type": "number",
"title": "API Key Requests"
},
"usage_based_reqs": {
"type": "number",
"title": "Usage-based Requests"
},
"bugbot_usages": {
"type": "number",
"title": "Bugbot Usages"
},
"most_used_model": {
"type": "string",
"title": "Most Used Model"
},
"total_active_users": {
"type": "number",
"title": "Total Active Users"
},
"total_input_tokens": {
"type": "number",
"title": "Total Input Tokens"
},
"total_output_tokens": {
"type": "number",
"title": "Total Output Tokens"
},
"total_cache_write_tokens": {
"type": "number",
"title": "Total Cache Write Tokens"
},
"total_cache_read_tokens": {
"type": "number",
"title": "Total Cache Read Tokens"
},
"total_cents": {
"type": "number",
"title": "Total Cost (cents)"
},
"breakdown": {
"type": "object",
"title": "Breakdown"
}
},
"required": ["record_date", "org"]
},
"mirrorProperties": {},
"calculationProperties": {
"acceptance_rate": {
"title": "Acceptance Rate",
"description": "Percentage of AI suggestions that were accepted",
"calculation": "if (.properties.total_accepts + .properties.total_rejects) > 0 then (.properties.total_accepts / (.properties.total_accepts + .properties.total_rejects)) * 100 else 0 end",
"type": "number",
"colorized": true,
"colors": {
"25": "red",
"50": "orange",
"75": "yellow",
"90": "green"
}
}
},
"aggregationProperties": {},
"relations": {}
}Cursor User Usage Record Blueprint (Click to expand)
User-level daily usage metrics:
{
"identifier": "cursor_user_usage_record",
"description": "A daily summary record of Cursor usage for a single user (UTC)",
"title": "Cursor User Usage Record",
"icon": "Cursor",
"schema": {
"properties": {
"record_date": {
"type": "string",
"format": "date-time",
"title": "Record Date (UTC)"
},
"org": {
"type": "string",
"title": "Organization"
},
"email": {
"type": "string",
"title": "User Email"
},
"is_active": {
"type": "boolean",
"title": "Active"
},
"total_accepts": {
"type": "number",
"title": "Total Accepts"
},
"total_rejects": {
"type": "number",
"title": "Total Rejects"
},
"total_tabs_shown": {
"type": "number",
"title": "Total Tabs Shown"
},
"total_tabs_accepted": {
"type": "number",
"title": "Total Tabs Accepted"
},
"total_lines_added": {
"type": "number",
"title": "Total Lines Added"
},
"total_lines_deleted": {
"type": "number",
"title": "Total Lines Deleted"
},
"accepted_lines_added": {
"type": "number",
"title": "Accepted Lines Added"
},
"accepted_lines_deleted": {
"type": "number",
"title": "Accepted Lines Deleted"
},
"composer_requests": {
"type": "number",
"title": "Composer Requests"
},
"chat_requests": {
"type": "number",
"title": "Chat Requests"
},
"agent_requests": {
"type": "number",
"title": "Agent Requests"
},
"subscription_included_reqs": {
"type": "number",
"title": "Subscription Included Requests"
},
"api_key_reqs": {
"type": "number",
"title": "API Key Requests"
},
"usage_based_reqs": {
"type": "number",
"title": "Usage-based Requests"
},
"bugbot_usages": {
"type": "number",
"title": "Bugbot Usages"
},
"most_used_model": {
"type": "string",
"title": "Most Used Model"
},
"input_tokens": {
"type": "number",
"title": "Input Tokens"
},
"output_tokens": {
"type": "number",
"title": "Output Tokens"
},
"cache_write_tokens": {
"type": "number",
"title": "Cache Write Tokens"
},
"cache_read_tokens": {
"type": "number",
"title": "Cache Read Tokens"
},
"total_cents": {
"type": "number",
"title": "Total Cost (cents)"
},
"breakdown": {
"type": "object",
"title": "Breakdown"
}
},
"required": [
"record_date",
"org",
"email"
]
},
"mirrorProperties": {},
"calculationProperties": {
"acceptance_rate": {
"title": "Acceptance Rate",
"description": "Percentage of AI suggestions that were accepted by this user",
"calculation": "if (.properties.total_accepts + .properties.total_rejects) > 0 then (.properties.total_accepts / (.properties.total_accepts + .properties.total_rejects)) * 100 else 0 end",
"type": "number",
"colorized": true,
"colors": {
"25": "red",
"50": "orange",
"75": "yellow",
"90": "green"
}
}
},
"aggregationProperties": {},
"relations": {
"user": {
"title": "User",
"target": "_user",
"required": false,
"many": false
}
}
}Cursor Team Usage Record Blueprint (Click to expand)
Team-level daily usage metrics:
{
"identifier": "cursor_team_usage_record",
"description": "A daily summary record of Cursor usage for a team (UTC)",
"title": "Cursor Team Usage Record",
"icon": "Cursor",
"schema": {
"properties": {
"record_date": {
"type": "string",
"format": "date-time",
"title": "Record Date (UTC)"
},
"org": {
"type": "string",
"title": "Organization"
},
"team": {
"type": "string",
"title": "Team"
},
"total_accepts": {
"type": "number",
"title": "Total Accepts"
},
"total_rejects": {
"type": "number",
"title": "Total Rejects"
},
"total_tabs_shown": {
"type": "number",
"title": "Total Tabs Shown"
},
"total_tabs_accepted": {
"type": "number",
"title": "Total Tabs Accepted"
},
"total_lines_added": {
"type": "number",
"title": "Total Lines Added"
},
"total_lines_deleted": {
"type": "number",
"title": "Total Lines Deleted"
},
"accepted_lines_added": {
"type": "number",
"title": "Accepted Lines Added"
},
"accepted_lines_deleted": {
"type": "number",
"title": "Accepted Lines Deleted"
},
"composer_requests": {
"type": "number",
"title": "Composer Requests"
},
"chat_requests": {
"type": "number",
"title": "Chat Requests"
},
"agent_requests": {
"type": "number",
"title": "Agent Requests"
},
"subscription_included_reqs": {
"type": "number",
"title": "Subscription Included Requests"
},
"api_key_reqs": {
"type": "number",
"title": "API Key Requests"
},
"usage_based_reqs": {
"type": "number",
"title": "Usage-based Requests"
},
"bugbot_usages": {
"type": "number",
"title": "Bugbot Usages"
},
"most_used_model": {
"type": "string",
"title": "Most Used Model"
},
"total_active_users": {
"type": "number",
"title": "Total Active Users"
},
"input_tokens": {
"type": "number",
"title": "Input Tokens"
},
"output_tokens": {
"type": "number",
"title": "Output Tokens"
},
"cache_write_tokens": {
"type": "number",
"title": "Cache Write Tokens"
},
"cache_read_tokens": {
"type": "number",
"title": "Cache Read Tokens"
},
"total_cents": {
"type": "number",
"title": "Total Cost (cents)"
},
"breakdown": {
"type": "object",
"title": "Breakdown"
}
},
"required": [
"record_date",
"org",
"team"
]
},
"mirrorProperties": {},
"calculationProperties": {
"acceptance_rate": {
"title": "Acceptance Rate",
"description": "Percentage of AI suggestions that were accepted by this team",
"calculation": "if (.properties.total_accepts + .properties.total_rejects) > 0 then (.properties.total_accepts / (.properties.total_accepts + .properties.total_rejects)) * 100 else 0 end",
"type": "number",
"colorized": true,
"colors": {
"25": "red",
"50": "orange",
"75": "yellow",
"90": "green"
}
}
},
"aggregationProperties": {},
"relations": {
"team_members": {
"title": "Team Members",
"target": "cursor_user_usage_record",
"many": true,
"required": false
}
}
}Cursor Commit Record Blueprint (Click to expand)
Individual commit tracking with AI assistance breakdown:
{
"identifier": "cursor_commit_record",
"description": "Individual AI-generated commit record with full details",
"title": "Cursor Commit Record",
"icon": "Cursor",
"schema": {
"properties": {
"commitHash": {
"type": "string",
"title": "Commit Hash"
},
"userId": {
"type": "string",
"title": "User ID"
},
"userEmail": {
"type": "string",
"title": "User Email"
},
"repoName": {
"type": "string",
"title": "Repository Name"
},
"branchName": {
"type": "string",
"title": "Branch Name"
},
"isPrimaryBranch": {
"type": "boolean",
"title": "Is Primary Branch"
},
"totalLinesAdded": {
"type": "number",
"title": "Total Lines Added"
},
"totalLinesDeleted": {
"type": "number",
"title": "Total Lines Deleted"
},
"tabLinesAdded": {
"type": "number",
"title": "TAB Lines Added"
},
"tabLinesDeleted": {
"type": "number",
"title": "TAB Lines Deleted"
},
"composerLinesAdded": {
"type": "number",
"title": "Composer Lines Added"
},
"composerLinesDeleted": {
"type": "number",
"title": "Composer Lines Deleted"
},
"nonAiLinesAdded": {
"type": "number",
"title": "Non-AI Lines Added"
},
"nonAiLinesDeleted": {
"type": "number",
"title": "Non-AI Lines Deleted"
},
"message": {
"type": "string",
"title": "Commit Message"
},
"commitTs": {
"type": "string",
"format": "date-time",
"title": "Commit Timestamp"
},
"createdAt": {
"type": "string",
"format": "date-time",
"title": "Created At"
},
"org": {
"type": "string",
"title": "Organization"
}
},
"required": [
"commitHash",
"userId",
"userEmail",
"repoName",
"branchName",
"org"
]
},
"mirrorProperties": {},
"calculationProperties": {
"ai_assistance_percentage": {
"title": "AI Assistance %",
"calculation": "if (.properties.totalLinesAdded + .properties.totalLinesDeleted) == 0 then 0 else ((.properties.tabLinesAdded + .properties.tabLinesDeleted + .properties.composerLinesAdded + .properties.composerLinesDeleted) / (.properties.totalLinesAdded + .properties.totalLinesDeleted)) * 100 end",
"type": "number"
},
"total_ai_lines": {
"title": "Total AI Lines Changed",
"calculation": ".properties.tabLinesAdded + .properties.tabLinesDeleted + .properties.composerLinesAdded + .properties.composerLinesDeleted",
"type": "number"
}
},
"aggregationProperties": {},
"relations": {
"user": {
"title": "User",
"target": "_user",
"required": false,
"many": false
},
"repository": {
"title": "Repository",
"target": "service",
"required": false,
"many": false
},
"githubPullRequest": {
"title": "GitHub Pull Request",
"target": "githubPullRequest",
"required": false,
"many": false
}
}
}Cursor Daily Commit Record Blueprint (Click to expand)
Daily aggregated commit statistics by user:
{
"identifier": "cursor_daily_commit_record",
"description": "A daily aggregated record of AI-generated commits by user",
"title": "Cursor Daily Commit Record",
"icon": "Cursor",
"schema": {
"properties": {
"record_date": {
"type": "string",
"format": "date-time",
"title": "Record Date (UTC)"
},
"org": {
"type": "string",
"title": "Organization"
},
"user_email": {
"type": "string",
"title": "User Email"
},
"total_commits": {
"type": "number",
"title": "Total Commits"
},
"total_lines_added": {
"type": "number",
"title": "Total Lines Added"
},
"total_lines_deleted": {
"type": "number",
"title": "Total Lines Deleted"
},
"tab_lines_added": {
"type": "number",
"title": "TAB Lines Added"
},
"tab_lines_deleted": {
"type": "number",
"title": "TAB Lines Deleted"
},
"composer_lines_added": {
"type": "number",
"title": "Composer Lines Added"
},
"composer_lines_deleted": {
"type": "number",
"title": "Composer Lines Deleted"
},
"non_ai_lines_added": {
"type": "number",
"title": "Non-AI Lines Added"
},
"non_ai_lines_deleted": {
"type": "number",
"title": "Non-AI Lines Deleted"
},
"primary_branch_commits": {
"type": "number",
"title": "Primary Branch Commits"
},
"total_unique_repos": {
"type": "number",
"title": "Total Unique Repositories"
},
"most_active_repo": {
"type": "string",
"title": "Most Active Repository"
},
"breakdown": {
"type": "object",
"title": "Breakdown Details"
}
},
"required": [
"record_date",
"org",
"user_email"
]
},
"mirrorProperties": {},
"calculationProperties": {
"ai_assistance_percentage_calc": {
"title": "AI Assistance %",
"calculation": "if (.properties.total_lines_added + .properties.total_lines_deleted) == 0 then 0 else ((.properties.tab_lines_added + .properties.tab_lines_deleted + .properties.composer_lines_added + .properties.composer_lines_deleted) / (.properties.total_lines_added + .properties.total_lines_deleted)) * 100 end",
"type": "number"
}
},
"aggregationProperties": {},
"relations": {
"user": {
"title": "User",
"target": "_user",
"required": false,
"many": false
}
}
}Cursor AI Code Change Record Blueprint (Click to expand)
Daily aggregated AI-generated code changes by user:
{
"identifier": "cursor_ai_code_change_record",
"description": "A daily aggregated record of AI-generated code changes by user",
"title": "Cursor AI Code Change Record",
"icon": "Cursor",
"schema": {
"properties": {
"record_date": {
"type": "string",
"format": "date-time",
"title": "Record Date (UTC)"
},
"org": {
"type": "string",
"title": "Organization"
},
"user_email": {
"type": "string",
"title": "User Email"
},
"total_changes": {
"type": "number",
"title": "Total AI Changes"
},
"total_lines_added": {
"type": "number",
"title": "Total Lines Added"
},
"total_lines_deleted": {
"type": "number",
"title": "Total Lines Deleted"
},
"tab_changes": {
"type": "number",
"title": "TAB Changes Count"
},
"composer_changes": {
"type": "number",
"title": "Composer Changes Count"
},
"tab_lines_added": {
"type": "number",
"title": "TAB Lines Added"
},
"tab_lines_deleted": {
"type": "number",
"title": "TAB Lines Deleted"
},
"composer_lines_added": {
"type": "number",
"title": "Composer Lines Added"
},
"composer_lines_deleted": {
"type": "number",
"title": "Composer Lines Deleted"
},
"most_used_model": {
"type": "string",
"title": "Most Used AI Model"
},
"unique_file_extensions": {
"type": "number",
"title": "Unique File Extensions"
},
"breakdown": {
"type": "object",
"title": "Breakdown Details"
}
},
"required": [
"record_date",
"org",
"user_email"
]
},
"mirrorProperties": {},
"calculationProperties": {
"tab_vs_composer_ratio_calc": {
"title": "TAB vs Composer Ratio",
"calculation": "if .properties.composer_changes > 0 then .properties.tab_changes / .properties.composer_changes else null end",
"type": "number"
},
"average_change_size_calc": {
"title": "Average Change Size",
"calculation": "if .properties.total_changes > 0 then (.properties.total_lines_added + .properties.total_lines_deleted) / .properties.total_changes else 0 end",
"type": "number"
}
},
"aggregationProperties": {},
"relations": {
"user": {
"title": "User",
"target": "_user",
"required": false,
"many": false
},
"ai_commits": {
"title": "AI Commits",
"target": "cursor_daily_commit_record",
"required": false,
"many": true
}
}
} -
Click
Saveto save the blueprint.
Configurationโ
After installation, define which endpoints to sync in your integration configuration. Each resource maps an API endpoint to Port entities using JQ expressions to transform the data.
Key mapping components:
kind: The API endpoint path (combined with your base URL).selector.query: JQ filter to include/exclude entities (use'true'to sync all).selector.data_path: JQ expression pointing to the array of items in the response.port.entity.mappings: How to map API fields to Port entity properties.
For more details on how the Ocean Custom Integration works, see the How it works section in the custom integration overview.
To configure the mappings:
-
Go to your data sources page.
-
Find your Cursor integration in the list.
-
Click on the integration to open the mapping editor.
-
Add the resource mapping configurations below.
Organization usage metrics mapping (Click to expand)
- kind: /teams/daily-usage-data
selector:
query: 'true'
method: POST
body: '{"startDate": ((now | floor) - (86400 * 30)) * 1000, "endDate": (now | floor) * 1000}'
data_path: '.data'
port:
entity:
mappings:
identifier: .org + "@" + .date
title: .org + " usage " + .date
blueprint: '"cursor_usage_record"'
properties:
record_date: .date + "T00:00:00Z"
org: .org
total_accepts: .totals.total_accepts
total_rejects: .totals.total_rejects
total_tabs_shown: .totals.total_tabs_shown
total_tabs_accepted: .totals.total_tabs_accepted
total_lines_added: .totals.total_lines_added
total_lines_deleted: .totals.total_lines_deleted
accepted_lines_added: .totals.accepted_lines_added
accepted_lines_deleted: .totals.accepted_lines_deleted
composer_requests: .totals.composer_requests
chat_requests: .totals.chat_requests
agent_requests: .totals.agent_requests
subscription_included_reqs: .totals.subscription_included_reqs
api_key_reqs: .totals.api_key_reqs
usage_based_reqs: .totals.usage_based_reqs
bugbot_usages: .totals.bugbot_usages
most_used_model: .totals.most_used_model
total_active_users: .totals.total_active_users
total_input_tokens: .totals.total_input_tokens
total_output_tokens: .totals.total_output_tokens
total_cache_write_tokens: .totals.total_cache_write_tokens
total_cache_read_tokens: .totals.total_cache_read_tokens
total_cents: .totals.total_cents
breakdown: .breakdownUser-level usage events mapping (Click to expand)
This endpoint provides individual usage events with detailed information about each AI interaction:
resources:
- kind: /teams/filtered-usage-events
selector:
query: 'true'
method: POST
body: '{"startDate": ((now | floor) - (86400 * 30)) * 1000, "endDate": (now | floor) * 1000, "page": 1, "pageSize": 100}'
data_path: '.usageEvents'
port:
entity:
mappings:
identifier: .id
title: .userEmail + " - " + .eventType + " (" + .createdAt + ")"
blueprint: '"cursor_user_usage_record"'
properties:
record_date: .createdAt
email: .userEmail
org: .org
composer_requests: 'if .eventType == "composer" then 1 else 0 end'
chat_requests: 'if .eventType == "chat" then 1 else 0 end'
agent_requests: 'if .eventType == "agent" then 1 else 0 end'
total_accepts: .totalAccepts // 0
total_rejects: .totalRejects // 0
input_tokens: .inputTokens // 0
output_tokens: .outputTokens // 0
cache_write_tokens: .cacheWriteTokens // 0
cache_read_tokens: .cacheReadTokens // 0
total_cents: .totalCents // 0
most_used_model: .model
breakdown: '{eventType: .eventType, model: .model, eventId: .id, timestamp: .createdAt}'PaginationThis endpoint returns paginated results. The example shows page 1 with 100 results. For production use, you may want to implement pagination logic or increase the
pageSizeparameter (max 1000).Enterprise: Individual commit tracking (Click to expand)
Requires Cursor EnterpriseThis endpoint requires a Cursor Enterprise subscription. You'll receive a
401error if your API key doesn't have enterprise access.resources:
- kind: /analytics/ai-code/commits
selector:
query: 'true'
query_params:
startDate: "30d"
endDate: "0d"
page: "1"
pageSize: "100"
data_path: '.items'
port:
entity:
mappings:
identifier: .commitHash
title: .commitHash + " by " + .userEmail
blueprint: '"cursor_commit_record"'
properties:
commitHash: .commitHash
userId: .userId
userEmail: .userEmail
repoName: .repoName
branchName: .branchName
isPrimaryBranch: .isPrimaryBranch
totalLinesAdded: .totalLinesAdded
totalLinesDeleted: .totalLinesDeleted
tabLinesAdded: .tabLinesAdded
tabLinesDeleted: .tabLinesDeleted
composerLinesAdded: .composerLinesAdded
composerLinesDeleted: .composerLinesDeleted
nonAiLinesAdded: .nonAiLinesAdded
nonAiLinesDeleted: .nonAiLinesDeleted
message: .message
commitTs: .commitTs
createdAt: .createdAt
org: .org
relations:
user: .userEmail
repository: .repoNameEnterprise: AI code changes tracking (Click to expand)
Requires Cursor EnterpriseThis endpoint requires a Cursor Enterprise subscription. You'll receive a
401error if your API key doesn't have enterprise access.resources:
- kind: /analytics/ai-code/changes
selector:
query: 'true'
query_params:
startDate: "30d"
endDate: "0d"
page: "1"
pageSize: "100"
data_path: '.items'
port:
entity:
mappings:
identifier: .userEmail + "@" + .createdAt + "@changes"
title: .userEmail + " code changes " + .createdAt
blueprint: '"cursor_ai_code_change_record"'
properties:
record_date: .createdAt
org: .org
user_email: .userEmail
total_changes: .totalChanges
total_lines_added: .totalLinesAdded
total_lines_deleted: .totalLinesDeleted
tab_changes: .tabChanges
composer_changes: .composerChanges
tab_lines_added: .tabLinesAdded
tab_lines_deleted: .tabLinesDeleted
composer_lines_added: .composerLinesAdded
composer_lines_deleted: .composerLinesDeleted
most_used_model: .mostUsedModel
unique_file_extensions: .uniqueFileExtensions
breakdown: .metadata
relations:
user: .userEmail -
Click
Saveto save the mapping.
Customizationโ
If you want to customize your setup or test different API endpoints before committing to a configuration, use the interactive builder.
The interactive builder helps you:
- Test your Cursor API endpoints with live data.
- Automatically detect the data structure and field types.
- Generate blueprints and resource mappings tailored to your preferences.
- Get installation commands with your configuration pre-filled.
Simply provide your Cursor API details, and the builder will generate everything you need to install and create the integration in Port.
Visualize Cursor metricsโ
Once your Cursor data is synced to Port, you can create dashboards to monitor AI coding assistant usage, track adoption, analyze costs, and measure developer productivity. This section shows you how to build insightful visualizations using Port's dashboard widgets.
Create a dashboardโ
-
Navigate to your software catalog.
-
Click on the
+ Newbutton in the left sidebar. -
Select New dashboard.
-
Name the dashboard Cursor AI Insights.
-
Input
Monitor Cursor AI usage, adoption, and productivity metricsunder Description. -
Select the
Cursoricon. -
Click
Create.
You now have a blank dashboard where you can add widgets to visualize your Cursor metrics.
Add widgetsโ
Create the following widgets to gain insights into your Cursor usage:
Total Active Users
-
Click on
+ Widgetand select Number Chart. -
Fill in the following details:
-
Title:
Total Active Users. -
Description:
Number of active users using Cursor AI. -
Icon:
Users. -
Blueprint:
cursor_usage_record. -
Chart type: Select
Count entities.
-
-
Click Save.
Total AI Accepts
-
Click on
+ Widgetand select Number Chart. -
Fill in the following details:
-
Title:
Total AI Accepts. -
Description:
Total number of AI suggestions accepted. -
Icon:
Checklistc. -
Blueprint:
cursor_usage_record. -
Chart type: Select
Aggregate by property. -
Property:
total_accepts. -
Function:
Sum.
-
-
Click Save.
Total Cost
-
Click on
+ Widgetand select Number Chart. -
Fill in the following details:
-
Title:
Total Cost. -
Description:
Total cost of Cursor AI usage. -
Blueprint:
cursor_usage_record. -
Chart type: Select
Aggregate by property. -
Property:
total_cents. -
Function:
Sum.
-
-
Click Save.
AI Suggestion Acceptance Rate Over Time
-
Click on
+ Widgetand select Line Chart. -
Fill in the following details:
-
Title:
AI Suggestion Acceptance Rate Over Time. -
Description:
Track how well users are accepting AI suggestions. -
Icon:
LineChart. -
Blueprint:
cursor_usage_record. -
Chart type: Select
Aggregate by property. -
Property:
Total Accepts,Total Rejects,Total Lines Added,Total Lines Deleted. -
Function:
Average. -
Time interval:
Week. -
Time range:
In the past 30 days. -
Measure time by:
$record_date.
-
-
Click Save.
Daily Cost Trends
-
Click on
+ Widgetand select Line Chart. -
Fill in the following details:
-
Title:
Daily Cost Trends. -
Description:
Track AI usage costs over time. -
Icon:
LineChart. -
Blueprint:
cursor_usage_record. -
Chart type: Select
Aggregate by property. -
Property:
total_cents. -
Function:
Sum. -
Time interval:
Week. -
Time range:
In the past 30 days. -
Measure time by:
$record_date.
-
-
Click Save.
AI Code Generation Trends
-
Click on
+ Widgetand select Line Chart. -
Fill in the following details:
-
Title:
AI Code Generation Trends. -
Description:
Track TAB vs Composer usage for code changes. -
Icon:
LineChart. -
Blueprint:
cursor_ai_code_change_record. -
Chart type: Select
Aggregate by property. -
Property:
tab_changes,composer_changes. -
Function:
Average. -
Time interval:
Week. -
Time range:
In the past 30 days. -
Measure time by:
$record_date.
-
-
Click Save.
AI Model Usage Distribution
-
Click on
+ Widgetand select Pie Chart. -
Fill in the following details:
-
Title:
AI Model Usage Distribution. -
Description:
Which AI models are being used most frequently. -
Icon:
Pie. -
Blueprint:
cursor_usage_record. -
Property:
most_used_model.
-
-
Click Save.
User Activity Breakdown
-
Click on
+ Widgetand select Table. -
Fill in the following details:
-
Title:
User Activity Breakdown. -
Description:
Detailed view of individual user productivity and AI usage patterns. -
Icon:
Table. -
Blueprint:
cursor_user_usage_record.
-
-
In the Displayed properties section, select the following columns:
$identifier$titleemailtotal_acceptstotal_rejectsacceptance_ratetotal_centsrecord_date
-
Click Save.
Daily Commit Activity
-
Click on
+ Widgetand select Line Chart. -
Fill in the following details:
-
Title:
Daily Commit Activity. -
Description:
Track code commits with AI assistance breakdown. -
Icon:
LineChart. -
Blueprint:
cursor_daily_commit_record. -
Chart type: Select
Count entities. -
Function:
count. -
Property:
Total Commits. -
Time interval:
Week. -
Time range:
In the past 30 days. -
Measure time by:
$record_date.
-
-
Click Save.