Langfuse joins ClickHouse! Learn more →
DocsObservabilityFeaturesMetadata

Metadata

Observations (see Langfuse Data Model) can be enriched with metadata to help you better understand your application and to correlate observations in Langfuse.

You can filter by metadata keys in the Langfuse UI and API.

Propagated Metadata

Use propagate_attributes() to ensure metadata is automatically applied to all observations within a context. Propagated metadata are key-value pairs with values limited to max 200 characters strings. Keys are limited to alphanumeric characters only. If a metadata value exceeds 200 characters, it will be dropped.

When using the @observe() decorator:

from langfuse import observe, propagate_attributes

@observe()
def process_data():
    # Propagate metadata to all child observations
    with propagate_attributes(
        metadata={"source": "api", "region": "us-east-1", "user_tier": "premium"}
    ):
        # All nested observations automatically inherit this metadata
        result = perform_processing()
        return result

When creating observations directly:

from langfuse import get_client, propagate_attributes

langfuse = get_client()

with langfuse.start_as_current_observation(as_type="span", name="process-request") as root_span:
    # Propagate metadata to all child observations
    with propagate_attributes(metadata={"request_id": "req_12345", "region": "us-east-1"}):
        # All observations created here automatically have this metadata
        with root_span.start_as_current_observation(
            as_type="generation",
            name="generate-response",
            model="gpt-4o"
        ) as gen:
            # This generation automatically has the metadata
            pass

When using the context manager:

import { startActiveObservation, propagateAttributes } from "@langfuse/tracing";

await startActiveObservation("context-manager", async (span) => {
  span.update({
    input: { query: "What is the capital of France?" },
  });

  // Propagate metadata to all child observations
  await propagateAttributes(
    {
      metadata: { source: "api", region: "us-east-1", userTier: "premium" },
    },
    async () => {
      // All observations created here automatically have this metadata
      // ... your logic ...
    }
  );
});

When using the observe wrapper:

import { observe, propagateAttributes } from "@langfuse/tracing";

const processData = observe(
  async (data: string) => {
    // Propagate metadata to all child observations
    return await propagateAttributes(
      { metadata: { source: "api", region: "us-east-1" } },
      async () => {
        // All nested observations automatically inherit this metadata
        const result = await performProcessing(data);
        return result;
      }
    );
  },
  { name: "process-data" }
);

const result = await processData("input");

See JS/TS SDK docs for more details.

from langfuse import get_client, propagate_attributes
from langfuse.openai import openai

langfuse = get_client()

with langfuse.start_as_current_observation(as_type="span", name="openai-call"):
    # Propagate metadata to all observations including OpenAI generation
    with propagate_attributes(
        metadata={"source": "api", "region": "us-east-1"}
    ):
        completion = openai.chat.completions.create(
            name="test-chat",
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "You are a calculator."},
                {"role": "user", "content": "1 + 1 = "}
            ],
            temperature=0,
        )
import OpenAI from "openai";
import { observeOpenAI } from "@langfuse/openai";
import { startActiveObservation, propagateAttributes } from "@langfuse/tracing";

await startActiveObservation("openai-call", async () => {
  // Propagate metadata to all observations
  await propagateAttributes(
    {
      metadata: { source: "api", region: "us-east-1" },
    },
    async () => {
      const res = await observeOpenAI(new OpenAI()).chat.completions.create({
        messages: [{ role: "system", content: "Tell me a story about a dog." }],
        model: "gpt-3.5-turbo",
        max_tokens: 300,
      });
    }
  );
});
from langfuse import get_client, propagate_attributes
from langfuse.langchain import CallbackHandler

langfuse = get_client()
langfuse_handler = CallbackHandler()

with langfuse.start_as_current_observation(as_type="span", name="langchain-call"):
    # Propagate metadata to all child observations
    with propagate_attributes(
        metadata={"foo": "bar", "baz": "qux"}
    ):
        response = chain.invoke(
            {"topic": "cats"},
            config={"callbacks": [langfuse_handler]}
        )
import { startActiveObservation, propagateAttributes } from "@langfuse/tracing";
import { CallbackHandler } from "langfuse-langchain";

const langfuseHandler = new CallbackHandler();

// Propagate metadata to all child observations
await propagateAttributes(
  {
    metadata: { key: "value" },
  },
  async () => {
    await chain.invoke(
      { input: "<user_input>" },
      { callbacks: [langfuseHandler] }
    );
  }
);

You can set the metadata via the override configs, see the Flowise Integration docs for more details.

Note on Attribute Propagation
We use Attribute Propagation to propagate `metadata` across all observations of a trace. We will use all observations with `metadata` to create `metadata`-level metrics. Please consider the following when using Attribute Propagation:
  • Values must be strings ≤200 characters
  • Metadata keys: Alphanumeric characters only (no whitespace or special characters)
  • Call early in your trace to ensure all observations are covered. This way you make sure that all Metrics in Langfuse are accurate.
  • Invalid values are dropped with a warning

Non-Propagated Metadata

You can also add metadata to specific observations only:

# Python SDK
from langfuse import get_client

langfuse = get_client()

with langfuse.start_as_current_observation(as_type="span", name="process-request") as root_span:
    # Add metadata to this specific observation only
    root_span.update(metadata={"stage": "parsing"})

    # ... or access span via the current context
    langfuse.update_current_span(metadata={"stage": "parsing"})
// TypeScript SDK
import {
  startActiveObservation,
  updateActiveObservation,
} from "@langfuse/tracing";

await startActiveObservation("process-request", async (span) => {
  // Add metadata to this specific observation only
  span.update({
    metadata: { stage: "parsing" },
  })

  // ... or access span via the current context
  updateActiveObservation({
    metadata: { stage: "parsing" },
  });
});

GitHub Discussions


Was this page helpful?