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

# LangChain & LangGraph

> Integrate The Context Company with LangChain and LangGraph

<Note>This setup works for both LangChain and LangGraph. The same instrumentation handles both frameworks.</Note>

## Set TCC environment variables

<Tip>Our SDKs default to using the `TCC_API_KEY` environment variable.</Tip>

```bash .env theme={null}
TCC_API_KEY="your-api-key"
```

## Instrument LangChain & LangGraph

<Tabs>
  <Tab title="Python">
    #### Step 1: Install dependencies

    <CodeGroup>
      ```Title pip theme={null}
      pip install "contextcompany[langchain]"
      ```

      ```Title poetry theme={null}
      poetry add "contextcompany[langchain]"
      ```
    </CodeGroup>

    #### Step 2: Add instrumentation

    You'll need to initialize instrumentation **before** LangChain or LangGraph is imported. This is typically at the top of your application's entry point (for example, in `main.py` or `app.py`).

    **LangChain example:**

    ```python main.py theme={null}
    import os
    from dotenv import load_dotenv
    load_dotenv()

    # Import and initialize TCC instrumentation BEFORE importing LangChain
    from contextcompany.langchain import instrument_langchain

    instrument_langchain()

    # Your existing LangChain code
    from langchain_openai import ChatOpenAI
    from langchain.agents import create_openai_functions_agent, AgentExecutor

    model = ChatOpenAI(model="gpt-4")
    agent = create_openai_functions_agent(model, tools=[])
    executor = AgentExecutor(agent=agent, tools=[])
    ```

    **LangGraph example:**

    ```python main.py theme={null}
    import os
    from dotenv import load_dotenv
    load_dotenv()

    # Import and initialize TCC instrumentation BEFORE importing LangGraph
    from contextcompany.langchain import instrument_langchain

    instrument_langchain()

    # Your existing LangGraph code
    from langchain_openai import ChatOpenAI
    from langgraph.prebuilt import create_react_agent

    model = ChatOpenAI(model="gpt-4")
    agent = create_react_agent(model, tools=[])
    ```

    That's it! Your app will now be instrumented and any LangChain/LangGraph runs, steps, and tool calls will be viewable in the dashboard.
  </Tab>

  <Tab title="TypeScript">
    #### Step 1: Install dependencies

    <CodeGroup>
      ```Title pnpm theme={null}
      pnpm add @contextcompany/langchain @langchain/core
      ```

      ```Title npm theme={null}
      npm i @contextcompany/langchain @langchain/core
      ```

      ```Title bun theme={null}
      bun add @contextcompany/langchain @langchain/core
      ```
    </CodeGroup>

    #### Step 2: Add instrumentation

    You can instrument LangChain.js and LangGraph by either passing the callback handler directly to your chain/agent invocations, or by setting it as a global handler.

    **Option A: Pass callback handler directly**

    Pass `TCCCallbackHandler` to your chain or agent's `invoke()` call:

    ```typescript main.ts theme={null}
    import { TCCCallbackHandler } from "@contextcompany/langchain";
    import { ChatOpenAI } from "@langchain/openai";

    const handler = new TCCCallbackHandler();

    const model = new ChatOpenAI({ model: "gpt-4" });

    const result = await model.invoke("Hello, world!", {
      callbacks: [handler],
    });
    ```

    **Option B: Set global handler**

    Register the handler globally so all LangChain/LangGraph calls are automatically instrumented:

    ```typescript main.ts theme={null}
    import { TCCCallbackHandler, setGlobalHandler } from "@contextcompany/langchain";

    // Set up global instrumentation once at app startup
    setGlobalHandler(new TCCCallbackHandler());

    // All subsequent LangChain/LangGraph calls are automatically traced
    import { ChatOpenAI } from "@langchain/openai";

    const model = new ChatOpenAI({ model: "gpt-4" });
    const result = await model.invoke("Hello, world!");
    ```

    **Using with LangGraph:**

    The same callback handler works seamlessly with LangGraph:

    ```typescript graph.ts theme={null}
    import { TCCCallbackHandler } from "@contextcompany/langchain";
    import { StateGraph } from "@langchain/langgraph";

    const handler = new TCCCallbackHandler();

    // Your LangGraph workflow
    const graph = new StateGraph({ ... })
      .addNode("agent", agentNode)
      .addNode("tools", toolNode)
      .compile();

    const result = await graph.invoke(
      { messages: [{ role: "user", content: "Hello!" }] },
      { callbacks: [handler] }
    );
    ```

    That's it! Your app will now be instrumented and any LangChain/LangGraph runs, steps, and tool calls will be viewable in the dashboard.
  </Tab>
</Tabs>

## Adding custom metadata

Custom metadata allows you to add additional properties to your [agent runs](/concepts#agent-runs).

This is particularly useful for tying agent runs to your own specific business logic, letting you filter and analyze agent runs by user, organization, feature, or some other dimension.

<Tabs>
  <Tab title="Python">
    Custom metadata must be passed as a key-value pair through LangChain/LangGraph's `RunnableConfig` as the second argument to `invoke()`:

    ```python main.py theme={null}
    result = agent_executor.invoke(
        {"input": "Hello!"},
        {
            "metadata": {
                # e.g. tag this agent run with a user id
                "userId": "4a6b111c-b53a-4d00-a877-67185022ab9e",
            }
        }
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    Custom metadata is passed directly in LangChain's `metadata` config. All keys outside the `tcc` object are automatically tracked as custom metadata on the run:

    ```typescript main.ts theme={null}
    import { ChatOpenAI } from "@langchain/openai";

    const model = new ChatOpenAI({ model: "gpt-4" });
    const result = await model.invoke("Hello!", {
      metadata: {
        // e.g. tag this agent run with a user id
        userId: "4a6b111c-b53a-4d00-a877-67185022ab9e",
        environment: "production",
      },
    });
    ```
  </Tab>
</Tabs>

Agent runs are automatically indexed by your custom metadata fields and can be filtered directly in the dashboard.

<Note>
  The `tcc.*` namespace is reserved. Only the [reserved TCC metadata keys](/concepts#tcc-metadata-keys) (`tcc.runId`, `tcc.sessionId`, `tcc.conversational`, `tcc.agent`, `tcc.userId`, `tcc.userName`, `tcc.orgId`, `tcc.orgName`) are recognized; any other `tcc.*` keys are ignored. None of them appear in your custom metadata.
</Note>

## Adding user feedback

User feedback allows you to collect score (thumbs up & thumbs down) and text feedback (up to 2000 characters) from end users on your [agent runs](/concepts#agent-runs).

This is useful for tracking user satisfaction, identifying problematic responses, and filtering agent runs in the dashboard to focus on positive or negative feedback.

<Tabs>
  <Tab title="Python">
    ### Step 1: Generate and pass a run ID

    ```python main.py theme={null}
    import uuid

    # Generate a unique run ID (must be a UUID) before your agent execution
    run_id = str(uuid.uuid4())

    result = agent_executor.invoke(
        {"input": "Hello!"},
        {
            "metadata": {
                "tcc.runId": run_id,  # Pass the run ID in metadata
            }
        }
    )

    # Return the run_id to your client
    return {"result": result, "run_id": run_id}
    ```

    ### Step 2: Submit feedback from your client

    Store the `run_id` on your client, then when the user provides feedback, submit it using the `submit_feedback` function.

    Both `score` and `text` are optional individually, but each request must include at least one of them:

    `score` is the thumbs rating. Use only `"thumbs_up"` or `"thumbs_down"`.

    `text` is written feedback from your user, up to 2000 characters.

    ```python feedback.py theme={null}
    from contextcompany import submit_feedback

    # Submit score and/or text feedback:
    submit_feedback(
        run_id=run_id,  # The run ID from your agent execution
        score="thumbs_up",  # Optional thumbs rating: "thumbs_up" or "thumbs_down"
        text="This was a helpful response!",  # Optional written user feedback, up to 2000 characters
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ### Step 1: Generate and pass a run ID

    ```typescript main.ts theme={null}
    import { ChatOpenAI } from "@langchain/openai";
    import { randomUUID } from "crypto";

    // Generate a unique run ID (must be a UUID) before your agent execution
    const runId = randomUUID();

    const model = new ChatOpenAI({ model: "gpt-4" });
    const result = await model.invoke("Hello!", {
      metadata: {
        tcc: { runId },
      },
    });

    // Return the runId to your client
    return { result, runId };
    ```

    ### Step 2: Submit feedback from your client

    Store the `runId` on your client, then when the user provides feedback, submit it using the `submitFeedback` function.

    Both `score` and `text` are optional individually, but each request must include at least one of them:

    `score` is the thumbs rating. Use only `"thumbs_up"` or `"thumbs_down"`.

    `text` is written feedback from your user, up to 2000 characters.

    ```typescript feedback-route.ts theme={null}
    import { submitFeedback } from "@contextcompany/langchain";

    // Submit score and/or text feedback:
    await submitFeedback({
      runId: runId, // The run ID from your agent execution
      score: "thumbs_up", // Optional thumbs rating: "thumbs_up" or "thumbs_down"
      text: "This was a helpful response!", // Optional written user feedback, up to 2000 characters
    });
    ```
  </Tab>
</Tabs>

Agent runs with feedback can be filtered in the dashboard using the feedback filter.

## Tracking agent sessions

[Agent sessions](/concepts#agent-sessions) represent multiple agent runs that are grouped together. The most common use case is tracking entire conversations between a human user and an AI agent in chatbot interfaces.

<Tabs>
  <Tab title="Python">
    Agent sessions can be tracked by setting a `tcc.sessionId` key under metadata.

    ```python main.py theme={null}
    session_id = "unique-session-identifier"

    result = agent_executor.invoke(
        {"input": "Hello!"},
        {
            "metadata": {
                "tcc.sessionId": session_id,  # Track agent sessions
            }
        }
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    Agent sessions can be tracked by passing `sessionId` in the `tcc` metadata config:

    ```typescript main.ts theme={null}
    import { ChatOpenAI } from "@langchain/openai";

    const model = new ChatOpenAI({ model: "gpt-4" });
    const result = await model.invoke("Hello!", {
      metadata: {
        tcc: { sessionId: "unique-session-identifier" },
      },
    });
    ```
  </Tab>
</Tabs>

The value of `sessionId` should be a unique identifier for the agent session. This can be any string, but it's generally recommended to use a UUID.

Agent sessions are automatically indexed and can be filtered directly in the dashboard.

## Marking runs as conversational

A [conversational run](/concepts#conversational-runs) is an agent run that was initiated by a user. Marking a run as conversational tells The Context Company that this run involves direct user interaction.

This is important because conversational runs are the only runs monitored for user insights, such as user confusion, frustration, or any other custom insights you want to track. Runs that are not marked as conversational (e.g. background jobs, cron tasks, or internal automations) are excluded from user insight analysis.

<Tabs>
  <Tab title="Python">
    Mark a run as conversational by setting `tcc.conversational` to `"true"` in metadata:

    ```python main.py theme={null}
    result = agent_executor.invoke(
        {"input": "Hello!"},
        {
            "metadata": {
                "tcc.conversational": "true",
            }
        }
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    Mark a run as conversational by setting `conversational` to `true` in the `tcc` metadata config:

    ```typescript main.ts theme={null}
    import { ChatOpenAI } from "@langchain/openai";

    const model = new ChatOpenAI({ model: "gpt-4" });
    const result = await model.invoke("Hello!", {
      metadata: {
        tcc: { conversational: true },
      },
    });
    ```

    <Note>
      The nested `tcc: { ... }` object is a typed shortcut for the reserved [TCC metadata keys](/concepts#tcc-metadata-keys).
    </Note>
  </Tab>
</Tabs>

## Identifying the agent

If your product ships more than one named agent, set the reserved `tcc.agent` metadata key to scope the run to a specific [agent](/concepts#agents). The dashboard's top-level agent selector, per-agent patterns and recaps, and the `agent` filter on the [REST API](/access-data/api) and [MCP tools](/access-data/mcp) all read from this key.

<Tabs>
  <Tab title="Python">
    ```python main.py theme={null}
    from langchain_openai import ChatOpenAI

    model = ChatOpenAI(model="gpt-4")
    result = model.invoke(
        "Hello!",
        config={
            "metadata": {
                "tcc.agent": "support-agent",
            }
        }
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript main.ts theme={null}
    import { ChatOpenAI } from "@langchain/openai";

    const model = new ChatOpenAI({ model: "gpt-4" });
    const result = await model.invoke("Hello!", {
      metadata: {
        tcc: {
          agent: "support-agent",
        },
      },
    });
    ```
  </Tab>
</Tabs>

<Note>
  Agent names that collide with reserved dashboard routes (for example `runs`, `sessions`, `patterns`, `recaps`, `overview`, `search`, `failures`, `feedback`, `tools`, `topics`, `views`, `settings`, `mcp-and-api`) are dropped.
</Note>

## Identifying users and organizations

Attach the end user and their organization to a run as first-class identity using the reserved `tcc.userId`, `tcc.userName`, `tcc.orgId`, and `tcc.orgName` metadata keys. This is **not the same** as adding a `userId` field to custom metadata — these keys promote user and org identity to dedicated dashboard filters and unlock native user/org search, per-user views, and per-org analytics. See [User and organization identity](/concepts#user-and-organization-identity) for the full concept.

Set these whenever you have a stable identifier for the end user or their organization in your product.

<Tabs>
  <Tab title="Python">
    ```python main.py theme={null}
    from langchain_openai import ChatOpenAI

    model = ChatOpenAI(model="gpt-4")
    result = model.invoke(
        "Hello!",
        config={
            "metadata": {
                "tcc.userId": "user-123",
                "tcc.userName": "Jane Doe",
                "tcc.orgId": "org-456",
                "tcc.orgName": "Acme Inc.",
            }
        }
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript main.ts theme={null}
    import { ChatOpenAI } from "@langchain/openai";

    const model = new ChatOpenAI({ model: "gpt-4" });
    const result = await model.invoke("Hello!", {
      metadata: {
        tcc: {
          userId: "user-123",
          userName: "Jane Doe",
          orgId: "org-456",
          orgName: "Acme Inc.",
        },
      },
    });
    ```
  </Tab>
</Tabs>

<Note>
  `tcc.userName` and `tcc.orgName` require the corresponding ID (`tcc.userId` / `tcc.orgId`) to also be set. Names without IDs are dropped.
</Note>

## Combining multiple options (TypeScript)

You can combine all TCC options in a single invocation. TCC-specific config goes under the `tcc` key, while all other keys in the metadata object are automatically tracked as custom metadata on the run:

```typescript main.ts theme={null}
import { ChatOpenAI } from "@langchain/openai";
import { randomUUID } from "crypto";

const model = new ChatOpenAI({ model: "gpt-4" });

const result = await model.invoke("Hello!", {
  metadata: {
    tcc: {
      sessionId: "session-abc-123",
      conversational: true,
      runId: randomUUID(),
      agent: "support-agent",
      userId: "user-123",
      userName: "Jane Doe",
      orgId: "org-456",
      orgName: "Acme Inc.",
    },
    // Custom metadata (tracked automatically)
    feature: "booking",
    environment: "production",
  },
});
```

| Key                  | Type      | Description                                                        |
| -------------------- | --------- | ------------------------------------------------------------------ |
| `tcc.sessionId`      | `string`  | Session ID for grouping runs                                       |
| `tcc.conversational` | `boolean` | Whether this run involves user interaction                         |
| `tcc.runId`          | `string`  | Custom run ID for feedback tracking                                |
| `tcc.agent`          | `string`  | Agent name for first-class agent filtering                         |
| `tcc.userId`         | `string`  | End user's ID. Required if setting `tcc.userName`.                 |
| `tcc.userName`       | `string`  | End user's display name. Ignored unless `tcc.userId` is also set.  |
| `tcc.orgId`          | `string`  | End user's organization ID. Required if setting `tcc.orgName`.     |
| `tcc.orgName`        | `string`  | Organization display name. Ignored unless `tcc.orgId` is also set. |
| Other keys           | `unknown` | Custom metadata for filtering (tracked automatically)              |

## Debug mode (TypeScript only)

You can enable debug mode in TypeScript to log spans as they are created and exported:

```typescript main.ts theme={null}
import { TCCCallbackHandler } from "@contextcompany/langchain";

const handler = new TCCCallbackHandler({
  debug: true,
});
```

## Examples

See our [examples repository](https://github.com/The-Context-Company/examples) for more detailed usage examples.
