OpenTelemetry baggage lets a service attach a small key-value item to the active context and send it with an outgoing request. Propagating a safe value such as a tenant or routing hint makes the same context available to downstream code without adding a custom application parameter to every function call.
A direct Python implementation uses the W3C baggage propagator to write the baggage HTTP header on the sending side and read it on the receiving side. Framework instrumentation often handles propagation automatically, but the manual path is useful for custom clients, workers, and transport wrappers where the request headers are assembled in application code.
Baggage travels as request metadata and may cross a trust boundary when a service calls another service. Use bounded values that are safe to disclose, avoid credentials and personal data, and copy baggage into span attributes or logs only when receiving code explicitly needs that value.
$ python3 -m venv baggage-demo
$ . baggage-demo/bin/activate
$ python -m pip install opentelemetry-api ##### snipped ##### Successfully installed opentelemetry-api-1.38.0
from http.server import BaseHTTPRequestHandler, HTTPServer from opentelemetry import baggage from opentelemetry.baggage.propagation import W3CBaggagePropagator class Handler(BaseHTTPRequestHandler): def do_GET(self): carrier = {"baggage": self.headers.get("baggage", "")} context = W3CBaggagePropagator().extract(carrier) tenant = baggage.get_baggage("tenant", context=context) or "missing" body = f"downstream baggage tenant={tenant}\n".encode() self.send_response(200) self.send_header("Content-Type", "text/plain") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) def log_message(self, format, *args): return HTTPServer(("127.0.0.1", 8080), Handler).serve_forever()
The explicit carrier keeps the key as baggage, which is what the default text-map getter reads from a plain Python dictionary.
from urllib.request import Request, urlopen from opentelemetry import baggage from opentelemetry.baggage.propagation import W3CBaggagePropagator context = baggage.set_baggage("tenant", "acme-retail") headers = {} W3CBaggagePropagator().inject(headers, context=context) print(f"outgoing baggage header: {headers['baggage']}") request = Request("http://127.0.0.1:8080/orders", headers=headers) with urlopen(request, timeout=5) as response: print(response.read().decode().strip())
Do not put access tokens, email addresses, or other personal data in baggage. Automatic instrumentation may forward baggage on service requests where headers are visible to another team or vendor.
$ . baggage-demo/bin/activate
$ python downstream.py
The service listens on 127.0.0.1:8080 and keeps the terminal open until it is stopped.
$ python send_request.py outgoing baggage header: tenant=acme-retail downstream baggage tenant=acme-retail
Ctrl+C
$ rm -r baggage-demo downstream.py send_request.py