SDK
JavaScript SDK
Installation
npm
npm install @introspection-sdk/introspection-nodeFor browser usage:
npm install @introspection-sdk/introspection-browserConfiguration
import { IntrospectionClient } from "@introspection-sdk/introspection-node"
const client = new IntrospectionClient()The client reads credentials from the environment by default. You can also pass them explicitly:
const client = new IntrospectionClient({
token: "intro_xxx",
serviceName: "my-app",
baseUrl: "https://otel.introspection.dev",
flushIntervalMs: 5000,
maxBatchSize: 100,
})| Option | Type | Default | Description |
|---|---|---|---|
token | string | INTROSPECTION_TOKEN env var | API token |
serviceName | string | INTROSPECTION_SERVICE_NAME or "introspection-client" | Service name for trace attribution |
baseUrl | string | INTROSPECTION_BASE_URL or "https://otel.introspection.dev" | API endpoint |
flushIntervalMs | number | 5000 | How often buffered events are sent |
maxBatchSize | number | 100 | Max events per batch |
Quick Start
Track an event, identify a user, and send feedback:
import { IntrospectionClient } from "@introspection-sdk/introspection-node"
const client = new IntrospectionClient()
// Identify a user
client.identify("user_123", { plan: "pro", name: "Jane" })
// Track a product event
client.track("query_submitted", { source: "chat" })
// Send feedback tied to a conversation
await client.withUserId("user_123", async () => {
await client.withConversation("conv_456", "msg_123", async () => {
client.feedback("thumbs_down", { comments: "This answer was wrong" })
})
})
// Flush and shut down before process exit
await client.shutdown()Identifying Users
Use identify to attach traits to a user:
client.identify("user_123", { plan: "pro", name: "Jane", email: "jane@example.com" })Use withUserId to set the user context for a block of code. All events inside are automatically associated:
await client.withUserId("user_123", async () => {
client.track("page_viewed", { path: "/dashboard" })
client.feedback("thumbs_up")
})Tracking Events
client.track("query_submitted", { source: "chat", model: "gpt-4o" })Feedback
client.feedback("thumbs_down", { comments: "Answer was off-topic" })Use withConversation to tie feedback to a specific conversation and message:
await client.withConversation("conv_456", "msg_789", async () => {
client.feedback("thumbs_up")
})Browser
Use the browser package for client-side events:
import { IntrospectionClient } from "@introspection-sdk/introspection-browser"
const client = new IntrospectionClient({ token: "intro_xxx" })
client.track("page_viewed", { path: "/pricing" })
client.identify("user_123", { plan: "pro" })
client.feedback("thumbs_up")The browser package sends events directly from the client. Use @introspection-sdk/introspection-node for server-side integrations where the token should stay private.
OpenAI Agents
Use IntrospectionTracingProcessor for OpenAI Agents:
import { Agent, run, addTraceProcessor } from "@openai/agents"
import { IntrospectionTracingProcessor } from "@introspection-sdk/introspection-node"
const processor = new IntrospectionTracingProcessor()
addTraceProcessor(processor)
const agent = new Agent({
name: "Weather Assistant",
model: "gpt-4o",
instructions: "You are a helpful weather assistant.",
})
const result = await run(agent, "What's the weather in Tokyo?")
console.log(result.finalOutput)
await processor.shutdown()Claude Agent SDK
Use withIntrospection() for Claude Agent SDK:
import * as sdk from "@anthropic-ai/claude-agent-sdk"
import { withIntrospection } from "@introspection-sdk/introspection-node"
const tracedSdk = withIntrospection(sdk)
const stream = tracedSdk.query({
prompt: "What is 2 + 2?",
options: { model: "claude-sonnet-4-5-20250929", maxTurns: 1 },
})
for await (const message of stream) {
// Handle streamed messages
}
await tracedSdk.shutdown()withIntrospection() wraps the entire SDK module. All sessions created from the traced SDK are automatically instrumented.
Vercel AI SDK
Use IntrospectionAISDKIntegration with the Vercel AI SDK:
import { IntrospectionAISDKIntegration } from "@introspection-sdk/introspection-node"
import { generateText } from "ai"
import { openai } from "@ai-sdk/openai"
const introspection = new IntrospectionAISDKIntegration()
const { text } = await generateText({
model: openai("gpt-4o"),
prompt: "Hello!",
experimental_telemetry: { isEnabled: true, integrations: [introspection] },
})
await introspection.shutdown()LangChain / LangGraph
import { IntrospectionCallbackHandler } from "@introspection-sdk/introspection-node/langchain"
import { ChatOpenAI } from "@langchain/openai"
const handler = new IntrospectionCallbackHandler({
serviceName: "my-langchain-app",
})
const model = new ChatOpenAI({ modelName: "gpt-4o-mini" })
await model.invoke("Hello!", { callbacks: [handler] })
await handler.shutdown()Mastra
import { Observability } from "@mastra/observability"
import { IntrospectionMastraExporter } from "@introspection-sdk/introspection-node/mastra"
const observability = new Observability({
configs: {
otel: {
serviceName: "mastra-app",
exporters: [new IntrospectionMastraExporter()],
},
},
})Tracing
Use IntrospectionSpanProcessor when you already have OpenTelemetry or OpenInference in place. This is the most flexible integration path — it works with any instrumentation library.
import OpenAI from "openai"
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node"
import { OpenAIInstrumentation } from "@arizeai/openinference-instrumentation-openai"
import { registerInstrumentations } from "@opentelemetry/instrumentation"
import { IntrospectionSpanProcessor } from "@introspection-sdk/introspection-node"
const provider = new NodeTracerProvider({
spanProcessors: [new IntrospectionSpanProcessor()],
})
provider.register()
const instrumentation = new OpenAIInstrumentation()
instrumentation.manuallyInstrument(OpenAI)
registerInstrumentations({ instrumentations: [instrumentation] })If you already export traces to another backend (Datadog, Honeycomb, etc.), you can add IntrospectionSpanProcessor as an additional processor alongside your existing one. See Dual Export for details.
Shutdown
Call shutdown() before your process exits to flush any buffered events:
await client.shutdown()For integrations that expose their own processor (e.g. IntrospectionTracingProcessor, IntrospectionAISDKIntegration), call shutdown() on the processor instance instead.
Error Handling
The SDK is designed to never throw in your application’s hot path. Events are buffered and sent asynchronously. If a request fails, the SDK retries internally and logs the failure.