What Is Baggage in OpenTelemetry?

What Is Baggage in OpenTelemetry?

A plain-English guide to the small set of labels that travels with a request from service to service, so that every step along the way knows who the request is for and why it exists, and to the dangers that come with carrying it.

Imagine you are travelling through several airports on one long trip. At each stop, the staff look at your passport and your ticket, but they also look at the tags on your suitcase. One tag says “priority”, another says “fragile”, and a third says “final stop: Delhi”. Nobody has to phone the first airport to ask what to do with your bag. The instructions simply travel with it.

Software requests need the same thing. A request enters through a front door, passes through ten different services, and each of them might want to know something that only the front door knew, such as “this customer is on the premium plan” or “this request comes from the mobile app”. Asking the front door again at every step would be slow and awkward. OpenTelemetry offers a neat answer: a small bag of labels that rides along with the request. That bag is called baggage.

In this guide, you will learn what baggage is, how it differs from the other things that travel with a request, how it moves across the network, how the SDK handles it, and, just as importantly, the risks that come with it. No prior knowledge is needed. Every new word is explained the first time it appears.

1What Is Baggage?

Baggage is a small collection of name and value pairs that is attached to a request and carried across every service the request visits.

A set of labels that travels

Baggage in OpenTelemetry is a set of key and value pairs, such as “customer tier equals premium” or “region equals europe”. It is part of the request’s context, the invisible package that follows the request through your code. When one service calls another over the network, the baggage is written into the outgoing message, and the receiving service reads it back out. Every service in the chain can look at the baggage, add to it, or remove from it.

Not telemetry, but a helper for telemetry

This is the first thing to understand clearly: baggage is not itself telemetry. It does not show up in your traces, logs, or metrics on its own. It is a delivery service for small facts. What you do with the facts, such as copying them onto spans or using them to decide behavior, is up to you.

Everyday Analogy

Think of a school trip. Each child wears a wristband with the group name and a note, such as “allergic to peanuts”. Every teacher, guide, and bus driver along the trip can read the wristband. The band is not a diary of the trip. It is information carried to every place the child goes. Baggage is the wristband of a request.

1
header on the wire carries the whole bag
0
entries copied to telemetry automatically
100%
of downstream services can read it
i
Tip

Remember the three verbs: set at one place, travel with the request, and read at another place. Everything about baggage fits into those three steps.

2Why Baggage Exists: The Problem It Solves

Every feature exists because of a pain. Let us look at the pain that baggage removes.

Facts known at the front, needed at the back

Many facts are known only at the beginning of a request. The front door knows which customer plan is being used, which mobile app version sent the request, and which experiment group the user is in. But the services deep in the chain, such as pricing, recommendations, or payment, may want exactly these facts. A payment service that wants to add a “premium customer” label to its telemetry cannot see the original login. It sees only a request from the order service.

The awkward alternatives

  • Ask again. Each service looks up the customer record again. It works, but it adds extra calls, extra load, and extra delay for every request.
  • Add a parameter to every call. Every function and every API between services must carry the extra field, even those that never use it. Changing hundreds of interfaces is slow and error-prone.
  • Invent your own header. Every team invents a different header and a different format, and nothing works with anything else.

Baggage replaces all of these with one standard, agreed way. Put the facts in once, near the front. The SDK and the propagation rules carry them everywhere the request goes, with no change to function signatures and no extra lookups.

Everyday Analogy

Imagine a hospital where the patient’s allergy was recorded at the entrance. Without a wristband, every ward has to call the reception to ask. Without a standard, each ward would invent its own coloured card. With a standard wristband, every nurse sees the allergy at once. Baggage is that standard wristband for software.

A short history

The idea is older than OpenTelemetry. The earlier OpenTracing project had “baggage items” that were attached to a span’s context and traveled with it. OpenCensus had a similar idea called tags. When these projects merged to form OpenTelemetry, baggage was redesigned as its own feature, separate from spans, so that it can be used even when no tracing is active.

3Core Vocabulary: The Words You Need

A small set of words appears in every discussion of baggage. Learn them once, and the rest of the guide will be easy.

TermPlain meaningExample
BaggageThe whole set of key and value pairs carried with a requestCustomer tier and region together
Entry (or member)One key with its value“region” with the value “europe”
Key (or name)The label of an entry“customer tier”
ValueThe content of an entry, always text“premium”
Metadata (or properties)An optional extra note attached to an entryA tag saying the entry is for internal use
ContextThe invisible package that follows the code and holds baggage and the active spanThe request’s backpack
PropagatorThe component that writes context into outgoing messages and reads it from incoming onesThe W3C baggage propagator
InjectWrite the baggage into an outgoing requestAdding the header to an HTTP call
ExtractRead the baggage from an incoming requestReading the header on arrival
PropagationThe whole act of carrying context between servicesInject, travel, extract

The word “bag”

A good way to remember the word is to keep the picture of a bag with tags. The bag can be passed from hand to hand. Anybody holding it can look inside, put a new tag in, or take a tag out. And because it travels with the traveler, it reaches every stop.

i
Good to Know

Baggage values are text. If you need to carry a number or a yes-or-no answer, you write it as text, such as “42” or “true”, and the reader turns it back into the type it needs.

4Baggage vs Trace Context vs Attributes vs Resource

Beginners often mix up baggage with several neighbors. Each does a different job. Let us separate them carefully.

ItemWhat it describesTravels to other services?Appears in telemetry automatically?
Trace contextWhere the request sits in a trace (trace ID, span ID, sampling flag)YesYes, as IDs on spans and logs
BaggageFree-form facts you chose to share about the requestYesNo
Span attributesDetails about one single stepNoYes, on that span
Resource attributesFacts about the service producing telemetryNoYes, on all its telemetry
Trace stateVendor-specific hints that ride with trace contextYesSometimes, depending on the tool

The easy way to tell them apart

Identity

Trace context

Answers “which request is this, and where in the story are we?” It is created by the system and must be kept intact.

Message

Baggage

Answers “what do I want every downstream service to know about this request?” You choose the contents.

Detail

Span attributes

Answers “what happened in this one step?” They stay on that single span and go nowhere else.

Origin

Resource attributes

Answers “which service, version, and machine produced this?” They are fixed for the life of the process.

Everyday Analogy

A parcel has a tracking number, which is the trace context, and it identifies the parcel and its journey. A sticker saying “fragile, handle with care” is the baggage, a message that every handler along the way should see. The note a worker writes at one warehouse, such as “box dented at loading dock”, is a span attribute. The name of the warehouse itself, printed on the stamp, is a resource attribute.

!
Watch Out

Putting a value into baggage does not put it on any span. If you set “customer tier” in baggage and then search your traces for it, you will find nothing, unless you also copy it to span attributes. Chapter 11 explains how.

5The Anatomy of a Baggage Entry

What exactly is inside the bag? Each entry is small and simple, and the rules about size and format keep it that way on purpose.

Part one

Key

The name of the entry, such as a lowercase, dotted name. Keys should be short, descriptive, and consistent across your company.

Part two

Value

The text content. Special characters are encoded when written to the wire, so they travel safely.

Part three

Metadata

An optional note attached to the entry. The SDK treats it as opaque text and passes it along without interpreting it.

Rules that keep the bag small and safe

  • Text only. Both keys and values are text. Numbers and flags are written as text.
  • Size limits. The standard sets minimum limits that every implementation must support, roughly on the order of dozens of entries and a few kilobytes in total. Going beyond the limits means that some entries may be dropped.
  • Unchangeable once built. A baggage object cannot be edited in place. Setting a value creates a new baggage object with the change, and that new object is placed into the context.
  • One value per key. If you set the same key again, the new value replaces the old one.
Everyday Analogy

Think of the luggage tag on a suitcase. It is small, so only a few short words fit. You can change what the tag says only by replacing it with a new tag. Airlines also set a limit on how much tag you can attach. Baggage follows the same philosophy: small, simple, and replaceable.

i
Tip

Choose keys with a clear prefix, such as the name of your company or team, so that two teams do not accidentally use the same key for different meanings.

6How Baggage Travels: The Wire Format

When baggage crosses a network, it must be written into the message in a format that every service understands. That format is a public standard.

The baggage header

The standard for carrying baggage is the W3C Baggage format. For web requests, it uses an HTTP header named baggage. The value of the header is a comma-separated list of entries, written as key, an equals sign, and value. For example, a header could carry “customer.tier=premium” and “region=eu” together, separated by a comma. Special characters in values are percent-encoded so that they cannot break the format. An entry’s optional metadata is added after a semicolon.

flowchart LR
    GW["API Gateway sets customer tier and region"] -- "baggage header" --> OS["Order Service reads and forwards"]
    OS -- "baggage header" --> PS["Payment Service reads"]
    OS -- "baggage header" --> IS["Inventory Service reads"]
Figure 1: One set of labels is written once and read by every service downstream

Read the figure from left to right. The gateway puts the labels in at the start. The order service receives them, can read them, and passes them on to both the payment and inventory services. Nobody had to write any special code to look up the customer tier again.

Same idea for other protocols

HTTP is only one road. For gRPC, the baggage rides in the call’s metadata. For message queues, it rides in the message’s properties or headers. The idea never changes: the propagator writes the entries into the carrier on the way out, and reads them from the carrier on the way in. Only the type of carrier is different.

CarrierWhere baggage travels
HTTP requestThe baggage header
gRPC callCall metadata
Message queueMessage headers or properties
Background jobJob metadata, if you copy it there
i
Good to Know

The baggage header travels next to the traceparent header. They are separate headers that are written and read by two different propagators, usually configured together.

7Inside the SDK: Context, API, and Propagator

Let us follow the baggage from the moment code sets it to the moment another service reads it.

sequenceDiagram
    participant A as Service A Code
    participant B as Baggage API
    participant C as Context
    participant P as Propagator
    participant H as HTTP Client
    participant S as Service B
    A->>B: Set customer tier to premium
    B->>C: New baggage placed in context
    A->>H: Call Service B
    H->>P: Inject context into headers
    P->>C: Read baggage
    P-->>H: Add baggage header
    H->>S: Request with baggage header
    S->>S: Propagator extracts baggage into context
    S->>S: Service B code reads customer tier
Figure 2: From a set call in service A to a read call in service B
1

Code sets a value

Your code asks the baggage API to add an entry. The API builds a new baggage object that includes it.

2

The context holds it

The new baggage is placed into the current context, so any code running in the same flow can see it.

3

An outgoing call starts

The instrumented HTTP client calls the propagators, which look inside the context and write the baggage header.

4

The request travels

The header goes over the network with the request, next to the trace context header.

5

The receiver extracts

The server instrumentation reads the header and builds a baggage object in the receiving service’s own context.

6

Code reads it

Any code in the receiving service can now ask the baggage API for an entry, and it will find the value set upstream.

Notice that the baggage API and the propagator are separate parts. The API is the part your code touches, to set and read entries. The propagator is the part that moves the baggage in and out of messages. If the propagator for baggage is not enabled, your code will set values successfully, but nothing will cross the network.

!
Watch Out

Setting baggage on its own does nothing across services unless the baggage propagator is configured on both sides. The default setup of many SDKs includes it, but check yours.

8Working with Baggage in Code: The Basic Operations

The baggage API is deliberately tiny. Knowing its four basic moves is enough to use it well.

Read

Get an entry

Ask for the value of one key. You receive the value, and perhaps its metadata, or nothing if the key is missing.

Read

Get all entries

Ask for the whole bag, to display it or to copy it somewhere. Useful for debugging.

Write

Set an entry

Add or replace one entry. This builds a new baggage object, and you then place it in the context.

Write

Remove an entry

Take a key out of the bag. The result is a new baggage object without that key.

Making the change take effect

Because baggage is unchangeable, building a new bag is only half the job. The new bag must be placed into the context, and the context must be made current, so that code running after the change, and outgoing calls, see it. Most SDKs provide a way to do this for a specific stretch of code, called a scope. Inside the scope, the new baggage is visible. When the scope ends, the earlier baggage returns.

Everyday Analogy

A traveler at an airport is handed a new luggage tag. Changing the tag on a bag does nothing if the traveler leaves the old bag on the conveyor belt. The new bag must be the one that goes on the plane. In the same way, the new baggage must be the one held by the current context.

Where to set it

The best place to set baggage is at the entrance of the request, for example in the gateway or the first service. Setting it deep in the chain still works, but it reaches only the services that are called after that point, not those that were called earlier.

Removing before you hand over

Sometimes you want to stop an entry from going any further, for example before calling a third-party service. You build a bag without that entry, and use it only for that outgoing call. The entry is not lost for the rest of your own code, if you keep the original bag for other work.

i
Tip

Keep baggage handling in one small helper in your codebase. When many teams read and write baggage in their own ways, it becomes hard to see which keys exist and who owns them.

9Baggage Across Service Borders

The true power of baggage appears when a request crosses many services. Each service can read what the earlier ones wrote, and add its own notes for the later ones.

sequenceDiagram
    participant U as User App
    participant G as API Gateway
    participant O as Order Service
    participant P as Payment Service
    participant R as Recommendation Service
    U->>G: HTTP request
    Note over G: Sets customer tier and app version
    G->>O: Request with baggage header
    Note over O: Reads tier and adds experiment group
    O->>P: Request with tier, version, and group
    Note over P: Reads tier for risk rules
    O->>R: Request with tier, version, and group
    Note over R: Reads group to choose an algorithm
    P-->>O: Response
    R-->>O: Response
    O-->>G: Response
    G-->>U: Response
Figure 3: Services read earlier labels and add their own for the services that come later

Three kinds of actions

Origin

Set at the start

The gateway or first service puts in facts only it knows, such as the customer plan and the app version.

Middle

Add along the way

A service that makes a decision, such as choosing an experiment group, adds that fact for the services after it.

End

Read where needed

A downstream service reads the facts it cares about and ignores the rest.

Branches do not mix

When the order service calls both the payment and recommendation services, each call carries its own copy of the baggage. If the payment service adds a new entry, the recommendation service will not see it, because they are separate branches of the request. Baggage flows downward, along the direction of the calls. It does not flow back upward in the response, and it does not flow sideways between sibling calls.

Everyday Analogy

A manager hands the same briefing sheet to two team members who go on separate errands. If one member writes a note on her own copy, the other member does not see it. The sheets were photocopies. Baggage works like photocopies handed down along each branch of a request.

!
Watch Out

Do not use baggage to send results back to the caller. It travels only in the direction of calls. If a downstream service must send information back, use the response itself.

10Threads, Async Work, and Message Queues

Modern programs do many things at once, and requests often hop through queues. Baggage lives in the context, so it follows the same rules as every other piece of context.

Inside one process

When code hands work to another thread or task, the context must be carried along. If it is not, the new worker starts with an empty context, with no active span and no baggage. Many instrumentation libraries and automatic agents wrap the common thread pools so that the context moves with the work. When you write your own concurrency, check that you pass it on.

Through a message queue

With queues, the sender and receiver do not talk directly. The sender puts a message in, and the receiver takes it out later. The propagator writes the baggage into the message’s headers on the way in, and reads it from the headers on the way out. The receiver can then rebuild the context, even if hours have passed.

flowchart LR
    PR["Producer Service sets baggage"] --> IN["Propagator writes baggage into message headers"]
    IN --> Q["Message Queue holds the message"]
    Q --> OUT["Consumer reads message headers"]
    OUT --> EX["Propagator rebuilds baggage in the context"]
    EX --> CO["Consumer code reads the entries"]
Figure 4: Baggage rides inside the message and is rebuilt on the other side
SituationWhat happens to baggageWhat to do
Same threadStays in the contextNothing special
Thread pool or async taskMay be lost if not wrappedUse context-aware wrappers
Message queueTravels only if the propagator writes it into the messageEnable the propagator on both sides
Scheduled job started laterNot present, unless saved in the job dataStore needed entries with the job explicitly
Retries after a long delayMay carry stale factsRe-check any fact that could have changed
i
Tip

Facts in baggage describe the request at the time it started. If a message waits in a queue for hours, a fact such as “customer tier” may have changed. For important decisions, look up the live value.

11Baggage Is Not Telemetry: Getting It into Your Data

This is the point where most beginners are surprised. Putting something in baggage does not make it visible in your traces, logs, or metrics.

The surprise

When a service exports spans, the exporter sends the span’s own fields: IDs, name, times, status, and attributes. It does not look inside the baggage. The baggage stays in the context and in the headers. If you want an entry to appear on telemetry, something must read it from the baggage and write it into the telemetry deliberately.

flowchart LR
    CX["Context with baggage"] --> BP["Baggage span processor (optional)"]
    BP --> SA["Span attributes"]
    SA --> EX["Exporter"]
    EX --> BE["Backend: searchable by customer tier"]
    CX -. "without a processor" .-> NO["Baggage never reaches the backend"]
Figure 5: Baggage reaches your data only when something copies it onto telemetry

Ways to copy baggage into telemetry

Automatic

A baggage span processor

Several language SDKs offer a ready-made component that copies chosen baggage entries onto every new span as attributes. You usually give it a list of allowed keys.

Manual

Read and set in code

At a key point, read an entry from baggage and add it to the current span as an attribute, or to a log record as a field.

Logs

A log enrichment step

A logging integration can add selected baggage entries to each log record, so logs can be searched by them.

Metrics

Selected labels, with care

You can pass a few safe, low-variety entries as metric labels in your own code. Never copy open-ended values.

Everyday Analogy

A passenger’s boarding pass says “window seat”. The airline’s flight report does not automatically list every passenger’s seat. Someone has to copy the seat numbers onto the report if they want to. Baggage is the boarding pass, and telemetry is the flight report. A step must connect them.

!
Watch Out

Copying all baggage onto every span, without a list of allowed keys, will copy whatever any caller sends, including values you never planned for. Always use an allowed list.

12Using Baggage Across Traces, Logs, and Metrics

Once baggage entries are copied onto telemetry, they become powerful ways to slice and filter your data. Each signal has its own rules about which entries suit it.

SignalGood use of baggage entriesCare needed
TracesSearch slow traces by customer tier, experiment group, or app versionUse an allowed list. Do not copy personal data.
LogsFilter log lines of one tenant or experimentMake sure log retention rules suit the data
MetricsSplit latency by customer tier, if there are only a few tiersOnly low-variety values, or the cost will explode

The cardinality rule for metrics

Cardinality is the number of different values a label can have. A label with three values, such as free, standard, and premium, creates three series. A label with a million values, such as a user ID, creates a million series. Metrics become slow and expensive very quickly if their labels have many values. So, for metrics, copy only entries with a small and fixed set of possible values. For traces and logs, where each record stands alone, you can afford richer values.

Everyday Analogy

A school can keep one attendance sheet for each class, which is manageable. If it kept a separate sheet for each student for each day, the cupboards would overflow. Labels with few values are class sheets, and labels with endless values are the sheet for each student.

Good for metrics

Plan tier

A handful of values. Safe and useful for splitting charts.

Good for metrics

Region or app platform

A few dozen values at most. Fine in most systems.

Traces and logs only

Experiment group or tenant name

Many values, but each record carries only one. Good for search.

Avoid everywhere

User ID, email, session token

Personal or secret, with endless values. Keep them out of baggage and telemetry.

13What Belongs in Baggage, and What Does Not

Because baggage travels everywhere, it deserves careful choices. A good entry is small, safe, stable, and useful to more than one service.

Good fits

Customer

Plan or tier

Lets downstream services label telemetry or choose a limit without another lookup.

Experiment

Experiment or variant name

Lets every service tag its data with the same group, so results can be compared across the whole request.

Origin

Client type and version

Tells backend services whether the call came from a phone, a browser, or a partner.

Traffic

Synthetic or test flag

Marks load-test traffic so that dashboards and alerts can ignore it.

Place

Region or tenant name

Useful in multi-region or multi-tenant systems to filter data without extra lookups.

Debug

A debug request marker

Asks all services to log extra detail for this one request, useful in controlled troubleshooting.

Poor fits

Do not put in baggageWhy
Passwords, tokens, API keys, session secretsThey travel in headers to every service and may leak into logs and proxies
Personal data such as emails, phone numbers, namesIt spreads to many systems and may break privacy rules
Large values like documents or listsEvery call carries the extra bytes
Anything that grants permissionCallers can forge the header
Results to send back upstreamBaggage flows only downward
Values that change during the requestCopies on separate branches will disagree
!
Watch Out

A useful test: imagine the baggage header printed on a sign above the front door of every company you call. If the content would be awkward on that sign, it does not belong in baggage.

14A Decision Guide: Baggage or Something Else?

Baggage is one tool among several. Use this path of simple questions to decide whether it is the right one.

flowchart TB
    S["I have a fact about this request"] --> Q1{"Do other services need it?"}
    Q1 -- No --> A1["Span attribute on the current span"]
    Q1 -- Yes --> Q2{"Is it safe, small, and not secret?"}
    Q2 -- No --> A2["Do not use baggage: look it up securely or pass it in the API"]
    Q2 -- Yes --> Q3{"Will services use it for decisions or for telemetry only?"}
    Q3 -- Decisions --> A3["Prefer a trusted lookup. Baggage can be forged"]
    Q3 -- Telemetry --> A4["Baggage with an allowed list copied to telemetry"]
Figure 6: A short path for choosing between baggage and other options

Reading the guide

Start with the fact. If no other service needs it, a plain span attribute is enough, and nothing has to travel. If other services need it, ask whether it is safe to share, small, and not secret. If it is not safe, find another way, such as a secure lookup. If it is safe, ask what it will be used for. When it is only for labeling telemetry, baggage is a great fit. When it will drive important decisions such as permissions, prefer a trusted source, since anyone can forge a header.

NeedBest tool
Describe one stepSpan attribute
Describe the service itselfResource attribute
Identify the request in a traceTrace context
Share a safe label with all downstream servicesBaggage
Pass sensitive or important data between servicesThe request payload or a secure lookup

15A Worked Example: Slicing Latency by Customer Tier

Let us walk through a realistic need, step by step, and see exactly where baggage helps.

The need

A shop notices that checkout is sometimes slow, and wonders whether premium customers, who have a promise of fast service, are affected more or less than free customers. Only the gateway knows the customer’s plan. The payment service, where most of the time is spent, does not.

1

Set at the gateway

When a request arrives and the user is identified, the gateway sets a baggage entry named “customer tier” with a value such as “premium”, “standard”, or “free”.

2

Travel with the request

The order, payment, and inventory services receive the entry through the baggage header, because the propagators are enabled.

3

Copy to spans

Each service uses a span processor with an allowed list that contains only “customer tier”. Every span now carries the attribute.

4

Query the backend

The engineer groups traces by the attribute and compares the duration of the payment span for each tier.

5

Read the answer

Free customers show a median of 220 milliseconds, standard 230, and premium 410. Premium customers go through an extra risk check. The team now knows where to look.

Customer tierMedian payment span (ms)Observation
Free220Normal
Standard230Normal
Premium410Slower, caused by an extra risk check

What baggage saved

Without baggage, the payment service would have to look up the customer plan in a database for each request, or every interface between services would need a new parameter. With baggage, one entry was set once, and every service gained the ability to label its data. The example also shows the three-step discipline: set early, carry on, and copy to telemetry only what you need.

i
Good to Know

The numbers in the table are an invented example to show the workflow. Your own data will differ, but the process of setting, carrying, copying, and querying stays the same.

16Size, Limits, and Performance

Baggage looks tiny, but it is added to every call. Small amounts, repeated millions of times, become real costs.

The arithmetic of extra bytes

Suppose your baggage holds ten entries of about forty bytes each. That is roughly 400 extra bytes on every request. If your internal services make 100,000 calls per second, that adds up to 40,000,000 bytes, or about 40 megabytes, of extra traffic every second, only for baggage. Every call also spends a bit of time writing and reading the header.

400 B
extra per call with ten small entries
100,000
internal calls per second in the example
40 MB/s
extra traffic from baggage alone

What limits exist

  • The W3C standard sets minimum sizes that implementations must support, roughly on the order of dozens of entries and a few kilobytes in total. Implementations may drop entries beyond their limits.
  • Web servers, proxies, and gateways have their own header size limits. A very large baggage header can cause a request to be rejected.
  • Each hop reads and writes the header again, so a larger bag costs more at every hop.
Keep small

Few entries

Aim for a handful of entries, not dozens. Every entry costs bytes on every call.

Keep short

Short keys and values

Use compact names and codes instead of long sentences.

Trim

Remove what is no longer needed

If only the first two services need an entry, remove it before calling the rest.

Measure

Watch header sizes

Track the size of the baggage header in your gateways and proxies, and alert if it grows.

Everyday Analogy

A single sticker on a suitcase weighs almost nothing. A hundred stickers on every suitcase of a large airline add up to a lot of paper, and slow the handlers. A small bag is a polite bag.

i
Tip

Treat the baggage budget like a team resource. Decide a maximum size, list the allowed keys in a shared document, and review additions as you would review a new database column.

17Security, Part One: Where the Bag Can Leak

The same feature that makes baggage useful, that it goes everywhere, makes it risky. Everything in the bag is sent to every service that the request calls, and that includes services you do not control.

flowchart LR
    NET["Public Internet"] --> ED["Edge: validate or strip incoming baggage"]
    ED --> IS["Internal Services share baggage"]
    IS --> TP["Third-party API: send no baggage"]
    IS --> DB["Internal database or queue"]
    IS --> LG["Logs and proxies may record headers"]
Figure 7: Baggage should be controlled where it enters and where it leaves your systems

The places a bag can leak

Outbound

Third-party calls

If your service calls an outside company, an instrumented client may attach your baggage header to that call. The outsider can now read whatever is in it.

Records

Proxies and logs

Gateways, load balancers, and debugging tools sometimes record request headers. A baggage entry can end up stored in places you never planned.

Plain text

No encryption by itself

Baggage is readable text. Only the connection, such as encryption in transit, protects it on the wire.

Telemetry

Copy to spans and logs

When baggage is copied onto telemetry, any sensitive value becomes visible to everyone who can view traces and logs.

Browsers

Calls from front-end code

If browser code adds baggage to its requests, users can see and change it. Never trust or place secrets in baggage that starts in a browser.

Spread

Reach grows with the system

Each new service that joins the call chain gets to read the baggage. A harmless entry today may be read by a very different team next year.

How to stop the leaks

  • Put only safe, non-secret, non-personal values into baggage. Treat it as public inside your company.
  • Configure clients so that baggage and trace headers are sent only to hosts you trust, not to arbitrary outside addresses.
  • Use encrypted connections between all services.
  • Use an allowed list when copying baggage to telemetry.
  • Review proxies and logging settings so that baggage is not recorded where it should not be.
Everyday Analogy

A luggage tag can be read by every porter, every guard, and every curious stranger at every airport. You would write your destination on it, but not your bank PIN. Think of baggage tags as visible to the whole journey.

!
Watch Out

The most common leak is the outbound call to a third party. Check what headers your HTTP clients send to outside addresses, and stop baggage from leaving your trusted boundary.

18Security, Part Two: Never Trust the Bag You Receive

Leaks are about what goes out. The other half of the story is what comes in. Anyone can send a request with any baggage header they like.

Forged baggage

A caller outside your company can simply add a header such as “customer tier equals premium” to their request. If your services believe it, a free user could receive premium treatment, higher limits, or access to features. Baggage is information that arrived with the request. It is not proof that the information is true.

Forgery

Fake entries

Attackers can invent entries to unlock behavior that depends on them. Never use baggage alone for permission or pricing decisions.

Overload

Huge headers

An attacker can send an enormous baggage header to slow your services or trigger errors. Set limits at the edge.

Pollution

Junk in telemetry

If you copy incoming baggage to spans, an attacker can fill your data with random keys and values, making searches useless and storage costly.

Injection

Unsafe values

A value may contain text meant to confuse tools, such as control characters or very long strings. Treat values as untrusted input.

Protective habits

  • Strip or replace at the edge. At the public boundary, remove incoming baggage from unknown callers, and set your own entries from trusted sources, such as your login system.
  • Use an allowed list on read. Services read only the keys they expect, and ignore the rest.
  • Validate values. Accept only known values, such as the three allowed tiers, and ignore anything else.
  • Keep decisions out of baggage. For permissions and billing, look up the real value from a trusted system.
  • Cap size. Reject or trim baggage that is too large.
Everyday Analogy

Imagine a nightclub where a guest can show up wearing a wristband that says “VIP”. The doorman does not simply believe it. He checks his own list. Services should treat a baggage entry that says “premium” the same way, as a claim to be checked and not a fact to be trusted.

i
Tip

A simple rule works well: baggage may describe, but it may never authorize. Use it to label and to route telemetry, not to decide who is allowed to do what.

19Monitoring and Governing Your Baggage

Because baggage is invisible by default, it is easy to lose control of it. A little governance keeps it healthy.

Keep an inventory

Maintain a short shared list that records every baggage key in use, who owns it, what it means, what values are allowed, and which services read it. Without this list, nobody knows what is inside the bag, and nobody dares remove anything.

KeyOwnerAllowed valuesReadersCopied to telemetry?
customer.tierIdentity teamfree, standard, premiumPayment, recommendationsSpans and metrics
experiment.groupGrowth teamGroup names from the experiment toolRecommendations, searchSpans and logs
client.platformMobile teamios, android, webAll servicesSpans and metrics
traffic.syntheticPlatform teamtrue or absentAll servicesSpans

What to measure

Size

Header size

Track the typical and maximum size of the baggage header at gateways. Alert on sudden growth.

Keys

Unknown keys

Count how often keys outside the inventory appear. Spikes may indicate misuse or an attack.

Drops

Missing expected entries

If a service expects an entry and it is often missing, propagation may be broken somewhere.

Cost

Telemetry labels

Watch the number of distinct values of any baggage-derived label in metrics.

i
Good to Know

Because baggage is not telemetry, you only see its health indirectly, through header sizes at proxies and through the attributes you copy. Plan these measures on purpose, instead of hoping to discover problems.

20Configuration: Turning Baggage On, Off, and Narrow

Baggage works only when the right propagator is set up. A few settings decide whether it flows, and where.

The propagators setting

OpenTelemetry has a standard environment variable named OTEL_PROPAGATORS, which lists the propagators that the SDK should use. A common default is to use both the trace context propagator and the baggage propagator. If baggage is missing from the list, the SDK will not write or read the baggage header, even if your code sets entries.

SettingEffect on baggage
Trace context and baggage both listedBoth trace identity and baggage travel
Only trace context listedTraces connect, but baggage does not cross services
Only baggage listedBaggage travels, but traces break at service borders
No propagatorsNothing crosses service borders

Narrowing where it goes

  • Many HTTP client instrumentations let you limit the hosts that receive propagation headers, so outside addresses get nothing.
  • You can configure a gateway or proxy to remove the baggage header from outbound calls to specific destinations.
  • You can build the bag for a particular call, leaving out entries that the destination should not see.

Consistency across the fleet

Every service in a call chain needs the same propagator choices. If service A writes baggage but service B does not read it, the entries stop at B and the services after it never see them. Agree on one setup, and apply it through shared configuration, container images, or platform defaults, so each team does not have to remember.

Everyday Analogy

It is like a relay race where every runner must use the same baton shape. If one runner switches to a different baton, the handover fails, and the rest of the team never receives it. Shared configuration keeps the baton the same for everyone.

i
Tip

Include one test in your deployment checks that sends a request with a known baggage entry through your main path, and verifies that the last service sees it.

21Advantages, Disadvantages, and Trade-offs

Baggage is simple and powerful, and it carries real risks. A fair view includes both sides.

Advantages

  • Shares facts from the front door with every downstream service, without extra lookups.
  • No need to change function signatures or APIs.
  • Works across languages, because the format is a public standard.
  • Lets all services label telemetry with the same business facts.
  • Independent of tracing, so it works even when tracing is off.
  • Simple API with four basic moves.

Disadvantages

  • Adds bytes and processing to every call.
  • Visible to every service in the chain, including outsiders if not controlled.
  • Can be forged by any caller, so it cannot be trusted for decisions.
  • Does not reach telemetry unless you copy it.
  • Lost easily when context is not carried across threads and queues.
  • Without governance, becomes a messy shared storage with unclear owners.

Decisions to make on purpose

DecisionChoose the first whenChoose the second when
Baggage or lookup in a serviceThe fact is small, safe, and needed by many servicesThe fact is sensitive, large, or changes often
Copy to all spans or fewYou need to search across every service by the labelYou only need it at a few key spans, to save cost
Strip at the edge or acceptCallers are the public or unknown partnersAll callers are inside your trust boundary
Baggage or span attributeOther services must see itOnly the current step matters

22Design Patterns and Anti-patterns

Teams that use baggage for years find the same good habits, and the same traps.

Patterns worth copying

Pattern

Set once at the edge

One component, such as the gateway, owns writing the standard entries from trusted sources.

Pattern

Allowed list on both sides

Only known keys are copied to telemetry, and only known keys are read by services.

Pattern

Shared helper library

One small library handles setting, reading, validating, and removing entries, so teams do not each invent their own.

Pattern

Key inventory

A short list shows who owns each key, its meaning, allowed values, and who reads it.

Pattern

Trim before third parties

Outbound calls to outside services use a clean bag with no entries at all.

Pattern

Low-variety labels for metrics

Only entries with a few possible values become metric labels.

Anti-patterns to avoid

ANTI-PATTERN 01Avoid
The Mistake

Using baggage to carry user IDs, emails, or tokens so that “every service knows who the user is”.

Why It Hurts

Personal data and secrets spread to every service, every log that records headers, and every outside system you call. A single leak affects everything.

Do This Instead

Pass identity through a proper authentication token, and let services look up what they need from a trusted system.

ANTI-PATTERN 02Avoid
The Mistake

Making access or billing decisions based on a baggage entry, such as granting premium limits when baggage says “premium”.

Why It Hurts

Any caller can send that header. The decision can be forged by anyone who knows the key name.

Do This Instead

Decide using a trusted source. Use baggage only for labeling and diagnostics.

ANTI-PATTERN 03Avoid
The Mistake

Copying every baggage entry onto every span, log, and metric without a list.

Why It Hurts

Telemetry fills with junk and sensitive values, metric costs explode, and a malicious caller can pollute your data at will.

Do This Instead

Copy only a short allowed list of safe keys, and only the low-variety ones to metrics.

23Best Practices and Common Mistakes

Keep this short list close. It prevents most of the trouble that teams meet with baggage.

1

Decide what is allowed

Write down a short list of keys, with owners and meanings, before the first service uses baggage.

2

Set at the edge from trusted sources

Create entries where the facts are certain, such as after authentication, and not from incoming headers.

3

Keep it small

Use few entries with short values, and remove entries once they are no longer useful.

4

Never store secrets or personal data

Treat the bag as readable by every service and by outsiders if it leaks.

5

Copy to telemetry deliberately

Use an allowed list and copy only what you will query. Keep only low-variety values on metrics.

6

Control the exits

Stop baggage from leaving your trust boundary in calls to outside services.

7

Test the full path

Send a request with a test entry and verify it arrives at the last service, through queues and threads.

Common mistakes and their fixes

MistakeWhat you will seeFix
Baggage propagator not enabledValues set in one service never reach the nextAdd it to the propagators setting on both sides
New bag built but not made currentOutgoing calls miss the new entryPlace the new bag into the context and make it current
Expecting baggage in tracesSearches by the key find nothingCopy selected entries onto spans
Baggage lost across threadsEntries present in some code paths but not othersCarry the context into workers and callbacks
Oversized headersRequests rejected, or entries silently droppedTrim the bag, and check proxy limits
Trusting incoming entriesWrong behavior, or forged privilegesValidate at the edge, and never decide permissions from baggage
Leaking to third partiesInternal facts visible to outsidersLimit which hosts receive propagation headers

24Troubleshooting: Why Did My Baggage Not Arrive?

When an entry is missing downstream, follow the path of the header from the point where it was set to the point where it should have been read.

1

Was it really set?

Check that the code built a new bag, placed it in the context, and made it current before the outgoing call.

2

Is the propagator enabled on the sender?

Confirm that the propagators setting includes baggage in the sending service.

3

Is the header on the wire?

Look at a request in a proxy log or a debugging tool, and check that the baggage header is present and not empty.

4

Did a hop remove it?

Gateways, load balancers, and security tools can strip unknown or oversized headers. Check each hop’s rules.

5

Is the receiver extracting it?

Confirm that the receiving service has the baggage propagator enabled, and that its server instrumentation is active.

6

Is the reading code in the right place?

Reading in a background thread that lost the context will show nothing, even if the header arrived.

SymptomLikely causeWhat to try
Entry never leaves the first servicePropagator missing, or bag not currentCheck the propagators setting and the scope
Entry reaches some services but not othersOne hop strips the header, or one service has no propagatorCompare headers before and after each hop
Entry arrives but reads as empty in some codeContext lost in a thread or callbackCarry the context into the worker
Entry present in baggage, absent in tracesNothing copies it to spansAdd a span processor with an allowed list
Entries cut off or missingSize limits reachedReduce entries and value lengths
Strange values from outsideIncoming baggage not validatedStrip or validate at the edge
i
Tip

Test with a fake entry that nobody else uses, such as a unique test key, so you can search for it across logs and headers without confusion.

25Real-World and Industry Examples

First, a made-up story that shows baggage at work. Then, a look at the common ways organizations use the same idea.

An illustrative story: the slow free trial

Imagine a video service where users on a free trial complain that videos start slowly. Dashboards show healthy averages, because most users are paying customers. The gateway begins to set a baggage entry for the plan, and every service copies it onto its spans using an allowed list. A week later the team groups the startup span by plan, and sees that free-trial requests wait in a shared queue behind a heavy background job. The fix is a separate queue. Without the entry traveling to every service, the queue service could not have told free requests from paid ones. (This is a made-up example to show the workflow, not a report from a real company.)

Experiments and feature flags

Teams that run experiments often need all services to know which variant a request belongs to, so that each service’s telemetry can be compared fairly. Passing the experiment name in baggage is a common way to do this, using the same standard header across languages.

Marking test and synthetic traffic

Platform teams frequently mark traffic from load tests and health checks, so that dashboards and alerts can ignore it. A baggage entry set at the test tool can reach every service in the path with no code changes in those services beyond reading the label.

Multi-tenant platforms

In systems that serve many customers from the same services, a tenant name carried in baggage lets each service label its telemetry per tenant, helping teams to find which tenant causes load or errors. Because tenant names can be sensitive, access to such telemetry is usually restricted.

The standards behind it

Baggage follows a W3C standard header, which means different tools, languages, and vendors can read and write it in the same way. This is the same approach as the trace context header, and it is why a gateway in one language, a service in another, and a proxy from a third vendor can all take part in carrying the same bag.

26Architecture and Components Involved in Baggage

Baggage is not one single box. It is a small team of parts, each with one clear job. Naming them helps you find the part that failed.

Your code

The baggage API

The small interface your code calls to set, read, and remove entries. It holds no network logic.

Storage

The context

The invisible package that holds the current bag for the running flow of code, next to the active span.

Carrier

The propagator

Writes the bag into outgoing messages and rebuilds it from incoming ones, using the standard header format.

Transport

Client and server instrumentation

Hooks inside HTTP, gRPC, and messaging libraries that call the propagator automatically at the right moments.

Bridge

Span or log processors

Optional parts that copy chosen bag entries onto spans and logs, so they appear in your data.

Guard

Gateways and proxies

Components at the borders of your system that can validate, trim, or strip baggage headers.

Settings

Propagator configuration

The list of enabled propagators, usually set by an environment variable or a startup option.

Read

Receiving code

Any code in a downstream service that asks the API for an entry and acts on it.

Everyday Analogy

Think of an airport baggage system. A traveler fills in the tag (your code and the API). The tag sits on the bag (the context). Conveyor belts and loaders move the bag from plane to plane (propagators and instrumentation). Security staff at the borders may open and check bags (gateways). Each part has one job, and a missing bag usually means one part did not do its job.

i
Tip

When baggage fails, ask which part is missing: the API call, the context, the propagator, the transport hook, or the reading code. The answer is almost always one of these five.

27Data Flow and Lifecycle of a Bag

Every bag has a life: it is made, it travels, it changes, and it ends. Knowing the stages makes it easier to reason about what a given service will see.

1

Birth at the edge

A request arrives. The first service decides which trusted facts to put in the bag, and builds it.

2

Activation

The bag is placed in the context and made current, so code and outgoing calls can see it.

3

Departure

On each outgoing call, the propagator writes the current bag into the message. Each branch receives its own copy.

4

Arrival

The receiving service extracts the bag into its own context. Its code can read the entries.

5

Change along the way

A service may add, replace, or remove entries. Because bags are unchangeable, it builds a new bag, and only the calls made from that point onward carry the change.

6

Optional copying to telemetry

Processors copy allowed entries onto spans and logs, where they live on after the request is over.

7

End of life

When the request finishes, the context ends and the bag disappears. Nothing is stored unless you copied it to telemetry.

Where the data is stored

The bag itself lives only in memory and in headers while the request is alive. It is not saved to any database by OpenTelemetry. This is good news for privacy, because there is no hidden store. The only lasting copies are the ones you create by copying entries to spans, logs, or metrics, and the ones recorded by proxies or tools that log headers.

i
Good to Know

Think of baggage as a message in transit. It exists only on the road, and what you keep from it is what you deliberately copy.

28Baggage Together with Sampling, Flags, and Routing

Because baggage sits in the context, other parts of the SDK that look at the context can use it. This opens clever uses, and some warnings.

Sampling decisions

A sampler decides which traces to keep. In several SDKs, the sampler receives the parent context when a span starts. A custom sampler could read a baggage entry such as a debug marker, and decide to always keep traces for requests that carry it. This is useful for a support engineer who wants to see one specific request in full detail. Use it carefully, because anyone who can send the header can force sampling, which raises your telemetry volume and cost.

Feature flags and experiments

A feature flag is a switch that turns a feature on for some users. Many flag systems already provide their own evaluations, so you rarely need baggage to hold the flag itself. But carrying the name of an experiment variant in baggage is a good way to label telemetry. Each service stays free to look up the flag, and the label lets you compare the results across the whole request.

Routing and decisions

Some teams use baggage to hint at routing, such as sending test traffic to a test database. Be careful. Since the header can be forged, a hint in baggage can be misused to reach systems that should not be reachable. Make sure that the final decision is enforced by a trusted component, and treat baggage as a suggestion that is checked.

UseValueRiskSafeguard
Force sampling of a debug requestSee one request in full detailCallers can inflate your data volumeAllow only from trusted callers, and rate limit
Label experiment variantCompare results across all servicesFake variants pollute dataValidate against known names
Mark test trafficKeep dashboards cleanReal traffic marked as test hides real problemsSet the marker only from trusted tools
Route to a test systemSafe testing in productionMisrouted real traffic or access to test dataEnforce the routing in a trusted component
Everyday Analogy

A luggage tag that says “priority” may speed a bag through the airport. But if anyone could print “priority” tags at home, the airline would need to check them against its own records. A hint in baggage deserves the same quiet check.

!
Watch Out

Every clever use of baggage for control, such as sampling, routing, or limits, creates a new thing that an attacker can try to flip. For each use, ask what happens if a stranger sets the entry.

29Frequently Asked Questions

Quick answers to the questions people ask most often about baggage.

Q1What is baggage in OpenTelemetry in one sentence?
Baggage is a small set of key and value pairs that travels with a request across service borders, so that every service can read facts set earlier in the request.
Q2Is baggage the same as span attributes?
No. Span attributes describe one span and stay on it. Baggage travels to other services but does not appear on spans unless you copy it there.
Q3Does baggage show up in my traces automatically?
No. You need a step that copies chosen entries from baggage onto spans, such as a baggage span processor with an allowed list, or code that does it by hand.
Q4Does baggage need tracing to work?
No. Baggage is independent of tracing. It rides in the context and is carried by its own propagator, so it works even when no spans are created.
Q5How does baggage cross the network?
Through a standard header called baggage for HTTP, and through metadata or message headers for gRPC and queues. A propagator writes it on the way out and reads it on the way in.
Q6Can I put a user ID or an email in baggage?
You should not. Baggage goes to every service the request visits, may be recorded by proxies, and can leak to outside companies. Keep personal data and secrets out of it.
Q7Can I use baggage to decide who is allowed to do something?
No. Anyone can send a baggage header, so it can be forged. Use it for labeling and diagnostics, and use a trusted source for permissions.
Q8Why does my entry disappear after a few services?
Common causes are a proxy that strips the header, a service without the baggage propagator, context lost in a thread or callback, or size limits that dropped the entry.
Q9Does baggage flow back to the caller in the response?
No. Baggage flows downward along the direction of calls. To send information back, use the response itself.
Q10How big can baggage be?
The standard sets minimum limits of roughly dozens of entries and a few kilobytes. Proxies may have stricter header limits. Keep the bag small, since it is added to every call.
Q11Where should baggage be set?
At the edge of your system, such as the gateway or first service, from trusted sources. Entries set later reach only the services that are called after that point.

30Summary and Key Takeaways

You started with a suitcase and a few tags. You now know how that picture maps onto requests, services, and the real risks of carrying a bag everywhere.

Key Takeaways

  • Baggage is a small bag of labels that travels with a request. It is a set of key and value pairs held in the context, written into messages on the way out, and read back on the way in.
  • It is not telemetry. Baggage does not appear on spans, logs, or metrics unless something copies selected entries there. Use an allowed list when you do.
  • It is different from its neighbors. Trace context identifies the request, span attributes describe one step, resource attributes describe the service, and baggage shares chosen facts with every downstream service.
  • Propagators make it travel. The baggage propagator must be enabled on both sides. In HTTP, the standard baggage header carries it, and it flows only downward along the calls.
  • Keep it small. Every entry is repeated on every call, so a few short entries are enough. Ten small entries on 100,000 calls per second add up to about 40 megabytes per second.
  • Treat it as readable by everyone. Never store secrets or personal data, and stop baggage from leaving your trust boundary toward third parties.
  • Never trust it for decisions. Any caller can forge baggage. Validate or strip incoming entries at the edge, and keep permissions and billing in trusted systems.