Skip to main content
Send traces and logs from your existing OpenTelemetry instrumentation to Braintrust. Use an OTLP trace exporter or Braintrust span processor for traces, and an OTLP logs exporter or OpenTelemetry Collector for logs. For combining Braintrust and OpenTelemetry spans in the same trace, see Link spans.

Choose an integration path

Choose the setup that matches how your application produces telemetry. To control how span attributes map to inputs, outputs, and metadata in Braintrust, see Attributes and events.

Send traces

Traces capture the operations within a request, including their timing and parent-child relationships. Send OpenTelemetry spans to Braintrust using an OTLP trace exporter or a Braintrust span processor in your application.

OTLP trace exporter

To send traces through an existing OpenTelemetry pipeline, configure its OTLP exporter with your Braintrust endpoint and credentials. Once you set up an OTLP exporter to send traces to Braintrust, Braintrust automatically converts LLM calls into Braintrust LLM spans, which convert LLM calls into Braintrust LLM spans, which can be saved as prompts and evaluated in the playground. For applications that use the OpenTelemetry SDK to export traces, set the following environment variables:
The trace endpoint URL is https://api.braintrust.dev/otel/v1/traces. If your exporter uses signal-specific environment variables, you’ll need to set the full path: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.braintrust.dev/otel/v1/traces
If your organization is on the EU data plane, use https://api-eu.braintrust.dev/otel instead. If you’re self-hosting Braintrust, substitute your stack’s Universal API URL. For example: OTEL_EXPORTER_OTLP_ENDPOINT=https://dfwhllz61x709.cloudfront.net/otelSee Data plane region.
The x-bt-parent header sets the trace’s parent project or experiment. You can use a prefix like project_id:, project_name:, or experiment_id: here, or pass in a span slug (span.export()) to nest the trace under a span within the parent object.
To find your project ID, go to your project’s configuration page and find the Copy Project ID button at the bottom of the page.
For JavaScript/TypeScript applications, you can use the BraintrustExporter directly:

Braintrust span processor

Braintrust span processors send trace spans from your application to Braintrust.
To send spans from your TypeScript application, configure a Braintrust span processor.Install the integration and attach it to your OpenTelemetry provider.
1

Install and configure credentials

Starting with v1.0, OpenTelemetry functionality has been moved to the separate @braintrust/otel npm package. This solves ESM build issues in Next.js (edge), Cloudflare Workers, Bun, and TanStack applications, and adds support for both OpenTelemetry v1 and v2. BraintrustSpanProcessor works with @opentelemetry/sdk-trace-base@1.x and v2 spans.If you’re upgrading from v0.x, see the upgrade guide for migration instructions.
Install the Braintrust TypeScript SDK with the following OpenTelemetry dependencies:
2

Configure the span processor

For TypeScript and JavaScript applications, use the BraintrustSpanProcessor with NodeSDK:
opentelemetry-braintrust.ts
Or configure it manually with a custom tracer provider:
opentelemetry-braintrust.ts
Configure the processor with these arguments:
  • apiKey: The API key to use for Braintrust. Defaults to the BRAINTRUST_API_KEY environment variable.
  • apiUrl: The URL of the Braintrust API. Defaults to the BRAINTRUST_API_URL environment variable or https://api.braintrust.dev if not set.
  • parent: The parent project or experiment to use for Braintrust. Defaults to the BRAINTRUST_PARENT environment variable.
  • filterAISpans: Defaults to false. If true, only AI-related spans will be sent to Braintrust.
  • customFilter: A function that gives you fine-grained control over which spans are sent to Braintrust. It takes a span and returns a boolean. If true, the span will be sent to Braintrust. If false, the span will be dropped. If null, don’t influence the sampling decision.

Verify trace ingestion

After configuring either trace export method, confirm that spans reach the destination you selected:
  1. Run an instrumented operation with a distinctive span name. Let the operation finish and ensure pending spans are exported before the application exits.
  2. Open Logs in the destination project and find the trace. If you configured an experiment destination, open that experiment instead.
  3. Inspect the trace’s span names, timing, and parent-child relationships. Check that any inputs, outputs, and metadata you sent appear in the expected fields, using Attributes and events as a reference.
If the trace is missing, see Why are my traces not showing up?.

Send logs

Logs capture individual application events, such as a worker starting or a request retrying. Send these records to Braintrust using an OTLP logs exporter or OpenTelemetry Collector. The logs endpoint accepts OTLP over HTTP with application/json or application/x-protobuf payloads. For self-hosted deployments, the endpoint requires data plane v2.12.0 or later. Use data plane v2.14.0 or later for the log-row format and span-event ingestion described below. Data plane v2.14.0 ships with AWS Terraform v6.8.0 and Helm chart 6.18.0. See Self-hosting releases for deployment requirements and Upgrade your data plane if your deployment predates these versions. To find your organization’s API URL, go to Settings > Data plane.

OTLP logs exporter

Set BRAINTRUST_API_KEY to a Braintrust API key with permission to write to your project, and BRAINTRUST_PROJECT_ID to the project ID. For an exporter that supports the standard OTLP environment variables, configure the logs signal:
Replace the endpoint with the URL for your deployment. These variables configure the exporter. You also need to enable log collection in your application’s OpenTelemetry SDK. The signal-specific OTEL_EXPORTER_OTLP_LOGS_ENDPOINT includes /v1/logs. If you use the shared OTEL_EXPORTER_OTLP_ENDPOINT instead, set it to the base URL ending in /otel and let the exporter append the signal path. The C# SDK uses /otel/v1/logs as its default logs endpoint path, configured by BRAINTRUST_LOGS_PATH.

OpenTelemetry Collector

To receive OTLP logs from an application on the same host and forward them to Braintrust, use this Collector configuration. Set BRAINTRUST_API_KEY and BRAINTRUST_PROJECT_ID in the Collector’s environment.
Point your application’s HTTP logs exporter at http://localhost:4318/v1/logs. The Collector batches the records and sends them to Braintrust. Replace the Braintrust exporter endpoint with your deployment’s base URL ending in /otel. Collector versions that use the otlphttp exporter name require otlphttp/braintrust in both the exporter definition and the pipeline. For stored fields, trace correlation, and severity semantics, see Log records.

Verify log ingestion

Send a log with a distinctive message and inspect its stored row in your project using the SQL sandbox. Check that output contains the message and span_attributes.type is log. To test correlation, send a span and a log with matching trace and span IDs, then verify that their span_id and root_span_id match while their row id values differ.

Troubleshooting

Check these common causes when traces are missing or log ingestion fails.
  • Braintrust’s logs table only shows traces that have a root span (i.e. span_parents is empty). If you only send children spans, they will not appear in the logs table. A common reason for this is only sending spans to Braintrust which have a traceparent header. To fix this, make sure to send a root span for every trace you want to appear in the UI.
  • Make sure the OTEL_EXPORTER_OTLP_ENDPOINT matches your organization’s data plane region. Organizations on the EU data plane should use https://api-eu.braintrust.dev/otel. Self-hosted deployments should use their custom API URL, for example https://dfwhllz61x709.cloudfront.net/otel.
  • You must explicitly set up OpenTelemetry in your application. If you’re using Next.js, then follow the Next.js OpenTelemetry guide. If you are using Node.js without a framework, then follow this example to set up a basic exporter.
If ingestion fails, check the response:
  • A response with partialSuccess.rejectedLogRecords greater than zero means some records were rejected. Check their parent routing attributes and the x-bt-parent header.
  • A 403 can indicate that the API key lacks write permission or that the destination cannot be resolved. Verify the API key and project ID.
  • A 404 can indicate an incorrect endpoint or a self-hosted version without logs support. Check the signal-specific path and data plane version.

Resources