Set up delivery performance scorecards
Scorecards let you define maturity levels for your services and teams, giving engineering leaders a clear view of which areas meet delivery standards and which need attention.
This guide demonstrates how to set up Delivery Performance scorecards at different levels of the organization:
- Service: PR throughput, cycle time, stale PR management for individual services.
- Team: Same metrics normalized per-service so teams are compared fairly.
- Group: Executive-level delivery health for business units.
- Organization: Top-level delivery view across the entire org.
Each scorecard evaluates entities against progressive maturity levels: Bronze, Silver, and Gold. Thresholds are informed by DORA benchmarks and industry engineering data.
Common use cases
- Set clear, measurable delivery expectations across engineering teams.
- Identify services that are falling behind on cycle time, throughput, or stale PR hygiene.
- Compare team and group delivery maturity at a glance and drive improvement initiatives.
- Gate deployments or trigger alerts when services drop below a minimum scorecard level.
Prerequisites
This guide assumes the following:
- You have a Port account and have completed the onboarding process.
- You have completed the Set up PR delivery metrics guide, which configures the required properties on the
service,_team, andorganizationblueprints.
Maturity levels
Port scorecards use four fixed maturity levels. An entity must pass all rules at a given level (and all levels below it) to achieve that level.
| Level | Progression | Description |
|---|---|---|
| Basic | 0 (default) | Entity exists but meets no scorecard criteria |
| Bronze | 1 | Foundational hygiene and minimum viable standards |
| Silver | 2 | Good practices — actively maintained, reasonable thresholds |
| Gold | 3 | Excellence — elite-tier metrics |
Create the scorecards
PR throughput and cycle time targets aligned with DORA benchmarks and industry engineering data. Select the level you want to configure:
- Service
- Team
- Group
- Organization
Blueprint: Service
| # | Rule | Level | Property | Condition |
|---|---|---|---|---|
| 1 | Merged PRs >= 2/week | Bronze | merged_prs_last_month | >= 8 |
| 2 | Open PRs <= 8 | Bronze | open_prs | <= 8 |
| 3 | Stale PR share <= 10% | Bronze | stale_pr_share_percent | <= 10 |
| 4 | PR cycle time < 7 days | Bronze | pr_cycle_time | < 168 hours |
| 5 | Open PRs <= 5 | Silver | open_prs | <= 5 |
| 6 | Stale PRs <= 1 | Silver | stale_prs_7d | <= 1 |
| 7 | PR cycle time < 24h | Silver | pr_cycle_time | < 24 hours |
| 8 | Throughput not degrading | Silver | throughput_trend | != "Degrading" |
| 9 | Merged PRs >= 5/week | Silver | merged_prs_last_month | >= 20 |
| 10 | Open PRs <= 3 | Gold | open_prs | <= 3 |
| 11 | Stale PRs = 0 | Gold | stale_prs_7d | = 0 |
| 12 | PR cycle time < 1h | Gold | pr_cycle_time | < 1 hour |
| 13 | PR cycle time not degrading | Gold | cycle_time_trend | != "Degrading" |
| 14 | Merged PRs >= 10/week | Gold | merged_prs_last_month | >= 40 |
Create the delivery performance scorecard on the service blueprint
-
Go to the Builder page of your portal.
-
Search for the Service blueprint and select it.
-
Click on the Scorecards tab.
-
If the
delivery_performancescorecard does not exist, click + New Scorecard. If it already exists, open it instead. -
Click on the
{...}button in the top right corner, and choose Edit JSON. -
Paste the following JSON configuration:
Service Delivery Performance scorecard (click to expand)
{
"identifier": "delivery_performance",
"title": "Delivery Performance",
"levels": [
{
"color": "paleBlue",
"title": "Basic"
},
{
"color": "bronze",
"title": "Bronze"
},
{
"color": "silver",
"title": "Silver"
},
{
"color": "gold",
"title": "Gold"
}
],
"rules": [
{
"identifier": "has_merged_prs",
"title": "Merged PRs ≥ 2/week",
"description": "Service merges at least 8 PRs per month, indicating active development.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_last_month",
"value": 8
}
]
}
},
{
"identifier": "manageable_open_prs",
"title": "Open PRs ≤ 8",
"description": "Keeps the number of open PRs manageable to avoid review overload.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "open_prs",
"value": 8
}
]
}
},
{
"identifier": "low_stale_prs",
"title": "Stale PR share ≤ 10%",
"description": "No more than 10% of open PRs are older than 7 days.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "stale_pr_share_percent",
"value": 10
}
]
}
},
{
"identifier": "cycle_time_under_7d",
"title": "PR cycle time < 7 days",
"description": "Average time from PR creation to merge is under one week.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 168
}
]
}
},
{
"identifier": "good_open_pr_management",
"title": "Open PRs ≤ 5",
"description": "Tighter open PR limit indicating strong review discipline.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "open_prs",
"value": 5
}
]
}
},
{
"identifier": "minimal_stale_prs",
"title": "Stale PRs ≤ 1",
"description": "At most one PR has been open longer than 7 days.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "stale_prs_7d",
"value": 1
}
]
}
},
{
"identifier": "cycle_time_under_24h",
"title": "PR cycle time < 24h",
"description": "PRs are merged within a day on average.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 24
}
]
}
},
{
"identifier": "throughput_not_degrading",
"title": "Throughput not degrading",
"description": "Weekly merge rate is not declining compared to the monthly average.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "throughput_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "good_throughput",
"title": "Merged PRs ≥ 5/week",
"description": "Service merges at least 20 PRs per month, showing strong delivery pace.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_last_month",
"value": 20
}
]
}
},
{
"identifier": "excellent_open_pr_management",
"title": "Open PRs ≤ 3",
"description": "Very few PRs are open at any time, indicating rapid review cycles.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "open_prs",
"value": 3
}
]
}
},
{
"identifier": "no_stale_prs",
"title": "Stale PRs = 0",
"description": "No open PRs have been sitting for more than 7 days.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "stale_prs_7d",
"value": 0
}
]
}
},
{
"identifier": "cycle_time_under_1h",
"title": "PR cycle time < 1h",
"description": "PRs are merged in under an hour on average — elite performance.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 1
}
]
}
},
{
"identifier": "cycle_time_not_degrading",
"title": "PR cycle time not degrading",
"description": "Weekly cycle time is not increasing compared to the monthly average.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "cycle_time_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "excellent_throughput",
"title": "Merged PRs ≥ 10/week",
"description": "Service merges at least 40 PRs per month — top-tier throughput.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_last_month",
"value": 40
}
]
}
}
]
} -
Click Save to create the scorecard.
Blueprint: Team
Same thresholds as service-level, but absolute count rules use per-service normalized metrics (e.g. open_prs_per_service) so that teams are evaluated fairly regardless of how many services they own. Rate, trend, and cycle-time rules are unchanged since they already scale naturally.
| # | Rule | Level | Property | Condition |
|---|---|---|---|---|
| 1 | Merged PRs >= 2/week per service | Bronze | merged_prs_per_service_last_month | >= 8 |
| 2 | Open PRs <= 8 per service | Bronze | open_prs_per_service | <= 8 |
| 3 | Stale PR share <= 10% | Bronze | stale_pr_share_percent | <= 10 |
| 4 | PR cycle time < 7 days | Bronze | pr_cycle_time | < 168 hours |
| 5 | Open PRs <= 5 per service | Silver | open_prs_per_service | <= 5 |
| 6 | Stale PRs <= 1 per service | Silver | stale_prs_per_service_7d | <= 1 |
| 7 | PR cycle time < 24h | Silver | pr_cycle_time | < 24 hours |
| 8 | Throughput not degrading | Silver | throughput_trend | != "Degrading" |
| 9 | Merged PRs >= 5/week per service | Silver | merged_prs_per_service_last_month | >= 20 |
| 10 | Open PRs <= 3 per service | Gold | open_prs_per_service | <= 3 |
| 11 | Stale PRs = 0 per service | Gold | stale_prs_per_service_7d | = 0 |
| 12 | PR cycle time < 1h | Gold | pr_cycle_time | < 1 hour |
| 13 | PR cycle time not degrading | Gold | cycle_time_trend | != "Degrading" |
| 14 | Merged PRs >= 10/week per service | Gold | merged_prs_per_service_last_month | >= 40 |
Create the delivery performance scorecard on the team blueprint
-
Go to the Builder page.
-
Search for the Team blueprint and select it.
-
Click on the Scorecards tab.
-
If the
team_delivery_performancescorecard does not exist, click + New Scorecard. If it already exists, open it instead. -
Click on the
{...}button in the top right corner, and choose Edit JSON. -
Paste the following JSON configuration:
Team Delivery Performance scorecard (click to expand)
{
"identifier": "team_delivery_performance",
"title": "Delivery Performance",
"filter": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "type",
"value": "team"
}
]
},
"levels": [
{
"color": "paleBlue",
"title": "Basic"
},
{
"color": "bronze",
"title": "Bronze"
},
{
"color": "silver",
"title": "Silver"
},
{
"color": "gold",
"title": "Gold"
}
],
"rules": [
{
"identifier": "has_merged_prs",
"title": "Merged PRs ≥ 2/week per service",
"description": "Each service in the team merges at least 8 PRs per month on average.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 8
}
]
}
},
{
"identifier": "manageable_open_prs",
"title": "Open PRs ≤ 8 per service",
"description": "Open PR count per service stays manageable.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "open_prs_per_service",
"value": 8
}
]
}
},
{
"identifier": "low_stale_prs",
"title": "Stale PR share ≤ 10%",
"description": "No more than 10% of the team's open PRs are older than 7 days.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "stale_pr_share_percent",
"value": 10
}
]
}
},
{
"identifier": "cycle_time_under_7d",
"title": "PR cycle time < 7 days",
"description": "Average PR cycle time across team services is under one week.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 168
}
]
}
},
{
"identifier": "good_open_pr_management",
"title": "Open PRs ≤ 5 per service",
"description": "Tighter open PR limit per service.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "open_prs_per_service",
"value": 5
}
]
}
},
{
"identifier": "minimal_stale_prs",
"title": "Stale PRs ≤ 1 per service",
"description": "At most one stale PR per service on average.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "stale_prs_per_service_7d",
"value": 1
}
]
}
},
{
"identifier": "cycle_time_under_24h",
"title": "PR cycle time < 24h",
"description": "Team-wide PR cycle time is under 24 hours.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 24
}
]
}
},
{
"identifier": "throughput_not_degrading",
"title": "Throughput not degrading",
"description": "Team's weekly merge rate is not declining.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "throughput_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "good_throughput",
"title": "Merged PRs ≥ 5/week per service",
"description": "Each service in the team merges at least 20 PRs per month on average.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 20
}
]
}
},
{
"identifier": "excellent_open_pr_management",
"title": "Open PRs ≤ 3 per service",
"description": "Very few open PRs per service.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "open_prs_per_service",
"value": 3
}
]
}
},
{
"identifier": "no_stale_prs",
"title": "Stale PRs = 0 per service",
"description": "No stale PRs across any of the team's services.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "stale_prs_per_service_7d",
"value": 0
}
]
}
},
{
"identifier": "cycle_time_under_1h",
"title": "PR cycle time < 1h",
"description": "Team-wide PR cycle time is under one hour — elite performance.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 1
}
]
}
},
{
"identifier": "cycle_time_not_degrading",
"title": "PR cycle time not degrading",
"description": "Team's weekly cycle time is not increasing.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "cycle_time_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "excellent_throughput",
"title": "Merged PRs ≥ 10/week per service",
"description": "Each service merges at least 40 PRs per month on average — top-tier throughput.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 40
}
]
}
}
]
} -
Click Save to create the scorecard.
Blueprint: Team (filtered to type = "group")
Executive-level delivery health for business units. Uses rate, trend, and per-service normalized throughput metrics since groups aggregate multiple teams.
| # | Rule | Level | Property | Condition |
|---|---|---|---|---|
| 1 | Stale PR share <= 10% | Bronze | stale_pr_share_percent | <= 10 |
| 2 | Avg PR cycle time < 7 days | Bronze | pr_cycle_time | < 168 hours |
| 3 | Merged PRs >= 2/week per service | Bronze | merged_prs_per_service_last_month | >= 8 |
| 4 | Avg PR cycle time < 24h | Silver | pr_cycle_time | < 24 hours |
| 5 | Throughput not degrading | Silver | throughput_trend | != "Degrading" |
| 6 | Merged PRs >= 5/week per service | Silver | merged_prs_per_service_last_month | >= 20 |
| 7 | Avg PR cycle time < 1h | Gold | pr_cycle_time | < 1 hour |
| 8 | PR cycle time not degrading | Gold | cycle_time_trend | != "Degrading" |
| 9 | Merged PRs >= 10/week per service | Gold | merged_prs_per_service_last_month | >= 40 |
Create the delivery performance scorecard for groups
-
Go to the Builder page.
-
Search for the Team blueprint and select it.
-
Click on the Scorecards tab.
-
If the
group_delivery_performancescorecard does not exist, click + New Scorecard. If it already exists, open it instead. -
Click on the
{...}button in the top right corner, and choose Edit JSON. -
Paste the following JSON configuration:
Group Delivery Performance scorecard (click to expand)
{
"identifier": "group_delivery_performance",
"title": "Delivery Performance (Group)",
"filter": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "type",
"value": "group"
}
]
},
"levels": [
{
"color": "paleBlue",
"title": "Basic"
},
{
"color": "bronze",
"title": "Bronze"
},
{
"color": "silver",
"title": "Silver"
},
{
"color": "gold",
"title": "Gold"
}
],
"rules": [
{
"identifier": "low_stale_prs",
"title": "Stale PR share ≤ 10%",
"description": "No more than 10% of open PRs across the group are stale.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "stale_pr_share_percent",
"value": 10
}
]
}
},
{
"identifier": "cycle_time_under_7d",
"title": "Avg PR cycle time < 7 days",
"description": "Group-wide average PR cycle time is under one week.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 168
}
]
}
},
{
"identifier": "has_merged_prs",
"title": "Merged PRs ≥ 2/week per service",
"description": "Each service in the group merges at least 8 PRs per month on average.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 8
}
]
}
},
{
"identifier": "cycle_time_under_24h",
"title": "Avg PR cycle time < 24h",
"description": "Group-wide PR cycle time is under 24 hours.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 24
}
]
}
},
{
"identifier": "throughput_not_degrading",
"title": "Throughput not degrading",
"description": "Group's weekly merge rate is not declining.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "throughput_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "good_throughput",
"title": "Merged PRs ≥ 5/week per service",
"description": "Each service merges at least 20 PRs per month on average.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 20
}
]
}
},
{
"identifier": "cycle_time_under_1h",
"title": "Avg PR cycle time < 1h",
"description": "Group-wide PR cycle time is under one hour.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 1
}
]
}
},
{
"identifier": "cycle_time_not_degrading",
"title": "PR cycle time not degrading",
"description": "Group's weekly cycle time is not increasing.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "cycle_time_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "excellent_throughput",
"title": "Merged PRs ≥ 10/week per service",
"description": "Each service merges at least 40 PRs per month on average — top-tier throughput.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 40
}
]
}
}
]
} -
Click Save to create the scorecard.
Blueprint: Organization
Executive-level delivery health for the entire organization. Uses rate, trend, and per-service normalized throughput metrics since the org aggregates all teams and services.
| # | Rule | Level | Property | Condition |
|---|---|---|---|---|
| 1 | Stale PR share <= 10% | Bronze | stale_pr_share_percent | <= 10 |
| 2 | Avg PR cycle time < 7 days | Bronze | pr_cycle_time | < 168 hours |
| 3 | Merged PRs >= 2/week per service | Bronze | merged_prs_per_service_last_month | >= 8 |
| 4 | Avg PR cycle time < 24h | Silver | pr_cycle_time | < 24 hours |
| 5 | Throughput not degrading | Silver | throughput_trend | != "Degrading" |
| 6 | Merged PRs >= 5/week per service | Silver | merged_prs_per_service_last_month | >= 20 |
| 7 | Avg PR cycle time < 1h | Gold | pr_cycle_time | < 1 hour |
| 8 | PR cycle time not degrading | Gold | cycle_time_trend | != "Degrading" |
| 9 | Merged PRs >= 10/week per service | Gold | merged_prs_per_service_last_month | >= 40 |
Create the delivery performance scorecard on the organization blueprint
-
Go to the Builder page.
-
Search for the Organization blueprint and select it.
-
Click on the Scorecards tab.
-
If the
org_delivery_performancescorecard does not exist, click + New Scorecard. If it already exists, open it instead. -
Click on the
{...}button in the top right corner, and choose Edit JSON. -
Paste the following JSON configuration:
Organization Delivery Performance scorecard (click to expand)
{
"identifier": "org_delivery_performance",
"title": "Delivery Performance",
"levels": [
{
"color": "paleBlue",
"title": "Basic"
},
{
"color": "bronze",
"title": "Bronze"
},
{
"color": "silver",
"title": "Silver"
},
{
"color": "gold",
"title": "Gold"
}
],
"rules": [
{
"identifier": "low_stale_prs",
"title": "Stale PR share ≤ 10%",
"description": "No more than 10% of open PRs across the organization are stale.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<=",
"property": "stale_pr_share_percent",
"value": 10
}
]
}
},
{
"identifier": "cycle_time_under_7d",
"title": "Avg PR cycle time < 7 days",
"description": "Organization-wide average PR cycle time is under one week.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 168
}
]
}
},
{
"identifier": "has_merged_prs",
"title": "Merged PRs ≥ 2/week per service",
"description": "Each service merges at least 8 PRs per month on average.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 8
}
]
}
},
{
"identifier": "cycle_time_under_24h",
"title": "Avg PR cycle time < 24h",
"description": "Organization-wide PR cycle time is under 24 hours.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 24
}
]
}
},
{
"identifier": "throughput_not_degrading",
"title": "Throughput not degrading",
"description": "Organization's weekly merge rate is not declining.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "throughput_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "good_throughput",
"title": "Merged PRs ≥ 5/week per service",
"description": "Each service merges at least 20 PRs per month on average.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 20
}
]
}
},
{
"identifier": "cycle_time_under_1h",
"title": "Avg PR cycle time < 1h",
"description": "Organization-wide PR cycle time is under one hour.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "pr_cycle_time",
"value": 1
}
]
}
},
{
"identifier": "cycle_time_not_degrading",
"title": "PR cycle time not degrading",
"description": "Organization's weekly cycle time is not increasing.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "!=",
"property": "cycle_time_trend",
"value": "Degrading"
}
]
}
},
{
"identifier": "excellent_throughput",
"title": "Merged PRs ≥ 10/week per service",
"description": "Each service merges at least 40 PRs per month on average — top-tier throughput.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "merged_prs_per_service_last_month",
"value": 40
}
]
}
}
]
} -
Click Save to create the scorecard.
Visualize scorecard results
Once the scorecards are in place, create a dashboard to monitor delivery maturity across services and teams.
Create the dashboard
- 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 Delivery Performance Scorecards 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 bottom left 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 dp_scorecards_dashboard.json:Dashboard JSON payload (click to expand)
{
"identifier": "delivery_performance_scorecards",
"title": "Delivery Performance Scorecards",
"icon": "Star",
"type": "dashboard",
"parent": "engineering_intelligence",
"widgets": [
{
"id": "dpScorecardsDashboardWidget",
"type": "dashboard-widget",
"layout": [
{
"height": 400,
"columns": [
{"id": "serviceLevelDistribution", "size": 4},
{"id": "teamLevelDistribution", "size": 4},
{"id": "servicesBelowBronze", "size": 4}
]
},
{
"height": 400,
"columns": [
{"id": "serviceScorecardsTable", "size": 12}
]
},
{
"height": 400,
"columns": [
{"id": "teamScorecardsTable", "size": 12}
]
},
{
"height": 400,
"columns": [
{"id": "groupScorecardsTable", "size": 12}
]
},
{
"height": 400,
"columns": [
{"id": "orgScorecardsTable", "size": 12}
]
}
],
"widgets": [
{
"id": "serviceLevelDistribution",
"type": "entities-pie-chart",
"title": "Service Delivery Performance Levels",
"icon": "Pie",
"description": "Distribution of delivery performance scorecard levels across services",
"blueprint": "service",
"property": "scorecard#delivery_performance",
"dataset": {
"combinator": "and",
"rules": []
}
},
{
"id": "teamLevelDistribution",
"type": "entities-pie-chart",
"title": "Team Delivery Performance Levels",
"icon": "Pie",
"description": "Distribution of delivery performance scorecard levels across teams",
"blueprint": "_team",
"property": "scorecard#team_delivery_performance",
"dataset": {
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "type",
"value": "team"
}
]
}
},
{
"id": "servicesBelowBronze",
"type": "entities-number-chart",
"title": "Services Below Bronze",
"icon": "Alert",
"description": "Number of services that have not reached Bronze level",
"blueprint": "service",
"chartType": "countEntities",
"calculationBy": "entities",
"func": "count",
"unit": "none",
"dataset": {
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "scorecard#delivery_performance",
"value": "Basic"
}
]
}
},
{
"id": "serviceScorecardsTable",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Service Delivery Scorecard Overview",
"icon": "Table",
"description": "Services with their delivery performance scorecard level and key metrics",
"blueprint": "service",
"dataset": {"combinator": "and", "rules": []},
"excludedFields": [],
"blueprintConfig": {
"service": {
"groupSettings": {"groupBy": ["team"]},
"propertiesSettings": {
"order": ["$title", "team", "scorecard-property#delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_last_month", "throughput_trend", "open_prs", "stale_prs_7d", "stale_pr_share_percent"],
"shown": ["$title", "team", "scorecard-property#delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_last_month", "throughput_trend", "open_prs", "stale_prs_7d", "stale_pr_share_percent"]
},
"filterSettings": {"filterBy": {"combinator": "and", "rules": []}},
"sortSettings": {"sortBy": []}
}
}
},
{
"id": "teamScorecardsTable",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Team Delivery Scorecard Overview",
"icon": "Table",
"description": "Teams with their delivery performance scorecard level and key metrics",
"blueprint": "_team",
"dataset": {"combinator": "and", "rules": []},
"excludedFields": [],
"blueprintConfig": {
"_team": {
"groupSettings": {"groupBy": ["parent_team_name"]},
"propertiesSettings": {
"order": ["$title", "scorecard-property#team_delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_per_service_last_month", "throughput_trend", "open_prs_per_service", "stale_prs_per_service_7d", "stale_pr_share_percent", "services_count"],
"shown": ["$title", "scorecard-property#team_delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_per_service_last_month", "throughput_trend", "open_prs_per_service", "stale_prs_per_service_7d", "stale_pr_share_percent", "services_count"]
},
"filterSettings": {
"filterBy": {
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "type",
"value": "team"
}
]
}
},
"sortSettings": {"sortBy": []}
}
}
},
{
"id": "groupScorecardsTable",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Group Delivery Scorecard Overview",
"icon": "Table",
"description": "Business units with their delivery performance scorecard level and key metrics",
"blueprint": "_team",
"dataset": {"combinator": "and", "rules": []},
"excludedFields": [],
"blueprintConfig": {
"_team": {
"groupSettings": {},
"propertiesSettings": {
"order": ["$title", "scorecard-property#group_delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_per_service_last_month", "throughput_trend", "stale_pr_share_percent"],
"shown": ["$title", "scorecard-property#group_delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_per_service_last_month", "throughput_trend", "stale_pr_share_percent"]
},
"filterSettings": {
"filterBy": {
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "type",
"value": "group"
}
]
}
},
"sortSettings": {"sortBy": []}
}
}
},
{
"id": "orgScorecardsTable",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Organization Delivery Scorecard Overview",
"icon": "Table",
"description": "Organization with its delivery performance scorecard level and key metrics",
"blueprint": "organization",
"dataset": {"combinator": "and", "rules": []},
"excludedFields": [],
"blueprintConfig": {
"organization": {
"groupSettings": {},
"propertiesSettings": {
"order": ["$title", "scorecard-property#org_delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_per_service_last_month", "throughput_trend", "stale_pr_share_percent"],
"shown": ["$title", "scorecard-property#org_delivery_performance", "pr_cycle_time", "cycle_time_trend", "merged_prs_per_service_last_month", "throughput_trend", "stale_pr_share_percent"]
},
"filterSettings": {"filterBy": {"combinator": "and", "rules": []}},
"sortSettings": {"sortBy": []}
}
}
}
]
}
]
}
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 @dp_scorecards_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.
Scorecard level distribution
Service delivery performance levels — pie chart (click to expand)
- Click
+ Widgetand select Pie Chart. - Title:
Service Delivery Performance Levels. - Description:
Distribution of delivery performance scorecard levels across services. - Choose Service as the Blueprint.
- Select
Delivery Performancefrom the Breakdown by property dropdown (this is thescorecard#delivery_performanceproperty). - Click Save.
Team delivery performance levels — pie chart (click to expand)
-
Click
+ Widgetand select Pie Chart. -
Title:
Team Delivery Performance Levels. -
Description:
Distribution of delivery performance scorecard levels across teams. -
Choose Team as the Blueprint.
-
Select
Delivery Performancefrom the Breakdown by property dropdown (this is thescorecard#team_delivery_performanceproperty). -
Add this JSON to the Additional filters editor:
{
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "type",
"value": "team"
}
]
} -
Click Save.
Attention metrics
Services below Bronze — number chart (click to expand)
-
Click
+ Widgetand select Number Chart. -
Title:
Services Below Bronze. -
Description:
Number of services that have not reached Bronze level. -
Select
Count EntitiesChart type and choose Service as the Blueprint. -
Add this JSON to the Additional filters editor:
{
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "scorecard#delivery_performance",
"value": "Basic"
}
]
} -
Click Save.
Scorecard tables
Service delivery scorecard overview — table (click to expand)
- Click
+ Widgetand select Table. - Title:
Service Delivery Scorecard Overview. - Description:
Services with their delivery performance scorecard level and key metrics. - Choose Service as the Blueprint.
- Group by Team.
- Configure the displayed columns to show: title, team, delivery performance level, PR cycle time, cycle time trend, merged PRs last month, throughput trend, open PRs, stale PRs (7d), and stale PR share.
- Click Save.
Team delivery scorecard overview — table (click to expand)
- Click
+ Widgetand select Table. - Title:
Team Delivery Scorecard Overview. - Description:
Teams with their delivery performance scorecard level and key metrics. - Choose Team as the Blueprint.
- Group by Parent Team.
- Add a filter for
type = teamto exclude groups and organizations. - Configure the displayed columns to show: title, delivery performance level, PR cycle time, cycle time trend, merged PRs per service, throughput trend, open PRs per service, stale PRs per service (7d), stale PR share, and services count.
- Click Save.
Group delivery scorecard overview — table (click to expand)
- Click
+ Widgetand select Table. - Title:
Group Delivery Scorecard Overview. - Description:
Business units with their delivery performance scorecard level and key metrics. - Choose Team as the Blueprint.
- Add a filter for
type = group. - Configure the displayed columns to show: title, delivery performance level, PR cycle time, cycle time trend, merged PRs per service, throughput trend, and stale PR share.
- Click Save.
Organization delivery scorecard overview — table (click to expand)
- Click
+ Widgetand select Table. - Title:
Organization Delivery Scorecard Overview. - Description:
Organization with its delivery performance scorecard level and key metrics. - Choose Organization as the Blueprint.
- Configure the displayed columns to show: title, delivery performance level, PR cycle time, cycle time trend, merged PRs per service, throughput trend, and stale PR share.
- Click Save.
Design decisions
Team-level normalization
Team-level scorecards use per-service normalized metrics for absolute count rules (open PRs, merged PRs, stale PRs).
This ensures teams are evaluated fairly regardless of how many services they own.
For example, a team with 5 services and 40 open PRs is evaluated as 8 open PRs per service, the same threshold as a single service with 8.
Rate metrics (stale PR share), trend metrics (throughput, cycle time), and time-based metrics (PR cycle time) are not normalized as they already scale naturally across any number of services.
Executive-level scorecards (Group and Organization)
Group and Organization scorecards use rate, trend, and per-service normalized throughput metrics only.
Absolute count rules are omitted because groups and organizations span varying numbers of teams and services, making raw counts misleading.
Threshold sources
- DORA: Industry-standard DevOps Research and Assessment benchmarks for software delivery performance.
Next steps
- Add automations: Use Port automations to send Slack notifications when a service drops below Bronze, or create Jira tickets for teams with degrading trends.
- Customize thresholds: Adjust the numeric values in the scorecard rules to match your organization's delivery standards. For example, if your teams typically merge fewer PRs, lower the throughput thresholds.
Related guides
- Measure PR delivery metrics : Set up the underlying data model these scorecards depend on.
- Gain visibility into delivery performance : A broader delivery performance guide covering dashboards and AI agents.