Documentation Index
Fetch the complete documentation index at: https://mintlify.com/getsentry/sentry-javascript/llms.txt
Use this file to discover all available pages before exploring further.
The OpenAI integration automatically instruments OpenAI SDK calls to capture performance data and errors.
Installation
The integration is enabled by default:import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'your-dsn',
// openAIIntegration is included by default
});
Use manual instrumentation:import * as Sentry from '@sentry/browser';
import { instrumentOpenAiClient } from '@sentry/browser';
import OpenAI from 'openai';
Sentry.init({
dsn: 'your-dsn',
});
const openai = instrumentOpenAiClient(new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
dangerouslyAllowBrowser: true,
}));
Basic Usage
Just use the OpenAI SDK normally:
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
// Automatically instrumented
const completion = await openai.chat.completions.create({
model: 'gpt-4',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'What is the capital of France?' },
],
});
Configuration
Default Behavior
By default, prompts and responses are not captured:
Sentry.init({
dsn: 'your-dsn',
sendDefaultPii: false, // Default: no prompts/responses
});
Capture Prompts and Responses
Global Setting
OpenAI Only
Inputs Only
Enable for all AI integrations:Sentry.init({
dsn: 'your-dsn',
sendDefaultPii: true, // Captures all inputs/outputs
});
Enable only for OpenAI:Sentry.init({
dsn: 'your-dsn',
sendDefaultPii: false,
integrations: [
Sentry.openAIIntegration({
recordInputs: true,
recordOutputs: true,
}),
],
});
Capture prompts but not responses:Sentry.init({
dsn: 'your-dsn',
integrations: [
Sentry.openAIIntegration({
recordInputs: true,
recordOutputs: false,
}),
],
});
Integration Options
recordInputs
boolean
default:"sendDefaultPii"
Capture prompt messages
recordOutputs
boolean
default:"sendDefaultPii"
Capture completion responses
Captured Data
Always Captured
These attributes are always included:
{
'gen_ai.operation.name': 'chat',
'gen_ai.request.model': 'gpt-4',
'gen_ai.system': 'openai',
'gen_ai.usage.input_tokens': 25,
'gen_ai.usage.output_tokens': 100,
'gen_ai.response.finish_reasons': ['stop'],
'gen_ai.request.temperature': 1.0,
'gen_ai.request.max_tokens': 256,
}
Prompt messages are captured:
{
'gen_ai.prompt.0.role': 'system',
'gen_ai.prompt.0.content': 'You are a helpful assistant.',
'gen_ai.prompt.1.role': 'user',
'gen_ai.prompt.1.content': 'What is the capital of France?',
}
When recordOutputs: true
Completion responses are captured:
{
'gen_ai.completion.0.role': 'assistant',
'gen_ai.completion.0.content': 'The capital of France is Paris.',
'gen_ai.completion.0.finish_reason': 'stop',
}
Supported Operations
The integration instruments all OpenAI operations:
Chat Completions
const completion = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello!' }],
});
// Span: gen_ai.chat.completions
Streaming Completions
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
// Span includes full streaming response
Embeddings
const embedding = await openai.embeddings.create({
model: 'text-embedding-ada-002',
input: 'Your text here',
});
// Span: gen_ai.embeddings.create
Function Calling
const completion = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'What is the weather?' }],
functions: [
{
name: 'get_weather',
description: 'Get current weather',
parameters: {
type: 'object',
properties: {
location: { type: 'string' },
},
},
},
],
});
// Tool calls captured in span attributes
Practical Examples
Customer Support Bot
import * as Sentry from '@sentry/node';
import OpenAI from 'openai';
const openai = new OpenAI();
async function answerSupportQuery(userId, query) {
return await Sentry.startSpan(
{
name: 'Answer Support Query',
op: 'ai.support',
attributes: {
'user.id': userId,
'support.category': 'general',
},
},
async () => {
const completion = await openai.chat.completions.create({
model: 'gpt-4',
messages: [
{
role: 'system',
content: 'You are a helpful customer support agent.',
},
{ role: 'user', content: query },
],
});
return completion.choices[0].message.content;
}
);
}
Content Generation
async function generateBlogPost(topic, keywords) {
return await Sentry.startSpan(
{
name: 'Generate Blog Post',
op: 'ai.content_generation',
attributes: {
'content.topic': topic,
'content.keywords': keywords.join(', '),
},
},
async () => {
const completion = await openai.chat.completions.create({
model: 'gpt-4',
messages: [
{
role: 'system',
content: 'You are a professional content writer.',
},
{
role: 'user',
content: `Write a blog post about ${topic} including these keywords: ${keywords.join(', ')}`,
},
],
temperature: 0.8,
max_tokens: 2000,
});
return completion.choices[0].message.content;
}
);
}
Semantic Search with Embeddings
async function searchDocuments(query, documents) {
return await Sentry.startSpan(
{ name: 'Semantic Search', op: 'ai.search' },
async () => {
// Get query embedding
const queryEmbedding = await openai.embeddings.create({
model: 'text-embedding-ada-002',
input: query,
});
// Compare with document embeddings
const results = findSimilarDocuments(
queryEmbedding.data[0].embedding,
documents
);
return results;
}
);
}
Error Handling
async function generateWithRetry(prompt, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const completion = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
});
return completion.choices[0].message.content;
} catch (error) {
Sentry.captureException(error, {
contexts: {
openai: {
attempt,
max_retries: maxRetries,
model: 'gpt-4',
},
},
});
if (attempt === maxRetries) {
throw error;
}
// Exponential backoff
await new Promise(resolve => setTimeout(resolve, 2 ** attempt * 1000));
}
}
}
View OpenAI performance in Sentry:
- Response Times: Track API latency
- Token Usage: Monitor prompt and completion tokens
- Error Rates: Identify rate limits and failures
- Model Comparison: Compare performance across models
Source Code
The OpenAI integration is implemented in:
packages/node/src/integrations/tracing/openai/index.ts:11
Privacy Best Practices
Be careful about capturing sensitive user data in prompts and responses.
Filter Sensitive Content
Sentry.init({
dsn: 'your-dsn',
sendDefaultPii: true,
beforeSendSpan(span) {
// Remove PII from prompts
const promptContent = span.attributes?.['gen_ai.prompt.1.content'];
if (promptContent && typeof promptContent === 'string') {
span.attributes['gen_ai.prompt.1.content'] = promptContent
.replace(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, '[EMAIL]')
.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN]');
}
return span;
},
});
Conditional Capture
const isSensitiveQuery = query.toLowerCase().includes('password');
const integration = isSensitiveQuery
? Sentry.openAIIntegration({ recordInputs: false, recordOutputs: false })
: Sentry.openAIIntegration({ recordInputs: true, recordOutputs: true });
Troubleshooting
Spans Not Appearing
Ensure tracing is enabled:
Sentry.init({
dsn: 'your-dsn',
tracesSampleRate: 1.0, // Capture 100% of traces
});
Missing Token Data
Token usage is always captured from OpenAI’s response:
// Check the span attributes in Sentry for:
// - gen_ai.usage.input_tokens
// - gen_ai.usage.output_tokens