> ## Documentation Index
> Fetch the complete documentation index at: https://docs.galileo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Tags and Metadata

> Learn to use tags and metadata in Galileo logging and monitoring

{/*<!-- markdownlint-enable MD044 -->*/}

Galileo’s **Tags and Metadata** feature enables teams to label, categorize, and organize model interactions in a structured way.
This structured labeling is essential for building reproducible, observable, and scalable evaluation workflows.

Tags and Metadata provide additional context to your logs and traces.
By adding Tags and Metadata to logged Sessions, Traces, and Spans, teams can:

* Track and compare experiments.
* View a clear timeline of how an agent’s behavior evolves across experiments.
* Track prompt versions and understand how version changes impact performance.

## Overview

**Tags** and **Metadata** are added to logged Sessions, Traces, and Spans.

**Tags** - short, flat labels (strings) you assign to a trace or span to make them easy to group and filter.

* Unlimited number of tags per trace/span (practical limit ≈ 50)
* Case-sensitive strings ≤ 50 chars each
* Ideal for boolean-style filters (e.g., “show me all traces tagged physics”)

**Metadata** - key-value dictionaries that travel with a Trace or a Span, perfect for structured information like user IDs, experiment hashes, timestamps, or numeric metrics.

* Keys and values are strings ≤ 256 chars
* Appears in Log streams as new columns
* Ideal for structured attributes you can filter, group, and aggregate

## Add Tags and Metadata

> **Note:** This guide uses OpenAI as the example LLM. The code snippets are OpenAI-specific,
> especially in how the model response is handled (e.g., `response.choices[0].message.content`).
> If you are using a different LLM or following a different [Log Your First Trace](/getting-started/quickstart),
> the code will differ slightly—each LLM returns responses in its own format. Adjust the code as needed for your provider.
> Follow this step-by-step guide to get started using **Tags and Metadata** in your AI projects.

### Prerequisites

First, follow the [Log Your First Trace](/getting-started/quickstart) guide if you don't already have a Galileo Project set up.

Then, use the following steps to add Tags and Metadata to your logged Traces and Spans to your Project.

<Steps>
  <Step title="Open your Galileo app">
    Open your Galileo application in your code editor.
    In this guide, we are building on top of the **finished demo application** from the
    [Log Your First Trace](/getting-started/quickstart) guide.

    <CodeGroup>
      ```python Python theme={null}
      from datetime import datetime
      from galileo import galileo_context
      from galileo import GalileoLogger
      from galileo.config import GalileoPythonConfig
      import openai
      from dotenv import load_dotenv

      # Load environment variables from the .env file
      load_dotenv()

      # Set the project and Log stream, these are created if they don't exist.
      galileo_context.init(project="MyFirstTagandMetadata",
                           log_stream="MyFirstTagandMetatdata")           
      ```

      ```typescript TypeScript theme={null}
      import { config as dotenvConfig } from "dotenv";
      import { GalileoLogger, init } from "galileo";
      import OpenAI from "openai";

      // Load environment variables from .env file
      dotenvConfig();

      // Set the project and Log stream, these are created if they don't exist.
      init({
        projectName: "MyFirstTagandMetadata",
        logstream: "MyFirstTagandMetatdata"
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Define tags and metadata">
    Create **descriptive tags and metadata** to be attached to your logs.
    Both [Spans](/sdk-api/logging/galileo-logger#add-spans) and
    [Traces](/sdk-api/logging/galileo-logger#start-a-trace)
    can have their own tags and metadata. Define `tags` as a list of relevant labels,
    and `metadata` as a dictionary of label types and their values.
    The individual tag and metadata values must be strings.

    > **Note:** The `answer` variable is set to the raw text output of the
    > model so that it can be used later.

    <CodeGroup>
      ```python Python theme={null}
      answer = response.choices[0].message.content.strip()

      # Define tags and metadata
      tags = ["newton", "test", "new-version"]
      metadata = {"experimentNumber": "1",
                  "promptVersion": "0.0.1",
                  "field": "physics"}
      ```

      ```typescript TypeScript theme={null}
      const answer: string = response.choices[0].message.content.trim();

      // Define tags and metadata
      const tags = ["newton", "test", "new-version"];
      const metadata = {
          experimentNumber: "1",
          promptVersion: "0.0.1",
          field: "physics"
      };
      ```
    </CodeGroup>
  </Step>

  <Step title="Initialize Galileo Logger">
    Initialize logging by importing and calling the **Galileo Logger**.\
    The **Project name** and **Log stream name** are used as inputs to
    define in which Galileo Project and Log stream the logs will be created.\
    After running our application, the logs will appear in the chosen
    Project's Log stream in the [Galileo Console](https://app.galileo.ai/).

    <CodeGroup>
      ```python Python theme={null}
      # Include GalileoLogger in imports
      from galileo import GalileoLogger

      ...application code...

      # Initialize logger
      logger = GalileoLogger()
      ```

      ```typescript TypeScript theme={null}
      // Include GalileoLogger in imports
      import { GalileoLogger } from "galileo";

      ...application code...

      // Initialize logger
      const logger = new GalileoLogger();
      ```
    </CodeGroup>
  </Step>

  <Step title="Initialize new trace">
    Initialize a new [Trace](/sdk-api/logging/galileo-logger#start-a-trace)
    to start listening for data to log.\
    By using the `tags` and `metadata` inputs, important information is
    added to the Trace.

    <CodeGroup>
      ```python Python theme={null}
      # Initialize a new Trace and start listening for logs to add to it
      trace = logger.start_trace(
          input=prompt,
          tags=tags,
          metadata=metadata
      )
      ```

      ```typescript TypeScript theme={null}
      // Initialize a new Trace and start listening for logs to add to it
      const trace = logger.startTrace({
          input: prompt,
          tags: tags,
          metadata: metadata
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Create new span">
    Create a new [Span](/sdk-api/logging/galileo-logger#add-spans) containing
    the data created by running the LLM. By using the `tags` and `metadata` inputs,
    important information is added to the Span.

    > **Note:** In this guide, the tags and metadata used for the Span
    > and the Trace are identical. But, they don't have to be. You can use
    > different tags and metadata for Spans and the Traces they're attached to.

    <CodeGroup>
      ```python Python theme={null}
      # Create a Span to log LLM outputs. This is captured by the Trace
      logger.add_llm_span(
          input=[{"role": "system", "content": prompt}],
          output=response.choices[0].message.content,
          model="gpt-4o",
          tags=tags,
          metadata=metadata
      )
      ```

      ```typescript TypeScript theme={null}
      // Create a Span to log LLM outputs. This is captured by the Trace
      logger.addLlmSpan({
          input: [{ role: "system", content: prompt }],
          output: response.choices[0].message.content,
          model: "gpt-4.1-mini",
          tags: tags,
          metadata: metadata
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Close trace & push logs">
    To close the new Trace and **complete the logging session**,
    we use `logger.conclude()` with the LLM's raw text output as the input.\
    Then, `logger.flush()` pushes the logs to the selected
    Project's [Log stream](/sdk-api/logging/logging-basics).

    <CodeGroup>
      ```python Python theme={null}
      # Close the Trace and push captured logs to it
      logger.conclude(answer)
      logger.flush()
      ```

      ```typescript TypeScript theme={null}
      // Close the Trace and push captured logs to it
      logger.conclude({output: answer});
      logger.flush();
      ```
    </CodeGroup>
  </Step>

  <Step title="Review your code">
    By adding each previous code snippet to your Galileo application,
    it is ready to run and create tags and metadata logs.\
    Below is the **final combined application code** for the
    [Log Your First Trace](/getting-started/quickstart) demo application,
    with our tags and metadata added to logged Traces and Spans.

    <CodeGroup>
      ```python Python theme={null}
      from datetime import datetime
      from galileo import galileo_context
      from galileo import GalileoLogger
      from galileo.config import GalileoPythonConfig
      import openai
      from dotenv import load_dotenv

      # Load environment variables from the .env file
      load_dotenv()

      # Set the project and Log stream, these are created if they don't exist.
      # You can also set these using the GALILEO_PROJECT and GALILEO_LOG_STREAM
      # environment variables.
      galileo_context.init(project="MyFirstTagandMetadata",
                           log_stream="MyFirstTagandMetatdata")

      # Get the Galileo logger instance
      logger = galileo_context.get_logger_instance()

      # Start a Galileo session
      logger.start_session()

      # Initialize the OpenAI client
      client = openai.OpenAI()

      # Define a system prompt with guidance
      system_prompt = f"""
      You are a helpful assistant that wants to provide a user as much
      information as possible. Avoid saying I don't know.
      """

      # Define a user prompt with a question
      user_prompt = f"Explain the following topic succinctly: Newton's First Law"


      # Send a request to the LLM
      response = client.chat.completions.create(
          model="gpt-4o-mini",
          messages=[
              {"role": "system", "content": system_prompt},
              {"role": "user", "content": user_prompt}
          ],
      )

      # Print the response
      print(response.choices[0].message.content.strip())

      answer = response.choices[0].message.content.strip()

      # Define tags and metadata
      tags = ["newton", "test", "new-version"]
      metadata = {"experimentNumber": "1",
                  "promptVersion": "0.0.1",
                  "field": "physics"}


      # Initialize a new Trace and start listening for logs to add to it
      trace = logger.start_trace(
          input=user_prompt,
          tags=tags,
          metadata=metadata
      )

      # Create a span to log LLM outputs. This is captured by the Trace.
      logger.add_llm_span(
          input=[{"role": "system", "content": user_prompt}],
          output=response.choices[0].message.content,
          model="gpt-4o",
          tags=tags,
          metadata=metadata,
      )

      # Close the Trace and push captured logs to it
      logger.conclude(answer)
      logger.flush()

      # Show Galileo information after the response
      config = GalileoPythonConfig.get()
      project_url = f"{config.console_url}project/{logger.project_id}"
      log_stream_url = f"{project_url}/log-streams/{logger.log_stream_id}"

      print()
      print("🚀 GALILEO LOG INFORMATION:")
      print(f"🔗 Project   : {project_url}")
      print(f"📝 Log Stream: {log_stream_url}")
      ```

      ```typescript TypeScript theme={null}
      import { config as dotenvConfig } from "dotenv";
      import { GalileoLogger, init } from "galileo";
      import OpenAI from "openai";

      // Load environment variables from .env file
      dotenvConfig();

      // Set the project and log stream (can also use env vars GALILEO_PROJECT, GALILEO_LOG_STREAM)
      init({
        projectName: "MyFirstTagandMetadata",
        logStreamName: "MyFirstTagandMetatdata"
      });

      // Initialize logger
      const logger = new GalileoLogger();

      async function main() {
        // Start a Galileo session
        await logger.startSession();

        // Initialize the OpenAI client
        const client = new OpenAI();

        // Define a system prompt with guidance
        const systemPrompt = `
      You are a helpful assistant that wants to provide a user as much
      information as possible. Avoid saying I don't know.
      `;

        // Define a user prompt with a question
        const userPrompt = "Explain the following topic succinctly: Newton's First Law";

        // Send a request to the LLM
        const response = await client.chat.completions.create({
          model: "gpt-4o-mini",
          messages: [
            { role: "system", content: systemPrompt },
            { role: "user", content: userPrompt }
          ],
        });

        // Print the response
        const answer: string = response.choices[0].message.content.trim();
        console.log(answer);

        // Define tags and metadata
        const tags = ["newton", "test", "new-version"];
        const metadata = {
          experimentNumber: "1",
          promptVersion: "0.0.1",
          field: "physics"
        };

        // Start a trace and add tags and metadata
        const trace = logger.startTrace({
          input: userPrompt,
          tags,
          metadata
        });

        // Log an LLM span using the response
        logger.addLlmSpan({
          input: [
            { role: "system", content: systemPrompt },
            { role: "user", content: userPrompt }
          ],
          output: answer,
          model: "gpt-4o-mini",
          tags,
          metadata
        });

        // Conclude and flush the logger
        logger.conclude({ output: answer });
        await logger.flush();

        // Show Galileo information after the response
        const galileoConsoleUrl = (process.env.GALILEO_CONSOLE_URL ?? "https://app.galileo.ai").
        replace(/\/+$/, "");
        // @ts-ignore
        const projectUrl = `${galileoConsoleUrl}/project/${logger.client.projectId}`;
        // @ts-ignore
        const logStreamUrl = `${projectUrl}/log-streams/${logger.client.logStreamId}`;

        console.log();
        console.log("🚀 GALILEO LOG INFORMATION:");
        console.log(`🔗 Project   : ${projectUrl}`);
        console.log(`📝 Log Stream: ${logStreamUrl}`);
      }

      main().catch(console.error);

      ```
    </CodeGroup>
  </Step>

  <Step title="Run your application">
    Run your Galileo application.\
    If your application file is named `app`
    (as in the [Log Your First Trace](/getting-started/quickstart) demo),
    you can run it by using the following command in your terminal.

    <CodeGroup>
      ```bash Python theme={null}
      python app.py
      ```

      ```bash TypeScript theme={null}
      npm install tsx
      npx tsx app.ts
      ```
    </CodeGroup>
  </Step>

  <Step title="Open project in Galileo Console">
    In the [Galileo Console](https://app.galileo.ai/), select your Project
    and Log stream in the top-left corner.  For **each time you run your application**,
    you will see a new Trace entry in your Log stream.  Click the
    column icon to open the column selector, and enable the tags and
    metadata keys you created earlier to view them in the Trace table.

    <img src="https://mintcdn.com/v2galileo/edOJut9aCghCY9Pl/sdk-api/logging/tag-and-metadata-column-log-stream.png?fit=max&auto=format&n=edOJut9aCghCY9Pl&q=85&s=6e40ed7bcf66b373a3a5788ee83bbbd1" alt="Tag and MetadataLog stream" width="2818" height="1118" data-path="sdk-api/logging/tag-and-metadata-column-log-stream.png" />
  </Step>

  <Step title="View trace Tags and Metadata">
    Click on an entry in the list.\
    You will see the data logged to the Trace. This includes:

    * The raw text input (because we initialized the Trace with `input=prompt`)
    * The raw text output from the LLM
      (because we closed the Trace with `logger.conclude(answer)`)
    * The tags and metadata we created
      (found in the **Parameters** section in the top-right)

          <img src="https://mintcdn.com/v2galileo/edOJut9aCghCY9Pl/sdk-api/logging/parameters-trace.png?fit=max&auto=format&n=edOJut9aCghCY9Pl&q=85&s=1c6d216f250ed32d5886a416fb0cfa26" alt="Parameters in Trace" width="1913" height="719" data-path="sdk-api/logging/parameters-trace.png" />
  </Step>

  <Step title="View span Tags and Metadata">
    With the Trace open, click the `llm` button below `Trace`
    in the data map on the left.\
    You will see the data logged to the Span. This includes:

    * The complete JSON LLM input
      (because we created the Span with `input=[{"role": "system", "content": prompt}]`)
    * The complete JSON LLM output
      (because we created the Span with `output=response.choices[0].message.content`)
    * The tags and metadata we created
      (found in the **Parameters** section in the top-right)

          <img src="https://mintcdn.com/v2galileo/edOJut9aCghCY9Pl/sdk-api/logging/parameters-span.png?fit=max&auto=format&n=edOJut9aCghCY9Pl&q=85&s=5558d35202148d10f3135766f45266c7" alt=" Parameters in Span" width="1909" height="856" data-path="sdk-api/logging/parameters-span.png" />
  </Step>
</Steps>

## Session metadata

In addition to adding metadata to Traces and Spans, you can also add metadata to [Sessions](/concepts/logging/sessions/sessions-overview). Session metadata allows you to attach structured information like customer IDs, environment names, or application versions at the session level.

To add metadata to a session, pass the `metadata` parameter when starting a session:

<CodeGroup>
  ```python Python theme={null}
  # Start a session with metadata
  session_id = logger.start_session(
      name="My session",
      external_id="chat-1",
      metadata={"brand_id": "acme", "environment": "production"}
  )
  ```

  ```typescript TypeScript theme={null}
  // Start a session with metadata
  const sessionId = await logger.startSession({
    name: "My session",
    externalId: "chat-1",
    metadata: { brand_id: "acme", environment: "production" }
  });
  ```
</CodeGroup>

Session metadata keys and values follow the same rules as Trace and Span metadata:

* Metadata is a flat dictionary (no nested objects or arrays).
* Both keys and values must be strings.
* Each key and value is limited to 256 characters.

<Note>
  Session metadata is visible as columns in the Sessions view. Use the column selector to display specific metadata keys. Session metadata is not currently shown in the Trace detail view.
</Note>

## Best practices

Use **Tags and Metadata** to:

* Keep your [experimentation](/sdk-api/experiments/experiments) process organized.
* Coordinate with your team and track development.
* Track individual steps in your AI project with [Traces](/sdk-api/logging/galileo-logger#start-a-trace) containing multiple [Spans](/sdk-api/logging/galileo-logger#add-spans) that each have their own distinct tags and metadata.
* Use the tag and metadata values in your code to automate alerts and improvements.
* Tag early. Start the trace yourself and pass tags before the first LLM call; otherwise auto-spans may end up in an untagged trace.
* Keep tags coarse-grained. A handful of well-chosen tags beat hundreds of one-offs.
* Standardize metadata keys. Stick to a naming convention (`experiment`, `user_id`, etc.) so dashboards stay tidy.
* Avoid sensitive data. Never put [PII](https://v2docs.galileo.ai/concepts/metrics/safety-and-compliance/pii#pii) or keys in either tags or metadata; they become queryable in the UI.
