4.3 W3C Baggage & Alternative Propagators

Key Takeaways

  • W3C Baggage provides distributed, execution-scoped key-value context propagation alongside trace context across multi-hop distributed architectures.

  • Baggage is exclusively an in-memory and wire propagation mechanism; Baggage key-values are NEVER automatically converted into span attributes or metrics.

  • To make Baggage visible in trace search or metrics, applications must explicitly copy Baggage values into span attributes or register an SDK baggage span processor; the Collector never sees baggage headers.

  • Baggage travels across the network in plaintext HTTP headers, presenting significant security, privacy (PII leakage), and header size bloat risks if misused.

  • OpenTelemetry supports legacy and cloud-native propagation formats (Zipkin B3, Jaeger, AWS X-Ray) and enables seamless multi-protocol bridging via CompositeTextMapPropagator and OTEL_PROPAGATORS.

Last updated: September 2026

4.3 W3C Baggage & Alternative Propagators

While the W3C Trace Context specification provides the structural identifiers (TraceID, SpanID, TraceFlags) necessary to assemble a distributed trace tree, distributed applications often need to propagate contextual business and operational metadata across network hops. For example, an edge API gateway may authenticate an incoming customer and determine their account_id, customer_tier, or data_center_region. Downstream microservices located four or five network hops away may need this contextual metadata to make local routing decisions, execute tenant isolation logic, or partition database connections, without requiring database re-queries at every hop.

To standardize this capability, OpenTelemetry implements the W3C Baggage Specification alongside a rich ecosystem of Alternative and Legacy Propagators.


The W3C Baggage Specification

Baggage is a set of user-defined, execution-scoped string key-value pairs that travel alongside distributed trace context across process and network boundaries. Popularized by OpenTracing, baggage is now standardized by the W3C Baggage specification (a Candidate Recommendation Snapshot published on 30 May 2024). The specification asks platforms to propagate at least 64 list members and at least 8,192 bytes; beyond that, members may be dropped.

The baggage HTTP Header Syntax

On the wire, Baggage is serialized into an HTTP header named baggage consisting of a comma-separated list of key-value pairs with optional semicolon-delimited metadata properties:

baggage: userId=alice,serverNode=DF%2028,isProduction=false;propertyKey=propValue
  • Key and Value Encoding: Keys are tokens (letters, digits, and a limited set of punctuation). Value characters outside the allowed set, such as spaces, commas, semicolons, and backslashes, are percent-encoded (e.g., a space becomes %20).
  • Optional Properties: Each baggage entry can carry optional metadata properties separated by semicolons (e.g., ;propertyKey=propValue). These properties are transmitted alongside the entry and preserved by compliant propagators.
  • Immutability in Memory: Just like Context, the OpenTelemetry Baggage object is completely immutable. Adding, modifying, or removing a baggage entry returns a new Baggage instance.

The Critical Distinction: Baggage vs. Span Attributes

A fundamental distinction to master is the difference between Baggage and Span Attributes:

+-------------------------------------------------------------------------+
|                           Span Attributes                               |
|  - Attached strictly to a SINGLE Span                                   |
|  - Exported to the tracing backend with that specific span              |
|  - Indexed in search backends for trace queries and latency filtering   |
|  - NEVER transmitted over the network wire to downstream services       |
+-------------------------------------------------------------------------+
                                     VS
+-------------------------------------------------------------------------+
|                            W3C Baggage                                  |
|  - Stored in in-memory Context and transmitted across EVERY network hop |
|  - Propagated downstream over HTTP, gRPC, and messaging headers         |
|  - Available in-memory to all downstream services in the execution tree |
|  - NEVER automatically recorded as span attributes or metrics!          |
+-------------------------------------------------------------------------+

CRITICAL RULE: Baggage is purely a transport carrier. Setting a key-value pair in Baggage DOES NOT make it appear as an attribute on spans created in that service or downstream services. It will not show up in APM trace search screens, and it will not appear on metric timeseries unless you explicitly bridge it.

How to Make Baggage Visible in Telemetry

To record Baggage values onto spans or metrics, engineering teams must use one of two mechanisms:

  1. Explicit Application Code: Read the Baggage from the active Context and set it as an attribute on the active span:
    from opentelemetry import baggage, trace
    
    # Extract baggage value from active context
    customer_tier = baggage.get_baggage("customer_tier")
    if customer_tier:
        # Explicitly attach it to the current span
        trace.get_current_span().set_attribute("customer.tier", customer_tier)
    
  2. A Baggage Span Processor in the SDK: Register an opt-in processor, available in the Java, JavaScript, Python, and Go contrib repositories, that copies selected baggage entries onto each span in OnStart (JavaScript also has a log-record variant). This cannot be moved to the Collector: baggage lives in request headers between services and is not part of the OTLP data that the SDK exports.

Security, Privacy, and Operational Risks of Baggage

Because Baggage propagates automatically across network boundaries, it introduces severe architectural and security risks if not managed with extreme discipline:

  • PII and Sensitive Data Leakage: Because Baggage headers travel across all downstream services—including third-party payment gateways, external partner APIs, CDNs, and load balancers—storing Personally Identifiable Information (PII) like customer names, emails, credit card numbers, or authorization tokens in Baggage exposes that data to external network sniffing and log scraping.
  • HTTP Header Size Bloat: Every microservice hop must transmit the complete baggage header. Accumulating dozens of baggage keys across complex microservice chains can cause HTTP request headers to exceed web server size limits (e.g., 8 KB in Nginx or Apache), resulting in HTTP 431 Request Header Fields Too Large errors.
  • Data Tampering & Injection: Baggage headers are unencrypted and unsigned by default. Untrusted public clients could inject fabricated baggage keys (such as role=admin or account_balance=1000000) into edge requests. Production gateways must sanitize and strip untrusted incoming baggage headers.

Alternative and Legacy Propagators

While the W3C standards represent the modern cloud-native future, enterprise architectures rarely start from scratch. OpenTelemetry provides built-in support for legacy and proprietary wire formats to enable smooth brownfield migrations.

1. B3 Propagation Specification (Zipkin)

Created by the Zipkin project, the B3 specification is widely used in Spring Boot (spring-cloud-sleuth) and Finagle architectures. B3 exists in two distinct wire formats:

  • B3 Single Header: Collapses all identifiers into a single b3 header separated by hyphens:
    b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId}
    
    Example (Sampled):
    b3: 4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1
    
    Example (Not Sampled):
    b3: 4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-0
    
  • B3 Multiple Headers: Transmits each identifier in a dedicated HTTP header prefix with X-B3-:
    • X-B3-TraceId: 16 or 32 hex characters (64-bit or 128-bit).
    • X-B3-SpanId: 16 hex characters (64-bit).
    • X-B3-Sampled: 1 (sampled) or 0 (not sampled).
    • X-B3-ParentSpanId: 16 hex characters (optional parent span ID).
    • X-B3-Flags: 1 indicates debug sampling (forces recording).

2. Jaeger Native Propagation Format

Prior to adopting W3C, Jaeger used a single colon-delimited HTTP header named uber-trace-id:

uber-trace-id: {trace-id}:{span-id}:{parent-span-id}:{flags}

Example:
uber-trace-id: 4bf92f3577b34da6a3ce929d0e0e4736:00f067aa0ba902b7:0:1
  • flags is an 8-bit bitmap represented as a hex value, where 1 indicates sampled and 2 indicates debug.

3. AWS X-Ray Propagation Format

AWS services (API Gateway, Application Load Balancers, Lambda, ECS) use the proprietary X-Amzn-Trace-Id header:

X-Amzn-Trace-Id: Root=1-5759e988-bd862e3da4e61099937233ac;Parent=53995cbe316dc808;Sampled=1
  • Semicolon-delimited key-value structure.
  • The Root trace ID has a unique structure: 1-{8-hex-digit Unix epoch timestamp}-{24 random hex digits}.
  • OpenTelemetry provides the AWS X-Ray Propagator to parse and emit this format seamlessly.

4. The Composite Propagator (CompositeTextMapPropagator)

In heterogeneous enterprise environments, a microservice might receive incoming requests from legacy services sending B3 headers, modern services sending W3C headers, and AWS ALBs sending X-Ray headers. To support multiple wire formats simultaneously, OpenTelemetry provides the CompositeTextMapPropagator.

A composite propagator combines multiple individual propagators into an ordered chain:

  • During Extraction (extract): The composite propagator calls every registered propagator in order against the same carrier, passing along the context built so far. Each one adds what it finds (for example, W3C Trace Context extracts the span context and the Baggage propagator extracts baggage). If two formats both carry a trace context, the propagator that runs later overwrites the earlier result, so order matters.
  • During Injection (inject): The composite propagator invokes the inject method of every registered propagator in sequence. This means an outgoing HTTP call can simultaneously carry traceparent, tracestate, baggage, and b3 headers, ensuring compatibility with whichever downstream service receives the call.
                       +----------------------------------+
                       |    Incoming HTTP Request         |
                       |    Headers: [b3, baggage]        |
                       +----------------------------------+
                                        |
                                        v
+-----------------------------------------------------------------------------------+
|                       CompositeTextMapPropagator Extraction                        |
|                                                                                   |
|  1. TraceContextPropagator.extract() -> No traceparent found (skips)              |
|  2. B3Propagator.extract()           -> Extracts TraceID & SpanID from b3 header   |
|  3. BaggagePropagator.extract()      -> Extracts Baggage key-values               |
+-----------------------------------------------------------------------------------+
                                        |
                                        v
                       +----------------------------------+
                       |    Combined In-Memory Context    |
                       +----------------------------------+

Configuring Propagators with OTEL_PROPAGATORS

Rather than writing hard-coded Java, Go, or Python code to configure propagators, OpenTelemetry standardizes their selection through the OTEL_PROPAGATORS environment variable (the default is tracecontext,baggage).

The value is a comma-separated list of recognized propagator identifiers:

# Configure standard W3C Trace Context, W3C Baggage, and B3 propagation
export OTEL_PROPAGATORS="tracecontext,baggage,b3"

Standard Propagator Identifiers

Propagator IdentifierSpecification / ProtocolHTTP Header(s) Injected / Extracted
tracecontextW3C Trace Context (Default)traceparent, tracestate
baggageW3C Baggage (Default)baggage
b3Zipkin B3 Single Headerb3
b3multiZipkin B3 Multiple HeadersX-B3-TraceId, X-B3-SpanId, X-B3-Sampled, X-B3-ParentSpanId
jaegerJaeger Native (deprecated)uber-trace-id
xrayAWS X-Ray (third party)X-Amzn-Trace-Id
ottraceOpenTracing Basic (third party, deprecated)ot-tracer-traceid, ot-tracer-spanid, ot-tracer-sampled
noneNo-op PropagatorDisables all context propagation

Propagator Comparison Matrix

The following table compares the major propagation formats:

Propagator FormatPrimary Wire Header(s)Syntax StructureTraceID SizeSpanID SizeCarries Business Data?OTEL_PROPAGATORS Identifier
W3C Trace Contexttraceparent, tracestateHyphen-delimited (4 parts) & comma-separated opaque pairs16 bytes (32 hex)8 bytes (16 hex)Yes (vendor routing in tracestate)tracecontext
W3C BaggagebaggageComma-separated key=value with ;propsN/A (Context only)N/A (Context only)Yes (arbitrary key-value strings)baggage
B3 Single Headerb3Hyphen-delimited ({trace}-{span}-{flag}-{parent})8 or 16 bytes (16 or 32 hex)8 bytes (16 hex)No (trace identifiers only)b3
B3 Multi-HeaderX-B3-TraceId, X-B3-SpanId, X-B3-SampledIndividual HTTP headers per field8 or 16 bytes (16 or 32 hex)8 bytes (16 hex)No (trace identifiers only)b3multi
Jaeger Nativeuber-trace-idColon-delimited ({trace}:{span}:{parent}:{flags})8 or 16 bytes (16 or 32 hex)8 bytes (16 hex)No (trace identifiers only)jaeger
AWS X-RayX-Amzn-Trace-IdSemicolon-delimited Root=1-{time}-{rand};Parent={id}16 bytes (embedded timestamp)8 bytes (16 hex)No (sampling flags only)xray
Loading diagram...
CompositeTextMapPropagator Multi-Protocol Ingestion and Egress
Test Your Knowledge

A development team instruments an API gateway to populate an OpenTelemetry Baggage entry with 'customer.tier=premium' for every authenticated request. Downstream microservices process the requests and produce trace spans. However, when querying the APM backend, engineers discover that the attribute 'customer.tier' does not appear on any downstream spans. What explains this behavior?

A

The OpenTelemetry SDK automatically compresses Baggage headers using gzip, preventing APM backends from reading them.

B

The downstream services must be running in debug mode to permit Baggage entries to cross microservice boundaries.

C

The W3C Baggage specification only allows numerical integers, so string values like 'premium' are silently dropped.

D

Baggage is purely a context propagation carrier and is never automatically converted into span attributes or metrics.

Test Your Knowledge

An enterprise is migrating legacy microservices from Zipkin B3 instrumentation to OpenTelemetry W3C Trace Context. During the multi-month phased migration, newly upgraded OpenTelemetry services must accept traces from legacy Zipkin services and send calls to other legacy Zipkin services, while also supporting modern W3C headers. How should the platform team configure the OpenTelemetry environment variable on the upgraded services?

A

Set OTEL_PROPAGATORS="tracecontext,b3" to instantiate a CompositeTextMapPropagator that extracts and injects both formats.

B

Set OTEL_PROPAGATORS="none" to allow the Linux network stack to dynamically negotiate header protocols.

C

Set OTEL_PROPAGATORS="w3c_strict" to force legacy Zipkin services to upgrade their HTTP headers automatically.

D

Set OTEL_PROPAGATORS="zipkin" and deploy an external sidecar proxy to rewrite all outgoing HTTP requests.

Test Your Knowledge

A security auditor discovers that a microservice architecture stores plaintext JWT session tokens and user email addresses inside OpenTelemetry Baggage so that downstream services can identify the requesting user. Why does the auditor classify this architecture as a high-severity security risk?

A

Baggage items are written to a public global registry accessible to all Docker containers on the same physical host.

B

Baggage is transmitted over the wire across every downstream network hop and proxy in unencrypted HTTP headers, risking token exposure and header size bloat.

C

The OpenTelemetry API automatically encrypts Baggage with a hard-coded public key that can be reversed by any OpenTelemetry Collector.

D

Baggage headers are restricted by the W3C standard to internal localhost loopback addresses and fail on production networks.

Sections you finish are checked off in the contents.