Datadog CI Visibility: What It Actually Tracks
Most teams treat CI as a binary gate: green ships, red blocks. Datadog CI Visibility is built on the premise that the interesting signal lives in the time-series underneath that binary — duration trends, flake rates per branch, retry deltas, and the correlation between a slow test suite and a downstream deploy that quietly missed its SLO. If you've already instrumented your services with Datadog APM, CI Visibility extends that same trace model into your pipelines and test runs.
The technical problem is that CI telemetry is usually scattered: JUnit XML artifacts in S3, GitHub Actions logs behind a 90-day TTL, Slack alerts that no one correlates back to a specific commit. CI Visibility consolidates pipeline spans, test spans, and log context into a single queryable backend — but the data model has real constraints worth understanding before you commit to it.
By the end of this article you'll know exactly what CI Visibility ingests, how to instrument it for meaningful queries, and where the model breaks down so you can decide whether it fits your stack or whether you need a complementary layer.
Learn practical strategies for generating, managing, validating, and scaling reliable test data.
The Telemetry Model Behind CI Visibility
CI Visibility models your pipeline as a trace tree: a pipeline span at the root, stage spans as children, job spans beneath those, and — when you instrument your test runner — individual test spans at the leaf level. Each span carries the standard Datadog tag set plus CI-specific attributes: ci.pipeline.name, ci.job.name, git.commit.sha, git.branch, test.status, test.is_flaky, and test.is_retry. This is not a separate product bolted on; it's the same intake pipeline as APM, which means you can correlate a slow database migration test with a spike in real-user latency on the same commit — something no standalone test reporter can do natively.
Within the test span layer, CI Visibility distinguishes four statuses: pass, fail, skip, and error (runner-level crash vs. assertion failure). Flakiness detection is automatic when you enable DD_CIVISIBILITY_FLAKY_RETRY_ENABLED: the agent reruns failed tests up to N times, tags test.is_flaky: true when results are inconsistent, and surfaces a Known Flaky Tests list in the UI. That list feeds directly into the same kind of pattern recognition discussed in the three common flakiness patterns teams encounter at scale — environment-sensitive, timing-sensitive, and order-dependent failures all show distinct signatures in the span data.
Instrumenting CI Visibility for Actionable Queries
For GitHub Actions, the fastest path is the official datadog/agent-github-action combined with the DD_API_KEY secret. Add this to your workflow before your test step:
- name: Start Datadog Agent
uses: datadog/agent-github-action@v1.3
with:
api_key: ${{ secrets.DD_API_KEY }}
datadog_site: datadoghq.com
- name: Run Pytest with CI Visibility
env:
DD_CIVISIBILITY_AGENTLESS_ENABLED: "true"
DD_API_KEY: ${{ secrets.DD_API_KEY }}
DD_SERVICE: "payments-api"
DD_ENV: "ci"
run: |
pip install ddtrace pytest
ddtrace-run pytest tests/ \
--ddtrace \
--junit-xml=results.xml
The ddtrace-run wrapper intercepts pytest's internal hooks and emits spans directly; the JUnit XML is a fallback for artifact retention, not the primary ingestion path. For Playwright, swap in @datadog/datadog-ci and run datadog-ci junit upload post-suite — CI Visibility parses the XML and back-fills spans, though you lose the retry-level granularity you get from native instrumentation.
Once data flows, the real value is in the Test Runs Explorer query language. These are Datadog log-query syntax queries against the ci_test index:
# P95 duration by test name, last 7 days, failing tests only
@test.status:fail
@ci.pipeline.name:"payments-api"
| stats p95(@duration) by @test.full_name
| sort desc
| limit 20
# Flake rate by branch — useful for catching branch-specific environment drift
@test.is_flaky:true
@git.branch:main
| stats count() by @test.full_name, @git.branch
| sort count desc
Wiring these queries into a custom Datadog dashboard alongside your deploy frequency and MTTR metrics is where CI Visibility earns its keep beyond a pretty test report. One team running ~4,000 Selenium tests reduced triage time from 22 minutes per failure to under 5 once they pinned a timeseries widget to @test.full_name with a 14-day lookback — they could see immediately whether a failure was a regression or a recurring flake without opening a single log line. For teams managing multiple pipelines, this integrates naturally into multi-pipeline visibility workflows where leaders need cross-repo signal in one place.
Instrumentation Mistakes That Corrupt Your CI Visibility Data
The most common mistake is mixing agentless and agent-based ingestion in the same pipeline. When DD_CIVISIBILITY_AGENTLESS_ENABLED=true is set but a Datadog Agent is also running on the runner, spans are duplicated — you'll see inflated test counts and false flake detections. The fix is explicit: set agentless mode or configure the agent's apm_config.enabled: true with DD_TRACE_AGENT_URL pointing at the sidecar, never both. This happens because the GitHub Actions setup guide and the self-hosted runner guide were written independently and neither warns about the conflict.
The second mistake is not tagging DD_SERVICE consistently across repos. CI Visibility groups flake history and duration baselines by service name; if payments-api appears as payments_api, PaymentsAPI, and payments-service across three repos, your Known Flaky Tests list fragments and the automatic flakiness detection loses its historical window. Enforce service name conventions in a shared workflow template — GitHub Actions reusable workflows or Jenkins shared libraries are the right enforcement layer, not documentation. This is also the point where deferred flake fixes start accumulating invisible debt: inconsistent tagging hides the true quarantine rate per service.
What Teams Misread About CI Visibility's Flakiness Detection
Myth 1: test.is_flaky: true means the test is definitively flaky. It means the test produced inconsistent results within a single pipeline run's retry window. A test that fails deterministically on a cold runner but passes on a warm one will be tagged flaky — it's an environment issue, not test non-determinism. CI Visibility's flakiness score is a probability signal, not a verdict. Treat it as a triage starting point and cross-reference with failure sequencing to separate infrastructure noise from logic instability before quarantining anything.
Myth 2: CI Visibility replaces your test reporting layer. It doesn't. CI Visibility is optimized for time-series trend queries and pipeline-level correlation; it's not designed for deep per-run diffing, historical JUnit XML archival, or the kind of step-by-step failure drill-down that Allure or ReportPortal provide. Use CI Visibility when you need to answer "is this test getting slower over 30 days?" or "which tests fail most on feature branches?" Use Allure when your QA team needs annotated screenshots, step-level logs, and a shareable HTML report per run. They solve different problems and the overlap is smaller than the Datadog marketing page implies.
CI Visibility is a solid foundation for pipeline observability if you instrument it correctly and understand its data model. Start by enforcing consistent DD_SERVICE tagging across all repos, wire native instrumentation instead of relying on JUnit XML upload, and build your first dashboard query around P95 duration trends before you touch flakiness detection. The flake signal is only trustworthy once the span data is clean — get the plumbing right first.
Note: This article is for informational purposes only and is not a substitute for professional advice. If you need guidance on specific situations described in this article, consider consulting a qualified professional.