Skip to Content
SDKJavaScript SDK

JavaScript SDK

Track AI events, feedback, and traces in your TypeScript app.

Installation

npm install @introspection-sdk/introspection-node

For browser usage:

npm install @introspection-sdk/introspection-browser

Configuration

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, })
OptionTypeDefaultDescription
tokenstringINTROSPECTION_TOKEN env varAPI token
serviceNamestringINTROSPECTION_SERVICE_NAME or "introspection-client"Service name for trace attribution
baseUrlstringINTROSPECTION_BASE_URL or "https://otel.introspection.dev"API endpoint
flushIntervalMsnumber5000How often buffered events are sent
maxBatchSizenumber100Max 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.

Last updated on