> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Visualize GitHub Copilot metrics

Supported integration

This guide is scoped to GitHub Copilot. If you also operate other AI coding tools (e.g. Claude Code, Cursor), 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 GitHub Copilot adoption dashboard in Port. We will set up the data model, connect the GitHub Copilot 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 Copilot, what is the acceptance rate, and how many seats are inactive?
  • Team: Which teams are leading or lagging on Copilot adoption, acceptance, and LOC efficiency?
  • User: Which contributors are driving accepted lines of code, which users have low engagement, and which Copilot 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 Copilot adoption and impact, helping you identify enablement opportunities and quantify ROI.

GitHub Copilot AI Adoption dashboard in Port showing headline KPIs, adoption tier distribution, and team-level metrics

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 Copilot license utilization (active vs inactive seats) across the organization.
  • Surface low-engagement Copilot users who may benefit from enablement sessions.
  • Compare Copilot adoption rates and acceptance rates across teams to identify outliers.
  • Monitor daily Copilot activity, LOC trends, and acceptance trends over time.
  • Identify "Copilot active but zero output" users whose suggestions are not landing in code.
  • Correlate Copilot adoption with engineering outcomes such as PR delivery metrics, DORA metrics, or pipeline reliability to see whether higher AI usage actually improves delivery.

Modeling Copilot data in Port

Port lets you visualize and model Copilot 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 Copilot records (githubCopilotUserUsage / githubCopilotOrganizationUsage) directly whenever you want day-by-day trends or org-wide totals across every seat reported by GitHub. 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 Copilot records.

Assign Port users to an AI profile

We recommend assigning every Port user who uses an AI coding tool to their matching AI tool profile (such as Copilot). This is what lets you model Copilot 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 org-wide 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 GitHub Copilot integration is installed in your account and ingesting data from at least one GitHub organization or enterprise.
  • The githubCopilotUserUsage and githubCopilotOrganizationUsage blueprints already exist (these are created automatically when you install the GitHub Copilot 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.

MetricWhat it measuresWhy it matters
Days active (monthly)Number of days the user had any Copilot activityHeadline engagement signal for an individual
Adoption tierNone / Low (1-5 d) / Medium (6-15 d) / High (16+ d)Bucket users for enablement, recognition, or license review
Acceptance rateAccepted suggestions / generated suggestionsWhether the user finds Copilot suggestions useful
LOC efficiencyLines kept / lines suggestedHow much of what Copilot proposes lands in their code
LOC added (monthly)Sum of Copilot-accepted lines added this monthConcrete contribution Copilot made to this person's code
Chat / Agent daysDays the user engaged Chat or Agent featuresAdoption of features beyond inline completion

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 GitHub Copilot integration automatically creates two blueprints when installed:

  • GitHub Copilot User Usage (githubCopilotUserUsage) - daily per-user Copilot activity records
  • GitHub Copilot Organization Usage (githubCopilotOrganizationUsage) - daily per-org Copilot activity records

In this guide, we will:

  1. Create two new blueprints that serve as tool-agnostic foundations for AI activity:
    • AI User Profile (ai_user)
    • AI Org Profile (ai_org)
  2. Extend the existing GitHub Copilot User Usage (githubCopilotUserUsage), GitHub Copilot Organization Usage (githubCopilotOrganizationUsage), User, Team, and Organization blueprints with the calculation and aggregation properties (and relations) needed to surface Copilot 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)TypeRole
GitHub Copilot User Usage (githubCopilotUserUsage)Blueprint (integration-owned)Daily per-user Copilot activity records
GitHub Copilot Organization Usage (githubCopilotOrganizationUsage)Blueprint (integration-owned)Daily per-org Copilot activity records
AI User Profile (ai_user)Blueprint (created here)Per-tool AI activity profile, one per user per tool
AI Org Profile (ai_org)Blueprint (created here)Per-tool AI activity profile, one per organization
User (_user)Blueprint (foundation)Port users; surfaces each person's Copilot 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 UserAI User ProfileLinks each Port user to their AI profile(s); every user/team/org rollup traverses it
AI User Profile (copilot_user)Relation on GitHub Copilot User UsageAI User ProfileWires each daily user record to its profile. Copilot-specific; other AI tools add their own <tool>_user relation
AI Org Profile (copilot_org)Relation on GitHub Copilot Organization UsageAI Org ProfileWires each daily org record to its profile. Copilot-specific; other AI tools add their own <tool>_org 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 githubCopilotUserUsage records and each person's Port User profile.

  1. Go to your Builder page.

  2. Click + Blueprint and choose Create from JSON.

  3. 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 (Copilot, Claude, …).",
    "schema": {
    "properties": {
    "display_name": {"icon": "User", "title": "Display Name", "type": "string"},
    "email": {"format": "user", "icon": "User", "title": "Email", "type": "string"},
    "copilot_username": {"title": "Copilot Username", "icon": "DefaultProperty", "type": "string"},
    "tool": {
    "title": "AI Tool",
    "icon": "DefaultProperty",
    "type": "string",
    "enum": ["Copilot"],
    "enumColors": {"Copilot": "blue"}
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {}
    }
    Multiple AI tools

    The tool enum only includes Copilot for this guide. If you later layer Claude Code, Cursor, etc. on top of the same foundation, add their identifiers to this enum.

  4. Once created, open the blueprint, click the {...} button in the top right corner, choose Edit JSON, and merge the following entries into its aggregationProperties section:

    AI User Profile aggregation properties (click to expand)
    "copilot_code_acceptances_monthly": {
    "title": "Copilot Code Acceptances (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "code_acceptance_activity_count"
    }
    },
    "copilot_code_generations_monthly": {
    "title": "Copilot Code Generations (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "code_generation_activity_count"
    }
    },
    "copilot_days_active_monthly": {
    "title": "Copilot Days Active (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "entities",
    "func": "count"
    }
    },
    "copilot_days_using_agent_monthly": {
    "title": "Copilot Days Using Agent (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "used_agent", "value": true},
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "entities",
    "func": "count"
    }
    },
    "copilot_days_using_chat_monthly": {
    "title": "Copilot Days Using Chat (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "used_chat", "value": true},
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "entities",
    "func": "count"
    }
    },
    "copilot_interactions_monthly": {
    "title": "Copilot Interactions (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "user_initiated_interaction_count"
    }
    },
    "copilot_loc_added_monthly": {
    "title": "Copilot LOC Added (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "loc_added_sum"
    }
    },
    "copilot_loc_deleted_monthly": {
    "title": "Copilot LOC Deleted (Monthly)",
    "type": "number",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "loc_deleted_sum"
    }
    },
    "copilot_loc_suggested_monthly": {
    "title": "Copilot LOC Suggested (Monthly)",
    "type": "number",
    "description": "Total lines suggested by Copilot this month before acceptance/rejection",
    "target": "githubCopilotUserUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "loc_suggested_to_add_sum"
    }
    }
  5. Merge the following entries into the existing calculationProperties section (keep any properties already there):

    AI User Profile calculation properties (click to expand)
    "copilot_acceptance_rate": {
    "title": "Copilot Acceptance Rate (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot suggestions accepted this month",
    "calculation": "if (.properties.copilot_code_generations_monthly // 0) > 0 then ((.properties.copilot_code_acceptances_monthly // 0) / .properties.copilot_code_generations_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "copilot_loc_efficiency": {
    "title": "Copilot LOC Efficiency (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot-suggested lines actually kept",
    "calculation": "if (.properties.copilot_loc_suggested_monthly // 0) > 0 then ((.properties.copilot_loc_added_monthly // 0) / .properties.copilot_loc_suggested_monthly) * 100 | round else 0 end",
    "type": "number"
    }
  6. Click Save to update the blueprint.

Create the AI Org Profile blueprint

The ai_org blueprint stores per-tool AI activity for an organization (e.g. one entity per GitHub organization sending Copilot data). It is the bridge between the raw per-day githubCopilotOrganizationUsage records and your core organization entity.

  1. Go to your Builder page.

  2. Click + Blueprint and choose Create from JSON.

  3. Paste the following JSON and click Create:

    AI Org Profile blueprint (click to expand)
    {
    "identifier": "ai_org",
    "title": "AI Org Profile",
    "icon": "Organization",
    "description": "Per-tool AI activity profile for an organization (e.g. one GitHub org sending Copilot data).",
    "schema": {
    "properties": {
    "display_name": {"icon": "Organization", "title": "Display Name", "type": "string"},
    "organization_id": {"icon": "Organization", "title": "Organization ID", "type": "string"}
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {
    "organization": {
    "title": "Organization",
    "target": "organization",
    "required": false,
    "many": false
    }
    }
    }
  4. Once created, open the blueprint, click the {...} button in the top right corner, choose Edit JSON, and merge the following entries into its aggregationProperties section:

    AI Org Profile aggregation properties (click to expand)
    "copilot_code_acceptances_monthly": {
    "title": "Copilot Code Acceptances (Monthly)",
    "type": "number",
    "description": "Sum of code acceptance events across all daily org records this month",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "code_acceptance_activity_count"
    }
    },
    "copilot_code_generations_monthly": {
    "title": "Copilot Code Generations (Monthly)",
    "type": "number",
    "description": "Sum of code generation events across all daily org records this month",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "code_generation_activity_count"
    }
    },
    "copilot_latest_daily_active_users": {
    "title": "Copilot Peak DAU (Last 7d)",
    "type": "number",
    "description": "Highest daily_active_users value across the last 7 days of org reports",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastWeek"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "max",
    "property": "daily_active_users"
    }
    },
    "copilot_latest_weekly_active_users": {
    "title": "Copilot Peak WAU (Last 7d)",
    "type": "number",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastWeek"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "max",
    "property": "weekly_active_users"
    }
    },
    "copilot_latest_monthly_active_chat_users": {
    "title": "Copilot Peak MAU Chat (Last 7d)",
    "type": "number",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastWeek"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "max",
    "property": "monthly_active_chat_users"
    }
    },
    "copilot_latest_monthly_active_agent_users": {
    "title": "Copilot Peak MAU Agent (Last 7d)",
    "type": "number",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastWeek"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "max",
    "property": "monthly_active_agent_users"
    }
    },
    "copilot_loc_added_monthly": {
    "title": "Copilot LOC Added (Monthly)",
    "type": "number",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "loc_added_sum"
    }
    },
    "copilot_loc_suggested_monthly": {
    "title": "Copilot LOC Suggested (Monthly)",
    "type": "number",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "loc_suggested_to_add_sum"
    }
    },
    "copilot_prs_created_monthly": {
    "title": "Copilot PRs Created (Monthly)",
    "type": "number",
    "description": "Org-level only. Cannot be attributed to individual teams or users.",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "prs_created_by_copilot"
    }
    },
    "copilot_prs_merged_monthly": {
    "title": "Copilot PRs Merged (Monthly)",
    "type": "number",
    "description": "Org-level only. Cannot be attributed to individual teams or users.",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "prs_merged_by_copilot"
    }
    },
    "copilot_prs_reviewed_monthly": {
    "title": "Copilot PRs Reviewed (Monthly)",
    "type": "number",
    "description": "Org-level only. Cannot be attributed to individual teams or users.",
    "target": "githubCopilotOrganizationUsage",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "between", "property": "record_date", "value": {"preset": "lastMonth"}}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "prs_reviewed_by_copilot"
    }
    }
  5. Merge the following entries into the existing calculationProperties section (keep any properties already there):

    AI Org Profile calculation properties (click to expand)
    "copilot_acceptance_rate": {
    "title": "Copilot Acceptance Rate (%)",
    "icon": "Metric",
    "description": "Code acceptance rate from org-level Copilot API",
    "calculation": "if (.properties.copilot_code_generations_monthly // 0) > 0 then ((.properties.copilot_code_acceptances_monthly // 0) / .properties.copilot_code_generations_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "copilot_loc_efficiency": {
    "title": "Copilot LOC Efficiency (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot-suggested lines that were actually kept this month",
    "calculation": "if (.properties.copilot_loc_suggested_monthly // 0) > 0 then ((.properties.copilot_loc_added_monthly // 0) / .properties.copilot_loc_suggested_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "copilot_seat_mau_proxy": {
    "title": "Copilot Seat MAU (Proxy)",
    "icon": "User",
    "description": "Max of chat-MAU and agent-MAU from Copilot org reports. Best available proxy for licensed seat activity.",
    "calculation": "[(.properties.copilot_latest_monthly_active_chat_users // 0), (.properties.copilot_latest_monthly_active_agent_users // 0)] | max",
    "type": "number"
    }
  6. Click Save to update the blueprint.

Update blueprints

Update the GitHub Copilot User Usage blueprint

Add a calculation property for the per-record acceptance rate, and a relation that links each daily record to the right ai_user profile.

  1. Go to the Builder page of your portal.

  2. Find the GitHub Copilot User Usage blueprint and click on it.

  3. 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.

  4. Merge the following entry into the existing calculationProperties section (keep any properties already there). It powers the Acceptance Trend line chart later in this guide:

    Acceptance rate calculation property (click to expand)
    "acceptance_rate": {
    "title": "Acceptance Rate",
    "icon": "DefaultProperty",
    "calculation": "if (.properties.code_generation_activity_count == 0) then 0 else ((.properties.code_acceptance_activity_count / .properties.code_generation_activity_count) * 100 | round) end",
    "type": "number"
    }
  5. Merge the following entry into the existing relations section. It is the relation the integration mapping uses to wire each daily record to the matching AI User Profile:

    Copilot User relation (click to expand)
    "copilot_user": {
    "title": "AI User Profile",
    "target": "ai_user",
    "required": false,
    "many": false
    }
  6. Click Save to update the blueprint.

Update the GitHub Copilot Organization Usage blueprint

Add a relation that links each daily org record to the matching AI Org Profile.

  1. Go to the Builder page of your portal.

  2. Find the GitHub Copilot Organization Usage blueprint and click on it.

  3. Click on the {...} button in the top right corner, choose Edit JSON, and merge the entry below into the existing definition - do not replace it.

  4. Merge the following entry into the existing relations section. The integration mapping uses it to wire each daily org record to the matching AI Org Profile:

    Copilot Org relation (click to expand)
    "copilot_org": {
    "title": "AI Org Profile",
    "target": "ai_org",
    "required": false,
    "many": false
    }
  5. 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 Copilot activity, acceptance, efficiency, and adoption tier.

  1. Go to your Builder page.

  2. Find the User blueprint and click on it.

  3. 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.

  4. Merge the following entry into the existing relations section. 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
    }
  5. Merge the following entries into the existing aggregationProperties section (keep any properties already there). These roll up the per-tool Copilot metrics from the linked ai_user entity:

    User Copilot aggregation properties (click to expand)
    "copilot_days_active_monthly": {
    "title": "Copilot Days Active (Monthly)",
    "type": "number",
    "description": "Days Copilot was active this month, from linked ai_user entity",
    "target": "ai_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "tool", "value": "Copilot"}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_days_active_monthly"
    }
    },
    "copilot_loc_added_monthly": {
    "title": "Copilot LOC Added (Monthly)",
    "type": "number",
    "target": "ai_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "tool", "value": "Copilot"}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_loc_added_monthly"
    }
    },
    "copilot_loc_deleted_monthly": {
    "title": "Copilot LOC Deleted (Monthly)",
    "type": "number",
    "target": "ai_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "tool", "value": "Copilot"}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_loc_deleted_monthly"
    }
    },
    "copilot_loc_suggested_monthly": {
    "title": "Copilot LOC Suggested (Monthly)",
    "type": "number",
    "description": "Total lines suggested by Copilot this month before acceptance/rejection",
    "target": "ai_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "tool", "value": "Copilot"}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_loc_suggested_monthly"
    }
    },
    "copilot_code_acceptances_monthly": {
    "title": "Copilot Code Acceptances (Monthly)",
    "type": "number",
    "target": "ai_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "tool", "value": "Copilot"}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_code_acceptances_monthly"
    }
    },
    "copilot_code_generations_monthly": {
    "title": "Copilot Code Generations (Monthly)",
    "type": "number",
    "target": "ai_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "tool", "value": "Copilot"}
    ]
    },
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_code_generations_monthly"
    }
    }
  6. Merge the following entries into the existing calculationProperties section (keep any properties already there). These derive engagement flags and adoption tiers that are referenced by the dashboard widgets:

    User Copilot calculation properties (click to expand)
    "is_copilot_active_monthly": {
    "title": "Copilot Active (Monthly)",
    "icon": "DefaultProperty",
    "description": "True if this person used Copilot at least one day this month",
    "calculation": "(.properties.copilot_days_active_monthly // 0) > 0",
    "type": "boolean"
    },
    "is_copilot_inactive": {
    "title": "Copilot Inactive This Month",
    "icon": "DefaultProperty",
    "description": "True if this person appears in Copilot data but had zero active days this month",
    "calculation": "(.properties.copilot_days_active_monthly != null) and ((.properties.copilot_days_active_monthly // 0) == 0)",
    "type": "boolean"
    },
    "copilot_acceptance_rate": {
    "title": "Copilot Acceptance Rate (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot suggestions accepted this month",
    "calculation": "if (.properties.copilot_code_generations_monthly // 0) > 0 then ((.properties.copilot_code_acceptances_monthly // 0) / .properties.copilot_code_generations_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "copilot_loc_efficiency": {
    "title": "Copilot LOC Efficiency (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot-suggested lines that were actually kept",
    "calculation": "if (.properties.copilot_loc_suggested_monthly // 0) > 0 then ((.properties.copilot_loc_added_monthly // 0) / .properties.copilot_loc_suggested_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "adoption_tier": {
    "title": "Copilot Adoption Tier",
    "icon": "Metric",
    "description": "Based on Copilot days active this month: None / Low (1-5) / Medium (6-15) / High (16+)",
    "calculation": "(.properties.copilot_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": {
    "None": "darkGray",
    "Low": "yellow",
    "Medium": "blue",
    "High": "green"
    }
    },
    "is_copilot_high_adopter": {
    "title": "Copilot High Adopter",
    "icon": "DefaultProperty",
    "description": "True if this person used Copilot 16+ days this month",
    "calculation": "(.properties.copilot_days_active_monthly // 0) >= 16",
    "type": "boolean"
    }
  7. 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 Copilot adoption metrics. Aggregations roll up from members (User entities) and child teams.

  1. Go to your Builder page.

  2. Find the Team blueprint and click on it.

  3. 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.

  4. Merge the following entries into the existing aggregationProperties section (keep any properties already there):

    Team Copilot aggregation properties (click to expand)
    "ai_copilot_active_users_monthly": {
    "title": "AI Copilot Active Users (Monthly)",
    "type": "number",
    "description": "Number of team members who used Copilot at least one day this month",
    "target": "_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "is_copilot_active_monthly", "value": true}
    ]
    },
    "calculationSpec": {"calculationBy": "entities", "func": "count"},
    "pathFilter": [{"fromBlueprint": "_user", "path": ["$team"]}]
    },
    "ai_copilot_inactive_users_monthly": {
    "title": "Copilot Inactive Users (Monthly)",
    "type": "number",
    "description": "Team members who appear in Copilot data but had zero active days this month",
    "target": "_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "is_copilot_inactive", "value": true}
    ]
    },
    "calculationSpec": {"calculationBy": "entities", "func": "count"},
    "pathFilter": [{"fromBlueprint": "_user", "path": ["$team"]}]
    },
    "ai_copilot_code_acceptances_monthly": {
    "title": "Copilot Total Code Acceptances (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_code_acceptances_monthly"
    },
    "pathFilter": [{"fromBlueprint": "_user", "path": ["$team"]}]
    },
    "ai_copilot_code_generations_monthly": {
    "title": "Copilot Total Code Generations (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_code_generations_monthly"
    },
    "pathFilter": [{"fromBlueprint": "_user", "path": ["$team"]}]
    },
    "ai_copilot_loc_added_monthly": {
    "title": "Copilot Total LOC Added (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_loc_added_monthly"
    },
    "pathFilter": [{"fromBlueprint": "_user", "path": ["$team"]}]
    },
    "ai_copilot_loc_suggested_monthly": {
    "title": "Copilot Total LOC Suggested (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_loc_suggested_monthly"
    },
    "pathFilter": [{"fromBlueprint": "_user", "path": ["$team"]}]
    },
    "ai_copilot_high_adopters_monthly": {
    "title": "Copilot High Adopters (Monthly)",
    "type": "number",
    "description": "Team members who used Copilot 16+ days this month",
    "target": "_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "is_copilot_high_adopter", "value": true}
    ]
    },
    "calculationSpec": {"calculationBy": "entities", "func": "count"},
    "pathFilter": [{"fromBlueprint": "_user", "path": ["$team"]}]
    },
    "child_copilot_active_users_monthly": {
    "title": "Child Teams Copilot Active Users (Monthly)",
    "type": "number",
    "description": "Sum of Copilot active users from direct child teams (one level down)",
    "target": "_team",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "ai_copilot_active_users_monthly"
    },
    "pathFilter": [{"fromBlueprint": "_team", "path": ["parent_team"]}]
    },
    "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"
    },
    "pathFilter": [{"fromBlueprint": "_team", "path": ["parent_team"]}]
    }

    Note on the two child_* aggregations:
    child_copilot_active_users_monthly and child_members_count target _team (the blueprint aggregating over itself), and the pathFilter [{"fromBlueprint": "_team", "path": ["parent_team"]}] is required - keep it. It scopes the rollup to direct child teams only (downward through parent_team). Without it, a self-referential _team → _team aggregation traverses the parent_team relation in both directions, so a leaf team would also pull in its parent's active users and double-count them, producing adoption rates above 100% (e.g. 200%). These two rollups only go one level deep; for hierarchies deeper than parent → child, they would need to be extended.

  5. Merge the following entries into the existing calculationProperties section (keep any properties already there):

    Team Copilot 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"
    },
    "ai_copilot_adoption_rate": {
    "title": "AI Copilot Adoption Rate (%)",
    "icon": "Metric",
    "description": "Percentage of team members (including child teams) active on Copilot this month",
    "calculation": "((.properties.ai_copilot_active_users_monthly // 0) + (.properties.child_copilot_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"
    },
    "ai_copilot_acceptance_rate": {
    "title": "Copilot Acceptance Rate (%)",
    "icon": "Metric",
    "description": "Team-level Copilot suggestion acceptance rate this month",
    "calculation": "if (.properties.ai_copilot_code_generations_monthly // 0) > 0 then ((.properties.ai_copilot_code_acceptances_monthly // 0) / .properties.ai_copilot_code_generations_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "ai_copilot_loc_efficiency": {
    "title": "Copilot LOC Efficiency (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot-suggested lines that were actually kept across the team this month",
    "calculation": "if (.properties.ai_copilot_loc_suggested_monthly // 0) > 0 then ((.properties.ai_copilot_loc_added_monthly // 0) / .properties.ai_copilot_loc_suggested_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "ai_copilot_inactive_license_rate": {
    "title": "Copilot Inactive Users (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot users with zero activity this month",
    "calculation": "((.properties.ai_copilot_active_users_monthly // 0) + (.properties.ai_copilot_inactive_users_monthly // 0)) as $total | if $total == 0 then 0 else ((.properties.ai_copilot_inactive_users_monthly // 0) / $total) * 100 | round end",
    "type": "number"
    },
    "ai_copilot_adoption_tier": {
    "title": "Copilot Adoption Tier",
    "icon": "Metric",
    "description": "Tier based on the share of team members active on Copilot: None / Low (1-33%) / Medium (34-66%) / High (67-100%)",
    "calculation": "((.properties.ai_copilot_active_users_monthly // 0) + (.properties.child_copilot_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": {
    "None": "darkGray",
    "Low": "yellow",
    "Medium": "blue",
    "High": "green"
    }
    },
    "ai_copilot_high_adopter_rate": {
    "title": "Copilot High Adoption Rate (%)",
    "icon": "Metric",
    "description": "Percentage of team members who reached High adoption tier (16+ days) this month",
    "calculation": "(.properties.total_members // 0) as $s | if $s == 0 then 0 else ((.properties.ai_copilot_high_adopters_monthly // 0) / $s) * 100 | round end",
    "type": "number"
    }

    Note on total_members and size:
    The Team blueprint already has a built-in size aggregation (count of direct members) provided by Port's _team system blueprint. The total_members calculation above combines size with child_members_count so adoption rates work for parent teams as well as leaf teams.

  6. 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 Copilot KPIs (adoption rate, inactive license rate, etc.) used by the top-row dashboard tiles resolve correctly.

  1. Go to your Builder page.

  2. Find the Organization blueprint and click on it.

  3. 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.

  4. Merge the following entries into the existing aggregationProperties section (keep any properties already there):

    Organization Copilot 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"}
    },
    "ai_copilot_active_users_monthly": {
    "title": "AI Copilot Active Users (Monthly)",
    "type": "number",
    "description": "Distinct users who used Copilot at least one day this month",
    "target": "_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "is_copilot_active_monthly", "value": true}
    ]
    },
    "calculationSpec": {"calculationBy": "entities", "func": "count"}
    },
    "ai_copilot_inactive_users_monthly": {
    "title": "Copilot Inactive Users (Monthly)",
    "type": "number",
    "description": "Distinct users who appear in Copilot data but had zero active days this month",
    "target": "_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "is_copilot_inactive", "value": true}
    ]
    },
    "calculationSpec": {"calculationBy": "entities", "func": "count"}
    },
    "ai_copilot_code_acceptances_monthly": {
    "title": "Copilot Total Code Acceptances (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_code_acceptances_monthly"
    }
    },
    "ai_copilot_code_generations_monthly": {
    "title": "Copilot Total Code Generations (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_code_generations_monthly"
    }
    },
    "ai_copilot_loc_added_monthly": {
    "title": "Copilot Total LOC Added (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_loc_added_monthly"
    }
    },
    "ai_copilot_loc_suggested_monthly": {
    "title": "Copilot Total LOC Suggested (Monthly)",
    "type": "number",
    "target": "_user",
    "calculationSpec": {
    "calculationBy": "property",
    "func": "sum",
    "property": "copilot_loc_suggested_monthly"
    }
    },
    "ai_copilot_high_adopters_monthly": {
    "title": "Copilot High Adopters (Monthly)",
    "type": "number",
    "description": "Distinct users who used Copilot 16+ days this month",
    "target": "_user",
    "query": {
    "combinator": "and",
    "rules": [
    {"operator": "=", "property": "is_copilot_high_adopter", "value": true}
    ]
    },
    "calculationSpec": {"calculationBy": "entities", "func": "count"}
    }
  5. Merge the following entries into the existing calculationProperties section (keep any properties already there):

    Organization Copilot calculation properties (click to expand)
    "ai_copilot_adoption_rate": {
    "title": "AI Copilot Adoption Rate (%)",
    "icon": "Metric",
    "description": "Percentage of Port users active on Copilot this month",
    "calculation": "(.properties.total_port_users // 0) as $t | if $t == 0 then 0 else ((.properties.ai_copilot_active_users_monthly // 0) / $t) * 100 | round end",
    "type": "number"
    },
    "ai_copilot_acceptance_rate": {
    "title": "Copilot Acceptance Rate (%)",
    "icon": "Metric",
    "description": "Org-level Copilot suggestion acceptance rate this month",
    "calculation": "if (.properties.ai_copilot_code_generations_monthly // 0) > 0 then ((.properties.ai_copilot_code_acceptances_monthly // 0) / .properties.ai_copilot_code_generations_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "ai_copilot_loc_efficiency": {
    "title": "Copilot LOC Efficiency (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot-suggested lines that were actually kept across the org this month",
    "calculation": "if (.properties.ai_copilot_loc_suggested_monthly // 0) > 0 then ((.properties.ai_copilot_loc_added_monthly // 0) / .properties.ai_copilot_loc_suggested_monthly) * 100 | round else 0 end",
    "type": "number"
    },
    "ai_copilot_inactive_license_rate": {
    "title": "Copilot Inactive Users (%)",
    "icon": "Metric",
    "description": "Percentage of Copilot users with zero activity this month",
    "calculation": "((.properties.ai_copilot_active_users_monthly // 0) + (.properties.ai_copilot_inactive_users_monthly // 0)) as $total | if $total == 0 then 0 else ((.properties.ai_copilot_inactive_users_monthly // 0) / $total) * 100 | round end",
    "type": "number"
    },
    "ai_copilot_high_adopter_rate": {
    "title": "Copilot High Adoption Rate (%)",
    "icon": "Metric",
    "description": "Percentage of Port users who reached High adoption tier this month",
    "calculation": "(.properties.total_port_users // 0) as $t | if $t == 0 then 0 else ((.properties.ai_copilot_high_adopters_monthly // 0) / $t) * 100 | round end",
    "type": "number"
    }
  6. Click Save to update the blueprint.

Update integration mapping

The default GitHub Copilot integration mapping ingests daily user and organization metrics into the GitHub Copilot User Usage (githubCopilotUserUsage) and GitHub Copilot Organization Usage (githubCopilotOrganizationUsage) blueprints. To power the metrics in this guide, it needs two additions:

  • A copilot_user relation on the user-level resources and a copilot_org relation on the org-level resources, so each daily record links to its profile, and
  • Two new resource entries that create entities in the AI User Profile (ai_user) and AI Org Profile (ai_org) blueprints - one per Copilot user and one per GitHub organization.

Follow the steps below to update the integration mapping:

  1. Go to your Data Sources page.

  2. Click on the GitHub Copilot integration.

  3. Open the Mapping tab. Your existing resources already map the daily-record properties - leave those untouched. Make only the following additions, keeping every resource you already have:

    • Add the copilot_user relation to the resource(s) that map into githubCopilotUserUsage (typically the user-usage-metrics resource, and enterprise-user-usage-metrics if you use a GitHub enterprise). The full resource is below - the only addition is the relations block at the end (marked # add this):

      Copilot User relation (click to expand)
      - kind: user-usage-metrics
      selector:
      query: .user_login != null
      port:
      entity:
      mappings:
      blueprint: '"githubCopilotUserUsage"'
      identifier: (.user_login + "@" + .git_hub_org + "@" + .day)
      title: (.user_login + "@" + .git_hub_org + "@" + .day)
      properties:
      code_acceptance_activity_count: .code_acceptance_activity_count
      code_generation_activity_count: .code_generation_activity_count
      git_hub_org: .git_hub_org
      loc_added_sum: .loc_added_sum
      loc_deleted_sum: .loc_deleted_sum
      loc_suggested_to_add_sum: .loc_suggested_to_add_sum
      loc_suggested_to_delete_sum: .loc_suggested_to_delete_sum
      record_date: .day + "T00:00:00Z"
      used_agent: .used_agent
      used_chat: .used_chat
      used_cli: (.used_cli // false)
      user_initiated_interaction_count: .user_initiated_interaction_count
      username: .user_login
      relations: # add this
      copilot_user: (.user_email // .user_login)
    • Add the copilot_org relation to the organization-usage-metrics resource that maps into githubCopilotOrganizationUsage. The full resource is below - the only addition is the relations block at the end (marked # add this):

      Copilot Org relation (click to expand)
      - kind: organization-usage-metrics
      selector:
      query: 'true'
      port:
      entity:
      mappings:
      blueprint: '"githubCopilotOrganizationUsage"'
      identifier: (.__organization.login + "@" + .day)
      title: (.__organization.login + " copilot-metrics " + .day)
      properties:
      code_acceptance_activity_count: .code_acceptance_activity_count
      code_generation_activity_count: .code_generation_activity_count
      daily_active_users: .daily_active_users
      git_hub_org: .__organization.login
      loc_added_sum: .loc_added_sum
      loc_deleted_sum: .loc_deleted_sum
      loc_suggested_to_add_sum: .loc_suggested_to_add_sum
      loc_suggested_to_delete_sum: .loc_suggested_to_delete_sum
      monthly_active_agent_users: .monthly_active_agent_users
      monthly_active_chat_users: .monthly_active_chat_users
      prs_created_by_copilot: .prs_created_by_copilot
      prs_merged_by_copilot: .prs_merged_by_copilot
      prs_reviewed_by_copilot: .prs_reviewed_by_copilot
      record_date: .day + "T00:00:00Z"
      total_copilot_applied_suggestions: .total_copilot_applied_suggestions
      user_initiated_interaction_count: .user_initiated_interaction_count
      weekly_active_users: .weekly_active_users
      relations: # add this
      copilot_org: .__organization.login
    • Add a new resource entry that creates the AI User Profile (ai_user) entities:

      AI User Profile relation (click to expand)
      - kind: user-usage-metrics
      selector:
      query: .user_login != null
      port:
      entity:
      mappings:
      blueprint: '"ai_user"'
      identifier: (.user_email // .user_login)
      title: (.user_login + " (Copilot)")
      properties:
      display_name: .user_login
      tool: '"Copilot"'
    • Add a new resource entry that creates the AI Org Profile (ai_org) entities. If your foundational organization entity is not default-org, change the organization relation value to match:

      AI Org Profile relation (click to expand)
      - kind: organization-usage-metrics
      selector:
      query: 'true'
      port:
      entity:
      mappings:
      blueprint: '"ai_org"'
      identifier: .__organization.login
      title: .__organization.login
      properties:
      display_name: .__organization.login
      organization_id: (.organization_id | tostring)
      relations:
      organization: '"default-org"'

    If your mapping is still the default (unchanged), the simplest option is to paste the full reference mapping below as-is, since it already includes these additions on top of the default property mappings.

    Full integration mapping for reference (click to expand)
    createMissingRelatedEntities: true
    deleteDependentEntities: true
    resources:
    - kind: organization-usage-metrics
    selector:
    query: 'true'
    port:
    entity:
    mappings:
    blueprint: '"githubCopilotOrganizationUsage"'
    identifier: (.__organization.login + "@" + .day)
    title: (.__organization.login + " copilot-metrics " + .day)
    properties:
    code_acceptance_activity_count: .code_acceptance_activity_count
    code_generation_activity_count: .code_generation_activity_count
    daily_active_users: .daily_active_users
    git_hub_org: .__organization.login
    loc_added_sum: .loc_added_sum
    loc_deleted_sum: .loc_deleted_sum
    loc_suggested_to_add_sum: .loc_suggested_to_add_sum
    loc_suggested_to_delete_sum: .loc_suggested_to_delete_sum
    monthly_active_agent_users: .monthly_active_agent_users
    monthly_active_chat_users: .monthly_active_chat_users
    prs_created_by_copilot: .prs_created_by_copilot
    prs_merged_by_copilot: .prs_merged_by_copilot
    prs_reviewed_by_copilot: .prs_reviewed_by_copilot
    record_date: .day + "T00:00:00Z"
    total_copilot_applied_suggestions: .total_copilot_applied_suggestions
    user_initiated_interaction_count: .user_initiated_interaction_count
    weekly_active_users: .weekly_active_users
    relations:
    copilot_org: .__organization.login
    - kind: organization-usage-metrics
    selector:
    query: 'true'
    port:
    entity:
    mappings:
    blueprint: '"ai_org"'
    identifier: .__organization.login
    title: .__organization.login
    properties:
    display_name: .__organization.login
    organization_id: (.organization_id | tostring)
    relations:
    organization: '"default-org"'
    - kind: enterprise-usage-metrics
    selector:
    query: 'true'
    port:
    entity:
    mappings:
    blueprint: '"githubCopilotOrganizationUsage"'
    identifier: (.__enterprise + "@" + .day)
    title: (.__enterprise + " copilot-metrics " + .day)
    properties:
    code_acceptance_activity_count: .code_acceptance_activity_count
    code_generation_activity_count: .code_generation_activity_count
    daily_active_users: .daily_active_users
    git_hub_org: .__enterprise
    loc_added_sum: .loc_added_sum
    loc_deleted_sum: .loc_deleted_sum
    loc_suggested_to_add_sum: .loc_suggested_to_add_sum
    loc_suggested_to_delete_sum: .loc_suggested_to_delete_sum
    monthly_active_users: .monthly_active_users
    record_date: .day + "T00:00:00Z"
    user_initiated_interaction_count: .user_initiated_interaction_count
    weekly_active_users: .weekly_active_users
    - kind: user-usage-metrics
    selector:
    query: .user_login != null
    port:
    entity:
    mappings:
    blueprint: '"githubCopilotUserUsage"'
    identifier: (.user_login + "@" + .git_hub_org + "@" + .day)
    title: (.user_login + "@" + .git_hub_org + "@" + .day)
    properties:
    code_acceptance_activity_count: .code_acceptance_activity_count
    code_generation_activity_count: .code_generation_activity_count
    git_hub_org: .git_hub_org
    loc_added_sum: .loc_added_sum
    loc_deleted_sum: .loc_deleted_sum
    loc_suggested_to_add_sum: .loc_suggested_to_add_sum
    loc_suggested_to_delete_sum: .loc_suggested_to_delete_sum
    record_date: .day + "T00:00:00Z"
    used_agent: .used_agent
    used_chat: .used_chat
    used_cli: (.used_cli // false)
    user_initiated_interaction_count: .user_initiated_interaction_count
    username: .user_login
    relations:
    copilot_user: (.user_email // .user_login)
    - kind: enterprise-user-usage-metrics
    selector:
    query: .user_login != null
    port:
    entity:
    mappings:
    blueprint: '"githubCopilotUserUsage"'
    identifier: (.user_login + "@" + .__enterprise + "@" + .day)
    title: (.user_login + "@" + .__enterprise + "@" + .day)
    properties:
    code_acceptance_activity_count: .code_acceptance_activity_count
    code_generation_activity_count: .code_generation_activity_count
    git_hub_org: .__enterprise
    loc_added_sum: .loc_added_sum
    loc_deleted_sum: .loc_deleted_sum
    loc_suggested_to_add_sum: .loc_suggested_to_add_sum
    loc_suggested_to_delete_sum: .loc_suggested_to_delete_sum
    record_date: .day + "T00:00:00Z"
    used_agent: .used_agent
    used_chat: .used_chat
    used_cli: (.used_cli // false)
    user_initiated_interaction_count: .user_initiated_interaction_count
    username: .user_login
    relations:
    copilot_user: (.user_email // .user_login)
    - kind: user-usage-metrics
    selector:
    query: .user_login != null
    port:
    entity:
    mappings:
    blueprint: '"ai_user"'
    identifier: (.user_email // .user_login)
    title: (.user_login + " (Copilot)")
    properties:
    display_name: .user_login
    tool: '"Copilot"'
  4. Click Save & Resync to apply the mapping and trigger an initial sync.

After the resync completes, you should see one ai_user entity per Copilot user (titled e.g. mk-armah (Copilot)) and one ai_org entity per GitHub organization in your software catalog.

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 Copilot 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 Copilot profile. For a small number of users, you can assign them manually in the UI:

  1. 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).
  2. In the AI Tools field, select the matching ai_user profile (e.g. mk-armah (Copilot)).
  3. Save the entity.
Linking a Port User entity to their matching AI User Profile via the AI Tools field

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_user profile by email or username. 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_tools is set via a query lookup against ai_user (match on email or copilot_username). 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_user entity is created and upserts the matching Port User (by email or login), setting ai_tools to that profile. This links users reactively as their ai_user profiles appear, without touching the SCM mapping. As with the mapping option, make sure the upsert preserves any existing ai_tools values 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. :::
Metrics take up to ~15 minutes to appear

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.

Visualize metrics

We will create a dedicated dashboard to monitor GitHub Copilot 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 GitHub Copilot AI Adoption dashboard inside it:

  1. Navigate to your software catalog.
  2. Click on the + New button in the left sidebar.
  3. Select New folder.
  4. Name the folder Engineering Intelligence and click Create.
  5. Inside the Engineering Intelligence folder, click + New again.
  6. Select New dashboard.
  7. Name the dashboard GitHub Copilot 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.

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

  1. In your Port portal, click on your profile picture in the top right corner.

  2. Select Credentials.

  3. Click Generate API token.

  4. Copy the generated token and store it as an environment variable:

    export PORT_ACCESS_TOKEN="YOUR_GENERATED_TOKEN"
EU region

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 copilot_ai_adoption_dashboard.json:

Dashboard JSON payload (click to expand)
{
"identifier": "github-copilot-ai-adoption",
"title": "GitHub Copilot AI Adoption",
"icon": "Github",
"description": "GitHub Copilot adoption based on Port users, unless otherwise stated.",
"type": "dashboard",
"parent": "engineering_intelligence",
"widgets": [
{
"id": "dashboard-widget-root",
"type": "dashboard-widget",
"layout": [
{
"height": 400,
"columns": [
{"id": "org_adoption_rate", "size": 4},
{"id": "active_users", "size": 4},
{"id": "users_by_adoption_tier_pie", "size": 4}
]
},
{
"height": 400,
"columns": [
{"id": "inactive_licenses", "size": 4},
{"id": "inactive_users_count", "size": 4},
{"id": "high_adopter_rate", "size": 4}
]
},
{
"height": 600,
"columns": [
{"id": "team_adoption_table", "size": 12}
]
},
{
"height": 400,
"columns": [
{"id": "top_contributors_by_loc", "size": 12}
]
},
{
"height": 400,
"columns": [
{"id": "low_engagement", "size": 12}
]
},
{
"height": 400,
"columns": [
{"id": "inactive_copilot_users", "size": 12}
]
},
{
"height": 400,
"columns": [
{"id": "copilot_daily_activity", "size": 6},
{"id": "copilot_chat_agent_usage", "size": 6}
]
},
{
"height": 400,
"columns": [
{"id": "copilot_loc_trends", "size": 6},
{"id": "copilot_acceptance_trend", "size": 6}
]
}
],
"widgets": [
{
"id": "org_adoption_rate",
"type": "entities-number-chart",
"title": "Adoption Rate",
"icon": "TrendingUp",
"description": "% of users actively using Copilot",
"blueprint": "organization",
"chartType": "displaySingleProperty",
"entity": "default-org",
"property": "ai_copilot_adoption_rate",
"unit": "%",
"unitAlignment": "right"
},
{
"id": "active_users",
"type": "entities-number-chart",
"title": "Active Users",
"icon": "Users",
"description": "Users who used Copilot this month",
"blueprint": "organization",
"chartType": "displaySingleProperty",
"entity": "default-org",
"property": "ai_copilot_active_users_monthly",
"unit": "custom",
"unitCustom": "users"
},
{
"id": "users_by_adoption_tier_pie",
"type": "entities-pie-chart",
"title": "Users by Adoption Tier",
"icon": "PieChart",
"description": "User adoption distribution (Copilot only)",
"blueprint": "_user",
"property": "calculation-property#adoption_tier",
"dataset": {
"combinator": "and",
"rules": [
{"property": "is_copilot_active_monthly", "operator": "=", "value": true}
]
}
},
{
"id": "inactive_licenses",
"type": "entities-number-chart",
"title": "Inactive Users",
"icon": "AlertCircle",
"description": "Users with zero usage",
"blueprint": "organization",
"chartType": "displaySingleProperty",
"entity": "default-org",
"property": "ai_copilot_inactive_license_rate",
"unit": "%",
"unitAlignment": "right"
},
{
"id": "inactive_users_count",
"type": "entities-number-chart",
"title": "Inactive Users (this month)",
"icon": "Users",
"description": "Users with zero Copilot activity this month",
"blueprint": "organization",
"chartType": "displaySingleProperty",
"entity": "default-org",
"property": "ai_copilot_inactive_users_monthly",
"unit": "custom",
"unitCustom": "users"
},
{
"id": "high_adopter_rate",
"type": "entities-number-chart",
"title": "High Adopter Rate",
"icon": "Award",
"description": "% of Port users who reached High adoption tier (16+ days)",
"blueprint": "organization",
"chartType": "displaySingleProperty",
"entity": "default-org",
"property": "ai_copilot_high_adopter_rate",
"unit": "%",
"unitAlignment": "right"
},
{
"id": "team_adoption_table",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Copilot adoption per team",
"icon": "TrendingUp",
"description": "Teams ranked by Copilot adoption rate",
"blueprint": "_team",
"dataset": {
"combinator": "and",
"rules": [
{"property": "type", "operator": "=", "value": "team"}
]
},
"excludedFields": [],
"blueprintConfig": {
"_team": {
"filterSettings": {"filterBy": {"combinator": "and", "rules": []}},
"groupSettings": {"groupBy": []},
"propertiesSettings": {
"order": ["$icon", "$title", "ai_copilot_adoption_tier", "ai_copilot_adoption_rate", "ai_copilot_acceptance_rate", "ai_copilot_loc_efficiency", "ai_copilot_loc_added_monthly", "total_members", "ai_copilot_active_users_monthly", "ai_copilot_high_adopters_monthly", "FROZEN_RIGHT_COLUMN"],
"shown": ["$title", "ai_copilot_adoption_rate", "ai_copilot_acceptance_rate", "ai_copilot_loc_efficiency", "ai_copilot_loc_added_monthly", "ai_copilot_adoption_tier", "total_members", "ai_copilot_active_users_monthly", "ai_copilot_high_adopters_monthly"]
},
"sortSettings": {"sortBy": [{"property": "ai_copilot_adoption_rate", "order": "desc"}]}
}
}
},
{
"id": "top_contributors_by_loc",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Copilot User Contributors",
"icon": "Award",
"description": "Copilot users who actively accepted suggestions and added AI-generated lines of code this month",
"blueprint": "_user",
"dataset": {
"combinator": "and",
"rules": [
{"property": "is_copilot_active_monthly", "operator": "=", "value": true},
{"property": "copilot_loc_added_monthly", "operator": ">", "value": 0}
]
},
"excludedFields": [],
"blueprintConfig": {
"_user": {
"propertiesSettings": {
"shown": ["$identifier", "$title", "copilot_loc_suggested_monthly", "copilot_loc_added_monthly", "copilot_loc_efficiency", "copilot_acceptance_rate", "$team"]
},
"sortSettings": {"sortBy": [{"property": "copilot_loc_added_monthly", "order": "desc"}]}
}
}
},
{
"id": "low_engagement",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Low Engagement (≤5 Days)",
"icon": "AlertTriangle",
"description": "Active Copilot users with fewer than 5 days of usage this month",
"blueprint": "_user",
"dataset": {
"combinator": "and",
"rules": [
{"property": "is_copilot_active_monthly", "operator": "=", "value": true},
{"property": "copilot_days_active_monthly", "operator": "<=", "value": 5}
]
},
"excludedFields": [],
"blueprintConfig": {
"_user": {
"propertiesSettings": {
"shown": ["$identifier", "$title", "copilot_days_active_monthly", "copilot_acceptance_rate", "adoption_tier", "$team"]
},
"sortSettings": {"sortBy": [{"property": "copilot_days_active_monthly", "order": "asc"}]}
}
}
},
{
"id": "inactive_copilot_users",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Port Users using Copilot with no output",
"icon": "EyeOff",
"description": "Active Copilot users with zero lines of code added this month, or users marked Copilot-inactive",
"blueprint": "_user",
"dataset": {
"combinator": "or",
"rules": [
{"property": "is_copilot_inactive", "operator": "=", "value": true},
{
"combinator": "and",
"rules": [
{"property": "is_copilot_active_monthly", "operator": "=", "value": true},
{"property": "copilot_loc_added_monthly", "operator": "=", "value": 0}
]
}
]
},
"excludedFields": [],
"blueprintConfig": {
"_user": {
"propertiesSettings": {
"shown": ["$identifier", "$title", "copilot_acceptance_rate", "copilot_days_active_monthly", "copilot_loc_added_monthly", "$team"]
},
"sortSettings": {"sortBy": [{"property": "copilot_days_active_monthly", "order": "asc"}]}
}
}
},
{
"id": "copilot_daily_activity",
"type": "multi-line-chart",
"title": "Copilot Activity Trends",
"icon": "Activity",
"description": "Daily suggestions generated vs accepted. Includes all GitHub Copilot users, not just those mapped in Port.",
"lines": [
{
"title": "Suggestions Generated",
"blueprint": "githubCopilotUserUsage",
"chartType": "aggregatePropertiesValues",
"func": "sum",
"measureTimeBy": "record_date",
"properties": ["properties.code_generation_activity_count"],
"dataset": {"combinator": "and", "rules": []}
},
{
"title": "Suggestions Accepted",
"blueprint": "githubCopilotUserUsage",
"chartType": "aggregatePropertiesValues",
"func": "sum",
"measureTimeBy": "record_date",
"properties": ["properties.code_acceptance_activity_count"],
"dataset": {"combinator": "and", "rules": []}
}
],
"nullValueDisplayMode": "null",
"timeInterval": "day",
"timeRange": {"preset": "last3Months"},
"xAxisTitle": "Date",
"yAxisTitle": "Count"
},
{
"id": "copilot_chat_agent_usage",
"type": "multi-line-chart",
"title": "Chat & Agent Adoption",
"icon": "MessageSquare",
"description": "Chat and agent feature adoption. Includes all GitHub Copilot users, not just those mapped in Port.",
"lines": [
{
"title": "Chat Usage",
"blueprint": "githubCopilotUserUsage",
"chartType": "countEntities",
"func": "count",
"measureTimeBy": "record_date",
"dataset": {
"combinator": "and",
"rules": [
{"property": "used_chat", "operator": "=", "value": true}
]
}
},
{
"title": "Agent Usage",
"blueprint": "githubCopilotUserUsage",
"chartType": "countEntities",
"func": "count",
"measureTimeBy": "record_date",
"dataset": {
"combinator": "and",
"rules": [
{"property": "used_agent", "operator": "=", "value": true}
]
}
}
],
"nullValueDisplayMode": "null",
"timeInterval": "day",
"timeRange": {"preset": "last3Months"},
"xAxisTitle": "Date",
"yAxisTitle": "Days"
},
{
"id": "copilot_loc_trends",
"type": "multi-line-chart",
"title": "LOC Trends",
"icon": "Code",
"description": "Lines suggested vs added. Includes all GitHub Copilot users, not just those mapped in Port.",
"lines": [
{
"title": "Lines Suggested",
"blueprint": "githubCopilotUserUsage",
"chartType": "aggregatePropertiesValues",
"func": "sum",
"measureTimeBy": "record_date",
"properties": ["properties.loc_suggested_to_add_sum"],
"dataset": {"combinator": "and", "rules": []}
},
{
"title": "Lines Added",
"blueprint": "githubCopilotUserUsage",
"chartType": "aggregatePropertiesValues",
"func": "sum",
"measureTimeBy": "record_date",
"properties": ["properties.loc_added_sum"],
"dataset": {"combinator": "and", "rules": []}
}
],
"nullValueDisplayMode": "null",
"timeInterval": "day",
"timeRange": {"preset": "last3Months"},
"xAxisTitle": "Date",
"yAxisTitle": "Lines"
},
{
"id": "copilot_acceptance_trend",
"type": "multi-line-chart",
"title": "Acceptance Trend",
"icon": "Percent",
"description": "Acceptance rate over time. Includes all GitHub Copilot users, not just those mapped in Port.",
"lines": [
{
"title": "Acceptance %",
"blueprint": "githubCopilotUserUsage",
"chartType": "aggregatePropertiesValues",
"func": "average",
"measureTimeBy": "record_date",
"properties": ["properties.acceptance_rate"],
"dataset": {"combinator": "and", "rules": []}
}
],
"nullValueDisplayMode": "null",
"timeInterval": "day",
"timeRange": {"preset": "last3Months"},
"xAxisTitle": "Date",
"yAxisTitle": "%"
}
]
}
]
}

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 @copilot_ai_adoption_dashboard.json | python3 -m json.tool
Engineering Intelligence folder

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.

Extending to other AI tools

The data model in this guide is deliberately structured so that GitHub Copilot is just one tool plugged into a tool-agnostic foundation. You can layer Claude Code, Cursor, 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 four-layer structure:

  1. Raw daily activity lives in a tool-specific blueprint (e.g. githubCopilotUserUsage for Copilot, an equivalent claudeCodeAnalytics or cursorUserUsage for other tools). Each record is one user-day of activity.
  2. Per-tool user profile rolls daily records up to the month on the AI User Profile (ai_user) blueprint. The tool enum (Copilot, Claude, etc.) discriminates one tool from another, and each user has one ai_user entity per tool they use.
  3. Per-tool org profile rolls daily org-level records up on the AI Org Profile (ai_org) blueprint, same pattern.
  4. Cross-tool synthesis lives on the User, Team, and Organization blueprints. Aggregations sum across all linked ai_user entities filtered by tool, so adding a tool is purely additive. Existing Copilot metrics keep working.

Next steps

Once your dashboard is in place, consider these additional improvements:

  • Set up scorecards to grade teams against Copilot 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 Copilot users who have been inactive for two consecutive months.
  • Correlate adoption with engineering outcomes by overlaying Copilot 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.