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

# LangGraph

> Trace LangGraph graph execution in Braintrust to debug agent runs, inspect node transitions, evaluate models, and monitor production usage

[LangGraph](https://langchain-ai.github.io/langgraph/) is a library for building stateful, multi-actor applications with LLMs. Braintrust traces LangGraph graph execution, including node transitions and the model calls each node makes.

<View title="TypeScript" icon="/images/sdk-icons/typescript.svg">
  Trace LangGraph graphs built with the `@langchain/langgraph` and `@langchain/core` packages.

  <h2 id="setup-typescript">
    Setup
  </h2>

  Install LangGraph alongside Braintrust and the LangChain packages you use.

  <CodeGroup>
    ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    pnpm add braintrust @langchain/core@^1 @langchain/langgraph@^1 @langchain/openai@^1
    ```

    ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    npm install braintrust @langchain/core@^1 @langchain/langgraph@^1 @langchain/openai@^1
    ```
  </CodeGroup>

  <h2 id="auto-instrumentation-typescript">
    Auto-instrumentation
  </h2>

  To trace LangGraph graphs without modifying your application code, initialize Braintrust normally, then run your app with Braintrust's import hook to patch `@langchain/core` at runtime. Requires `@langchain/langgraph` v1 or later.

  <Steps>
    <Step title="Initialize Braintrust and build your graph">
      <CodeGroup>
        ```javascript title="trace-langgraph-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        import { END, START, StateGraph, Annotation } from "@langchain/langgraph";
        import { ChatOpenAI } from "@langchain/openai";
        import { initLogger } from "braintrust";

        initLogger({
          projectName: "My Project",
          apiKey: process.env.BRAINTRUST_API_KEY,
        });

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

        const StateAnnotation = Annotation.Root({
          message: Annotation(),
        });

        const graph = new StateGraph(StateAnnotation)
          .addNode("sayHello", async () => {
            const res = await model.invoke("Say hello");
            return { message: res.content };
          })
          .addNode("sayBye", () => ({ message: "Bye." }))
          .addEdge(START, "sayHello")
          .addEdge("sayHello", "sayBye")
          .addEdge("sayBye", END)
          .compile();

        await graph.invoke({});
        ```
      </CodeGroup>
    </Step>

    <Step title="Run with the import hook">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      node --import braintrust/hook.mjs trace-langgraph-auto.js
      ```

      The auto-instrumentation example uses plain JavaScript so `node --import` can run the file directly. The Braintrust APIs work the same in TypeScript projects — compile your TypeScript to JavaScript, then run the compiled file with the import hook.

      <Note>
        If you're using a bundler, see [Trace LLM calls](/docs/instrument/trace-llm-calls#auto-instrumentation) for plugin and loader setup.
      </Note>
    </Step>
  </Steps>

  <h2 id="manual-instrumentation-typescript">
    Manual instrumentation
  </h2>

  To control the LangChain handler yourself, construct a `BraintrustLangChainCallbackHandler` and pass it through the `callbacks` option when you invoke the graph.

  <CodeGroup>
    ```typescript title="trace-langgraph.ts" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import {
      BraintrustLangChainCallbackHandler,
    } from "braintrust";
    import { END, START, StateGraph, Annotation } from "@langchain/langgraph";
    import { ChatOpenAI } from "@langchain/openai";
    import { initLogger } from "braintrust";

    const logger = initLogger({
      projectName: "My Project",
      apiKey: process.env.BRAINTRUST_API_KEY,
    });

    const handler = new BraintrustLangChainCallbackHandler({ logger });

    const StateAnnotation = Annotation.Root({
      message: Annotation(),
    });

    const model = new ChatOpenAI({
      model: "gpt-5-mini",
    });

    async function sayHello(_state: typeof StateAnnotation.State) {
      const res = await model.invoke("Say hello");
      return { message: res.content };
    }

    function sayBye(_state: typeof StateAnnotation.State) {
      console.log("From the 'sayBye' node: Bye world!");
      return {};
    }

    async function main() {
      const graphBuilder = new StateGraph(StateAnnotation)
        .addNode("sayHello", sayHello)
        .addNode("sayBye", sayBye)
        .addEdge(START, "sayHello")
        .addEdge("sayHello", "sayBye")
        .addEdge("sayBye", END);

      const helloWorldGraph = graphBuilder.compile();

      await helloWorldGraph.invoke({}, { callbacks: [handler] });
    }

    main();
    ```
  </CodeGroup>

  <h2 id="what-traced-typescript">
    What Braintrust traces
  </h2>

  Braintrust logs each step of a graph run as a span nested under the graph invocation:

  * Graph and node execution spans (chain runs), with each step's inputs, outputs, and LangChain tags.
  * Chat model and LLM spans (`ChatOpenAI` and similar), with the input messages or prompts, the serialized model configuration and request parameters, and the full response including generated messages.
  * Model name metadata resolved from each model response.
  * Token usage metrics (`prompt_tokens`, `completion_tokens`, `tokens`, `prompt_cached_tokens`, cache-creation tokens, and `completion_reasoning_tokens` when the provider reports them).
  * Time to first token (`time_to_first_token`) for streaming model calls.
  * Tool spans (named for the tool), with the parsed tool input and the tool output.
  * Retriever spans, with the query as input and the retrieved documents as output.
  * Errors captured on the failing model, chain, tool, or retriever span.

  <h2 id="resources-typescript">
    Resources
  </h2>

  * [LangGraph documentation](https://langchain-ai.github.io/langgraph/).
  * [LangChain integration](/docs/integrations/sdk-integrations/langchain).

  <h2 id="langgraph-platform-sdk-typescript">
    LangGraph Platform SDK
  </h2>

  Trace runs dispatched to a deployed [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) server using the `@langchain/langgraph-sdk` package.

  <h3 id="setup-langgraph-platform-typescript">
    Setup
  </h3>

  Install the LangGraph Platform SDK alongside `braintrust`.

  <CodeGroup>
    ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    pnpm add braintrust @langchain/langgraph-sdk
    ```

    ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    npm install braintrust @langchain/langgraph-sdk
    ```
  </CodeGroup>

  <h3 id="auto-instrumentation-langgraph-platform-typescript">
    Auto-instrumentation
  </h3>

  To trace `RunsClient.wait()` and `RunsClient.stream()` calls without modifying your application code, initialize Braintrust normally, then run your app with Braintrust's import hook. Requires `@langchain/langgraph-sdk` v1.9.25 or later.

  <Steps>
    <Step title="Initialize Braintrust and call your deployed graph">
      <CodeGroup>
        ```javascript title="trace-langgraph-sdk-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        import { Client } from "@langchain/langgraph-sdk";
        import { initLogger } from "braintrust";

        initLogger({
          projectName: "My Project",
          apiKey: process.env.BRAINTRUST_API_KEY,
        });

        const client = new Client({
          apiUrl: process.env.LANGGRAPH_API_URL,
        });

        const result = await client.runs.wait(null, "agent", {
          input: { messages: [{ role: "user", content: "Say hello" }] },
        });
        ```
      </CodeGroup>
    </Step>

    <Step title="Run with the import hook">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      node --import braintrust/hook.mjs trace-langgraph-sdk-auto.js
      ```

      The auto-instrumentation example uses plain JavaScript so `node --import` can run the file directly. The Braintrust APIs work the same in TypeScript projects — compile your TypeScript to JavaScript, then run the compiled file with the import hook.

      <Note>
        If you're using a bundler, see [Trace LLM calls](/docs/instrument/trace-llm-calls#auto-instrumentation) for plugin and loader setup.
      </Note>
    </Step>
  </Steps>

  <h3 id="manual-instrumentation-langgraph-platform-typescript">
    Manual instrumentation
  </h3>

  To instrument the LangGraph Platform SDK without modifying every call site, wrap your client once with `wrapLangGraphSDK`. All subsequent `runs.wait()` and `runs.stream()` calls on the wrapped client are traced automatically.

  <CodeGroup>
    ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import { Client } from "@langchain/langgraph-sdk";
    import { initLogger, wrapLangGraphSDK } from "braintrust";

    initLogger({
      projectName: "My Project",
      apiKey: process.env.BRAINTRUST_API_KEY,
    });

    const raw = new Client({
      apiUrl: process.env.LANGGRAPH_API_URL,
    });
    const client = wrapLangGraphSDK(raw);

    const result = await client.runs.wait(null, "agent", {
      input: { messages: [{ role: "user", content: "Say hello" }] },
    });
    ```
  </CodeGroup>

  <h3 id="what-traced-langgraph-platform-typescript">
    What Braintrust traces
  </h3>

  Braintrust captures:

  * Run wait spans (`runs.wait`), with the thread ID, assistant ID, and run options as input, and the final graph state as output.
  * Run stream spans (`runs.stream`), with the thread ID, assistant ID, and run options as input. Each streamed event is consumed without individual child spans.
  * Errors on any span that fails, including HTTP errors from the LangGraph server.

  <h3 id="resources-langgraph-platform-typescript">
    Resources
  </h3>

  * [LangGraph Platform documentation](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/).
  * [`@langchain/langgraph-sdk` on npm](https://www.npmjs.com/package/@langchain/langgraph-sdk).
</View>

<View title="Python" icon="/images/sdk-icons/python.svg">
  Trace LangGraph graphs built with the `langgraph` and `langchain-core` packages.

  <h2 id="setup-python">
    Setup
  </h2>

  Install LangGraph alongside Braintrust and the LangChain packages you use.

  ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  pip install braintrust langchain-core langgraph langchain-openai
  ```

  <h2 id="auto-instrumentation-python">
    Auto-instrumentation
  </h2>

  To trace LangGraph graphs without modifying your application code, call `braintrust.auto_instrument()` before importing LangGraph, then initialize your logger.

  <CodeGroup>
    ```python title="trace-langgraph-auto.py" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    from typing import TypedDict

    import braintrust

    braintrust.auto_instrument()
    braintrust.init_logger(project="My Project")

    from langchain_openai import ChatOpenAI
    from langgraph.graph import END, START, StateGraph

    class GraphState(TypedDict, total=False):
        message: str

    def main():
        model = ChatOpenAI(model="gpt-5-mini")

        def say_hello(state: GraphState):
            response = model.invoke("Say hello")
            return {"message": response.content}

        def say_bye(state: GraphState):
            return {"message": f"{state.get('message', '')} Bye."}

        workflow = (
            StateGraph(state_schema=GraphState)
            .add_node("sayHello", say_hello)
            .add_node("sayBye", say_bye)
            .add_edge(START, "sayHello")
            .add_edge("sayHello", "sayBye")
            .add_edge("sayBye", END)
        )

        graph = workflow.compile()
        result = graph.invoke({})
        print(result)

    if __name__ == "__main__":
        main()
    ```
  </CodeGroup>

  <h2 id="manual-instrumentation-python">
    Manual instrumentation
  </h2>

  To control the handler yourself, construct a `BraintrustCallbackHandler` and register it as the global handler with `set_global_handler`.

  <CodeGroup>
    ```python title="trace-langgraph.py" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import asyncio
    import os
    from typing import TypedDict

    from braintrust import init_logger
    from braintrust.integrations.langchain import BraintrustCallbackHandler, set_global_handler
    from langchain_openai import ChatOpenAI
    from langgraph.graph import END, START, StateGraph

    class GraphState(TypedDict, total=False):
        message: str

    async def main():
        init_logger(project="My Project", api_key=os.environ["BRAINTRUST_API_KEY"])

        handler = BraintrustCallbackHandler()
        set_global_handler(handler)

        model = ChatOpenAI(model="gpt-5-mini")

        def say_hello(state: GraphState):
            response = model.invoke("Say hello")
            return {"message": response.content}

        def say_bye(state: GraphState):
            return {"message": f"{state.get('message', '')} Bye."}

        workflow = (
            StateGraph(state_schema=GraphState)
            .add_node("sayHello", say_hello)
            .add_node("sayBye", say_bye)
            .add_edge(START, "sayHello")
            .add_edge("sayHello", "sayBye")
            .add_edge("sayBye", END)
        )

        graph = workflow.compile()
        result = await graph.ainvoke({})
        print(result)

    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </CodeGroup>

  <h2 id="what-traced-python">
    What Braintrust traces
  </h2>

  Braintrust logs each step of a graph run as a span nested under the graph invocation:

  * Graph and node execution spans (a `LangGraph` root span plus one span per node, each named for the node), with each step's inputs, outputs, and LangChain tags.
  * Chat model and LLM spans (`ChatOpenAI` and similar), with the input messages or prompts, the serialized model configuration and request parameters, and the full response including generated messages.
  * Model and provider metadata resolved from each model response.
  * Token usage metrics (`prompt_tokens`, `completion_tokens`, `total_tokens`, `tokens`, `prompt_cached_tokens`, and cache-creation tokens).
  * Time to first token (`time_to_first_token`) for streaming model calls.
  * Tool spans (named for the tool), with the tool input and the tool output.
  * Retriever spans, with the query as input and the retrieved documents as output.
  * Errors captured on the failing model, chain, tool, or retriever span.

  <h2 id="resources-python">
    Resources
  </h2>

  * [LangGraph documentation](https://langchain-ai.github.io/langgraph/).
  * [LangChain integration](/docs/integrations/sdk-integrations/langchain).
</View>
