# Trace sampling, quotas and node capacity

> Monthly quotas, rate limits, retention and the node disk budget; how to sample by trace without breaking traces that cross services.

Traces and logs grow with traffic, not with problems. This page shows the limits on the default plan, what happens when you reach them, and how to send less without losing the traces you need.

## Limits on the default plan

| Limit | Default | What happens at the limit |
|---|---|---|
| Traces per month, for the workspace | 5 GB | Further trace requests get `429` until the month resets |
| Logs per month, for the workspace | 5 GB | Further log requests get `429` until the month resets |
| Sending rate, per project and signal | 1 MiB/s, bursts to 8 MiB | `429` with `Retry-After`; exporters wait and retry |
| Retention | 7 days (adjustable up to 90) | Older data is deleted on your node |
| Time traces and logs may wait at the edge while your node is offline | 15 minutes | Older waiting data is dropped and counted as *Expired in the buffer*; a full buffer answers `503` |

Your plan may differ; **Project settings → Traces, logs and metrics received** shows the quota used, retention, what was accepted and what was dropped, by reason. Errors are not part of these numbers and wait at the edge much longer while a node is offline.

## Your node's disk

Traces and logs share at most 30 % of your node's disk, split between them (half each by default; owners and admins can change the split in the same card). When a signal outgrows its share, its oldest days are deleted early and the card shows how many days are really kept. When the node is under heavy load — 85 % of memory or disk — it stops taking traces and logs first; errors keep flowing.

## Sample traces, not requests at random

Head sampling decides at the start of a trace whether to keep it. Use the parent-based ratio sampler, so a service follows the decision of the service that called it and traces never arrive half-kept:

```bash
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1
```

`0.1` keeps one trace in ten. Set the same sampler in every service; only the first service's ratio decides, the others follow it. Errors are not affected — they are sent by your error SDK, not sampled by OpenTelemetry.

Logs are not sampled by the trace sampler: a log line written during an unsampled request is still sent, with its trace id, but that trace has no spans. To send fewer logs, raise your logger's level (for example to `warn` in production).

## Send less of what you do not read

- Turn off noisy instrumentations (file system, DNS, every Redis call) — each recipe shows the variable.
- Drop health checks and readiness probes; in the [Collector](https://belvador.dev/en/docs/otel/collector) a `filter` processor can do it for all services at once.
- Compress: `OTEL_EXPORTER_OTLP_COMPRESSION=gzip`. Quotas and the rate limit count bytes as received, so the same data uses less of both.
- Send metrics only where you read them (`OTEL_METRICS_EXPORTER=otlp` per service), once a minute. Their cost is the number of series, not the number of requests — keep unbounded values such as user ids off metric attributes ([limits](https://belvador.dev/en/docs/otel/metrics#limits-that-keep-cost-predictable)).
