Module @arizeai/phoenix-otel

Arize Phoenix logo
@arizeai/phoenix-otel

NPM Version Documentation

A lightweight wrapper around OpenTelemetry for Node.js applications that simplifies sending traces to Arize Phoenix. This package provides an easy-to-use register function that handles all the boilerplate configuration for OpenTelemetry tracing.

Note: This package is under active development and APIs may change.

  • Simple Setup - One-line configuration with sensible defaults
  • Environment Variables - Automatic configuration from environment variables
  • Batch Processing - Built-in batch span processing for production use
npm install @arizeai/phoenix-otel

The simplest way to get started is to use the register function:

import { register } from "@arizeai/phoenix-otel";

// Register with default settings (connects to localhost:6006)
register({
projectName: "my-app",
});

For production use with Phoenix Cloud:

import { register } from "@arizeai/phoenix-otel";

register({
projectName: "my-app",
url: "https://app.phoenix.arize.com",
apiKey: process.env.PHOENIX_API_KEY,
});

The register function automatically reads from environment variables:

# For local Phoenix server (default)
export PHOENIX_COLLECTOR_ENDPOINT="http://localhost:6006"

# For Phoenix Cloud
export PHOENIX_COLLECTOR_ENDPOINT="https://app.phoenix.arize.com"
export PHOENIX_API_KEY="your-api-key"

The register function accepts the following parameters:

Parameter Type Default Description
projectName string "default" The project name for organizing traces in Phoenix
url string "http://localhost:6006" The URL to your Phoenix instance
apiKey string undefined API key for Phoenix authentication
headers Record<string, string> {} Custom headers for OTLP requests
batch boolean true Use batch span processing (recommended for production)
instrumentations Instrumentation[] undefined Array of OpenTelemetry instrumentations to register
global boolean true Register the tracer provider globally
diagLogLevel DiagLogLevel undefined Diagnostic logging level for debugging

Automatically instrument common libraries (works best with CommonJS):

import { register } from "@arizeai/phoenix-otel";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";

register({
projectName: "my-express-app",
instrumentations: [new HttpInstrumentation(), new ExpressInstrumentation()],
});

Note: Auto-instrumentation via the instrumentations parameter works best with CommonJS projects. ESM projects require manual instrumentation.

For ESM projects, manually instrument libraries:

// instrumentation.ts
import { register, registerInstrumentations } from "@arizeai/phoenix-otel";
import OpenAI from "openai";
import { OpenAIInstrumentation } from "@arizeai/openinference-instrumentation-openai";

register({
projectName: "openai-app",
});

// Manual instrumentation for ESM
const instrumentation = new OpenAIInstrumentation();
instrumentation.manuallyInstrument(OpenAI);

registerInstrumentations({
instrumentations: [instrumentation],
});
// main.ts
import "./instrumentation.ts";
import OpenAI from "openai";

const openai = new OpenAI();

const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello!" }],
});

Create custom spans using the OpenTelemetry API:

import { register, trace } from "@arizeai/phoenix-otel";

register({ projectName: "my-app" });

const tracer = trace.getTracer("my-service");

async function processOrder(orderId: string) {
return tracer.startActiveSpan("process-order", async (span) => {
try {
span.setAttribute("order.id", orderId);

// Your business logic here
const result = await fetchOrderDetails(orderId);

span.setAttribute("order.status", result.status);
return result;
} catch (error) {
span.recordException(error as Error);
span.setStatus({ code: SpanStatusCode.ERROR });
throw error;
} finally {
span.end();
}
});
}

Development (with debug logging):

import { register } from "@arizeai/phoenix-otel";
import { DiagLogLevel } from "@opentelemetry/api";

register({
projectName: "my-app-dev",
url: "http://localhost:6006",
batch: false, // Immediate span delivery for faster feedback
diagLogLevel: DiagLogLevel.DEBUG,
});

Production (optimized for performance):

import { register } from "@arizeai/phoenix-otel";

register({
projectName: "my-app-prod",
url: "https://app.phoenix.arize.com",
apiKey: process.env.PHOENIX_API_KEY,
batch: true, // Batch processing for better performance
});

Add custom headers to OTLP requests:

import { register } from "@arizeai/phoenix-otel";

register({
projectName: "my-app",
url: "https://app.phoenix.arize.com",
headers: {
"X-Custom-Header": "custom-value",
"X-Environment": process.env.NODE_ENV || "development",
},
});

Use the provider explicitly without registering globally:

import { register } from "@arizeai/phoenix-otel";

const provider = register({
projectName: "my-app",
global: false,
});

// Use the provider explicitly
const tracer = provider.getTracer("my-tracer");

For convenience, commonly used OpenTelemetry APIs are re-exported:

import {
trace, // Main tracing API
context, // Context API
SpanStatusCode, // Span status codes
registerInstrumentations, // Register instrumentations
type DiagLogLevel, // Diagnostic log levels
type Tracer, // Tracer type
type Instrumentation, // Instrumentation type
type NodeTracerProvider, // Provider type
} from "@arizeai/phoenix-otel";

Join our community to connect with thousands of AI builders:

  • 🌍 Join our Slack community
  • πŸ’‘ Ask questions and provide feedback in the #phoenix-support channel
  • 🌟 Leave a star on our GitHub
  • 🐞 Report bugs with GitHub Issues
  • 𝕏 Follow us on 𝕏
  • πŸ—ΊοΈ Check out our roadmap

Modules

config
createNoOpProvider
index
register
utils