# DD_TRACE_SAMPLE_RATE in Node.js: A Practical Guide

> Set DD_TRACE_SAMPLE_RATE in Node.js, understand rate limits and sampling rules, and verify which distributed traces reach Datadog.

- Published: 2026-09-23T00:00:00.000Z
- Updated: 2026-09-23T00:00:00.000Z
- Author: Terry Osayawe
- Tags: nodejs, distributed-tracing, observability, datadog
- Canonical: https://tracekit.dev/blog/dd-trace-sample-rate-nodejs

`DD_TRACE_SAMPLE_RATE` sets a global trace ingestion rate for Datadog's Node.js tracer. Set it to a decimal from `0.0` to `1.0`. For example, `0.2` selects about 20% of eligible root traces before other limits apply. The exact count will vary with traffic.

A sampling change affects what you can investigate later. This guide explains the rate, its limit, and targeted rules. It also gives you a test that checks complete distributed traces, not only a lower trace count.

## What does `DD_TRACE_SAMPLE_RATE` control?

Datadog uses [head-based sampling](https://docs.datadoghq.com/tracing/trace_pipeline/ingestion_mechanisms/). It makes the keep or drop decision at the root of a trace. That decision travels with the request context to downstream services. The setting controls Datadog trace ingestion. It does not reduce your application's requests or fix a slow route.

```bash
# Keep about one in five eligible root traces.
DD_TRACE_SAMPLE_RATE=0.2 node --require dd-trace/init app.js
```

Load the tracer before your application modules. Otherwise, missing spans may look like a sampling problem. Use the [dd-trace initialization order guide](/blog/dd-trace-init-order-nodejs) if you need a CommonJS, ESM, or TypeScript startup pattern.

| Value | Expected selection before limits | Use during a test |
| --- | --- | --- |
| `1.0` | All eligible root traces | Confirm instrumentation and export work |
| `0.2` | About 20% of eligible root traces | Reduce routine trace volume after validation |
| `0.0` | No routine root traces from this rule | Test only when losing routine traces is acceptable |

These are probabilities, not promises for a short test. A single request can disappear at `0.2`. Send enough controlled requests to see the rate trend.

## Check the rate limit before you estimate volume

Datadog's [Node.js SDK configuration](https://docs.datadoghq.com/tracing/trace_collection/library_config/nodejs/) says `DD_TRACE_RATE_LIMIT` applies when `DD_TRACE_SAMPLE_RATE` or `DD_TRACE_SAMPLING_RULES` is set. Its documented default is `100` sampled traces per second. Datadog describes that limit **per service instance**, so replicas do not share one global allowance.

```bash
DD_TRACE_SAMPLE_RATE=0.2 \
DD_TRACE_RATE_LIMIT=50 \
node --require dd-trace/init app.js
```

A 20% rate and a limit of 50 do not mean exactly 50 traces arrive each second. Traffic, other sampling rules, and the limit all affect the result. Measure ingestion after a change instead of calculating cost from the rate alone.

## Use rules when one global rate hides an important route

A low global rate can make a rare path hard to inspect. `DD_TRACE_SAMPLING_RULES` lets you set a rate for matching traces. Datadog evaluates rules in order and uses the first match. Its [configuration reference](https://docs.datadoghq.com/tracing/trace_collection/library_config/nodejs/) lists service, operation name, resource, and tag matchers.

```bash
DD_TRACE_SAMPLING_RULES='[{"service":"checkout-api","resource":"POST /checkout","sample_rate":1.0},{"sample_rate":0.1}]' \
node --require dd-trace/init app.js
```

The first rule keeps eligible checkout traces. The second rule sets a fallback rate for other traces. Check the actual resource name in your tracer before you copy this example. A rule that does not match has no effect.

A rate limit can still reduce traces selected by a rule. Do not call a 100% rule a guarantee that every request reaches the backend. Also avoid keeping every high-volume route without measuring the resulting ingestion.

## Verify a sampling change with one complete request path

Use a staging service or a safe production test route. Start at `1.0` while you check coverage. Then set the planned rate and repeat with enough requests.

1. Confirm the process starts with `dd-trace` before Express, database, and HTTP client modules.
2. Make a request that calls a known downstream service.
3. Find its root server span and outbound client span in Datadog.
4. Confirm the downstream server span shares the same trace ID.
5. Check the service's SDK configuration and ingestion controls for the active settings.
6. Repeat after the sampling change. Compare ingested traces with request count over a useful window.

Datadog documents the [SDK Configuration tab](https://docs.datadoghq.com/tracing/trace_collection/library_config/nodejs/) for checking runtime settings. Its [Ingestion Controls](https://docs.datadoghq.com/tracing/trace_pipeline/ingestion_controls/) can help explain why spans were ingested. A trace that is absent from the UI is not proof of one cause. Check startup order, export errors, service names, route coverage, and sampling.

| Symptom | First check |
| --- | --- |
| No traces at `1.0` | Tracer startup, Agent connection, and request instrumentation |
| Root span appears without database spans | Database library instrumentation and initialization order |
| Client span appears without downstream server span | Downstream instrumentation and propagated context |
| Volume stays below the planned percentage | `DD_TRACE_RATE_LIMIT`, traffic mix, and matching rules |
| A rare error is missing | Whether head sampling dropped its root trace |

## Keep Datadog and OpenTelemetry settings distinct

`DD_TRACE_SAMPLE_RATE` is a Datadog tracer setting. A separate OpenTelemetry SDK uses its own sampler configuration. OpenTelemetry documents `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG`; `parentbased_traceidratio` with an argument such as `0.2` is one option. Check your actual SDK before you migrate a setting. Copying an environment variable does not prove that the new tracer uses the same sampling policy.

For a vendor-neutral setup, read the [OpenTelemetry sampler configuration](https://opentelemetry.io/docs/languages/sdk-configuration/general/) and [JavaScript sampling guide](https://opentelemetry.io/docs/languages/js/sampling/). Tracekit accepts OTLP traces and shows their connected spans in its [distributed tracing view](/features/distributed-tracing). If you use Tracekit's Node.js SDK, its [Node.js integration guide](/docs/languages/nodejs) documents a separate `sampleRate` option. Set and verify the policy in the SDK that actually creates your traces.

Sampling is a tradeoff. Keep enough complete traces to answer your incident questions. Then measure volume and adjust the rate and rules with real traffic.
