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

# LangGraph

> Trace LangGraph agent workflows with Netra auto-instrumentation. Monitor graph state, node execution, and agent decisions across multi-step pipelines.

<img src="https://mintcdn.com/netra/u6ajHWd7ki_9CRWQ/images/integration-logos/ai-frameworks/langgraph.png?fit=max&auto=format&n=u6ajHWd7ki_9CRWQ&q=85&s=99fd20e22c171dd171ed74d63ed58d22" alt="LangGraph" width="540" height="80" data-path="images/integration-logos/ai-frameworks/langgraph.png" />

## Installation

Install both the Netra SDK and LangGraph:

<CodeGroup>
  ```bash Python theme={null}
  pip install netra-sdk langgraph
  ```

  ```bash Typescript theme={null}
  npm install netra-sdk langgraph
  ```
</CodeGroup>

## Usage

Initialize the Netra SDK to automatically trace all LangGraph operations:

<CodeGroup>
  ```python Python theme={null}
  from netra import Netra
  from langgraph.graph import StateGraph
  import os

  # Initialize Netra
  Netra.init(
      headers=f"x-api-key={os.environ.get('NETRA_API_KEY')}",
      trace_content=True
  )

  # Define your graph - automatically traced
  from typing import TypedDict

  class GraphState(TypedDict):
      messages: list[str]

  workflow = StateGraph(GraphState)
  ```

  ```typescript Typescript theme={null}
  import { Netra } from "netra-sdk";
  import { StateGraph } from "@langchain/langgraph";

  async function main() {
    // Initialize Netra (must await)
    await Netra.init({
      headers: `x-api-key=${process.env.NETRA_API_KEY}`,
      traceContent: true
    });

    // Define your graph - automatically traced
    interface GraphState {
      messages: string[];
    }

    const workflow = new StateGraph<GraphState>({
      channels: {
        messages: { value: (x, y) => x.concat(y) }
      }
    });
  }

  main();
  ```
</CodeGroup>

### Core Concepts

Trace LangGraph workflows with custom decorators:

<CodeGroup>
  ```python Python theme={null}
  from netra.decorators import workflow, agent, task
  from netra import SpanWrapper

  # Node function with task decorator
  @task()
  def process_node(state: GraphState) -> GraphState:
      span = SpanWrapper("node-processing", {
          "node.name": "process",
          "state.messages": len(state["messages"])
      }).start()
      
      result = {
          "messages": state["messages"] + ["Processed"]
      }
      
      span.end()
      return result

  # Build graph with workflow decorator
  @workflow()
  def build_graph():
      workflow.add_node("process", process_node)
      workflow.set_entry_point("process")
      workflow.set_finish_point("process")
      
      return workflow.compile()
  ```

  ```typescript Typescript theme={null}
  import { workflow, agent, task, SpanWrapper } from "netra-sdk";

  // Node function with task decorator
  @task()
  async function processNode(state: GraphState) {
    const span = new SpanWrapper("node-processing", {
      "node.name": "process",
      "state.messages": state.messages.length
    }).start();
    
    const result = {
      messages: [...state.messages, "Processed"]
    };
    
    span.end();
    return result;
  }

  // Build graph with workflow decorator
  @workflow()
  async function buildGraph() {
    workflow.addNode("process", processNode);
    workflow.setEntryPoint("process");
    workflow.setFinishPoint("process");
    
    return workflow.compile();
  }
  ```
</CodeGroup>

### Workflow Patterns

Trace multi-node agent workflows:

<CodeGroup>
  ```python Python theme={null}
  @agent()
  def agent_workflow(query: str):
      graph = StateGraph(GraphState)
      
      @task()
      def analyze(state: GraphState) -> GraphState:
          return {"messages": state["messages"] + ["Analyzed"]}
      
      @task()
      def decide(state: GraphState) -> GraphState:
          return {"messages": state["messages"] + ["Decision made"]}
      
      graph.add_node("analyze", analyze)
      graph.add_node("decide", decide)
      graph.add_edge("analyze", "decide")
      graph.set_entry_point("analyze")
      graph.set_finish_point("decide")
      
      app = graph.compile()
      return app.invoke({"messages": [query]})
  ```

  ```typescript Typescript theme={null}
  @agent()
  async function agentWorkflow(query: string) {
    const graph = new StateGraph<GraphState>({
      channels: {
        messages: { value: (x, y) => x.concat(y) }
      }
    });
    
    @task()
    async function analyze(state: GraphState) {
      return { messages: [...state.messages, "Analyzed"] };
    }
    
    @task()
    async function decide(state: GraphState) {
      return { messages: [...state.messages, "Decision made"] };
    }
    
    graph.addNode("analyze", analyze);
    graph.addNode("decide", decide);
    graph.addEdge("analyze", "decide");
    graph.setEntryPoint("analyze");
    graph.setFinishPoint("decide");
    
    const app = graph.compile();
    return await app.invoke({ messages: [query] });
  }
  ```
</CodeGroup>

### State Management

Capture state transitions with manual spans:

<CodeGroup>
  ```python Python theme={null}
  from netra import SpanWrapper
  import json

  def run_with_state_tracking(app, initial_state: GraphState):
      state_span = SpanWrapper("state-management").start()
      
      try:
          result = app.invoke(initial_state)
          state_span.set_attribute("state.initial", json.dumps(initial_state))
          state_span.set_attribute("state.final", json.dumps(result))
          state_span.end()
          return result
      except Exception as e:
          state_span.set_status(code=1, message=str(e))
          state_span.end()
          raise
  ```

  ```typescript Typescript theme={null}
  import { SpanWrapper } from "netra-sdk";

  async function runWithStateTracking(app: any, initialState: GraphState) {
    const stateSpan = new SpanWrapper("state-management").start();
    
    try {
      const result = await app.invoke(initialState);
      stateSpan.setAttribute("state.initial", JSON.stringify(initialState));
      stateSpan.setAttribute("state.final", JSON.stringify(result));
      stateSpan.end();
      return result;
    } catch (error) {
      stateSpan.setStatus({ code: 1, message: String(error) });
      stateSpan.end();
      throw error;
    }
  }
  ```
</CodeGroup>

## Next Steps

* [Quick Start Guide](https://docs.getnetra.ai/quick-start/python) - Complete setup and configuration
* [Decorators](https://docs.getnetra.ai/tracing/decorators) - Add custom tracing with `@workflow`, `@agent`, and `@task` decorators
* [Session Tracking](https://docs.getnetra.ai/tracing/session) - Track user sessions and conversations
* [LangGraph Documentation](https://langchain-ai.github.io/langgraph/) - Official LangGraph documentation
