Skip to main content
bryel is OpenTelemetry-native. On the server you have three ways in, all shipping the same OpenInference traces — models, tokens, cost, tool calls, full trajectory.

Vercel AI SDK

One processor + a per-call flag.

Any OTel app

Ship spans you already emit.

Provider SDKs

OpenAI / Anthropic / LangChain.

Vercel AI SDK

@bryel/vercel maps the AI SDK’s OpenTelemetry spans into OpenInference and ships them to bryel. You never wrap your model calls.
1

Install

bun add @bryel/vercel @vercel/otel
2

Register the processor once

In instrumentation.ts — Next.js calls this on startup.
instrumentation.ts
import { registerOTel } from "@vercel/otel";
import { bryelVercelProcessor } from "@bryel/vercel";

export function register() {
  registerOTel({
    serviceName: "my-app",
    spanProcessors: [bryelVercelProcessor({ apiKey: process.env.BRYEL_KEY! })],
  });
}
3

Enable telemetry per call

const result = streamText({
  model: openai("gpt-5"),
  prompt,
  experimental_telemetry: {
    isEnabled: true,
    metadata: { sessionId, userId },
  },
});
A streamed span finalizes only once the stream is fully consumed — always drain it.

Any OpenTelemetry app

If your app already emits OpenInference spans, add bryelSpanProcessor to your provider — no mapping.
bun add @bryel/sdk-core @opentelemetry/sdk-trace-base
import { NodeSDK } from "@opentelemetry/sdk-node";
import { bryelSpanProcessor } from "@bryel/sdk-core";

new NodeSDK({
  spanProcessors: [bryelSpanProcessor({ apiKey: process.env.BRYEL_KEY })],
}).start();
If your spans aren’t OpenInference yet, supply a SpanMapper (this is exactly what @bryel/vercel does):
import { buildSpanProcessor, type SpanMapper } from "@bryel/sdk-core";

const mapper: SpanMapper = {
  name: "my-framework",
  shouldMap: (span) => span.name.startsWith("my."),
  map: (span) => ({ /* OpenInference attributes to merge */ }),
};

const processor = buildSpanProcessor(mapper, { apiKey: process.env.BRYEL_KEY });

Provider SDKs

Calling OpenAI / Anthropic / LangChain directly? Add any OpenTelemetry instrumentation that emits GenAI spans, then ship them with bryelSpanProcessor — no call-site changes:
import { NodeSDK } from "@opentelemetry/sdk-node";
import { bryelSpanProcessor } from "@bryel/sdk-core";
// + the OpenTelemetry instrumentation for your provider SDK

new NodeSDK({
  instrumentations: [/* your GenAI instrumentation */],
  spanProcessors: [bryelSpanProcessor({ apiKey: process.env.BRYEL_KEY })],
}).start();

Grouping and feedback

The metadata you pass groups and joins your data:
sessionId
string
Groups turns into one conversation.
userId
string
The end user behind the run.
messageId
string
A per-turn id you mint (crypto.randomUUID()). bryel stamps it as bryel.interaction.id so feedback joins back to the turn.

API

apiKey
string
required
Project API key (bk_…).
endpoint
string
default:"https://ingest.eu.bryel.ai/v1/traces"
OTLP/HTTP endpoint. Override for self-hosting.
headers
Record<string, string>
Extra headers, merged after auth.
bryelVercelProcessor (AI SDK, with mapping), bryelSpanProcessor (no mapping), and buildSpanProcessor(mapper, options) (custom mapping) all take these options and return an OTel SpanProcessor.