Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.bentolabs.ai/llms.txt

Use this file to discover all available pages before exploring further.

Bento is an OpenTelemetry collector. If your agent framework already emits OpenTelemetry traces, point its exporter at one endpoint with one auth header and the traces land in Bento. In TypeScript you can do this with no Bento package at all.

The endpoint

Every OpenTelemetry exporter needs two settings. Send to ${BENTOLABS_BASE_URL}/v1/traces (the default base URL is https://api.bentolabs.ai), and add the header Authorization: Bearer bl_pk_... carrying your BENTOLABS_API_KEY.
Bento’s ingest accepts OTLP/HTTP with a JSON payload (gzip is fine), not protobuf. Configure your exporter for http/json. Some OpenTelemetry exporters default to protobuf, so check the per-language notes below.
Bento reads the standard gen_ai.* and openinference.* span attributes, so traces from these frameworks fill the same dashboard columns described in Attributes. Nothing about your spans is Bento-specific.

TypeScript / JavaScript, no Bento SDK

JavaScript’s OpenTelemetry exporters can emit JSON, so you can send traces to Bento without installing any Bento package.

Vercel AI SDK

Wire a JSON OTLP exporter once, then turn on telemetry per call. Use @vercel/otel’s OTLPHttpJsonTraceExporter, which sends JSON as the name says:
// instrumentation.ts
import { registerOTel, OTLPHttpJsonTraceExporter } from "@vercel/otel";

export function register() {
  registerOTel({
    serviceName: "my-app",
    traceExporter: new OTLPHttpJsonTraceExporter({
      url: `${process.env.BENTOLABS_BASE_URL ?? "https://api.bentolabs.ai"}/v1/traces`,
      headers: { Authorization: `Bearer ${process.env.BENTOLABS_API_KEY}` },
    }),
  });
}
// then enable telemetry on each call
await generateText({
  model,
  prompt,
  experimental_telemetry: { isEnabled: true, functionId: "my-fn" },
});
The AI SDK sets gen_ai.* attributes (model, token counts, finish reasons) on its LLM spans, so the model, cost, and token columns fill in. Prompt and response text live under ai.*. To populate the input and output columns too, add the @arizeai/openinference-vercel span processor to the same setup.

Mastra

Use Mastra’s OtelExporter with a custom provider and protocol: "http/json", which gives Bento the JSON it needs:
import { OtelExporter } from "@mastra/otel-exporter";

new OtelExporter({
  provider: {
    custom: {
      endpoint: `${process.env.BENTOLABS_BASE_URL ?? "https://api.bentolabs.ai"}/v1/traces`,
      protocol: "http/json",
      headers: { Authorization: `Bearer ${process.env.BENTOLABS_API_KEY}` },
    },
  },
});
Mastra’s ArizeExporter preset maps spans to OpenInference, but it can send protobuf, which Bento doesn’t accept, and it switches to Arize’s own headers when ARIZE_SPACE_ID is set in the environment. Use the OtelExporter with protocol: "http/json" shown above. Whichever you pick, run one real flow afterward and confirm the six dashboard columns fill (see Verify below).

Python, with the Bento span processor

Python’s OpenTelemetry exporters send protobuf, which Bento doesn’t accept, so Python has no no-SDK path. Install the Bento SDK and use its JSON span processor (BentoLabsSpanProcessor) together with your framework’s OpenInference instrumentor. Your call sites stay untouched.
pip install bentolabs-sdk openinference-instrumentation-langchain
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from openinference.instrumentation.langchain import LangChainInstrumentor

from bentolabs_sdk import BentoLabsSpanProcessor  # sends JSON to Bento

provider = TracerProvider()
provider.add_span_processor(BentoLabsSpanProcessor())
trace.set_tracer_provider(provider)

LangChainInstrumentor().instrument(tracer_provider=provider)
Swap the instrumentor for your framework: openinference-instrumentation-llama-index, -openai-agents, -crewai, -anthropic, and so on. The processor reads BENTOLABS_API_KEY and BENTOLABS_BASE_URL from the environment. See OTel transport for the processor details and Attributes for how attributes map to columns. This holds even for frameworks that emit OpenTelemetry natively, like Pydantic AI via Agent.instrument_all(). They still need a JSON exporter, so attach BentoLabsSpanProcessor rather than a stock OTLP exporter.

Which framework do I use?

FrameworkLanguageHow to send to Bento
Vercel AI SDKTypeScript@vercel/otel OTLPHttpJsonTraceExporter, no Bento SDK
MastraTypeScriptOtelExporter with protocol: "http/json", no Bento SDK
LangChain / LangGraphPythonOpenInference instrumentor + BentoLabsSpanProcessor
LlamaIndexPythonOpenInference instrumentor + BentoLabsSpanProcessor
Pydantic AIPythonAgent.instrument_all() + BentoLabsSpanProcessor
OpenAI Agents SDKPythonOpenInference instrumentor + BentoLabsSpanProcessor (its built-in tracing is not OTLP)
CrewAIPythonOpenInference instrumentor + BentoLabsSpanProcessor
Using Google ADK? Use the one-line bentolabs-sdk[adk] integration instead. It captures every call automatically.

Verify

A trace arriving is not the same as the dashboard filling in. After wiring the exporter, run one real flow, open platform.bentolabs.ai, and confirm the row has all six columns: provider, model, input, output, user_id, convo_id.
  • If input / output are empty, the framework emits metadata but not content. Add its OpenInference instrumentor (Python) or the @arizeai/openinference-vercel processor (Vercel) on the same exporter.
  • user_id and convo_id come from the gen_ai.user.id and gen_ai.conversation.id span attributes. With no Bento SDK, set them through your framework (a run attribute, a span processor, or OTLP resource attributes).

See also

Attributes

How gen_ai.* / openinference.* attributes map to dashboard columns.

OTel transport

The BentoLabsSpanProcessor and BentoLabsTraceExporter details.

Quickstart

Install the SDK and send your first trace.

Migrate an existing stack

Move from Langfuse or Raindrop to Bento.