Visualize Cursor metrics
Send this guide to your coding agent.
Prerequisite: Install Port MCP
Open plan mode. Implement this Port guide in my org via MCP: https://docs.port.io/guides/all/visualize-cursor-metrics Goal: get the guide's core flow working end-to-end in my org; adapting it to fit my existing setup takes priority over matching the guide 1:1. Plan: 1. Confirm MCP is connected, in the right org, with sufficient permissions. 2. Diff the guide's data model (blueprints, properties, relations, actions, agents, automations, integrations, secrets) against mine. 3. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates. 4. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out. 5. Stop on any blocker and give me options. Approving this plan authorizes the writes it lists; pause only for writes beyond what's listed. Build: - Extend blueprint schema additively when upserting; don't remove or overwrite existing properties, and treat type conflicts as a blocker, not an auto-fix. - List any mock data in the plan, minimal and labeled mock; once approved, seed it without re-asking, and tell me what you seeded. - For anything the guide writes downstream (e.g. a webhook target), use a real entity, not a mock. - For pages/widgets, use the real page identifier from the app URL, not a guessed slug. - When you hit a UI step confirmed (not assumed) unsupported via MCP, pause, give exact clicks, then resume via MCP. - Validate and give links after each meaningful step (only a tool-returned URL, no guessed paths); don't proceed if the last run wasn't a success. Done: - Confirm the guide's expected output exists and runs in Port. - Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.
This guide is scoped to Cursor. If you also operate other AI coding tools (e.g. GitHub Copilot, Claude Code), you can layer them on top of the same foundations described here. See Extending to other AI tools at the end of the guide.
Engineering organizations are investing heavily in AI coding assistants, but most cannot answer basic ROI questions: how many licensed seats are actively used, which teams are getting value, and whether suggestions are being kept or thrown away? Without per-user and per-team visibility, AI tooling budgets grow based on enthusiasm rather than evidence.
This guide walks you through building a comprehensive Cursor adoption dashboard in Port. We will set up the data model, connect the native Cursor integration to ingest live usage data, and build a dashboard on top of it. Once the integration is running and data is flowing, you can answer questions at three levels. The questions below are examples to get you started, not an exhaustive list:
- Organization: What share of Port users actively use Cursor, what is the acceptance rate, and how many seats are inactive?
- Team: Which teams are leading or lagging on Cursor adoption, acceptance, and LOC efficiency?
- User: Which contributors are driving accepted lines of code, which users have low engagement, and which Cursor users have zero output?
These three levels map to Port's Organization, Team, and User blueprints, but the structure is flexible and can mirror however your own organization is shaped, for example nesting teams into departments or business units. See example organization hierarchies for the patterns you can model.
By the end of this guide, you will have a dashboard that provides full visibility into Cursor adoption and impact, helping you identify enablement opportunities and quantify ROI.
The image above shows only the top portion of the dashboard as an example. The full dashboard built in this guide includes additional team, user, and activity-trend widgets further down.
Common use casesโ
- Track Cursor license utilization (active vs inactive seats) across the organization.
- Surface low-engagement Cursor users who may benefit from enablement sessions.
- Compare Cursor adoption rates and acceptance rates across teams to identify outliers.
- Monitor daily Cursor activity, LOC trends, and acceptance trends over time.
- Identify "Cursor active but zero output" users whose suggestions are not landing in code.
- Correlate Cursor adoption with engineering outcomes such as PR delivery metrics, DORA metrics, or pipeline reliability to see whether higher AI usage actually improves delivery.
Modeling Cursor data in Portโ
Port lets you visualize and model Cursor data based on your organization's structure. Usage is attributed to your User, Team, and Organization entities and enriched with derived metrics such as adoption rate, adoption tier, acceptance rate, and LOC efficiency, so you can compare teams, drill into individual users, sort by service ownership, and feed scorecards.
You can also chart the raw daily Cursor records (cursorDailyUsage) directly whenever you want day-by-day trends or totals across every seat reported by Cursor. By default these records are not related to your Team, service, or other catalog entities, so you cannot group them by those attributes unless you extend the integration mapping to relate the records to them.
The dashboard built in this guide uses both. The headline KPI tiles and team/user tables are attributed to your catalog entities, while the day-by-day activity-trend charts at the bottom chart the raw Cursor records.
We recommend assigning every Port user who uses an AI coding tool to their matching AI tool profile (such as Cursor). This is what lets you model Cursor data on your organization's structure: it lets you understand AI adoption at the team level, see how usage breaks down across teams and services, build scorecards that grade teams against adoption targets, and trigger workflows based on usage (for example, flagging inactive seats or low-engagement users). Without it, you are limited to raw daily trends and totals, and lose the ability to compare and act on usage across your organization.
Prerequisitesโ
This guide assumes the following:
- You have a Port account and have completed the onboarding process.
- You have completed the Create foundational Engineering Intelligence data model guide, which provisions the core Organization, Team, and User blueprints.
- Port's Cursor integration is installed in your account and ingesting data.
- The
cursorDailyUsageblueprint already exists (it is created automatically when you install the Cursor integration).
Key metrics overviewโ
The tables below are examples of metrics worth tracking at each scope. They are not exhaustive: the data model in this guide can produce many more, and you should add or drop metrics to match the questions your organization actually wants answered. Treat each list as a starting point for the widgets you build later.
- User
- Team
- Group
- Organization
| Metric | What it measures | Why it matters |
|---|---|---|
| Days active (monthly) | Number of days the user had any Cursor activity | Headline engagement signal for an individual |
| Adoption tier | None / Low (1-5 d) / Medium (6-15 d) / High (16+ d) | Bucket users for enablement, recognition, or license review |
| Acceptance rate | Accepted applies / total applies | Whether the user keeps the changes Cursor proposes |
| Tab acceptance rate | Tab completions accepted / shown | Adoption and usefulness of inline tab completions |
| LOC efficiency | Accepted lines / suggested lines | How much of what Cursor proposes lands in their code |
| LOC added (monthly) | Sum of Cursor-accepted lines added this month | Concrete contribution Cursor made to this person's code |
| Chat / Agent days | Days the user engaged Chat or Agent features | Adoption of features beyond inline completion |
| Metric | What it measures | Why it matters |
|---|---|---|
| Adoption rate (%) | Share of team members active on Cursor this month | Direct comparison of team-level adoption |
| Adoption tier | None / Low (1-33%) / Medium (34-66%) / High (67-100%) | One-glance bucket for leadership reporting |
| Acceptance rate | Aggregated accepted / total applies | Whether the team keeps Cursor's changes, not just triggers them |
| LOC efficiency (%) | Aggregated accepted lines / suggested lines | How much Cursor output the team actually keeps |
| LOC added (monthly) | Sum of Cursor-accepted lines across team members | Volume of Cursor contribution per team |
| High adopters (count) | Team members in the High tier (16+ days) | Identifies pockets of deep adoption |
| Inactive users (count) | Members with a Cursor seat but zero activity | Surface licenses that could be reassigned |
A Group is a Team whose type is group, typically a parent team representing a department, business unit, or product area. The metrics are identical to the Team tab. Team-blueprint aggregations over the User blueprint scope automatically to a team's members, and Port team membership is hierarchical, so a group's rollups include the members of its child teams.
| Metric | What it measures | Why it matters |
|---|---|---|
| Adoption rate (%) | Share of group members (including child teams) active on Cursor | Compare departments or business units |
| Adoption tier | None / Low / Medium / High | Roll-up bucket for executive reporting |
| Acceptance rate | Aggregated across the group | Effectiveness signal at the BU / department level |
| LOC efficiency (%) | Aggregated across the group | Same as Team, one level up |
| LOC added (monthly) | Sum across the entire group | Total Cursor contribution per group |
| High adopters (count) | Members in the High tier across the group | Where the heavy adopters are concentrated |
| Metric | What it measures | Why it matters |
|---|---|---|
| Adoption rate (%) | % of Port users active on Cursor this month | Headline KPI for the entire org |
| Active users (count) | Distinct users with at least one day of Cursor activity | Absolute volume of engaged seats |
| Inactive users (%) | Cursor users with zero activity / all Cursor users | Wasted licenses ripe for reclamation |
| Acceptance rate | Org-wide accepted / total applies | Aggregate signal of suggestion quality |
| LOC efficiency (%) | Org-wide accepted lines / suggested lines | How much Cursor output reaches the codebase org-wide |
| High adopter rate (%) | % of Port users reaching the High tier | How many people use Cursor deeply, not just occasionally |
| Daily activity trend | Requests vs accepted applies per day (raw Cursor records) | Day-over-day growth or decline in usage |
| LOC trend | Lines suggested vs accepted per day (raw Cursor records) | Whether accepted code volume is moving up or down |
| Chat & Agent adoption | Days users engaged Cursor Chat / Agent (raw Cursor records) | Adoption of features beyond inline completions |
Adoption rate is a penetration metric: active Cursor users divided by all members, not just those who hold a seat. A low number can also signal incomplete ai_tools linking rather than low usage. See the FAQ for how to interpret it and why the denominator is whole-headcount.
Set up data modelโ
Throughout this guide, blueprint and property titles (what you see in the Port UI) are written in bold, and their identifiers (what you use in JSON and integration mappings) in code formatting - for example, the AI User Profile blueprint has the identifier ai_user.
The Cursor integration automatically creates four blueprints when installed. This guide builds on the first:
- Cursor Daily Usage (
cursorDailyUsage) - daily per-user Cursor activity records. - Cursor Usage Event (
cursorUsageEvent) - per-event model, token, and cost detail. - Cursor Team Model Usage (
cursorTeamModelUsage) - daily team-level model breakdown. - Cursor User Model Usage (
cursorUserModelUsage) - daily per-user model breakdown.
In this guide, we will:
- Create a new blueprint that serves as a tool-agnostic foundation for AI activity:
- AI User Profile (
ai_user)
- AI User Profile (
- Extend the existing Cursor Daily Usage (
cursorDailyUsage), User, Team, and Organization blueprints with the calculation and aggregation properties (and relations) needed to surface Cursor adoption metrics at user, team, and organization scope.
The data model touches the following blueprints and relations. Use this as a reference whenever an identifier appears later in the guide:
| Title (identifier) | Type | Role |
|---|---|---|
Cursor Daily Usage (cursorDailyUsage) | Blueprint (integration-owned) | Daily per-user Cursor activity records |
AI User Profile (ai_user) | Blueprint (created here) | Per-tool AI activity profile, one per user per tool |
User (_user) | Blueprint (foundation) | Port users; surfaces each person's Cursor metrics |
Team (_team) | Blueprint (foundation) | Port teams; rolls up member and child-team metrics |
Organization (organization) | Blueprint (foundation) | The organization; holds org-wide KPIs |
AI Tools (ai_tools) | Relation on User โ AI User Profile | Links each Port user to their AI profile(s); every user/team/org rollup traverses it |
AI User Profile (cursor_user) | Relation on Cursor Daily Usage โ AI User Profile | Wires each daily user record to its profile. Cursor-specific; other AI tools add their own <tool>_user relation |
Create the AI User Profile blueprintโ
The ai_user blueprint stores the per-tool AI activity profile for each person. One entity per user per tool. It is the bridge between the raw per-day cursorDailyUsage records and each person's Port User profile.
ai_user is a shared, tool-agnostic blueprint. If it already exists (for example because you set it up for another AI tool), do not recreate it from the JSON below, as that would overwrite the other tool's configuration. Instead, open the existing blueprint, choose Edit JSON, and merge the Cursor-specific additions: add "Cursor" to the tool enum (keep any existing values), add the cursor_username property, then continue with the aggregation and calculation merges in steps 4 and 5. Skip step 3 below.
-
Go to your Builder page.
-
Click
+ Blueprintand choose Create from JSON. -
Paste the following JSON and click Create:
AI User Profile blueprint (click to expand)
{"identifier": "ai_user","title": "AI User Profile","icon": "User","description": "Per-tool AI activity profile for a person. One entity per tool (Cursor, Copilot, โฆ).","schema": {"properties": {"display_name": {"icon": "User", "title": "Display Name", "type": "string"},"email": {"format": "user", "icon": "User", "title": "Email", "type": "string"},"cursor_username": {"title": "Cursor Username", "icon": "DefaultProperty", "type": "string"},"tool": {"title": "AI Tool","icon": "DefaultProperty","type": "string","enum": ["Cursor"],"enumColors": {"Cursor": "purple"}}},"required": []},"mirrorProperties": {},"calculationProperties": {},"aggregationProperties": {},"relations": {}}Multiple AI toolsThe
toolenum only includesCursorfor this guide. If you later layer GitHub Copilot, Claude Code, etc. on top of the same foundation, add their identifiers to this enum. -
Once created, open the blueprint, click the
{...}button in the top right corner, choose Edit JSON, and merge the following entries into itsaggregationPropertiessection. These roll the dailycursorDailyUsagerecords up to a monthly per-person profile:AI User Profile aggregation properties (click to expand)
"cursor_loc_added_monthly": {"title": "Cursor LOC Added (Monthly)","type": "number","description": "Total lines of code accepted from Cursor suggestions this month","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "accepted_lines_added"}},"cursor_loc_suggested_monthly": {"title": "Cursor LOC Suggested (Monthly)","type": "number","description": "Total lines of code suggested by Cursor this month","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "total_lines_added"}},"cursor_loc_deleted_monthly": {"title": "Cursor LOC Deleted (Monthly)","type": "number","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "total_lines_deleted"}},"cursor_days_active_monthly": {"title": "Cursor Days Active (Monthly)","type": "number","description": "Count of days the user was active in Cursor this month","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "=", "property": "is_active", "value": true},{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_accepts_monthly": {"title": "Cursor Accepts (Monthly)","type": "number","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "total_accepts"}},"cursor_applies_monthly": {"title": "Cursor Applies (Monthly)","type": "number","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "total_applies"}},"cursor_tabs_shown_monthly": {"title": "Cursor Tabs Shown (Monthly)","type": "number","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "total_tabs_shown"}},"cursor_tabs_accepted_monthly": {"title": "Cursor Tabs Accepted (Monthly)","type": "number","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "total_tabs_accepted"}},"cursor_interactions_monthly": {"title": "Cursor Interactions (Monthly)","type": "number","description": "Sum of chat + composer + agent + cmd-k requests this month","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "total_requests"}},"cursor_days_using_agent_monthly": {"title": "Cursor Days Using Agent (Monthly)","type": "number","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": ">", "property": "agent_requests", "value": 0},{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_days_using_chat_monthly": {"title": "Cursor Days Using Chat (Monthly)","type": "number","target": "cursorDailyUsage","query": {"combinator": "and","rules": [{"operator": ">", "property": "chat_requests", "value": 0},{"operator": "between", "property": "day", "value": {"preset": "lastMonth"}}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}} -
Merge the following entries into the existing
calculationPropertiessection (keep any properties already there). Each is guarded bytool == "Cursor"so it stays null on profiles for other AI tools:AI User Profile calculation properties (click to expand)
"cursor_loc_efficiency": {"title": "Cursor LOC Efficiency (%)","icon": "Metric","description": "Percentage of Cursor lines added that were accepted this month","calculation": "if .properties.tool == \"Cursor\" then (if (.properties.cursor_loc_suggested_monthly // 0) > 0 then ((.properties.cursor_loc_added_monthly // 0) / .properties.cursor_loc_suggested_monthly * 100 | round) else 0 end) else null end","type": "number"},"cursor_acceptance_rate": {"title": "Cursor Acceptance Rate (%)","icon": "Metric","description": "Percentage of Cursor applies accepted this month (accepts/applies)","calculation": "if .properties.tool == \"Cursor\" then (if (.properties.cursor_applies_monthly // 0) > 0 then ((.properties.cursor_accepts_monthly // 0) / .properties.cursor_applies_monthly * 100 | round) else 0 end) else null end","type": "number"},"cursor_tab_acceptance_rate": {"title": "Cursor Tab Acceptance Rate (%)","icon": "Metric","description": "Percentage of Cursor tab completions accepted this month","calculation": "if .properties.tool == \"Cursor\" then (if (.properties.cursor_tabs_shown_monthly // 0) > 0 then ((.properties.cursor_tabs_accepted_monthly // 0) / .properties.cursor_tabs_shown_monthly * 100 | round) else 0 end) else null end","type": "number"},"cursor_adoption_tier": {"title": "Cursor Adoption Tier","icon": "Metric","description": "Individual usage intensity based on days active last month: None (0) / Low (1-5) / Medium (6-15) / High (16+).","calculation": "if .properties.tool != \"Cursor\" then null else ((.properties.cursor_days_active_monthly // 0) as $d | if $d == 0 then \"None\" elif $d <= 5 then \"Low\" elif $d <= 15 then \"Medium\" else \"High\" end) end","type": "string","colorized": true,"colors": {"High": "green", "Low": "yellow", "Medium": "blue", "None": "darkGray"}},"is_cursor_active_monthly": {"title": "Cursor Active (Monthly)","icon": "DefaultProperty","description": "True if this person used Cursor at least one day this month","calculation": "if .properties.tool == \"Cursor\" then ((.properties.cursor_days_active_monthly // 0) > 0) else null end","type": "boolean"},"is_cursor_high_adopter": {"title": "Cursor High Adopter","icon": "DefaultProperty","description": "True if this person used Cursor 16+ days this month","calculation": "if .properties.tool == \"Cursor\" then ((.properties.cursor_days_active_monthly // 0) >= 16) else null end","type": "boolean"},"is_cursor_inactive": {"title": "Cursor Inactive This Month","icon": "DefaultProperty","description": "True if this is a Cursor profile with zero active days this month","calculation": "if .properties.tool == \"Cursor\" then ((.properties.cursor_days_active_monthly // 0) == 0) else null end","type": "boolean"} -
Click Save to update the blueprint.
Update blueprintsโ
Update the Cursor Daily Usage blueprint
cursorDailyUsage is owned by the Cursor integration. We extend it (without replacing it) with a relation that links each daily record to the right ai_user profile, plus a derived total_requests property. The relation is the important one: every ai_user monthly aggregation traverses it to find its records, so without it the entire Port-scoped rollup chain stays empty.
-
Go to the Builder page of your portal.
-
Find the Cursor Daily Usage blueprint and click on it.
-
Click on the
{...}button in the top right corner, choose Edit JSON, and merge the entries below into the existing definition - do not replace it. -
Merge the following entry into the existing
schema.propertiessection. It is populated by the integration mapping (see Update integration mapping) and powers the Total Requests trend chart and thecursor_interactions_monthlyrollup:Total requests property (click to expand)
"total_requests": {"title": "Total Requests","description": "Sum of chat + composer + agent + cmd-k requests that day.","type": "number"} -
Merge the following entry into the existing
relationssection. It is the relation the integration mapping uses to wire each daily record to the matching AI User Profile, and the one everyai_useraggregation traverses:Cursor User relation (click to expand)
"cursor_user": {"title": "AI User Profile","target": "ai_user","required": false,"many": false} -
Click Save to update the blueprint.
Update the User blueprint
Add a relation to AI User Profile, plus aggregation and calculation properties to the existing User blueprint so that each Port user surfaces their own Cursor activity, acceptance, efficiency, and adoption tier.
-
Go to your Builder page.
-
Find the User blueprint and click on it.
-
Click on the
{...}button in the top right corner, choose Edit JSON, and merge the entries below into the existing definition - do not replace it. -
Merge the following entry into the existing
relationssection. This is the link that all User-level aggregations below traverse, and it is also what you populate in the AI Tools field when registering a Port User:AI Tools relation (click to expand)
"ai_tools": {"title": "AI Tools","target": "ai_user","required": false,"many": true} -
Merge the following entries into the existing
aggregationPropertiessection (keep any properties already there). These roll up the per-tool Cursor metrics from the linkedai_userentity:User Cursor aggregation properties (click to expand)
"cursor_loc_added_monthly": {"title": "Cursor LOC Added (Monthly)","type": "number","description": "Total lines accepted from Cursor suggestions this month","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_loc_added_monthly"}},"cursor_loc_suggested_monthly": {"title": "Cursor LOC Suggested (Monthly)","type": "number","description": "Total lines suggested by Cursor this month","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_loc_suggested_monthly"}},"cursor_loc_deleted_monthly": {"title": "Cursor LOC Deleted (Monthly)","type": "number","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_loc_deleted_monthly"}},"cursor_days_active_monthly": {"title": "Cursor Days Active (Monthly)","type": "number","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_days_active_monthly"}},"cursor_accepts_monthly": {"title": "Cursor Accepts (Monthly)","type": "number","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_accepts_monthly"}},"cursor_applies_monthly": {"title": "Cursor Applies (Monthly)","type": "number","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_applies_monthly"}},"cursor_interactions_monthly": {"title": "Cursor Interactions (Monthly)","type": "number","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_interactions_monthly"}},"cursor_days_using_agent_monthly": {"title": "Cursor Days Using Agent (Monthly)","type": "number","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_days_using_agent_monthly"}},"cursor_days_using_chat_monthly": {"title": "Cursor Days Using Chat (Monthly)","type": "number","target": "ai_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "tool", "value": "Cursor"}]},"calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_days_using_chat_monthly"}} -
Merge the following entries into the existing
calculationPropertiessection (keep any properties already there). These derive engagement flags and adoption tiers referenced by the dashboard widgets.primary_ai_toolis tool-agnostic: it compares Cursor against Copilot, and stays correct on a Cursor-only tenant (it readscopilot_days_active_monthlyas 0 when that property does not exist):User Cursor calculation properties (click to expand)
"cursor_loc_efficiency": {"title": "Cursor LOC Efficiency (%)","icon": "Metric","description": "Percentage of Cursor lines added that were accepted this month","calculation": "if (.properties.cursor_loc_suggested_monthly // 0) > 0 then ((.properties.cursor_loc_added_monthly // 0) / .properties.cursor_loc_suggested_monthly * 100 | round) else 0 end","type": "number"},"cursor_adoption_tier": {"title": "Cursor Adoption Tier","icon": "Metric","description": "Individual usage intensity based on days active last month: None (0) / Low (1-5) / Medium (6-15) / High (16+).","calculation": "(.properties.cursor_days_active_monthly // 0) as $d | if $d == 0 then \"None\" elif $d <= 5 then \"Low\" elif $d <= 15 then \"Medium\" else \"High\" end","type": "string","colorized": true,"colors": {"High": "green", "Low": "yellow", "Medium": "blue", "None": "darkGray"}},"cursor_acceptance_rate": {"title": "Cursor Acceptance Rate (%)","icon": "Metric","description": "Percentage of Cursor applies accepted this month","calculation": "if (.properties.cursor_applies_monthly // 0) > 0 then ((.properties.cursor_accepts_monthly // 0) / .properties.cursor_applies_monthly * 100 | round) else 0 end","type": "number"},"is_cursor_active_monthly": {"title": "Cursor Active (Monthly)","icon": "DefaultProperty","description": "True if this person used Cursor at least one day this month","calculation": "(.properties.cursor_days_active_monthly // 0) > 0","type": "boolean"},"is_cursor_high_adopter": {"title": "Cursor High Adopter","icon": "DefaultProperty","description": "True if this person used Cursor 16+ days this month","calculation": "(.properties.cursor_days_active_monthly // 0) >= 16","type": "boolean"},"is_cursor_inactive": {"title": "Cursor Inactive This Month","icon": "DefaultProperty","description": "True if this person appears in Cursor data but had zero active days this month","calculation": "(.properties.cursor_days_active_monthly != null) and ((.properties.cursor_days_active_monthly // 0) == 0)","type": "boolean"},"primary_ai_tool": {"title": "Primary AI Tool","icon": "Metric","description": "Tool with the most active days this month (Both = tie, None = no AI activity)","calculation": "(.properties.copilot_days_active_monthly // 0) as $c | (.properties.cursor_days_active_monthly // 0) as $cu | if ($c == 0 and $cu == 0) then \"None\" elif $c > $cu then \"Copilot\" elif $cu > $c then \"Cursor\" else \"Both\" end","type": "string","colorized": true,"colors": {"Copilot": "blue", "Cursor": "purple", "Both": "green", "None": "darkGray"}} -
Click Save to update the blueprint.
Update the Team blueprint
Add aggregation and calculation properties to the existing Team blueprint so that each team displays its own Cursor adoption metrics. Aggregations over the User blueprint automatically scope to a team's members.
-
Go to your Builder page.
-
Find the Team blueprint and click on it.
-
Click on the
{...}button in the top right corner, choose Edit JSON, and merge the entries below into the existing definition - do not replace it. -
Merge the following entries into the existing
aggregationPropertiessection (keep any properties already there):Team Cursor aggregation properties (click to expand)
"cursor_active_users_monthly": {"title": "Cursor Active Users (Monthly)","type": "number","description": "Number of team members who used Cursor at least one day this month","target": "_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "is_cursor_active_monthly", "value": true}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_inactive_users_monthly": {"title": "Cursor Inactive Users (Monthly)","type": "number","description": "Team members who appear in Cursor data but had zero active days this month","target": "_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "is_cursor_inactive", "value": true}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_high_adopters_monthly": {"title": "Cursor High Adopters (Monthly)","type": "number","description": "Team members who used Cursor 16+ days this month","target": "_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "is_cursor_high_adopter", "value": true}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_loc_added_monthly": {"title": "Cursor LOC Added (Monthly)","type": "number","description": "Total lines accepted from Cursor suggestions across team members this month","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_loc_added_monthly"}},"cursor_loc_suggested_monthly": {"title": "Cursor LOC Suggested (Monthly)","type": "number","description": "Total lines suggested by Cursor across team members this month","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_loc_suggested_monthly"}},"cursor_accepts_monthly": {"title": "Cursor Total Accepts (Monthly)","type": "number","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_accepts_monthly"}},"cursor_applies_monthly": {"title": "Cursor Total Applies (Monthly)","type": "number","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_applies_monthly"}},"cursor_interactions_monthly": {"title": "Cursor Interactions (Monthly)","type": "number","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_interactions_monthly"}},"child_members_count": {"title": "Child Teams Member Count","type": "number","description": "Sum of direct members across direct child teams (one level down)","target": "_team","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "size"}} -
Merge the following entries into the existing
calculationPropertiessection (keep any properties already there):Team Cursor calculation properties (click to expand)
"total_members": {"title": "Total Members","icon": "Metric","description": "Direct members plus members from direct child teams (one level down)","calculation": "(.properties.size // 0) + (.properties.child_members_count // 0)","type": "number"},"cursor_adoption_rate": {"title": "Cursor Adoption Rate (%)","icon": "Metric","description": "Percentage of direct team members active on Cursor at least once this month","calculation": "(.properties.cursor_active_users_monthly // 0) as $active | (.properties.total_members // 0) as $total | if $total == 0 then 0 else (($active / $total) * 100 | round) as $r | if $r > 100 then 100 else $r end end","type": "number"},"cursor_acceptance_rate": {"title": "Cursor Acceptance Rate (%)","icon": "Metric","description": "Team-level Cursor apply acceptance rate this month","calculation": "if (.properties.cursor_applies_monthly // 0) > 0 then ((.properties.cursor_accepts_monthly // 0) / .properties.cursor_applies_monthly) * 100 | round else 0 end","type": "number"},"cursor_loc_efficiency": {"title": "Cursor LOC Efficiency (%)","icon": "Metric","description": "Percentage of Cursor-suggested lines accepted across team members this month","calculation": "if (.properties.cursor_loc_suggested_monthly // 0) > 0 then ((.properties.cursor_loc_added_monthly // 0) / .properties.cursor_loc_suggested_monthly) * 100 | round else 0 end","type": "number"},"cursor_inactive_license_rate": {"title": "Cursor Inactive Users (%)","icon": "Metric","description": "Percentage of Cursor users on this team with zero activity this month","calculation": "((.properties.cursor_active_users_monthly // 0) + (.properties.cursor_inactive_users_monthly // 0)) as $total | if $total == 0 then 0 else ((.properties.cursor_inactive_users_monthly // 0) / $total) * 100 | round end","type": "number"},"cursor_adoption_tier": {"title": "Cursor Adoption Tier","icon": "Metric","description": "Team coverage tier based on direct members: None (0%) / Low (1-33%) / Medium (34-66%) / High (67-100%).","calculation": "(.properties.cursor_active_users_monthly // 0) as $active | (.properties.total_members // 0) as $total | if $total == 0 then \"None\" else (($active / $total) * 100 | round) as $r | if $r == 0 then \"None\" elif $r <= 33 then \"Low\" elif $r <= 66 then \"Medium\" else \"High\" end end","type": "string","colorized": true,"colors": {"High": "green", "Low": "yellow", "Medium": "blue", "None": "darkGray"}},"cursor_high_adopter_rate": {"title": "Cursor High Adoption Rate (%)","icon": "Metric","description": "Percentage of team members who used Cursor 16+ days this month","calculation": "(.properties.total_members // 0) as $s | if $s == 0 then 0 else ((.properties.cursor_high_adopters_monthly // 0) / $s) * 100 | round end","type": "number"}Note on
total_membersandsize: The Team blueprint already has a built-insizeaggregation (count of direct members) provided by Port's_teamsystem blueprint. Thetotal_memberscalculation above combinessizewithchild_members_countso adoption rates work for parent teams as well as leaf teams. -
Click Save to update the blueprint.
Update the Organization blueprint
Add aggregation and calculation properties to the existing organization blueprint so that the org-wide Cursor KPIs (adoption rate, inactive license rate, etc.) used by the top-row dashboard tiles resolve correctly.
-
Go to your Builder page.
-
Find the Organization blueprint and click on it.
-
Click on the
{...}button in the top right corner, choose Edit JSON, and merge the entries below into the existing definition - do not replace it. -
Merge the following entries into the existing
aggregationPropertiessection (keep any properties already there):Organization Cursor aggregation properties (click to expand)
"total_port_users": {"title": "Total Port Users","type": "number","description": "Total number of active Standard users in Port. Used as denominator for org-level adoption rates.","target": "_user","query": {"combinator": "and","rules": [{"operator": "=", "property": "status", "value": "Active"},{"operator": "=", "property": "port_type", "value": "Standard"}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_active_users_monthly": {"title": "Cursor Active Users (Monthly)","type": "number","description": "Distinct users active on Cursor at least one day this month","target": "_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "is_cursor_active_monthly", "value": true}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_inactive_users_monthly": {"title": "Cursor Inactive Users (Monthly)","type": "number","description": "Distinct users who appear in Cursor data but had zero active days this month","target": "_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "is_cursor_inactive", "value": true}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_high_adopters_monthly": {"title": "Cursor High Adopters (Monthly)","type": "number","description": "Distinct users who used Cursor 16+ days this month","target": "_user","query": {"combinator": "and", "rules": [{"operator": "=", "property": "is_cursor_high_adopter", "value": true}]},"calculationSpec": {"calculationBy": "entities", "func": "count"}},"cursor_loc_added_monthly": {"title": "Cursor LOC Added (Monthly)","type": "number","description": "Total lines accepted from Cursor suggestions across all users this month","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_loc_added_monthly"}},"cursor_loc_suggested_monthly": {"title": "Cursor LOC Suggested (Monthly)","type": "number","description": "Total lines suggested by Cursor across all users this month","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_loc_suggested_monthly"}},"cursor_accepts_monthly": {"title": "Cursor Total Accepts (Monthly)","type": "number","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_accepts_monthly"}},"cursor_applies_monthly": {"title": "Cursor Total Applies (Monthly)","type": "number","target": "_user","calculationSpec": {"calculationBy": "property", "func": "sum", "property": "cursor_applies_monthly"}} -
Merge the following entries into the existing
calculationPropertiessection (keep any properties already there):Organization Cursor calculation properties (click to expand)
"cursor_adoption_rate": {"title": "Cursor Adoption Rate (%)","icon": "Metric","description": "Percentage of Port users active on Cursor this month","calculation": "(.properties.total_port_users // 0) as $t | if $t == 0 then 0 else (((.properties.cursor_active_users_monthly // 0) / $t) * 100 | round) as $r | if $r > 100 then 100 else $r end end","type": "number"},"cursor_acceptance_rate": {"title": "Cursor Acceptance Rate (%)","icon": "Metric","description": "Org-level Cursor apply acceptance rate this month","calculation": "if (.properties.cursor_applies_monthly // 0) > 0 then ((.properties.cursor_accepts_monthly // 0) / .properties.cursor_applies_monthly) * 100 | round else 0 end","type": "number"},"cursor_loc_efficiency": {"title": "Cursor LOC Efficiency (%)","icon": "Metric","description": "Percentage of Cursor-suggested lines accepted across the entire org this month","calculation": "if (.properties.cursor_loc_suggested_monthly // 0) > 0 then ((.properties.cursor_loc_added_monthly // 0) / .properties.cursor_loc_suggested_monthly) * 100 | round else 0 end","type": "number"},"cursor_inactive_license_rate": {"title": "Cursor Inactive Users (%)","icon": "Metric","description": "Percentage of Cursor users with zero activity this month","calculation": "((.properties.cursor_active_users_monthly // 0) + (.properties.cursor_inactive_users_monthly // 0)) as $total | if $total == 0 then 0 else ((.properties.cursor_inactive_users_monthly // 0) / $total) * 100 | round end","type": "number"},"cursor_high_adopter_rate": {"title": "Cursor High Adoption Rate (%)","icon": "Metric","description": "Percentage of Port users who reached Cursor High adoption tier this month","calculation": "(.properties.total_port_users // 0) as $t | if $t == 0 then 0 else ((.properties.cursor_high_adopters_monthly // 0) / $t) * 100 | round end","type": "number"} -
Click Save to update the blueprint.
Update integration mappingโ
The native Cursor integration already ingests the daily per-user records into the Cursor Daily Usage (cursorDailyUsage) blueprint. To power the metrics in this guide, it needs two additions:
- A
cursor_userrelation and a derivedtotal_requestsproperty on the existingcursor-daily-usageresource, so each daily record links to its profile and exposes a single requests total, and - A new resource entry that creates entities in the AI User Profile (
ai_user) blueprint - one per Cursor user.
Follow the steps below to update the integration mapping:
-
Go to your Data Sources page.
-
Click on the Cursor integration.
-
Open the Mapping tab. Your existing resources already map the daily-record properties - leave those untouched, and keep the other resources (
cursor-usage-event,cursor-team-model-usage,cursor-user-model-usage) as they are. Make only the following additions:-
Extend the
cursor-daily-usageresource with thetotal_requestsproperty and thecursor_userrelation. The additions are marked# add this:Cursor Daily Usage additions (click to expand)
- kind: cursor-daily-usageselector:query: 'true'startDate: 30dendDate: 0dport:entity:mappings:blueprint: '"cursorDailyUsage"'identifier: (.userId + "-" + .day)title: (.email + " " + .day)properties:# ... keep all the properties the integration already maps ...total_requests: ((.composerRequests // 0) + (.chatRequests // 0) + (.agentRequests // 0) + (.cmdkUsages // 0)) # add thisrelations: # add thiscursor_user: .email # add this -
Add a new resource entry that creates the AI User Profile (
ai_user) entities, one per Cursor user (keyed by email so it matches your Port User identifier):AI User Profile resource (click to expand)
- kind: cursor-daily-usageselector:query: '.email != null and .email != ""'startDate: 30dendDate: 0dport:entity:mappings:blueprint: '"ai_user"'identifier: .emailtitle: (.email + " (Cursor)")properties:display_name: .emailemail: .emailcursor_username: .emailtool: '"Cursor"'
-
-
Click Save & Resync to apply the mapping and trigger a sync.
After the resync completes, you should see one ai_user entity per Cursor user (titled e.g. jane@acme.io (Cursor)) in your software catalog.
Link Port users to their AI User profilesโ
The AI Tools relation (ai_tools) you added to the User blueprint earlier in this guide points to one or many ai_user entities. All the aggregations defined here at the user, team, and organization levels traverse this relation: a Port user with no ai_tools link will show zero Cursor activity even if a matching ai_user entity exists.
Once the integration has created the ai_user entities, link each Port User to their matching Cursor profile. For a small number of users, you can assign them manually in the UI:
- Go to your software catalog and open the User entity for the person you want to link (or create a new User entity if needed).
- In the AI Tools field, select the matching
ai_userprofile (e.g.jane@acme.io (Cursor)). - Save the entity.
Automate this step
For larger orgs, doing this one-by-one in the UI is slow. You can populate the ai_tools relation automatically in several ways:
- Port AI: ask Port AI to link every Port User to their matching
ai_userprofile by email. It is the fastest option for one-off bulk runs and requires no code. - Integration mapping: extend the User-creation mapping in your SCM integration (e.g. GitHub, GitLab, Azure DevOps) so that whenever a User entity is upserted,
ai_toolsis set via a query lookup againstai_user(match on email). See the Engineering Intelligence data model guide for examples of relation lookups in mappings. This keeps the link in sync as new users join. - Automation: create a Port automation that triggers when an
ai_userentity is created and upserts the matching Port User (by email), settingai_toolsto that profile. This links users reactively as theirai_userprofiles appear. As with the mapping option, make sure the upsert preserves any existingai_toolsvalues if you run more than one AI tool. - Scripts / API: run a one-shot script against Port's REST API to bulk-patch User entities. Useful for backfills or when matching logic is more complex than what a mapping can express.
Aggregation and calculation property values are recalculated for all entities of a blueprint on a periodic cycle (roughly every 15 minutes, see aggregation property limitations). After you create these properties, resync the integration, or link a Port user to their ai_user profile, the metrics at the user, team, and organization levels may show 0 or empty for up to ~15 minutes even when everything is configured correctly. This is expected, so wait for the next recalculation before troubleshooting an empty dashboard. If values are still 0 after the recalculation window, then check the ai_tools link and the underlying ai_user data as described above.
The High tier and cursor_high_adopter_rate require 16+ active days in the rolling last month, so they only become reachable once your tenant has ingested roughly 16 days of Cursor history. A 0% high-adopter rate on a freshly-connected tenant is expected, not a bug.
Visualize metricsโ
We will create a dedicated dashboard to monitor Cursor adoption using Port's customizable widgets. The dashboard is organized into sections covering headline KPIs, distribution by adoption tier, team-level adoption, top contributors, low engagement, inactive users, and daily activity trends.
Create the dashboardโ
First, let's create an Engineering Intelligence folder to organize your dashboards (if you have not already), then add the Cursor AI Adoption dashboard inside it:
- Navigate to your software catalog.
- Click on the
+ Newbutton in the left sidebar. - Select New folder.
- Name the folder Engineering Intelligence and click Create.
- Inside the Engineering Intelligence folder, click
+ Newagain. - Select New dashboard.
- Name the dashboard Cursor AI Adoption and click Create.
Add widgetsโ
You can populate the dashboard using either an API script or by manually creating each widget through the UI.
- API script
- Manual setup
The fastest way to set up the dashboard is by using Port's API to create all widgets at once.
Get your Port API token
-
In your Port portal, click on your profile picture in the top right corner.
-
Select Credentials.
-
Click Generate API token.
-
Copy the generated token and store it as an environment variable:
export PORT_ACCESS_TOKEN="YOUR_GENERATED_TOKEN"
If your portal is hosted in the EU region, replace api.port.io with api.port-eu.io in the dashboard creation command below.
Create the dashboard with widgets
Save the following JSON to a file named cursor_ai_adoption_dashboard.json:Dashboard JSON payload (click to expand)
Then run the following command to create the dashboard with all widgets:
curl -s -X POST "https://api.port.io/v1/pages" \
-H "Authorization: Bearer $PORT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d @cursor_ai_adoption_dashboard.json | python3 -m json.tool
The script assumes an engineering_intelligence folder already exists in your catalog. If you haven't created it yet, follow steps 1-4 in the create the dashboard section first, otherwise you will run into an error when you run the script.
Headline KPIs
Start with the top-row tiles that give an at-a-glance view of Cursor adoption health. Click Title: Description: Choose the User blueprint. Select Add this JSON to the Additional filters editor: Click Save.Adoption rate (click to expand)
+ Widget and select Number Chart.Adoption Rate.% of Port users actively using Cursor this month.Display Single Property Chart type and choose Organization as the Blueprint.default-org.Cursor Adoption Rate (%) (cursor_adoption_rate) as the Property.%.Active users (click to expand)
+ Widget and select Number Chart.Active Users.Port users who used Cursor at least once this month.Display Single Property Chart type and choose Organization as the Blueprint.default-org.Cursor Active Users (Monthly) (cursor_active_users_monthly) as the Property.custom and Custom Unit to users.Users by adoption tier (click to expand)
+ Widget and select Pie Chart.Users by Adoption Tier.Intensity distribution for Port users using Cursor.Cursor Adoption Tier (cursor_adoption_tier) as the Breakdown by property.Inactive users (%) (click to expand)
+ Widget and select Number Chart.Inactive Users.% of Port users using Cursor with zero activity this month.Display Single Property Chart type and choose Organization as the Blueprint.default-org.Cursor Inactive Users (%) (cursor_inactive_license_rate) as the Property.%.Inactive users (this month) (click to expand)
+ Widget and select Number Chart.Inactive Users (this month).Port users with zero Cursor activity this month.Display Single Property Chart type and choose Organization as the Blueprint.default-org.Cursor Inactive Users (Monthly) (cursor_inactive_users_monthly) as the Property.custom and Custom Unit to users.High adopter rate (click to expand)
+ Widget and select Number Chart.High Adopter Rate.% of Port users using Cursor 16+ days this month.Display Single Property Chart type and choose Organization as the Blueprint.default-org.Cursor High Adoption Rate (%) (cursor_high_adopter_rate) as the Property.%.
Team adoption
Compare Cursor adoption metrics across teams to identify outliers. Click Title: Description: Choose the Team blueprint. Add this JSON to the Initial filters editor to show only teams (not groups): Click Save. Click on the In the top right corner of the table, click on Manage Properties and add the following columns: Sort by Click on the save icon in the top right corner of the widget to save the customized table.Cursor adoption per team (click to expand)
+ Widget and select Table.Cursor adoption per team.Teams ranked by share of members using Cursor at least once last month.... button in the top right corner of the table and select Customize table.
cursor_adoption_tier): None / Low / Medium / High.cursor_adoption_rate): Share of team members active on Cursor.cursor_acceptance_rate): Team-level acceptance rate.cursor_loc_efficiency): Share of suggested lines that landed in code.cursor_loc_added_monthly): Sum of Cursor-accepted lines for the team.total_members): Direct members plus child team members.cursor_active_users_monthly): Number of team members active on Cursor.cursor_high_adopters_monthly): Team members in the High tier.cursor_interactions_monthly): Total chat + composer + agent requests.Cursor Adoption Rate (%) descending.
User contributors and engagement
Surface top contributors, low-engagement users, and Cursor users with zero output to drive targeted enablement. Click Title: Description: Choose the User blueprint. Add this JSON to the Initial filters editor: Click Save. Click on Customize table and add the following columns: Sort by Save the customized table. Click Title: Description: Choose the User blueprint. Add this JSON to the Initial filters editor: Click Save. Click on Customize table and add the following columns: Sort by Save the customized table. Click Title: Description: Choose the User blueprint. Add this JSON to the Initial filters editor: Click Save. Click on Customize table and add the following columns: Sort by Save the customized table.Cursor user contributors (click to expand)
+ Widget and select Table.Cursor User Contributors.Port users using Cursor who added AI-generated lines of code this month, ranked by LOC added.
cursor_acceptance_rate).cursor_loc_efficiency).cursor_loc_added_monthly).cursor_loc_suggested_monthly).$team).Cursor LOC Added (Monthly) descending.Low engagement users (click to expand)
+ Widget and select Table.Low Engagement (โค5 Days).Port users using Cursor with 5 or fewer days of usage this month.
cursor_adoption_tier).cursor_acceptance_rate).cursor_days_active_monthly).$team).Cursor Days Active (Monthly) ascending.Port users using Cursor with no output (click to expand)
+ Widget and select Table.Port Users using Cursor with no output.Port users using Cursor with zero lines of code added this month, or users marked Cursor-inactive.
cursor_acceptance_rate).cursor_days_active_monthly).cursor_loc_added_monthly).$team).Cursor Days Active (Monthly) ascending.
Cursor activity trends
Track day-over-day Cursor usage, LOC volume, acceptance rate, and Chat/Agent adoption.
The activity-trend widgets aggregate the cursorDailyUsage records directly, so they include all Cursor users, including users who do not have a matching Port User entity. This is intentional: at the day-by-day level you usually want the full activity picture, whereas the user/team tables above are deliberately scoped to people you manage in Port.
Cursor activity trends (click to expand)
- Click
+ Widgetand select Multi Line Chart. - Title:
Cursor Activity Trends. - Description:
Daily total requests vs accepted applies. - Add a line:
- Title:
Total Requests. - Blueprint:
Cursor Daily Usage. - Chart type:
Aggregate Property Values. - Function:
sum. - Property:
Total Requests(total_requests). - Measure time by:
day.
- Title:
- Add another line:
- Title:
Accepted Applies. - Blueprint:
Cursor Daily Usage. - Chart type:
Aggregate Property Values. - Function:
sum. - Property:
Total Accepts(total_accepts). - Measure time by:
day.
- Title:
- Set X axis title to
Dateand Y axis title toCount. - Set Time interval to
dayand Time range tolast 3 months. - Click Save.
Chat & agent adoption (click to expand)
- Click
+ Widgetand select Multi Line Chart. - Title:
Chat & Agent Adoption. - Description:
Chat, agent and composer feature adoption. - Add a line:
- Title:
Agent Days. - Blueprint:
Cursor Daily Usage. - Chart type:
Count Entities. - Function:
count. - Measure time by:
day. - Filter:
agent_requests > 0.
- Title:
- Add another line:
- Title:
Chat Days. - Blueprint:
Cursor Daily Usage. - Chart type:
Count Entities. - Function:
count. - Measure time by:
day. - Filter:
chat_requests > 0.
- Title:
- Add another line:
- Title:
Composer Days. - Blueprint:
Cursor Daily Usage. - Chart type:
Count Entities. - Function:
count. - Measure time by:
day. - Filter:
composer_requests > 0.
- Title:
- Set X axis title to
Dateand Y axis title toDays. - Set Time interval to
dayand Time range tolast 3 months. - Click Save.
LOC trends (click to expand)
- Click
+ Widgetand select Multi Line Chart. - Title:
LOC Trends. - Description:
Lines suggested vs accepted. - Add a line:
- Title:
Lines Suggested. - Blueprint:
Cursor Daily Usage. - Chart type:
Aggregate Property Values. - Function:
sum. - Property:
Total Lines Added(total_lines_added). - Measure time by:
day.
- Title:
- Add another line:
- Title:
Lines Accepted. - Blueprint:
Cursor Daily Usage. - Chart type:
Aggregate Property Values. - Function:
sum. - Property:
Accepted Lines Added(accepted_lines_added). - Measure time by:
day.
- Title:
- Set X axis title to
Dateand Y axis title toLines. - Set Time interval to
dayand Time range tolast 3 months. - Click Save.
Acceptance volume trend (click to expand)
- Click
+ Widgetand select Multi Line Chart. - Title:
Acceptance Volume Trend. - Description:
Daily totals of applies vs accepts. True acceptance rate for a day = Accepts รท Applies. - Add a line:
- Title:
Applies. - Blueprint:
Cursor Daily Usage. - Chart type:
Aggregate Property Values. - Function:
sum. - Property:
Total Applies(total_applies). - Measure time by:
day.
- Title:
- Add another line:
- Title:
Accepts. - Blueprint:
Cursor Daily Usage. - Chart type:
Aggregate Property Values. - Function:
sum. - Property:
Total Accepts(total_accepts). - Measure time by:
day.
- Title:
- Set X axis title to
Dateand Y axis title toCount. - Set Time interval to
dayand Time range tolast 3 months. - Click Save.
Cursor user profiles (click to expand)
-
Click
+ Widgetand select Table. -
Title:
Cursor User Profiles. -
Description:
All Cursor users (AI User Profile entities) with usage metrics for last month. -
Choose the AI User Profile blueprint.
-
Add this JSON to the Initial filters editor:
{"combinator": "and","rules": [{"property": "tool", "operator": "=", "value": "Cursor"}]} -
Click Save.
-
Click on Customize table and add the following columns:
- Title.
- Cursor Adoption Tier (
cursor_adoption_tier). - Cursor Days Active (Monthly) (
cursor_days_active_monthly). - Cursor Acceptance Rate (%) (
cursor_acceptance_rate). - Cursor LOC Efficiency (%) (
cursor_loc_efficiency). - Cursor LOC Added (Monthly) (
cursor_loc_added_monthly). - Cursor Interactions (Monthly) (
cursor_interactions_monthly).
-
Sort by
Cursor LOC Added (Monthly)descending. -
Save the customized table.
Extending to other AI toolsโ
The data model in this guide is deliberately structured so that Cursor is just one tool plugged into a tool-agnostic foundation. You can layer GitHub Copilot, Claude Code, or any other AI coding assistant on top of the same backbone by following the same pattern.
The patternโ
Each AI tool follows the same structure:
- Raw daily activity lives in a tool-specific blueprint (e.g.
cursorDailyUsagefor Cursor,githubCopilotUserUsagefor Copilot). Each record is one user-day of activity. - Per-tool user profile rolls daily records up to the month on the AI User Profile (
ai_user) blueprint. Thetoolenum (Cursor,Copilot, etc.) discriminates one tool from another, and each user has oneai_userentity per tool they use. - Cross-tool synthesis lives on the User, Team, and Organization blueprints. Aggregations sum across all linked
ai_userentities filtered bytool, so adding a tool is purely additive. Existing Cursor metrics keep working. Theprimary_ai_toolcalculation on the User blueprint already compares Cursor against Copilot and starts reportingBothonce you add a second tool.
For the GitHub Copilot version of this guide, see Visualize GitHub Copilot metrics.
FAQโ
1. Why is a team's adoption rate low even though its members use Cursor?
Adoption rate measures penetration: active Cursor users divided by all members (the team's or org's full headcount), not just those who hold a Cursor seat. A team where 1 of 11 members uses Cursor is genuinely at ~9% adoption, which is the signal you want when deciding whether to expand seats.
A low rate can also mean incomplete data rather than low usage. Every rollup counts a member only if they are linked to their Cursor profile via the ai_tools relation; unlinked members sit in the denominator but can never appear in the numerator. Before reading too much into a low number, make sure all members are linked (see Link Port users to their AI User profiles).
2. Should adoption rate count only users who already have a Cursor seat?
No, and this is deliberate. Restricting the denominator to seat holders turns adoption rate into a different metric and makes it degenerate at small numbers (1 assigned / 1 active = 100%, indistinguishable from 50/50), so you lose the ability to rank teams by scale of rollout. The whole-headcount denominator answers "how widely has Cursor spread?" and keeps teams comparable.
3. The dashboard shows 0 or empty right after setup. Is something broken?
Aggregation and calculation properties recalculate on a periodic cycle (roughly every 15 minutes), so values can lag for a short while after you resync the integration or link a user. Wait for the next recalculation before troubleshooting an empty dashboard.
Next stepsโ
Once your dashboard is in place, consider these additional improvements:
- Set up scorecards to grade teams against Cursor adoption targets (e.g. โฅ60% active users, โฅ40% acceptance rate).
- Create automations to send Slack notifications when a team's adoption rate drops below threshold, or to flag Cursor users who have been inactive for two consecutive months.
- Chart model and cost data using the
cursorUsageEvent,cursorTeamModelUsage, andcursorUserModelUsageblueprints the integration also ships, to see which models are used most and what they cost. See Track AI coding assistants costs. - Correlate adoption with engineering outcomes by overlaying Cursor adoption against PR delivery metrics, DORA metrics, or pipeline reliability to see whether higher AI usage correlates with shorter cycle times, higher deployment frequency, or fewer failures.