Skip to main content
The LangChain integration automatically instruments LangChain applications by injecting Sentry callback handlers into all runnable instances.

Installation

The integration is enabled by default in Node.js:
import * as Sentry from '@sentry/node';

Sentry.init({
  dsn: 'your-dsn',
  // langChainIntegration is included by default
});

Basic Usage

Just use LangChain normally:
import { ChatOpenAI } from '@langchain/openai';

const model = new ChatOpenAI({
  modelName: 'gpt-4',
});

// Automatically instrumented
const response = await model.invoke('What is the capital of France?');

Configuration

Default Behavior

By default, inputs and outputs are not captured:
Sentry.init({
  dsn: 'your-dsn',
  sendDefaultPii: false, // Default: no inputs/outputs
});

Capture Inputs and Outputs

Enable for all AI integrations:
Sentry.init({
  dsn: 'your-dsn',
  sendDefaultPii: true, // Captures all inputs/outputs
});

Integration Options

recordInputs
boolean
default:"sendDefaultPii"
Capture input messages and prompts
recordOutputs
boolean
default:"sendDefaultPii"
Capture responses and outputs

Automatic Instrumentation

The integration automatically instruments:

LLM and Chat Models

import { ChatOpenAI } from '@langchain/openai';
import { ChatAnthropic } from '@langchain/anthropic';

const openai = new ChatOpenAI();
const anthropic = new ChatAnthropic();

// Both automatically tracked
await openai.invoke('Hello!');
await anthropic.invoke('Hello!');

Chains

import { ChatOpenAI } from '@langchain/openai';
import { PromptTemplate } from '@langchain/core/prompts';

const model = new ChatOpenAI();
const prompt = PromptTemplate.fromTemplate(
  'Tell me a joke about {topic}'
);

const chain = prompt.pipe(model);

// Chain execution tracked
const response = await chain.invoke({ topic: 'programming' });

Tools

import { DynamicTool } from '@langchain/core/tools';

const weatherTool = new DynamicTool({
  name: 'get_weather',
  description: 'Get the current weather',
  func: async (location) => {
    return `Weather in ${location}: Sunny, 72°F`;
  },
});

// Tool execution tracked
await weatherTool.invoke({ location: 'San Francisco' });

Captured Events

The integration captures these LangChain lifecycle events:
1

LLM/Chat Start

When a language model call begins
2

LLM/Chat End

When a language model call completes
3

LLM/Chat Error

When a language model call fails
4

Chain Start

When a chain execution begins
5

Chain End

When a chain execution completes
6

Chain Error

When a chain execution fails
7

Tool Start

When a tool is invoked
8

Tool End

When a tool execution completes
9

Tool Error

When a tool execution fails

Manual Callback Handler

You can also manually add the Sentry callback handler:
import * as Sentry from '@sentry/node';
import { ChatOpenAI } from '@langchain/openai';

const sentryHandler = Sentry.createLangChainCallbackHandler({
  recordInputs: true,
  recordOutputs: true,
});

const model = new ChatOpenAI();
const response = await model.invoke(
  'What is AI?',
  { callbacks: [sentryHandler, myOtherCallback] }
);

Practical Examples

Question Answering Chain

import * as Sentry from '@sentry/node';
import { ChatOpenAI } from '@langchain/openai';
import { PromptTemplate } from '@langchain/core/prompts';
import { StringOutputParser } from '@langchain/core/output_parsers';

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

const prompt = PromptTemplate.fromTemplate(`
Answer the following question based on the context:

Context: {context}

Question: {question}

Answer:
`);

const chain = prompt.pipe(model).pipe(new StringOutputParser());

// Automatically tracked in Sentry
const answer = await chain.invoke({
  context: 'Paris is the capital of France.',
  question: 'What is the capital of France?',
});

RAG (Retrieval-Augmented Generation)

import { ChatOpenAI } from '@langchain/openai';
import { OpenAIEmbeddings } from '@langchain/openai';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';
import { createRetrievalChain } from 'langchain/chains/retrieval';
import { createStuffDocumentsChain } from 'langchain/chains/combine_documents';

const embeddings = new OpenAIEmbeddings();
const vectorStore = await MemoryVectorStore.fromTexts(
  ['Paris is the capital of France', 'Berlin is the capital of Germany'],
  [{ source: 'doc1' }, { source: 'doc2' }],
  embeddings
);

const model = new ChatOpenAI();
const combineDocsChain = await createStuffDocumentsChain({ llm: model });
const retrievalChain = await createRetrievalChain({
  retriever: vectorStore.asRetriever(),
  combineDocsChain,
});

// Full RAG pipeline tracked
const response = await retrievalChain.invoke({
  input: 'What is the capital of France?',
});

Agent with Tools

import { ChatOpenAI } from '@langchain/openai';
import { DynamicTool } from '@langchain/core/tools';
import { createToolCallingAgent, AgentExecutor } from 'langchain/agents';
import { ChatPromptTemplate } from '@langchain/core/prompts';

const model = new ChatOpenAI({
  modelName: 'gpt-4',
  temperature: 0,
});

const tools = [
  new DynamicTool({
    name: 'calculator',
    description: 'Performs basic math operations',
    func: async (input) => {
      return eval(input).toString();
    },
  }),
  new DynamicTool({
    name: 'weather',
    description: 'Gets current weather',
    func: async (location) => {
      return `Weather in ${location}: Sunny`;
    },
  }),
];

const prompt = ChatPromptTemplate.fromMessages([
  ['system', 'You are a helpful assistant'],
  ['human', '{input}'],
  ['placeholder', '{agent_scratchpad}'],
]);

const agent = await createToolCallingAgent({ llm: model, tools, prompt });
const executor = new AgentExecutor({ agent, tools });

// Agent execution and tool calls tracked
const result = await executor.invoke({
  input: 'What is 25 * 4 and what is the weather in Paris?',
});

Streaming Responses

import { ChatOpenAI } from '@langchain/openai';

const model = new ChatOpenAI({
  streaming: true,
});

// Streaming tracked with final response
const stream = await model.stream('Tell me a story');

for await (const chunk of stream) {
  process.stdout.write(chunk.content);
}

Provider Integration

LangChain automatically disables OpenAI, Anthropic, and Google GenAI integrations to prevent duplicate spans.
When using LangChain, provider integrations are skipped:
import { ChatOpenAI } from '@langchain/openai';
import { ChatAnthropic } from '@langchain/anthropic';

// Only LangChain spans are created (no OpenAI/Anthropic duplicates)
const openai = new ChatOpenAI();
await openai.invoke('Hello');

const anthropic = new ChatAnthropic();
await anthropic.invoke('Hello');
Direct SDK usage still creates provider spans:
import OpenAI from 'openai';
import { ChatOpenAI } from '@langchain/openai';

const openai = new OpenAI();
const langchainModel = new ChatOpenAI();

// Creates OpenAI span
await openai.chat.completions.create({...});

// Creates LangChain span
await langchainModel.invoke('Hello');

Viewing LangChain Data

LangChain operations appear as spans in traces:
Transaction: POST /api/chat
├─ langchain.chain.start
│  ├─ langchain.llm.start (OpenAI GPT-4)
│  │  └─ Duration: 2.1s
│  ├─ langchain.tool.start (calculator)
│  │  └─ Duration: 15ms
│  └─ Duration: 2.5s
└─ Total: 2.5s

Performance Monitoring

  • Chain Execution Time: Track complex workflow performance
  • LLM Latency: Monitor model response times
  • Tool Performance: Identify slow tool executions
  • Error Rates: Track failures in chains and tools

Source Code

The LangChain integration is implemented in: packages/node/src/integrations/tracing/langchain/index.ts:11

Privacy Best Practices

Use recordInputs and recordOutputs selectively based on data sensitivity.

Filter Sensitive Prompts

Sentry.init({
  dsn: 'your-dsn',
  sendDefaultPii: true,
  
  beforeSendSpan(span) {
    // Remove sensitive data from LangChain spans
    if (span.op?.startsWith('langchain')) {
      const attributes = span.attributes || {};
      for (const key in attributes) {
        if (key.includes('input') || key.includes('prompt')) {
          attributes[key] = '[Filtered]';
        }
      }
    }
    return span;
  },
});

Troubleshooting

Spans Not Appearing

Ensure tracing is enabled:
Sentry.init({
  dsn: 'your-dsn',
  tracesSampleRate: 1.0,
});

Duplicate Spans

If you see duplicate spans, ensure you’re not manually instrumenting providers that LangChain already handles.

Custom Callbacks

To use custom callbacks alongside Sentry:
const sentryHandler = Sentry.createLangChainCallbackHandler();
const myHandler = new MyCustomHandler();

await model.invoke('Hello', {
  callbacks: [sentryHandler, myHandler],
});

Build docs developers (and LLMs) love