Skip to main content

Overview

Laminar is an open-source, OpenTelemetry-native observability platform for AI agents. Trace, debug, and monitor every LangChain chain and LangGraph agent in TypeScript and Python: each graph node, tool call, retriever query, and LLM call is recorded with its inputs, outputs, token usage, and cost. Self-host via Helm or use managed cloud. Your LangChain and LangGraph code stays as it is. Laminar builds the run tree from LangChain’s own callbacks. Calls to OpenAI and Anthropic models are recorded by Laminar’s OpenAI and Anthropic integrations, so each call is one LLM span with the provider’s full request and response.

Getting started

1

Install Laminar and LangChain

This needs @lmnr-ai/lmnr 0.8.53 or later. Install the model provider’s SDK (openai here, @anthropic-ai/sdk if you use @langchain/anthropic) as a direct dependency, because you pass it to Laminar in step 3.
2

Set up your environment variables

.env
Load them with a package like dotenv, or node --env-file=.env.
3

Initialize Laminar with your LangChain modules

Laminar can’t patch an ES module that your code has already imported, so pass the LangChain modules, and the SDK of each model provider you call, to instrumentModules. Do it once, in its own file:
instrumentation.ts
Then import it first in your entry point, before any LangChain code runs:
index.ts
Each module turns on part of the trace. The LangChain modules go under instrumentModules.langchain, and the provider SDKs go at the top level:
Pass the same copy of the provider SDK that the LangChain package loads. @langchain/anthropic and @langchain/openai each depend on a specific version of their provider’s SDK, and if your app depends on a different major version, npm installs two copies and Laminar patches the one LangChain doesn’t use. Run npm ls openai @anthropic-ai/sdk and check that each package resolves to a single version. When the copies differ, the calls are still recorded once, as the LangChain-side span.
In a CommonJS app, calling Laminar.initialize() before LangChain is loaded instruments it without instrumentModules. Passing the modules works in both module systems, so it’s the setup we recommend.
4

Use LangChain and LangGraph as usual

A chain:
chain.ts
A LangGraph agent with a tool:
agent.ts
Agents built with createAgent from the langchain package run on LangGraph, so they’re traced the same way. await Laminar.shutdown() sends the last spans before a short-lived script exits; a long-running server doesn’t need it.

What Laminar records

Each invocation of a chain or graph is one trace:

Which integration records each LLM call

  • OpenAI (including Azure OpenAI) and Anthropic chat models are recorded by Laminar’s provider integrations, as openai.chat, openai.response, or anthropic.chat spans. In Python, Google GenAI (langchain-google-genai 4 or later) and Groq models are handed off the same way.
  • Every other chat model (Gemini in TypeScript, Mistral, Amazon Bedrock, Ollama, and so on) is recorded by LangChain as an LLM span named after the model class, such as ChatGoogleGenerativeAI.chat or ChatMistralAI.chat. It carries the same messages, tool calls, model, token usage, and cost. Any provider SDK instrumentation underneath is silenced for that call, so nothing is recorded twice.

Group a LangGraph thread into a session

LangGraph’s thread_id is recorded on the graph and node spans. To see every run of a thread together in Laminar’s sessions view, wrap the call in observe with the thread ID as the session ID:
The graph’s spans nest under the weather_agent span, and the whole trace joins the session.

See what happened in a trace

Open a trace in Laminar and the default view is the transcript: the agent’s auto-extracted input, every LLM turn with a one-line preview of its response, and each tool call with its arguments and result, in the order they ran. You read the conversation instead of clicking through a tree of execute_task spans. Switch to tree view for the span-by-span structure, or open the LangGraph view to see which nodes ran. More on the trace UX: Viewing traces.

Track outcomes with Signals

Traces answer what happened on this run. Signals answer the cross-trace question: how often does the agent answer without calling the tool it needed, when does a graph loop between the same two nodes, which runs end with an apology instead of an answer. A Signal pairs a plain-language instruction with a JSON output schema. Laminar runs it live on new traces (Triggers) or backfills it across history (Jobs) and records a structured event every time it matches. From there you query, cluster, and alert on events across every trace.
Every new project ships with a Failure Detector Signal that categorizes issues on any trace over 1000 tokens. Open it from the Signals sidebar to see events as soon as your LangChain traces arrive.

Query across traces

  • SQL editor for ad-hoc queries across traces, spans, signals, and evals.
  • SQL API for programmatic access from scripts and pipelines.
  • CLI (lmnr-cli sql query) for terminal-driven queries and piping JSON into shell tools or coding agents.
  • MCP server to query Laminar from Claude Code, Cursor, or Codex.

Troubleshooting

  • Pass the LangChain modules to instrumentModules as shown in step 3. In an ES module app, Laminar.initialize() without them records nothing from LangChain.
  • Import your instrumentation file before any file that runs LangChain code.
  • Confirm LMNR_PROJECT_API_KEY is set in the process that runs LangChain.
  • Call await Laminar.shutdown() before a short-lived script exits.
Add chatModelsModule and llmsModule to instrumentModules.langchain. Without them, LangChain can’t hand the call to the provider integration, so both record it. Laminar logs a warning at startup when chatModelsModule is missing.
The OpenAI integration didn’t record the call, so LangChain recorded it instead. Pass OpenAI from openai to instrumentModules, and check with npm ls openai that @langchain/openai uses the same copy of openai that you import. The same applies to ChatAnthropic.chat and @anthropic-ai/sdk.
Point the SDK at your instance when initializing. For a local OSS deployment:

What’s next

Viewing traces

Read the transcript view, filter, and search across traces.

Signals

Detect behaviors and failures across every run, then query, cluster, and alert on them.

SQL editor and MCP server

Query traces programmatically from the UI, API, or your IDE.

Tracing structure

Sessions, user IDs, metadata, and tags.

deepagents

Trace deepagents runs, subagents, and tool calls.

Pydantic AI

Trace Pydantic AI agent runs and typed tool calls.

LiteLLM

One integration for every model LiteLLM routes to.

OpenAI

Trace the OpenAI SDK directly in TypeScript and Python.

Langfuse

Keep Langfuse and send the same spans to Laminar too.

All integrations

Browse every provider, framework, coding agent, and browser integration Laminar supports.