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

# Set Up Sessions

> Group related traces into sessions and track user identity across conversations

Conversations, not one-offs. Real users have multi-turn interactions where context across turns matters — sessions group those traces together so you can see the full conversation as a single unit.

# What are Sessions?

A **session** is a grouping of related traces. In a chatbot, each turn generates its own trace. Tag them with the same `session.id` and you can view the full conversation as one unit — spot where things went wrong across turns, identify when users become frustrated, and run session-level evaluations.

Arize AX tracks per session: duration, trace count, total prompt tokens, total completion tokens, and total tokens.

<Frame>
  <img src="https://storage.googleapis.com/arize-phoenix-assets/assets/images/arize-docs-images/instrument/session_id.png" alt="Sessions view in Arize AX showing session duration, trace count, and token usage" />
</Frame>

# Add Session ID

Adding `session.id` to your spans enables back-and-forth interactions to be grouped. The session ID must be a non-empty string.

<Tabs>
  <Tab title="Python">
    Use `using_session` as a context manager to add session ID to the current OpenTelemetry Context. OpenInference auto [instrumentors](https://github.com/Arize-ai/openinference/tree/main/python/instrumentation) will read this Context and pass the session ID as a span attribute, following the OpenInference [semantic conventions](https://github.com/Arize-ai/openinference/tree/main/python/openinference-semantic-conventions).

    ```python theme={null}
    from openinference.instrumentation import using_session

    with using_session(session_id="my-session-id"):
        # Calls within this block will generate spans with the attributes:
        # "session.id" = "my-session-id"
        ...
    ```

    It can also be used as a decorator:

    ```python theme={null}
    @using_session(session_id="my-session-id")
    def call_fn(*args, **kwargs):
        # Calls within this function will generate spans with the attributes:
        # "session.id" = "my-session-id"
        ...
    ```
  </Tab>

  <Tab title="JS/TS">
    Use the `setSession` function with [`context.with`](https://opentelemetry.io/docs/languages/js/context/#set-active-context) to set the active context. OpenInference [auto instrumentations](/ax/integrations) will then pick up these attributes and add them to any spans created within the `context.with` callback.

    ```bash theme={null}
    npm install --save @arizeai/openinference-core @opentelemetry/api
    ```

    ```typescript theme={null}
    import { context } from "@opentelemetry/api"
    import { setSession } from "@arizeai/openinference-core"

    context.with(
      setSession(context.active(), { sessionId: "session-id" }),
      () => {
          // Calls within this block will generate spans with the attributes:
          // "session.id" = "session-id"
      }
    )
    ```
  </Tab>
</Tabs>

Often you'll want to know *who* the session belongs to as well:

# Add User ID

Adding `user.id` associates traces with a specific user. The user ID must be a non-empty string.

<Tabs>
  <Tab title="Python">
    Use `using_user` as a context manager to add user ID to the current OpenTelemetry Context.

    ```python theme={null}
    from openinference.instrumentation import using_user

    with using_user("my-user-id"):
        # Calls within this block will generate spans with the attributes:
        # "user.id" = "my-user-id"
        ...
    ```

    It can also be used as a decorator:

    ```python theme={null}
    @using_user("my-user-id")
    def call_fn(*args, **kwargs):
        # Calls within this function will generate spans with the attributes:
        # "user.id" = "my-user-id"
        ...
    ```
  </Tab>

  <Tab title="JS/TS">
    Use the `setUser` function with `context.with`:

    ```typescript theme={null}
    import { context } from "@opentelemetry/api"
    import { setUser } from "@arizeai/openinference-core"

    context.with(
      setUser(context.active(), { userId: "user-id" }),
      () => {
          // Calls within this block will generate spans with the attributes:
          // "user.id" = "user-id"
      }
    )
    ```
  </Tab>
</Tabs>

Setting session and user one at a time works, but most apps need both. The `using_attributes` helper combines them:

# Framework-Specific Examples

Use `using_attributes` to set session and user IDs together with any supported framework.

<Tabs>
  <Tab title="OpenAI">
    <Info>
      Requires `pip install openinference-instrumentation-openai`
    </Info>

    ```python theme={null}
    import openai
    from openinference.instrumentation import using_attributes

    client = openai.OpenAI()

    # Set session and user together
    with using_attributes(
        session_id="my-session-id",
        user_id="my-user-id",
    ):
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": "Write a haiku."}],
            max_tokens=20,
        )
    ```

    Can also be used as a decorator:

    ```python theme={null}
    @using_attributes(session_id="my-session-id", user_id="my-user-id")
    def call_fn(client, *args, **kwargs):
        return client.chat.completions.create(*args, **kwargs)
    ```
  </Tab>

  <Tab title="LangChain">
    <Info>
      Requires `pip install openinference-instrumentation-langchain`
    </Info>

    ```python theme={null}
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_openai import ChatOpenAI
    from openinference.instrumentation import using_attributes

    prompt = ChatPromptTemplate.from_template("Tell me a {adjective} joke")
    llm = ChatOpenAI(model="gpt-4o-mini")
    chain = prompt | llm

    with using_attributes(
        session_id="my-session-id",
        user_id="my-user-id",
    ):
        response = chain.invoke({"adjective": "funny"})
    ```
  </Tab>

  <Tab title="LlamaIndex">
    <Info>
      Requires `pip install openinference-instrumentation-llama-index`
    </Info>

    ```python theme={null}
    from llama_index.core.chat_engine import SimpleChatEngine
    from openinference.instrumentation import using_attributes

    chat_engine = SimpleChatEngine.from_defaults()

    with using_attributes(
        session_id="my-session-id",
        user_id="my-user-id",
    ):
        response = chat_engine.chat(
            "Say something profound and romantic about fourth of July"
        )
    ```
  </Tab>

  <Tab title="Bedrock">
    <Info>
      Requires `pip install openinference-instrumentation-bedrock`
    </Info>

    ```python theme={null}
    import boto3
    from openinference.instrumentation import using_attributes

    session = boto3.session.Session()
    client = session.client("bedrock-runtime", region_name="us-west-2")

    with using_attributes(
        session_id="my-session-id",
        user_id="my-user-id",
    ):
        response = client.invoke_model(
            modelId="anthropic.claude-3-haiku-20240307-v1:0",
            body=(
                b'{"anthropic_version": "bedrock-2023-05-31", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello there, how are you?"}]}'
            )
        )
    ```
  </Tab>

  <Tab title="MistralAI">
    <Info>
      Requires `pip install openinference-instrumentation-mistralai`
    </Info>

    ```python theme={null}
    from mistralai import Mistral
    from openinference.instrumentation import using_attributes

    client = Mistral()

    with using_attributes(
        session_id="my-session-id",
        user_id="my-user-id",
    ):
        response = client.chat.complete(
            model="mistral-large-latest",
            messages=[
                {"content": "Who won the World Cup in 2018?", "role": "user"}
            ],
        )
    ```
  </Tab>

  <Tab title="DSPy">
    <Info>
      Requires `pip install openinference-instrumentation-dspy`
    </Info>

    ```python theme={null}
    import dspy
    from openinference.instrumentation import using_attributes

    lm = dspy.LM("openai/gpt-4o-mini")
    dspy.configure(lm=lm)

    class BasicQA(dspy.Signature):
        """Answer questions with short factoid answers."""
        question = dspy.InputField()
        answer = dspy.OutputField(desc="often between 1 and 5 words")

    predictor = dspy.Predict(BasicQA)

    with using_attributes(
        session_id="my-session-id",
        user_id="my-user-id",
    ):
        response = predictor(
            question="What is the capital of the united states?"
        )
    ```
  </Tab>
</Tabs>

Once sessions are wired up in your code, you can verify them in the Arize AX UI — but first, if you'd rather not write the code:

# Other Ways to Set Up

Sessions can also be added through an AI coding agent using the [Arize instrumentation skill](https://github.com/Arize-ai/arize-skills), or through Alyx in the Arize AX UI.

<Tabs>
  <Tab title="By Arize Skills">
    Three steps to add sessions with your AI coding agent:

    **Install skill**

    ```bash theme={null}
    npx skills add Arize-ai/arize-skills --skill "arize-instrumentation" --yes
    ```

    **Set up authentication**

    ```bash theme={null}
    export ARIZE_API_KEY="YOUR_API_KEY"
    export ARIZE_SPACE_ID="YOUR_SPACE_ID"
    ```

    **Add sessions**

    ```bash theme={null}
    # Ask your AI coding agent:
    "Add session ID and user ID tracking to my app"
    ```

    Works with Cursor, Claude Code, Codex, and more. The skill picks the right framework helper (`using_session` / `setSession`) and wires it into the right spots.
  </Tab>

  <Tab title="By Alyx">
    Ask **Alyx** for help configuring sessions:

    * *"How do I group traces into sessions?"*
    * *"Show me how to add session IDs with LangChain"*
    * *"What's the best way to track user identity across traces?"*

    <Frame>
      <img src="https://storage.googleapis.com/arize-phoenix-assets/assets/images/arize-docs-images/instrument/session_alyx.png" alt="Alyx in the Arize AX UI explaining how to group traces into sessions using the using_session context manager with a code example" />
    </Frame>
  </Tab>
</Tabs>

Now that sessions are in place, here's what you'll see in Arize AX:

# View Sessions

Once your traces have session IDs attached, head to your project in Arize AX and switch to the **Sessions** view. You'll see each session as a row — click into one to see the full multi-turn conversation with all its traces laid out in order.

For each session, Arize AX shows you:

* **Duration** — how long the conversation lasted
* **Trace count** — how many turns/requests were in the session
* **Token usage** — total prompt, completion, and combined tokens across all traces

This makes it easy to find long, expensive, or problematic conversations and drill into exactly where things went wrong.

<Frame>
  <img src="https://storage.googleapis.com/arize-phoenix-assets/assets/images/arize-docs-images/instrument/view_sessions.png" alt="Session detail view in Arize AX showing total duration, token count, trace list with evals, session coherence evaluation, and a session conversation JSON pane" />
</Frame>

***

## Next step

Sessions are set up. Learn how to combine auto and manual instrumentation for complete trace coverage:

<Card title="Next: Combine Auto + Manual" icon="arrow-right" href="/ax/instrument/combining-auto-and-manual" />
