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 $deploy event. 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 services list. When Span turns on deploy-to-PR linking for your organization, the teams of the linked PRs' authors instead. The deployer field is not used.

  • Team ownership for incidents: the incident.io team field you map, your Rootly team mappings, or owners on API incidents.

Setup

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

  2. Create your services with owning teams. Send POST /api/dora/v1/services once per service with name, slug, and owners such as [{"type": "team", "slug": "payments"}]. The team slug must match an existing Span team.

  3. Add a deployment step to every production pipeline. Send title, triggeredAt, completedAt, status: "success", environment, services, and git with the repository URL and the full 40-character commit SHA. Add an Idempotency-Key header so a retried call doesn't count twice. See the CircleCI example below, or the GitHub Actions and AWS CodePipeline article.

  4. 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 later endedAt.

  5. Ask Span to turn on deploy-to-PR linking if you want lead time for changes. It's off by default.

  6. 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.repoUrl must be one Span already syncs from your git connection, sent as a github.com, *.ghe.com, or dev.azure.com URL. To infer PRs, Span matches the full commit SHA in git.refName against PR merge commits on the default branch; a short SHA, branch, or tag won't match. To link specific PRs instead, send their numbers in pullRequests.

  • 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 to pending, which never counts.

  • Avoid double counting. Without an Idempotency-Key, every POST creates 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

Change Failure Rate Report

How does the Incident.io integration work?

Rootly Integration

Need help?

Contact your Span account team or reach out to support@span.app.