Snippet

Copy only trusted baggage onto spans

A complete OpenTelemetry processor that tags child spans with your own conversation ID and ignores whatever the caller sent.

csharpOct 6, 2026MIT

AI-generated, human-reviewed: the first draft was generated by an AI agent; I fact-checked, tested, and edited it. AI use policy

What it does#

Copies one server-generated baggage entry, gen_ai.conversation.id, onto child spans as a tag, so every span of a conversation can be found by its ID. It skips the incoming request span, because any baggage there came from the caller and is untrusted. The API setup clears caller baggage at the request boundary; any later baggage is generated by the server.

You need#

Where it goes#

Add the file to your API project and register it with .AddProcessor(new ConversationBaggageProcessor()).

ConversationBaggageProcessor.cs
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Sarang Datye
using System.Diagnostics;
using OpenTelemetry;

/// <summary>
/// Copies only the gen_ai.conversation.id baggage entry onto child spans as a tag.
/// Incoming request (server) spans are skipped, because any baggage they see came from the caller.
/// No other baggage entries, and no prompt or response content, are ever copied.
/// </summary>
public sealed class ConversationBaggageProcessor : BaseProcessor<Activity>
{
    public const string BaggageKey = "gen_ai.conversation.id";

    public override void OnStart(Activity activity)
    {
        // An incoming request span starts before the endpoint sets the baggage, so any value seen
        // here came from the caller's baggage header: untrusted text that must not become span data.
        if (activity.Kind == ActivityKind.Server)
        {
            return;
        }

        var conversationId = activity.GetBaggageItem(BaggageKey);
        if (!string.IsNullOrEmpty(conversationId))
        {
            activity.SetTag(BaggageKey, conversationId);
        }
    }
}

Check that it works#

Send a request with a baggage: gen_ai.conversation.id=anything header. The request span has no gen_ai.conversation.id tag; the agent’s child spans have the server-generated ID your API set.