TypeScript Setup
Setup Phoenix tracing in TypeScript/JavaScript with @arizeai/phoenix-otel.
Metadata
| Attribute | Value |
|---|---|
| Priority | Critical - required for all tracing |
| Setup Time | <5 min |
Quick Start
npm install @arizeai/phoenix-otel
import { register } from "@arizeai/phoenix-otel";
register({ projectName: "my-app" });
Connects to http://localhost:6006 by default.
Configuration
import { register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app",
url: "http://localhost:6006",
apiKey: process.env.PHOENIX_API_KEY,
batch: true
});
Environment variables:
export PHOENIX_API_KEY="your-api-key"
export PHOENIX_COLLECTOR_ENDPOINT="http://localhost:6006"
export PHOENIX_PROJECT_NAME="my-app"
ESM vs CommonJS
CommonJS (automatic):
const { register } = require("@arizeai/phoenix-otel");
register({ projectName: "my-app" });
const OpenAI = require("openai");
ESM (manual instrumentation required):
import { register, registerInstrumentations } from "@arizeai/phoenix-otel";
import { OpenAIInstrumentation } from "@arizeai/openinference-instrumentation-openai";
import OpenAI from "openai";
register({ projectName: "my-app" });
const instrumentation = new OpenAIInstrumentation();
instrumentation.manuallyInstrument(OpenAI);
registerInstrumentations({ instrumentations: [instrumentation] });
Why: ESM imports are hoisted, so manuallyInstrument() is needed.
Framework Integration
Next.js (App Router):
// instrumentation.ts
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
const { register } = await import("@arizeai/phoenix-otel");
register({ projectName: "my-nextjs-app" });
}
}
Express.js:
import { register } from "@arizeai/phoenix-otel";
register({ projectName: "my-express-app" });
const app = express();
Flushing Spans Before Exit
CRITICAL: Spans may not be exported if still queued in the processor when your process exits. Call provider.shutdown() to explicitly flush before exit.
Standard pattern:
const provider = register({
projectName: "my-app",
batch: true,
});
async function main() {
await doWork();
await provider.shutdown(); // Flush spans before exit
}
main().catch(async (error) => {
console.error(error);
await provider.shutdown(); // Flush on error too
process.exit(1);
});
Alternative:
// Use batch: false for immediate export (no shutdown needed)
register({
projectName: "my-app",
batch: false,
});
For production patterns including graceful termination, see production-typescript.md.
Verification
- Open Phoenix UI:
http://localhost:6006 - Run your application
- Check for traces in your project
Enable diagnostic logging:
import { DiagLogLevel, register } from "@arizeai/phoenix-otel";
register({
projectName: "my-app",
diagLogLevel: DiagLogLevel.DEBUG,
});
Troubleshooting
No traces:
- Verify
PHOENIX_COLLECTOR_ENDPOINTis correct - Set
PHOENIX_API_KEYfor Phoenix Cloud - For ESM: Ensure
manuallyInstrument()is called - With
batch: true: Callprovider.shutdown()before exit to flush queued spans (see Flushing Spans section)
Traces missing:
- With
batch: true: Callawait provider.shutdown()before process exit to flush queued spans - Alternative: Set
batch: falsefor immediate export (no shutdown needed)
Missing attributes:
- Check instrumentation is registered (ESM requires manual setup)
- See
instrumentation-auto-typescript.md
See Also
- Auto-instrumentation:
instrumentation-auto-typescript.md - Manual instrumentation:
instrumentation-manual-typescript.md - API docs: https://arize-ai.github.io/phoenix/