---
title: "Spans"
description: "Span creation, sampling, filtering, buffering, and wire format for the span-first tracing model."
url: https://develop.sentry.dev/sdk/telemetry/spans/
---

# Spans | Sentry Docs

This document uses key words such as "MUST", "SHOULD", and "MAY" as defined in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) to indicate requirement levels.

Statusstable[](https://develop.sentry.dev/sdk/getting-started/standards/spec-lifecycle.md "Learn about spec statuses")

Version`1.0.0`[(changelog)](https://develop.sentry.dev/sdk/telemetry/spans.md#changelog)

## [Overview](https://develop.sentry.dev/sdk/telemetry/spans.md#overview)

Spans are the primary telemetry type for Sentry's performance monitoring. A span measures the duration of an operation and carries attributes, links, and status information. This spec covers the span-first ("span streaming") model where spans are sent individually in batched envelopes rather than grouped into transaction events.

The APIs specified in this document **MUST** be implemented by all SDKs that don't use OpenTelemetry as their underlying tracing implementation. SDKs using OTel **SHOULD** follow their own already established span APIs but **MAY** orient themselves on this document if applicable.

Related specs:

* [Envelopes](https://develop.sentry.dev/sdk/foundations/envelopes.md) — transport format
* [Envelope Items](https://develop.sentry.dev/sdk/foundations/envelopes/envelope-items.md) — item headers and ingest settings
* [Trace Propagation](https://develop.sentry.dev/sdk/foundations/trace-propagation.md) — `sentry-trace` and `baggage` headers, dynamic sampling context
* [Scopes & Attributes](https://develop.sentry.dev/sdk/foundations/state-management/scopes/attributes.md) — scope-level attribute propagation
* [Span Data Conventions](https://develop.sentry.dev/sdk/telemetry/traces/span-data-conventions.md) — attribute naming conventions
* [Span Operations](https://develop.sentry.dev/sdk/telemetry/traces/span-operations.md) — operation naming conventions
* [Trace Origin](https://develop.sentry.dev/sdk/telemetry/traces/trace-origin.md) — origin naming scheme
* [Span Links](https://develop.sentry.dev/sdk/telemetry/traces/span-links.md) — linking spans across traces

***

## [Concepts](https://develop.sentry.dev/sdk/telemetry/spans.md#concepts)

**Span**: A timed operation with a name, attributes, status, and parent relationship. Spans form trees within a trace.

**Root Span**: The topmost span in a distributed span tree. It has no parent span. Groups its children with a representative name such as `GET /`.

**Segment Span**: The topmost span within a service boundary. Has a `parent_span_id` pointing to a remote span from the upstream service. A segment span on the originating service is also the root span of the entire tree.

**Noop Span**: A span implementing the full Span Interface that records no data and has no influence on the trace hierarchy. Returned when a span should not be recorded.

**Active Span**: A span attached to the current scope. Child spans started while an active span exists become its children.

**Span-First / Span Streaming**: The `traceLifecycle: 'stream'` mode where spans are captured individually via `captureSpan`, buffered, and sent in batched envelopes — as opposed to the legacy transaction model (`traceLifecycle: 'static'`).

SDKs **MUST NOT** expose names like "segment span" to users and **SHOULD NOT** expose "root span" if avoidable.

***

## [Behavior](https://develop.sentry.dev/sdk/telemetry/spans.md#behavior)

### [Trace Lifecycle Option](https://develop.sentry.dev/sdk/telemetry/spans.md#trace-lifecycle-option)

Stablespecified since 1.0.0

SDKs that support both transaction-based tracing and span streaming **MUST** expose a top-level `traceLifecycle` (or `trace_lifecycle`) init option controlling whether traces are sent as transactions or as spans (v2).

* Allowed values **MUST** be `'static'` and `'stream'`.
* When span-first is introduced in a minor version, the SDK **MUST** default to `'static'` (transaction-based) and span-first **MUST** be an opt-in feature.
* Span-first behavior **MUST** only apply when `traceLifecycle` is set to `'stream'`.
* This option can be removed once support for transactions is removed from the SDK.

### [Starting Spans](https://develop.sentry.dev/sdk/telemetry/spans.md#starting-spans)

Stablespecified since 1.0.0

SDKs **MUST** expose at least one API to start a span. SDKs **MAY** expose additional APIs or variants of `startSpan`, depending on the platform, language conventions, and requirements (e.g. decorators, annotations, or closure- or callback-based APIs).

* Spans **MUST** be started as active by default. Any span started while another span is active **MUST** become a child of the active span.
* If `active: false`, the span **MUST** be started as inactive — spans started while it is running **MUST NOT** become its children, but siblings.
* If a `Span` is passed via `parentSpan`, it **MUST** take precedence over the currently active span.
* If `null` is passed via `parentSpan`, the new span **MUST** be started as a segment span.
* SDKs **MUST NOT** end spans automatically from the default `startSpan` API. SDKs **MAY** provide additional APIs that auto-end spans (e.g. callback-based, context managers). Additional APIs **MAY** also adjust the span status based on errors thrown.
* `startSpan` **MUST** always return a span instance, even if the trace is negatively sampled. See [Noop Span](https://develop.sentry.dev/sdk/telemetry/spans.md#noop-span) for details.

The span-first API **MUST NOT** expose old transaction properties or concepts (e.g. `op`, `description`, `tags`).

SDKs **MUST NOT** expose APIs like `Span::startChild`. The `parentSpan` option serves this purpose.

```ts
function startSpan(options: StartSpanOptions): Span;

interface StartSpanOptions {
  name: string;
  attributes?: Record<string, SpanAttributeValue>;
  parentSpan?: Span | null;
  active?: boolean;
  links?: SpanLink[];
}
```

*Other available variations of the above snippet: Python*

| Option       | Required | Description                                                                                                                     |
| ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `name`       | Yes      | Span name. **MUST** be set by users.                                                                                            |
| `attributes` | No       | Initial attributes. See [Attributes at Span Start](https://develop.sentry.dev/sdk/telemetry/spans.md#attributes-at-span-start). |
| `parentSpan` | No       | Parent span. See [three-state behavior](https://develop.sentry.dev/sdk/telemetry/spans.md#parentspan-three-state-behavior).     |
| `active`     | No       | Whether the span should be active (default: `true`).                                                                            |
| `links`      | No       | Initial span links.                                                                                                             |

#### [`parentSpan` Three-State Behavior](https://develop.sentry.dev/sdk/telemetry/spans.md#parentspan-three-state-behavior)

The `parentSpan` parameter has three states: `undefined`, `null`, and a span instance.

For languages without an `undefined` state, SDKs **SHOULD** model this using platform-appropriate mechanisms that preserve the semantic distinction between `undefined` and `null`, such as:

* Method/constructor overloading (e.g. an overload without `parentSpan`, and another accepting `parentSpan: Span?`)
* A default sentinel value/object representing `undefined`
* Other idiomatic platform mechanisms (e.g. enum types)

If `parentSpan` references a span that has already ended, the SDK **SHOULD** still create the new span and send it as a child of `parentSpan`. Handling and presentation of these relationships is deferred to downstream processing and the UI.

#### [Attributes at Span Start](https://develop.sentry.dev/sdk/telemetry/spans.md#attributes-at-span-start)

Instrumentations **MUST** pass attributes whose values are already available at span start via the `attributes` option, rather than setting them afterward with `setAttribute` or `setAttributes`. This ensures these attributes are available when evaluating [`ignoreSpans`](https://develop.sentry.dev/sdk/telemetry/spans.md#ignorespans) and, where applicable, [`tracesSampler`](https://develop.sentry.dev/sdk/telemetry/spans.md#tracessampler).

Attributes whose values only become available later **MAY** be set after span start.

### [Setting Spans on Scope](https://develop.sentry.dev/sdk/telemetry/spans.md#setting-spans-on-scope)

Stablespecified since 1.0.0

It **MUST** be possible to attach a span to a scope. In SDKs implementing the three-scope model, the span **SHOULD** be set on the current scope.

When a span is attached to a scope, a reference to the previous span **MUST** be stored. The previous span **MUST** be re-attached when the currently active span ends.

If a span is started with `active: true`, it **MUST** be attached to the scope. If `active: false`, it **SHOULD NOT** be attached to the scope.

If a Noop span would be a segment (no currently active span, or `parentSpan: null`), it **MAY** be set on the scope so children inherit its negative sampling decision.

### [Noop Span](https://develop.sentry.dev/sdk/telemetry/spans.md#noop-span)

Stablespecified since 1.0.0

A Noop span implements the full [Span Interface](https://develop.sentry.dev/sdk/telemetry/spans.md#span-interface) but records no data and has no influence on the trace hierarchy.

`startSpan` **MUST** always return a valid `Span` instance. If a span should not be recorded, the SDK **MUST** return a Noop span instead. This allows callers to use the span without null checks.

`startSpan` **MUST** return a Noop span in the following scenarios:

* The span's trace is negatively sampled.
* The span matches an `ignoreSpans` pattern.

#### [Noop Span Behavior](https://develop.sentry.dev/sdk/telemetry/spans.md#noop-span-behavior)

* All mutating methods (`setAttribute`, `setAttributes`, `removeAttribute`, `setStatus`, `setName`, `addLink`, `addLinks`, `end`) **MUST** be no-ops — they **MUST NOT** record or store data.
* Getter methods (`getName`, `getAttributes`) **SHOULD** return empty/default values.
* A Noop span **MUST NOT** be sent to Sentry.
* If a Noop span is active, its dummy properties **MUST NOT** populate outgoing trace headers. Headers **MUST** be populated from the propagation context instead. Custom APIs like `getTraceparent` and `getBaggage` **MUST** also use the propagation context.
* A Noop span **MUST NOT** become the parent of another non-Noop span. Spans that would otherwise be its children **MUST** use the Noop span's nearest non-Noop ancestor as their parent. If there is no such ancestor (the Noop span is a segment), those spans **MUST** also be Noop spans, inheriting its sampling or filtering decision.

#### [Default Property Values](https://develop.sentry.dev/sdk/telemetry/spans.md#default-property-values)

For platforms with non-nullable span properties:

| Property     | Default Value                                                         |
| ------------ | --------------------------------------------------------------------- |
| `traceId`    | `00000000000000000000000000000000` or random uuid (32 zero hex chars) |
| `spanId`     | `0000000000000000` or random uuid (16 zero hex chars)                 |
| `name`       | Empty string `""`                                                     |
| `attributes` | Empty map `{}`                                                        |
| `links`      | Empty array `[]`                                                      |
| `status`     | `ok`                                                                  |

SDKs **SHOULD** use these default values even on platforms that support nullable types, so callers don't need null checks. In particular, `name`, `attributes`, `links`, and `status` **SHOULD NOT** be nullable.

### [Sampling](https://develop.sentry.dev/sdk/telemetry/spans.md#sampling)

Stablespecified since 1.0.0

Sampling **MUST** only apply to segment spans. The APIs **MUST** be optimized for trace completeness and conclusive sampling decisions. SDKs **MUST** follow the [sampling decision hierarchy](https://develop.sentry.dev/sdk/telemetry/traces.md#sampling).

#### [`tracesSampleRate`](https://develop.sentry.dev/sdk/telemetry/spans.md#tracessamplerate)

The SDK **MUST** default `tracesSampleRate` to `null`. When users set `tracesSampleRate` to a value in `[0.0, 1.0]` and starting a segment span, the `tracesSampleRate` is compared against a random number in `[0.0, 1.0)`.

#### [`tracesSampler`](https://develop.sentry.dev/sdk/telemetry/spans.md#tracessampler)

If configured, `tracesSampler` **MUST** replace `tracesSampleRate`. The callback **MUST** receive sufficient arguments for users to define custom rules (e.g. span attributes, HTTP headers). The return value **MUST** be a float in `[0.0, 1.0]`.

If no `tracesSampler` is configured, a propagated sampling decision via the traceparent takes precedence over `tracesSampleRate`. Defining a `tracesSampler` **MAY** disable this behavior.

### [Filtering](https://develop.sentry.dev/sdk/telemetry/spans.md#filtering)

Stablespecified since 1.0.0

The SDK **MUST** implement a mechanism for users to filter spans. The result **MUST** be binary (`true` or `false`). Any filtering APIs **MUST** be optimized for trace completeness and conclusive sampling decisions.

#### [`ignoreSpans`](https://develop.sentry.dev/sdk/telemetry/spans.md#ignorespans)

The `ignoreSpans` option **MUST** accept a string and either RegExp or glob pattern (whichever the platform supports) matched against the span name.

Furthermore, `ignoreSpans` **SHOULD** accept objects with patterns matching the span name and/or span attributes:

```ts
type IgnoreSpanNamePattern = string | RegExp | GlobPattern;

type AttributeValueTypes = string | boolean | number | Array<string> | Array<boolean> | Array<number>;
type EnhancedAttributeValueTypes = AttributeValueTypes | RegExp | GlobPattern | Array<RegExp | GlobPattern>;

type IgnoreSpanFilter = {
  name: IgnoreSpanNamePattern;
  attributes?: Record<string, EnhancedAttributeValueTypes>;
} | {
  name?: IgnoreSpanNamePattern;
  attributes?: Record<string, EnhancedAttributeValueTypes>;
}

type IgnoreSpans = Array<IgnoreSpanNamePattern | IgnoreSpanFilter>
```

(`GlobPattern` is used as an illustrative type for platforms that support matching glob patterns. It is not a valid TypeScript type.)

If an SDK accepts `IgnoreSpanFilter` objects, string attribute values **MUST** be matched the same way as span names (contains for strings, match for patterns). Other attribute value types **MUST** strictly equal the provided value. This includes attributes whose values are arrays.

#### [Filter with `integrations`](https://develop.sentry.dev/sdk/telemetry/spans.md#filter-with-integrations)

The `integrations` option **MAY** perform in similar fashion as the `ignoreSpans` option, or make explicit opt-out possible via a boolean flag.

```js
Sentry.init({
  integrations: [
    Sentry.fsIntegration({
      ignoreSpans: ['fs.read'],
      readSpans: true,
      writeSpans: false,
    }),
  ],
});
```

#### [Other Approaches](https://develop.sentry.dev/sdk/telemetry/spans.md#other-approaches)

If both options mentioned above are not feasible to be implemented in certain SDKs, other approaches **MUST** be explored that have the same outcome.

#### [Implementation Requirements](https://develop.sentry.dev/sdk/telemetry/spans.md#implementation-requirements)

1. `ignoreSpans` patterns **MUST** be evaluated **before** the span is started.

2. Patterns **MUST** apply to all spans, including segment spans.

   * If a pattern matches a segment span, the span and all its children **MUST** be ignored.
   * If a pattern matches a child span, the child **MUST** be ignored but its children **MUST** be attempted to be reparented to the ignored span's parent.

3. If a span is ignored, the SDK **MUST** record a client report with the `ignored` discard reason and `span` category.

   * For each ignored child span, emit one outcome per span.
   * For each ignored segment span, emit one outcome for the segment and one per child span.

### [Data Scrubbing](https://develop.sentry.dev/sdk/telemetry/spans.md#data-scrubbing)

Stablespecified since 1.0.0

#### [`beforeSendSpan`](https://develop.sentry.dev/sdk/telemetry/spans.md#beforesendspan)

The `beforeSendSpan` callback **MUST NOT** allow removal of spans from the span tree. It receives a deep copy of a span:

```bash
{
  'name': 'GET /',
  'attributes': {
    'http.request.method': 'GET',
    'http.response.status_code': 200,
  }
}
```

Users **MAY** mutate any exposed properties to perform sanitization on sensitive data or PII. The return value **MUST** be merged with the original span prior to emission.

### [Trace Propagation](https://develop.sentry.dev/sdk/telemetry/spans.md#trace-propagation)

Stablespecified since 1.0.0

#### [Continue an Incoming Trace](https://develop.sentry.dev/sdk/telemetry/spans.md#continue-an-incoming-trace)

The SDK **MUST** expose a method to extract traceparent and baggage from incoming headers and apply them to the applicable scope. The method **MUST NOT** create a new segment span on its own. Newly created root spans **SHOULD** contain the extracted properties, such as `trace_id` and `parent_span_id`.

The function signature **MAY** require explicitly passing `sentry-trace` and `baggage`, or **MAY** accept a dictionary of headers or environment variables.

#### [Propagate an Outgoing Trace](https://develop.sentry.dev/sdk/telemetry/spans.md#propagate-an-outgoing-trace)

The SDK **MUST** expose methods to fetch the required information (traceparent, baggage) for downstream services to continue the trace.

#### [Start a New Trace](https://develop.sentry.dev/sdk/telemetry/spans.md#start-a-new-trace)

The SDK **MUST** offer a method to clear trace propagation data, allowing spans to be created with a fresh new trace.

### [Single-Span Processing Pipeline](https://develop.sentry.dev/sdk/telemetry/spans.md#single-span-processing-pipeline)

Stablespecified since 1.0.0

SDKs **MUST** implement a `captureSpan` API that takes a single span once it ends, processes it, and enqueues it into the span buffer. This **SHOULD** be a method on the `Client`. SDKs (e.g. JS Browser) **MAY** choose a different location if necessary.

Processing order:

1. Accept any span that has ended (has an `end_timestamp`).
2. Obtain current, isolation, and global scopes; merge scope data.
3. Apply [common span attributes](https://develop.sentry.dev/sdk/telemetry/spans.md#common-attribute-keys) from client and merged scope data to every span.
4. Apply scope attributes to every span.
5. Apply `contexts` and `request` data from merged scopes to the **segment span only**.
6. Apply span processing hooks (event processor [replacements](https://develop.sentry.dev/sdk/telemetry/spans.md#replacing-event-processors)).
7. Apply `beforeSendSpan`.
8. Enqueue the span into the span buffer.

The `captureSpan` pipeline **MUST NOT**:

* Drop any span
* Buffer spans before enqueuing
* Modify span relationships

#### [Span Filtering in the Pipeline](https://develop.sentry.dev/sdk/telemetry/spans.md#span-filtering-in-the-pipeline)

`ignoreSpans` is applied prior to span start, so `captureSpan` does not handle filtering. This means certain cases cannot be handled by the pipeline:

* Filtering spans based on data that is unknown prior to child span start.
* Filtering entire segments based on data that is unknown prior to segment start (e.g. `http.server` segments ending in a 404 response).

#### [Replacing Event Processors](https://develop.sentry.dev/sdk/telemetry/spans.md#replacing-event-processors)

Streamed spans are no longer events (as opposed to transactions), so they don't go through SDK event processors, which are used extensively by SDK clients, integrations, and users. For user-facing migration, `ignoreSpans` covers filtering and `beforeSendSpan` covers data enrichment and scrubbing.

For SDK-internal processing, SDKs are free to implement further processing mechanisms. It's strongly recommended to implement client [lifecycle hooks](https://github.com/getsentry/rfcs/blob/main/text/0034-sdk-lifecycle-hooks.md). SDKs with alternative established processing patterns **MAY** use those instead. The `captureSpan` pipeline emits a `process_span` message that any consumer (e.g. an integration) can subscribe to and apply its logic, similar to how it previously used event processors:

```js
// in captureSpan:
processed_span = client.emit("process_span", captured_span)

// Somewhere in e.g. an integration:
client.on("process_span", (span) => {
   span.attributes["sentry.origin"] = "auto.http.server"
})
```

With a few exceptions, event processors for transactions do two things:

1. Add and modify transaction and child span data.
2. Drop transaction events or remove child spans.

##### [Replacing Mutating Event Processors](https://develop.sentry.dev/sdk/telemetry/spans.md#replacing-mutating-event-processors)

Replace the mutation logic with span processing hooks. SDK-internally, configure the integration or call site that registers an event processor to also register a hook (e.g. a client lifecycle hook) that processes the span:

```js
// someIntegration:

client.addEventProcessor(event => {
   event.transaction = parameterizedRouteName;
   event.context.trace.data["http.route"] = parameterizedRouteName;
   event.spans.foreach(s => {s.data["http.route"] = parameterizedRouteName});
})

// for span streaming, add:
client.on("process_span", (span) => {
   if (span.is_segment) {
      span.name = parameterizedRouteName;
   }
   span.attributes["http.route"] = parameterizedRouteName;
})
```

##### [Replacing Filtering Event Processors](https://develop.sentry.dev/sdk/telemetry/spans.md#replacing-filtering-event-processors)

Ideally, replace retroactive filtering in event processors by configuring the integration to not emit these spans upfront. This should be the first approach when implementing span streaming.

If this doesn't apply to the use case, pre-configure the SDK's `ignoreSpans` option and leverage the existing span filtering logic to drop segments or child spans **upfront**:

```js
// someIntegration:

client.addEventProcessor(event => {
   if (event.type === "transaction" && event.transaction === "unknown") {
      return null;
   }
   return event;
})

// for span streaming, add:
client.options.ignore_spans = [
   ...client.options.ignore_spans,
   /^unknown$/
];
```

If the SDK also implements `ignoreSpans` for transactions, this *might* allow removing the event processor entirely.

#### [Known Limitations](https://develop.sentry.dev/sdk/telemetry/spans.md#known-limitations)

The following use cases cannot be directly replaced with span streaming:

* Filtering spans based on data added after span start (e.g. a span attribute that only gets added to the span after it was started).
* Filtering entire segments based on data unknown at segment start (e.g. `http.server` segments ending in a 404 response).
* Mutating or making decisions on multiple spans at once (e.g. calculating and setting the total token usage on parent spans of `gen_ai` spans). There's no guarantee that all spans are seen in time to safely aggregate their data. Previously, this was trivial by iterating over `event.spans`. Now, it would require a guarantee that child spans finish before their parent span, which often doesn't exist.
* Scoped event processors — currently not supported; can be re-evaluated if a use case arises that can't be solved with client-wide processing hooks.

These limitations reflect the current span streaming strategy and might be reconsidered based on feedback and demand.

Spans no longer going through event processors is a behavior-breaking change. For users, `ignoreSpans` and `beforeSendSpan` are the way forward. Internally, SDKs **MAY** use further processing mechanisms.

### [Span Buffer](https://develop.sentry.dev/sdk/telemetry/spans.md#span-buffer)

Stablespecified since 1.0.0

The span buffer batches spans, constructs envelopes, and forwards them to the transport. Spans are captured via `captureSpan` and enqueued into the span buffer instead of being sent as transaction events.

These requirements intentionally specify less than the [Telemetry Processor](https://develop.sentry.dev/sdk/foundations/processing/telemetry-processor.md). SDKs **MAY** implement and extend the span buffer with platform-specific behavior, as long as the core requirements are met.

1. The buffer **MUST** bucket spans by trace ID. When flushing, the buffer **MUST** create distinct envelopes for each trace ID.

2. The buffer **MUST NOT** add more than 1000 spans per envelope. If more than 1000 spans are held for a trace, the buffer **MUST** batch into multiple envelopes.

3. When the buffer drops spans, it **MUST** record a client report with the exact number of spans dropped.

4. The buffer **MAY** ignore priority-based scheduling with other telemetry categories.

5. The buffer **MUST** implement the following flushing behavior:

   * Flush on a regular interval, every 5 seconds (SDKs **MAY** adjust based on platform needs).
   * Flush a trace bucket when its segment span is finished.
   * Flush a trace bucket when it reaches the 1000 spans limit.
   * Flush when a trace bucket reaches 5MB (SDKs **MAY** adjust, but **MUST NOT** exceed 10MB).
   * Flush when `Sentry.flush()` is called.
   * Flush and stop on `Sentry.close()`. The buffer **MUST** stop accepting new spans to prevent unbounded memory use.

#### [Buckets per Trace ID](https://develop.sentry.dev/sdk/telemetry/spans.md#buckets-per-trace-id)

A recommended design is a map of **trace ID → list of spans**. SDKs **MAY** use other structures (e.g. a fixed ring buffer) as long as the requirements above are met.

```bash
spanBuffer = {
  "trace-a": [span1, span2, span3],
  "trace-b": [span4],
  "trace-c": [span5, span6]
}
```

When the span buffer adds a span, it **MUST** add it to the bucket for that span's trace ID. When no bucket exists, it **MUST** create one. After forwarding spans from a bucket, it **MUST** remove all spans and delete the bucket.

#### [Serialization and Dynamic Sampling Context](https://develop.sentry.dev/sdk/telemetry/spans.md#serialization-and-dynamic-sampling-context)

SDKs **SHOULD** materialize and freeze the DSC as late as possible:

* The buffer **SHOULD** enqueue spans but only create the final envelope at **flush time**.
* At flush time, the buffer **SHOULD** materialize and freeze the DSC on the segment span if not already done. That way, the `trace` envelope header (e.g. the transaction name in the DSC) reflects the latest data.

### [Span Links](https://develop.sentry.dev/sdk/telemetry/spans.md#span-links)

Stablespecified since 1.0.0

Links connect spans to other spans or traces, enabling cross-trace relationships.

* Links **MUST** only link to other spans (not errors or other event types).
* SDKs supporting span links **MUST** expose `addLink` and `addLinks` on the Span interface.
* SDKs supporting span links **SHOULD** allow specifying `links` in `startSpan` options.
* If the `links` array is empty, it **MAY** be omitted from the envelope.

See [Span Links](https://develop.sentry.dev/sdk/telemetry/traces/span-links.md#link-types) for predefined link types such as `previous_trace`.

### [Span Attachments](https://develop.sentry.dev/sdk/telemetry/spans.md#span-attachments)

Candidatespecified since 1.0.0

Span attachments are an experimental feature that is still under development.

To associate an attachment with a span, submit a [trace attachment](https://develop.sentry.dev/sdk/telemetry/attachments.md#trace-attachments) item with an additional `span_id` item header. The trace attachment **MUST** be submitted in the same envelope as the span itself.

* `span_id` identifies the owning span. Relay treats `span_id` as the owner of the attachment: the attachment is dropped with the span if the span is dropped by dynamic sampling, inbound filters, or rate limits.
* The SDK **MAY** set `span_id` to explicit `null`, meaning "owned by spans" but not by a specific one — the attachment can be dropped if span quota is exceeded, but it will not be dropped with a specific span because of, for example, inbound filters.

### [Attribute Conventions](https://develop.sentry.dev/sdk/telemetry/spans.md#attribute-conventions)

Stablespecified since 1.0.0

Attributes outside the [common attribute keys](https://develop.sentry.dev/sdk/telemetry/spans.md#common-attribute-keys) list **MUST** only be attached to the span they conceptually belong on, and **MUST NOT** be propagated to children. Attributes mirroring transaction context data **SHOULD** only be set on the segment span.

All attributes set on a streamed span **MUST** use keys defined in [Sentry Conventions](https://getsentry.github.io/sentry-conventions/) before introduction in an SDK.

Empty attributes **MUST** be omitted.

Guidelines for specific attributes:

* `http.request.body.data`: Attach on a best-effort basis, as long as it can be done without side effects like exhausting the body before the user/app can read it. Decide per SDK/integration whether this is feasible.

#### [HTTP Headers](https://develop.sentry.dev/sdk/telemetry/spans.md#http-headers)

HTTP headers **MUST** be emitted following the [`http.request.header.<key>`](https://getsentry.github.io/sentry-conventions/attributes/http/#http-request-header-key) and [`http.response.header.<key>`](https://getsentry.github.io/sentry-conventions/attributes/http/#http-response-header-key) conventions:

* `<key>` **MUST** be the lowercased, but otherwise unchanged, header name.
* The value **MUST** be a string array, even if the header has a single value. Multiple values for the same header **MUST** be emitted as separate array elements.
* Request and response headers **MUST** be collected according to the [`httpHeaders`](https://develop.sentry.dev/sdk/foundations/client/data-collection.md#http-header-collection) option. If collection is disabled for a direction, those headers **MUST** be omitted. Values of headers matching the [sensitive denylist](https://develop.sentry.dev/sdk/foundations/client/data-collection.md#sensitive-denylist) **MUST** be replaced with `"[Filtered]"` while the key is kept. The sensitive denylist applies in every collection mode, including when collection is fully enabled.

#### [Cookies](https://develop.sentry.dev/sdk/telemetry/spans.md#cookies)

`Cookie` and `Set-Cookie` headers **MUST** be collected according to the [`cookies`](https://develop.sentry.dev/sdk/foundations/client/data-collection.md#cookies-and-url-query-params) option instead of `httpHeaders`. They are emitted as `http.request.header.cookie` and `http.<request|response>.header.set-cookie`. If cookie collection is disabled, these attributes **MUST** be omitted, even if header collection is enabled.

The header value **MUST** be parsed into individual cookies:

* A `Cookie` header **MUST** be split on `;`. For a `Set-Cookie` header, only the part before the first `;` **MUST** be used, so cookie attributes like `HttpOnly` or `Path` are dropped. Each `Set-Cookie` header value holds one cookie.
* Name and value **MUST** be split on the first `=` only (`jwt=eyJhbGc=` has the value `eyJhbGc=`). Both **MUST** be trimmed.
* Empty segments and segments consisting only of `=` **MUST** be skipped.
* A segment without `=` is a nameless cookie whose whole segment is the value.

Each cookie **MUST** be emitted as its own `name=value` array element, in header order:

* Values **MUST NOT** be decoded or unquoted.
* If the cookie name matches the sensitive denylist, the value **MUST** be replaced: `name=[Filtered]`. SDKs **SHOULD** also match cookie names against additional cookie-specific terms for session and auth cookies whose names don't match the denylist, such as `.sid`, `sessid`, `remember`, `oidc`, `pkce`, `nonce`, `__secure-`, `__host-`, `mfa`, and `2fa`.
* A nameless cookie **MUST** be emitted as `[Filtered]`, since no name-based denylist can match it.
* If the header yields no cookies, the value **MUST** be `["[Filtered]"]`, since the header may still hold a token.

If the framework already provides parsed cookies, SDKs **SHOULD** use those pairs instead of serializing and re-parsing them. A decoded value can contain `;` and would otherwise split into a second, differently named cookie that escapes the denylist.

```json
{
  "http.request.header.accept": {
    "type": "array",
    "value": ["application/json"]
  },
  "http.request.header.authorization": {
    "type": "array",
    "value": ["[Filtered]"]
  },
  "http.request.header.cookie": {
    "type": "array",
    "value": [
      "user_session=[Filtered]",
      "connect.sid=[Filtered]",
      "theme=dark-mode"
    ]
  },
  "http.response.header.set-cookie": {
    "type": "array",
    "value": ["theme=light-mode"]
  }
}
```

***

## [Wire Format](https://develop.sentry.dev/sdk/telemetry/spans.md#wire-format)

### [Span v2 Envelope Header](https://develop.sentry.dev/sdk/telemetry/spans.md#span-v2-envelope-header)

The envelope header **MUST** contain the same properties as previously with transactions. There are no special requirements beyond those for standard envelopes.

```json
{
  "sent_at": "2025-02-07T14:16:00Z",
  "dsn": "https://e12d836b15bb49d7bbf99e64295d995b@sentry.io/42",
  "sdk": {
    // ...
  },
  "trace": {
    // ...
  }
}
```

Unlike transactions, envelope headers for spans **REQUIRE** [Dynamic Sampling Context](https://develop.sentry.dev/sdk/foundations/trace-propagation/dynamic-sampling-context.md). See also [Envelope Headers](https://develop.sentry.dev/sdk/foundations/envelopes.md#headers).

### [Span v2 Envelope Item Header](https://develop.sentry.dev/sdk/telemetry/spans.md#span-v2-envelope-item-header)

| Property       | Type    | Required | Description                                               |
| -------------- | ------- | -------- | --------------------------------------------------------- |
| `type`         | string  | Yes      | **MUST** be `"span"`                                      |
| `item_count`   | integer | Yes      | Number of span items in the payload                       |
| `content_type` | string  | Yes      | **MUST** be `"application/vnd.sentry.items.span.v2+json"` |

### [Span v2 Envelope Item Payload](https://develop.sentry.dev/sdk/telemetry/spans.md#span-v2-envelope-item-payload)

The payload is a JSON object that **MUST** include an `items` array of span objects.

The `items` array **MUST** contain at least one and at most 1000 span objects. An envelope **MUST** only contain spans from one trace, as the trace envelope header is shared.

#### [`version` and `ingest_settings` Properties](https://develop.sentry.dev/sdk/telemetry/spans.md#version-and-ingest_settings-properties)

Candidatespecified since 1.0.0

The payload **SHOULD** include top-level `version` and `ingest_settings` fields to instruct Relay to infer IP address and user agent from the incoming request:

```json
{
  "version": 2,
  "ingest_settings": {
    "infer_ip": "auto",
    "infer_user_agent": "auto"
  },
  "items": [{..span..}, {..span..}]
}
```

See the [Ingest Settings](https://develop.sentry.dev/sdk/foundations/envelopes/envelope-items.md#ingest-settings) spec for the full `ingest_settings` field reference.

### [Span Properties](https://develop.sentry.dev/sdk/telemetry/spans.md#span-properties)

| Property          | Type    | Required | Description                                                              |
| ----------------- | ------- | -------- | ------------------------------------------------------------------------ |
| `trace_id`        | string  | Yes      | 32-character lowercase hexadecimal string (a valid uuid4 without dashes) |
| `span_id`         | string  | Yes      | 16-character lowercase hexadecimal string (a valid uuid4 without dashes) |
| `parent_span_id`  | string  | No       | 16-character lowercase hexadecimal string (a valid uuid4 without dashes) |
| `name`            | string  | Yes      | Low-cardinality description (e.g. `"GET /users"`)                        |
| `status`          | string  | Yes      | Either `"ok"` or `"error"`                                               |
| `is_segment`      | boolean | Yes      | Whether the span is a segment span                                       |
| `start_timestamp` | number  | Yes      | Unix timestamp with fractional microseconds                              |
| `end_timestamp`   | number  | Yes      | Unix timestamp with fractional microseconds                              |
| `attributes`      | object  | No       | Key-value pairs of additional metadata                                   |
| `links`           | array   | No       | Array of link objects connecting to other spans                          |

### [Common Attribute Keys](https://develop.sentry.dev/sdk/telemetry/spans.md#common-attribute-keys)

**Strictly Required** and **Required** attributes **MUST** be attached to every span emitted from the SDK. **Conditional** attributes **MUST** be attached to every span when their condition is met.

| Attribute Key                | Type    | Required          | Description                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ---------------------------- | ------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sentry.segment.name`        | string  | Strictly Required | Segment name (e.g. `"GET /users"`)                                                                                                                                                                                                                                                                                                                                                                                                                |
| `sentry.segment.id`          | string  | Strictly Required | Segment span ID                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `sentry.trace_lifecycle`     | string  | Required          | The trace lifecycle mode. **MUST** be set to `"stream"`.                                                                                                                                                                                                                                                                                                                                                                                          |
| `sentry.sdk.name`            | string  | Required          | Sentry SDK name                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `sentry.sdk.version`         | string  | Required          | Sentry SDK version                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `sentry.origin`              | string  | Required          | [Trace origin](https://develop.sentry.dev/sdk/telemetry/traces/trace-origin.md)                                                                                                                                                                                                                                                                                                                                                                   |
| `sentry.platform`            | string  | Required          | Platform identifier                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `user_agent.original`        | string  | Required          | Full, unmodified user agent string of the client that made the request, e.g. the `User-Agent` header of an incoming request to a web backend (e.g. `"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ..."`)                                                                                                                                                                                                                                       |
| `sentry.op`                  | string  | Conditional       | The [span op](https://develop.sentry.dev/sdk/telemetry/traces/span-operations.md) (e.g. `"http.client"`, `"db.query"`). **MUST** be set on spans from auto instrumentation, **MAY** be set by manually started spans.                                                                                                                                                                                                                             |
| `sentry.segment.name.source` | string  | Conditional       | Source of the segment name. **MUST** be set on segment spans, and **MUST NOT** be set on any other span. See [Sentry Conventions](https://github.com/getsentry/sentry-conventions/blob/main/model/attributes/sentry/sentry__segment__name__source.json) for all supported sources and [Transaction Annotations](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/transaction.md#transaction-annotations) for more information. |
| `sentry.release`             | string  | Conditional       | Application release version. Set if the SDK has a `release` value set or auto-detected.                                                                                                                                                                                                                                                                                                                                                           |
| `sentry.environment`         | string  | Conditional       | Environment name (e.g. `"production"`, `"staging"`). Set if the SDK has an `environment` value set or uses a default.                                                                                                                                                                                                                                                                                                                             |
| `sentry.is_localhost`        | boolean | Conditional       | Whether the SDK determined the application is running on localhost. Used to enable the localhost inbound filter. The definition of "localhost" is platform-specific. Set by browser and backend SDKs.                                                                                                                                                                                                                                             |
| `sentry.profiler_id`         | string  | Conditional       | ID of the running continuous profiler. Set while a continuous profiling session is running. **MUST NOT** be set otherwise.                                                                                                                                                                                                                                                                                                                        |
| `sentry.replay_id`           | string  | Conditional       | ID of the active replay. Set while a replay is active. **MUST NOT** be set otherwise.                                                                                                                                                                                                                                                                                                                                                             |
| `os.name`                    | string  | Conditional       | Operating system name. Set if available on the platform.                                                                                                                                                                                                                                                                                                                                                                                          |
| `browser.name`               | string  | Conditional       | Browser name. Set by browser SDKs if available.                                                                                                                                                                                                                                                                                                                                                                                                   |
| `user.id`                    | string  | Conditional       | User ID. Set if user data is available (see below).                                                                                                                                                                                                                                                                                                                                                                                               |
| `user.email`                 | string  | Conditional       | User email. Set if user data is available (see below).                                                                                                                                                                                                                                                                                                                                                                                            |
| `user.ip_address`            | string  | Conditional       | User IP address. Set if user data is available (see below).                                                                                                                                                                                                                                                                                                                                                                                       |
| `user.name`                  | string  | Conditional       | User username. Set if user data is available (see below).                                                                                                                                                                                                                                                                                                                                                                                         |
| `thread.id`                  | integer | Conditional       | Thread ID. Set on platforms that expose thread information.                                                                                                                                                                                                                                                                                                                                                                                       |
| `thread.name`                | string  | Conditional       | Thread name. Set on platforms that expose thread information.                                                                                                                                                                                                                                                                                                                                                                                     |

Spans missing **Strictly Required** attributes **MAY** be rejected by Relay.

User attributes (`user.*`) **MUST** respect the [`userInfo`](https://develop.sentry.dev/sdk/foundations/client/data-collection.md#datacollection-options) option. User data populated automatically by the SDK **MUST NOT** be attached if `userInfo` is disabled. User data set explicitly by the user (e.g. via `setUser`) **MUST** be attached regardless of `userInfo`.

Empty attributes **MUST** be omitted.

See [Sentry Conventions](https://github.com/getsentry/sentry-conventions/) for a full list of supported attributes.

### [Attribute Value Format](https://develop.sentry.dev/sdk/telemetry/spans.md#attribute-value-format)

Each attribute value is an object with `type`, `value`, and optional `unit`:

```json
{
  "sentry.release": {
    "type": "string",
    "value": "1.0.0"
  },
  "http.response.status_code": {
    "type": "integer",
    "value": 200
  },
  "session.duration": {
    "type": "integer",
    "value": 164,
    "unit": "second"
  }
}
```

### [Link Object Properties](https://develop.sentry.dev/sdk/telemetry/spans.md#link-object-properties)

| Property     | Type    | Required | Description                                                    |
| ------------ | ------- | -------- | -------------------------------------------------------------- |
| `span_id`    | string  | Yes      | 16-character hexadecimal string (a valid uuid4 without dashes) |
| `trace_id`   | string  | Yes      | 32-character hexadecimal string (a valid uuid4 without dashes) |
| `sampled`    | boolean | No       | Whether the linked trace was sampled                           |
| `attributes` | object  | No       | Metadata about the link relationship                           |

### [Data Types and Formats](https://develop.sentry.dev/sdk/telemetry/spans.md#data-types-and-formats)

**Timestamps** use Unix time with fractional microseconds: `1742921669.158209`

**Trace ID**: 32-character (128-bit) lowercase hexadecimal string (a valid uuid4 without dashes).

**Span ID**: 16-character (64-bit) lowercase hexadecimal string (a valid uuid4 without dashes).

***

## [Public API](https://develop.sentry.dev/sdk/telemetry/spans.md#public-api)

### [Span Interface](https://develop.sentry.dev/sdk/telemetry/spans.md#span-interface)

SDKs **MUST** implement the following interface at minimum:

| Method            | Parameters                                            | Returns | Description                           |
| ----------------- | ----------------------------------------------------- | ------- | ------------------------------------- |
| `end`             | `endTimestamp?: SpanTimeInput`                        | void    | Ends the span. Records end timestamp. |
| `setAttribute`    | `key: string, value: SpanAttributeValue \| undefined` | this    | Sets a single attribute.              |
| `setAttributes`   | `attributes: SpanAttributes`                          | this    | Sets multiple attributes.             |
| `removeAttribute` | `key: string`                                         | this    | Removes an attribute.                 |
| `setStatus`       | `status: 'ok' \| 'error'`                             | this    | Sets the span status.                 |
| `setName`         | `name: string`                                        | this    | Sets the span name.                   |
| `addLink`         | `link: SpanLink`                                      | this    | Adds a single link.                   |
| `addLinks`        | `links: SpanLink[]`                                   | this    | Adds multiple links.                  |
| `getName`         | —                                                     | string  | Returns the span name.                |
| `getAttributes`   | —                                                     | Record  | Returns all attributes.               |

```ts
interface Span {
  private _spanId: string;

  end(endTimestamp?: SpanTimeInput): void;

  setAttribute(key: string, value: SpanAttributeValue | undefined): this;
  setAttributes(attributes: SpanAttributes): this;
  removeAttribute(key: string): this;

  setStatus(status: 'ok' | 'error'): this;

  setName(name: string): this;

  addLink(link: SpanLink): this;
  addLinks(links: SpanLink[]): this;

  getName(): string;
  getAttributes(): Record<string, SpanAttributeValue>
}
```

*Other available variations of the above snippet: Python*

SDKs **MAY** implement additional methods (e.g. `getStatus()`, `spanContext()`).

SDK implementers **SHOULD** disallow direct mutation of span properties without setters. SDK implementers **MAY** disallow direct read access.

### [`startSpan` Options](https://develop.sentry.dev/sdk/telemetry/spans.md#startspan-options)

See [Starting Spans](https://develop.sentry.dev/sdk/telemetry/spans.md#starting-spans) for the `startSpan` signature, options, and behavior.

### [Trace Propagation APIs](https://develop.sentry.dev/sdk/telemetry/spans.md#trace-propagation-apis)

| API                                              | Description                                                                  |
| ------------------------------------------------ | ---------------------------------------------------------------------------- |
| `continueTrace`                                  | Extracts traceparent and baggage from incoming headers and applies to scope. |
| `getTraceData` / `getTraceparent` + `getBaggage` | Returns trace data for outgoing requests.                                    |
| `startNewTrace` / `new_trace`                    | Clears propagation data, starts a fresh trace.                               |

### [Configuration Options](https://develop.sentry.dev/sdk/telemetry/spans.md#configuration-options)

| Option             | Type                   | Default    | Description                                             |
| ------------------ | ---------------------- | ---------- | ------------------------------------------------------- |
| `traceLifecycle`   | `'static' \| 'stream'` | `'static'` | Controls transaction vs span-first mode.                |
| `tracesSampleRate` | `number`               | `0.0`      | Float in `[0.0, 1.0]`, sampling rate for segment spans. |
| `tracesSampler`    | `function`             | —          | Callback returning per-trace sample rate.               |
| `ignoreSpans`      | `array`                | —          | Patterns to filter out spans.                           |
| `beforeSendSpan`   | `function`             | —          | Callback for data scrubbing.                            |

### [Utility APIs](https://develop.sentry.dev/sdk/telemetry/spans.md#utility-apis)

SDKs **MAY** expose additional utility APIs:

* `Scope::getSpan()`/`get_current_span()`/`Sentry.getActiveSpan()` — returns the currently active span.
* `Scope::_INTERNAL_getSegmentSpan()` — returns the segment span (**MUST NOT** be documented for users).

***

## [Implementation Guidelines](https://develop.sentry.dev/sdk/telemetry/spans.md#implementation-guidelines)

The steps below document what SDKs have been doing so far when implementing span-first. They are guidelines, not a strict specification.

### [Iterative Approach](https://develop.sentry.dev/sdk/telemetry/spans.md#iterative-approach)

Implement span-first incrementally. A rough suggestion for iterations:

1. Add the Span v2 envelope (type), serialization logic, and any utilities necessary to send the new envelope. See [Wire Format](https://develop.sentry.dev/sdk/telemetry/spans.md#wire-format).

2. Add the [`traceLifecycle`](https://develop.sentry.dev/sdk/telemetry/spans.md#trace-lifecycle-option) init option. Span-first **MUST** be an opt-in feature, and all span-first logic **MUST** only apply when `traceLifecycle` is set to `'stream'`.

3. As an initial PoC, leave the current transaction APIs in place and convert the transaction event to a v2 spans array sent in the new envelope.
   * At this point, spans can already be sent in batches (multiple envelopes) to send more than 1000 spans at once, respecting the [per-envelope limits](https://develop.sentry.dev/sdk/telemetry/spans.md#span-v2-envelope-item-payload).

4. If applicable, add the new [span starting APIs](https://develop.sentry.dev/sdk/telemetry/spans.md#starting-spans).

   * Start with the simplest possible `startSpan` API that leaves much control to users. Follow up with optional, more convenient APIs later.
   * The new API **MUST** only be used in conjunction with `traceLifecycle: 'stream'` and therefore only emit spans (no transactions).
   * Some SDKs already have `startSpan` or similar APIs. Each SDK **MAY** decide whether to reuse its existing API or add a new one, depending on what is practical for the language and platform.

5. Implement the [`captureSpan` pipeline](https://develop.sentry.dev/sdk/telemetry/spans.md#single-span-processing-pipeline).

   * Either reuse existing heuristics (e.g. flush when the segment span ends) or build a simple span buffer (e.g. similar to the existing buffers for logs or metrics).
   * The more complex [Telemetry Processor](https://develop.sentry.dev/sdk/foundations/processing/telemetry-processor.md) buffer and scheduler can be implemented at a later stage.

6. Achieve data parity with the existing transaction events.

   * Ensure data added by SDK integrations, event processors, etc. to transaction events is also added to spans (see [Replacing Event Processors](https://develop.sentry.dev/sdk/telemetry/spans.md#replacing-event-processors)).
   * Most additional data **MUST** only be added to the segment span. See [Common Attribute Keys](https://develop.sentry.dev/sdk/telemetry/spans.md#common-attribute-keys) for attributes that **MUST** be added to every span.
   * Mental model: all data the SDK *automatically* adds to a transaction **MUST** also be added to the segment span.

7. Implement the [span buffer](https://develop.sentry.dev/sdk/telemetry/spans.md#span-buffer) for proper, weighted span flushing.

8. In the next major release, drop support for sending traces as transactions. From that point on, the SDK only sends spans (v2).

### [Release](https://develop.sentry.dev/sdk/telemetry/spans.md#release)

Span streaming **SHOULD** (can) be released in a minor version of the SDK, given the behaviour is additive and does not interfere with transaction-based tracing.

* The feature is entirely opt-in via `traceLifecycle: 'stream'` and therefore doesn't introduce breaking changes for existing users.

* Release notes and user-facing documentation **SHOULD** clearly describe:

  * The availability of span-first behind the opt-in flag
  * Highlight the benefits of span-first, like higher span size limits, less memory pressure
  * Any known limitations

***

## [Examples](https://develop.sentry.dev/sdk/telemetry/spans.md#examples)

### [SDK API Usage](https://develop.sentry.dev/sdk/telemetry/spans.md#sdk-api-usage)

```ts
const checkoutSpan = Sentry.startSpan({
  name: 'on-checkout-click',
  attributes: { 'user.id': '123' }
})

const validationSpan = Sentry.startSpan({ name: 'validate-shopping-cart' })
startFormValidation().then((result) => {
  validationSpan.setAttribute('valid-form-data', result.success);
  validationSpan.end();
})

const processSpan = Sentry.startSpan({
  name: 'process-order',
  parentSpan: checkoutSpan
});
processOrder().then((result) => {
  processSpan.setAttribute('order-processed', result.success);
  processSpan.end();
}).catch((error) => {
  processSpan.setStatus('error');
  processSpan.setAttribute('order-processed', 'error');
  processSpan.end();
});

const unrelatedSpan = Sentry.startSpan({
  name: 'log-order',
  parentSpan: null
});
logOrder()
unrelatedSpan.end();

on('checkout-finished', ({ timestamp }) => {
  checkoutSpan.end(timestamp);
})
```

*Other available variations of the above snippet: Python, Dart*

### [Trace Propagation Usage](https://develop.sentry.dev/sdk/telemetry/spans.md#trace-propagation-usage)

```js
// Continue an incoming trace
Sentry.continueTrace({
  sentryTrace: request.headers['sentry-trace'],
  baggage: request.headers['baggage'],
}, () => {
  Sentry.startSpan({ name: 'handle-request' }, () => {
    // ...
  });
})

// Propagate to downstream services
const traceData = Sentry.getTraceData()

// Start a fresh trace
Sentry.startNewTrace(() => {
  Sentry.startSpan({ name: 'new-operation' }, () => {});
})
```

*Other available variations of the above snippet: Python*

### [Filtering Configuration](https://develop.sentry.dev/sdk/telemetry/spans.md#filtering-configuration)

```js
Sentry.init({
  ignoreSpans: [
    // apply on span name
    'GET /about',
    'events.signal *',
    /api\/\d+/,
    // ignore health check GET requests
    {
      name: /healthz?/,
      attributes: {
        'http.method': 'GET',
      }
    },
    // ignore all GET requests to /api/
    // (i.e. span name doesn't matter)
    {
      attributes: {
        'http.method': /GET \/api\/.*/,
      }
    },
    // ignore all spans with name starting with /imprint-
    // if glob patterns are supported
    {
      name: '/imprint-*'
    }
  ]
})

// Note: The glob patterns used in the example serve an illustrative purpose.
// They are not supported in JavaScript.
```

*Other available variations of the above snippet: Python*

### [Wire Format — Envelope Payload](https://develop.sentry.dev/sdk/telemetry/spans.md#wire-format--envelope-payload)

```json
{
  "version": 2,
  "ingest_settings": {
    "infer_ip": "auto",
    "infer_user_agent": "auto"
  },
  "items": [
    {
      "trace_id": "6cf173d587eb48568a9b2e12dcfbea52",
      "span_id": "438f40bd3b4a41ee",
      "name": "GET /users",
      "status": "ok",
      "is_segment": true,
      "start_timestamp": 1742921669.158209,
      "end_timestamp": 1742921669.180536,
      "attributes": {
        "sentry.segment.name": {
          "type": "string",
          "value": "GET /users"
        },
        "sentry.segment.id": {
          "type": "string",
          "value": "438f40bd3b4a41ee"
        },
        "sentry.op": {
          "type": "string",
          "value": "http.server"
        },
        "sentry.release": {
          "type": "string",
          "value": "1.0.0"
        },
        "sentry.environment": {
          "type": "string",
          "value": "local"
        },
        "sentry.segment.name.source": {
          "type": "string",
          "value": "route"
        },
        "sentry.trace_lifecycle": {
          "type": "string",
          "value": "stream"
        },
        "sentry.platform": {
          "type": "string",
          "value": "php"
        },
        "sentry.sdk.name": {
          "type": "string",
          "value": "sentry.php"
        },
        "sentry.sdk.version": {
          "type": "string",
          "value": "4.10.0"
        },
        "sentry.origin": {
          "type": "string",
          "value": "auto"
        },
        "sentry.is_localhost": {
          "type": "boolean",
          "value": true
        },
        "server.address": {
          "type": "string",
          "value": "127.0.0.1"
        },
        "http.response.status_code": {
          "type": "integer",
          "value": 200
        },
        "session.duration": {
          "type": "integer",
          "value": 164,
          "unit": "second"
        }
      },
      "links": [
        {
          "span_id": "6c71fc6b09b8b716",
          "trace_id": "627a2885119dcc8184fae7eef09438cb",
          "sampled": true,
          "attributes": {
            "sentry.link.type": {
              "type": "string",
              "value": "previous_trace"
            }
          }
        }
      ]
    },
    {
      "trace_id": "6cf173d587eb48568a9b2e12dcfbea52",
      "parent_span_id": "438f40bd3b4a41ee",
      "span_id": "f1196292f76e45c0",
      "name": "app.handle",
      "status": "ok",
      "is_segment": false,
      "start_timestamp": 1742921669.178306,
      "end_timestamp": 1742921669.180484,
      "attributes": {
        "sentry.segment.name": {
          "type": "string",
          "value": "GET /users"
        },
        "sentry.segment.id": {
          "type": "string",
          "value": "438f40bd3b4a41ee"
        },
        "sentry.op": {
          "type": "string",
          "value": "middleware"
        },
        "sentry.release": {
          "type": "string",
          "value": "1.0.0"
        },
        "sentry.environment": {
          "type": "string",
          "value": "local"
        },
        "sentry.sdk.name": {
          "type": "string",
          "value": "sentry.php"
        },
        "sentry.sdk.version": {
          "type": "string",
          "value": "4.10.0"
        },
        "sentry.trace_lifecycle": {
          "type": "string",
          "value": "stream"
        },
        "sentry.origin": {
          "type": "string",
          "value": "auto"
        },
        "sentry.is_localhost": {
          "type": "boolean",
          "value": true
        }
      }
    }
  ]
}
```

***

## [Changelog](https://develop.sentry.dev/sdk/telemetry/spans.md#changelog)

| Version | Date       | Summary                |
| ------- | ---------- | ---------------------- |
| `1.0.0` | 2026-06-22 | Initial stable release |
