Set up DORA metrics in Span
Last updated: October 27, 2026
This checklist walks you through everything Span needs to fill in your DORA page: deployments from your CI, incidents from your incident tool, team ownership, and PR linking for lead time.
Why it matters
Span's four DORA metrics depend on data that your git connection doesn't provide. Deployments have to come from your pipeline, incidents from incident.io, Rootly, or the API, and team ownership from services or PRs. Missing any piece leaves a chart empty, puts numbers under the wrong team, or makes change failure rate look wrong.
Metric | What Span needs |
|---|---|
Deployments / week | Successful production deployments |
Lead time for changes | Successful production deployments linked to merged PRs (Span turns linking on for your organization) |
Change failure rate | Production deployments and production incidents in the same range, mapped to the same teams |
Mean time to recover | Incidents with a start time and a resolved time |
How it works
Deployments reach Span only when your pipeline sends them, through the DORA API (
POST https://span.app/api/dora/v1/deployments) or a$deployevent. No connector reads deployments from GitHub Actions, GitLab CI/CD, Azure DevOps, CircleCI, or other CI tools.Which deployments count: status
success, and an environment that is blank or contains "prod" or "prd" in any letter case. Rollbacks and restarts count. Pending and failed deployments don't.Incidents come from incident.io, Rootly, or the DORA API (
POST /api/dora/v1/incidents). Use the API for PagerDuty, Opsgenie, or any tool Span doesn't connect to.Change failure rate divides production incidents by successful production deployments in the date range. Span doesn't attribute an incident to the specific deployment that caused it; it compares totals, per team and for the organization. So a team's CFR is only meaningful when both its incidents and its deployments map to that team.
Team ownership for deployments: by default, the teams that own the services in the deployment's
serviceslist. When Span turns on deploy-to-PR linking for your organization, the teams of the linked PRs' authors instead. Thedeployerfield is not used.Team ownership for incidents: the incident.io team field you map, your Rootly team mappings, or
ownerson API incidents.
Setup
Create a service account token. Go to Settings → Service Accounts, open the menu on the service account's row, choose Manage Token, then Generate. Store it as a CI secret named
SPAN_API_TOKEN. A service account token keeps working when people change roles or leave; a personal access token acts as one person.Create your services with owning teams. Send
POST /api/dora/v1/servicesonce per service withname,slug, andownerssuch as[{"type": "team", "slug": "payments"}]. The team slug must match an existing Span team.Add a deployment step to every production pipeline. Send
title,triggeredAt,completedAt,status: "success",environment,services, andgitwith the repository URL and the full 40-character commit SHA. Add anIdempotency-Keyheader so a retried call doesn't count twice. See the CircleCI example below, or the GitHub Actions and AWS CodePipeline article.Connect incidents. Connect incident.io or Rootly in Settings → Integrations and map their teams to Span teams, or send incidents through the DORA API with
startedAt,owners, and laterendedAt.Ask Span to turn on deploy-to-PR linking if you want lead time for changes. It's off by default.
Verify. Check Catalog → Deployments and Catalog → Incidents, then Insights → Productivity → DORA.
Example: CircleCI. Store SPAN_API_TOKEN in a CircleCI context or project environment variable. Add the first step at the start of your production deploy job and the last step at the end. Replace billing-api with your service slug.
version: 2.1
jobs:
deploy:
docker:
- image: cimg/base:stable
steps:
- checkout
- run:
name: Record deploy start
command: echo "export DEPLOY_STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$BASH_ENV"
# ... your existing deploy steps ...
- run:
name: Send deployment to Span
command: |
curl --fail-with-body -sS --retry 3 -X POST \
https://span.app/api/dora/v1/deployments \
-H "Authorization: Bearer ${SPAN_API_TOKEN}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: circleci-${CIRCLE_WORKFLOW_ID}-${CIRCLE_JOB}" \
-d "{\"title\":\"billing-api ${CIRCLE_SHA1:0:7}\",\"triggeredAt\":\"${DEPLOY_STARTED_AT}\",\"completedAt\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"status\":\"success\",\"environment\":\"production\",\"services\":[\"billing-api\"],\"httpUrl\":\"${CIRCLE_BUILD_URL}\",\"git\":{\"repoUrl\":\"https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\",\"refName\":\"${CIRCLE_SHA1}\"}}"
CircleCI runs the last step only if the earlier steps succeed. The example builds an https://github.com/owner/repo URL from CircleCI's project variables because Span can't match an SSH-style git@github.com: URL to your repository. If your code is on Azure DevOps, send https://dev.azure.com/org/project/_git/repo instead.
Things to know
Deploy-to-PR linking requirements. Span must turn it on for your organization. The repository in
git.repoUrlmust be one Span already syncs from your git connection, sent as agithub.com,*.ghe.com, ordev.azure.comURL. To infer PRs, Span matches the full commit SHA ingit.refNameagainst PR merge commits on the default branch; a short SHA, branch, or tag won't match. To link specific PRs instead, send their numbers inpullRequests.Turning on linking moves team credit. Deployments then count for the teams of the linked PRs' authors, not the services' owners, and a deployment with no linked PRs counts in the organization total only.
Send
status: "success". The DORA API defaults topending, which never counts.Avoid double counting. Without an
Idempotency-Key, everyPOSTcreates a new deployment. Team rows can also add up to more than the organization total when a deployment or incident belongs to two teams, so read the organization total rather than summing teams.Hotfixes and change failure rate. A hotfix deployment counts as a deployment. If your team fixes some failures with a hotfix and never opens an incident, send an incident for each through the DORA API so change failure rate counts it.
Processing time. Deployments and API incidents appear in the Catalog as soon as the call succeeds. incident.io and Rootly sync about every 2 hours. PR linking and lead time are calculated in the background; expect them within about 3 hours.
Worked example. The payments team owns
billing-api. In a 28-day range its pipeline sends 20 successful production deployments, and incident.io records 2 incidents mapped to payments. The DORA page shows 5.0 deployments per week (20 ÷ 28 × 7) and a change failure rate of 10% (2 ÷ 20) for payments. If the incidents weren't mapped to payments, the team would show 0% while the organization showed the incidents.
Related articles
How to use the DORA API to send deployment activity to Span
Send deployments to Span from GitHub Actions or AWS CodePipeline
Lead Time to Production in Span
How does the Incident.io integration work?
Need help?
Contact your Span account team or reach out to support@span.app.