Skip to main content
This page covers the key APIs in the Braintrust TypeScript SDK. For setup, see the Quickstart. For the complete reference, see the full TypeScript SDK reference.

Tracing

Tracing records what your application does as spans you can inspect in Braintrust. The recommended way to capture AI calls is auto-instrumentation: call initLogger() once at startup and run your app with the Braintrust import or build hook, and supported AI clients are traced with no per-call changes (see Install and instrument). Or, to learn how to instrument a specific provider client by hand, see Wrappers. The APIs below configure tracing and let you trace your own application code.

initLogger()

Creates the logger that sends your traces to Braintrust, your starting point for tracing. Call it once on startup: by default it becomes the current logger that traced(), startSpan(), and auto-instrumentation log through, and auto-instrumentation requires it.
Returns: Logger Options (all optional):
  • projectName (string): project name for logs. If omitted, logs go to the global project.
  • projectId (string): project ID. Takes precedence over projectName.
  • apiKey (string): API key. Defaults to BRAINTRUST_API_KEY.
  • appUrl (string): Braintrust app URL. Defaults to https://www.braintrust.dev.
  • orgName (string): organization name, useful when credentials can access multiple orgs.
  • asyncFlush (boolean): defaults to true. Set false to make logger calls like logger.log() awaitable.
  • setCurrent (boolean): defaults to true. Controls whether currentLogger() returns this logger and what logger auto-instrumentation logs through.
  • forceLogin (boolean): log in again even if the SDK already has credentials.
  • fetch (typeof fetch): custom fetch implementation for SDK requests. Takes a function that follows the same API as native fetch.
  • debugLogLevel ("error" | "warn" | "info" | "debug" | false): enables SDK troubleshooting output. Set false to also silence the SDK’s default warnings.
Useful logger methods:
  • log(event) → string: logs a span and returns its row ID. Returns Promise<string> when the logger uses asyncFlush: false.
  • traced(callback, args?) → the callback’s result: creates a root span under the logger and ends it when the callback finishes. Spans started within the callback are nested under the traced span.
  • startSpan(args?) → Span: starts a root span that you end manually.
  • logFeedback(event) → void: adds feedback scores, expected values, tags, or comments to an existing row.
  • updateSpan(event) → void: updates an already-written span by ID. Flush the original span before updating it.
  • export() → Promise<string>: a serialized parent string for distributed tracing.
  • flush() → Promise<void>: sends pending rows to Braintrust, resolving when they’re all flushed.
  • trace(body, options?), debug(body, options?), info(body, options?), warn(body, options?), error(body, options?), fatal(body, options?) → string: emits an application log at that severity level and returns its row ID. options.metadata adds metadata. Returns Promise<string> when the logger uses asyncFlush: false. trace() doesn’t start a trace.
  • fmt`...` (template literal tag) → a template object: preserves a template literal and its values for a severity method, such as logger.info(logger.fmt`User ${userId} signed in`). See Preserve message templates.

wrapConsole()

Forwards future console.log(), console.trace(), console.debug(), console.info(), console.warn(), and console.error() calls to Braintrust as application logs. console.log() maps to info, and the other methods keep their severity. Console output is unchanged.
Returns: () => void, a cleanup function that stops forwarding for this wrap. Arguments (all optional):
  • target (Pick<Console, "log" | "trace" | "debug" | "info" | "warn" | "error">): the console to wrap. Defaults to the global console.
  • options.logger (Logger): the logger that receives console messages. Defaults to the current logger at the time of each call.

currentLogger()

The logger most recently installed by initLogger({ setCurrent: true }), or undefined if no current logger exists.
Returns: Logger | undefined

traced()

Creates a span, sets it as the current span for the duration of your callback, and passes the span to your callback. Nested spans and traced LLM calls attach to it while it is current. Errors thrown in the callback are logged to the span, and the span ends when the callback returns. Returns the callback’s result. setCurrent defaults to true.
Returns: the callback’s result Parameters:
  • callback ((span) => R, required): the function to trace. Braintrust passes the span as its argument.
  • args (optional): span options.
    • name (string): span name shown in Braintrust.
    • type (SpanType): span type, such as function, task, tool, llm, score, or eval.
    • spanAttributes (Record<PropertyKey, unknown>): extra span attributes.
    • startTime (number): start time as a Unix timestamp in seconds.
    • parent (string | PropagationContext): exported parent span string or W3C trace context.
    • event (ExperimentLogPartialArgs): initial event data to log on the span.
    • propagatedEvent (ExperimentLogPartialArgs): event data propagated from another span.
    • spanId (string): explicit span ID.
    • parentSpanIds (ParentSpanIds | MultiParentSpanIds): explicit parent span IDs.
    • setCurrent (boolean): controls whether currentSpan() returns this span while the callback runs. Defaults to true.
    • asyncFlush (boolean): controls whether the span flushes asynchronously.

wrapTraced()

Wraps a function so each call creates a span, sets it as the current span while the function runs, logs thrown errors, and ends the span when the call finishes. Logs the function arguments as input and the return value as output. To trace a callback and log fields yourself, use traced() instead. setCurrent defaults to true.
Returns: the wrapped function Parameters:
  • fn ((...args) => R, required): the function to wrap. Its return value is returned by the wrapped function.
  • args (optional): span options for each call to the wrapped function.
    • name (string): span name shown in Braintrust. If omitted, Braintrust uses the wrapped function’s name.
    • type (SpanType): span type, such as function, task, tool, llm, score, or eval. If omitted, defaults to function.
    • spanAttributes (Record<PropertyKey, unknown>): extra span attributes.
    • startTime (number): start time as a Unix timestamp in seconds.
    • parent (string | PropagationContext): exported parent span string or W3C trace context.
    • event (ExperimentLogPartialArgs): initial event data to log on the span.
    • propagatedEvent (ExperimentLogPartialArgs): event data propagated from another span.
    • spanId (string): explicit span ID.
    • parentSpanIds (ParentSpanIds | MultiParentSpanIds): explicit parent span IDs.
    • setCurrent (boolean): controls whether currentSpan() returns this span while the wrapped function runs. Defaults to true.
    • asyncFlush (boolean): controls whether the span flushes asynchronously.
    • noTraceIO (boolean): for generator functions only, prevents wrapTraced() from automatically logging arguments as input and collected yielded values as output. For other functions, use traced() and call span.log() yourself.

startSpan()

Starts a span manually. See traced() for callback-based tracing, or wrapTraced() to trace a function automatically. A span from startSpan() is not current, so currentSpan() and nested spans will not attach to it unless you use withCurrent(). Call span.end() when the span is finished.
Returns: Span Parameters:
  • args (optional): span options.
    • name (string): span name shown in Braintrust.
    • type (SpanType): span type, such as function, task, tool, llm, score, or eval.
    • spanAttributes (Record<PropertyKey, unknown>): extra span attributes.
    • startTime (number): start time as a Unix timestamp in seconds.
    • parent (string | PropagationContext): exported parent span string or W3C trace context.
    • event (ExperimentLogPartialArgs): initial event data to log on the span.
    • propagatedEvent (ExperimentLogPartialArgs): event data propagated from another span.
    • spanId (string): explicit span ID.
    • parentSpanIds (ParentSpanIds | MultiParentSpanIds): explicit parent span IDs.
    • asyncFlush (boolean): controls whether the span flushes asynchronously.

currentSpan()

Returns the current span, so you can log to it without holding a direct reference, for example from a helper called while a traced() callback runs. If no span is current, returns a no-op span whose log() calls are ignored, so currentSpan().log(...) will not throw.
Returns: Span

withCurrent()

Makes an existing span the current span for the duration of a callback. A span from startSpan() isn’t current on its own, so spans and traced LLM calls created afterward won’t nest under it. Wrap that work in withCurrent(span, callback) and it nests under span, with currentSpan() returning it inside the callback.
Returns: the callback’s result Parameters:
  • span (Span, required): the span to make current inside the callback.
  • callback ((span) => R, required): the work to run with span current. Its return value is returned.

withParent()

Attaches the spans created inside its callback to a parent that lives somewhere else, such as another process, service, or job. Get the parent’s location by calling export() on a span or logger, pass that string to withParent(), and the work inside nests under the original trace. This is how you trace across process boundaries (distributed tracing).
Returns: the callback’s result Parameters:
  • parent (string, required): an exported parent string, from a span’s or logger’s export().
  • callback (() => R, required): the work to run under that parent. Its return value is returned.

injectTraceContext()

Serializes the current span’s context into W3C traceparent and baggage HTTP headers so a downstream service can continue the same trace. This is the standards-based alternative to export() and withParent(): it works across any HTTP boundary and interoperates with OpenTelemetry and other systems that respect W3C Trace Context.
Returns: the carrier with trace-context headers added. Called with no arguments, it returns a new plain object of headers representing the current span’s context. Parameters:
  • carrier (optional): an existing header carrier to add trace context to and return, such as a Headers instance, a plain object, or an ordinary Node.js http request object. Pass one to combine trace-context headers with the headers you are already sending. Omit it to get a fresh headers object.
  • options.span (Span, optional): the span to inject. Defaults to the current span.

extractTraceContextFromHeaders()

Reads W3C trace-context headers from an inbound request and returns an opaque parent context you pass to traced() or startSpan() as parent, continuing the trace started by the calling service. This is the receive-side counterpart of injectTraceContext().
Returns: PropagationContext | undefined — an opaque context for parent, or undefined when no valid traceparent header is present, in which case traced() starts a fresh root span. Parameters:
  • headers (required): the inbound request headers, such as a Web Request’s Headers, a plain object, or an ordinary Node.js http request object. Header lookups are case-insensitive.

logError()

Logs an error and stack trace to a span’s error field.
Returns: void Parameters:
  • span (Span, required): the span to attach the error to.
  • error (unknown, required): the caught error, whose message and stack are logged.
Errors thrown inside traced() are logged automatically, so use logError() for errors you catch yourself. Turns an exported span string into a shareable Braintrust UI URL, so you can link straight to a specific trace from your own logs, dashboards, or alerts. Pass the string returned by a span’s export().
Returns: Promise<string> Links can be generated before flushing, but they become viewable only after the span and its root have been flushed and ingested. If you have a span object, span.permalink() is usually simpler.

flush()

Sends any buffered log rows to Braintrust and returns a promise that resolves once they’re all sent. Call it before a script or short-lived process exits so pending events aren’t lost. In long-lived Node.js processes, logged rows wait up to 1 second before they’re sent, so nearby rows share one upload request. The SDK flushes pending rows when the process exits normally, but not when it exits through process.exit() or a signal. Call flush() in those shutdown paths. To change the delay, set BRAINTRUST_FLUSH_DELAY_MS.
Returns: Promise<void>

setMaskingFunction()

Installs a global masking function that runs over your logged data before it leaves your process, so you can redact sensitive values like PII or secrets before they ever reach Braintrust. Set it to null to remove a previously configured masking function.
Returns: void Masking applies to input, output, expected, metadata, context, scores, and metrics, just before the SDK uploads each record. It covers every record the SDK logs, including manually created spans, dataset rows, and feedback scores, but not feedback comments or feedback metadata. If you also configure span customizers, masking runs after them. See Masking functions for field coverage, examples, and error handling.

configureInstrumentation()

Configures auto-instrumentation. Import it from braintrust/instrumentation and call it at startup, before you import braintrust or any AI SDK. The same function is also exported from braintrust, but importing braintrust turns instrumentation on, so a call through that import logs a warning and has no effect. Static imports are hoisted, so load braintrust and your AI SDKs with dynamic imports after the call.
Returns: void Options (all optional):
  • integrations (InstrumentationIntegrationsConfig): an object of boolean flags keyed by integration name, such as openai, anthropic, aisdk, googleGenAI, groq, and langchain. All integrations are enabled by default. Setting a flag to false doesn’t disable the integration. To disable integrations, use the BRAINTRUST_DISABLE_INSTRUMENTATION environment variable. The livekit and mcp keys also accept options objects. See the LiveKit Agents and MCP SDK integration guides for configuration details.
  • spanCustomizers (readonly SpanCustomizer[]): span customizers that modify each outgoing record from an SDK span before upload. They run in array order. A later call that passes spanCustomizers replaces the list.
  • streamingAttachmentBufferBytes (number): target size in bytes of each attachment that instrumentation uploads from streaming media, such as LiveKit Agents call audio. Defaults to 4 MiB (4194304). Must be a positive safe integer. Other values throw an error. Instrumentation splits media only at valid boundaries, and whole-file responses can exceed this size. Audio recordings count raw PCM before compression, so compressed uploads are smaller. It doesn’t limit total memory and doesn’t turn on attachment capture.

SpanCustomizer

An object with an onSpanExport(data) method that modifies outgoing records from SDK spans. Pass customizers in the spanCustomizers option of configureInstrumentation(). See Span customizers for examples and behavior. Methods:
  • onSpanExport(data) → SpanExportData: called synchronously on each record the SDK logs. The SDK logs a span as several records as its data becomes available, such as one with the input and a later one with the output, so the method runs several times per span. See How customizers run. SpanExportData is Record<string, unknown>. Return the modified record or a replacement plain object.
Key rules:
  • Customizers run on all native SDK spans, including spans you create with traced(), startSpan(), and logger.log(). They don’t run on dataset rows or feedback. In v3.35.0, they run only on spans created by instrumentation and wrappers.
  • With v3.38.0 or later and @braintrust/otel v1.1.0 or later, customizers also run on OpenTelemetry spans that BraintrustSpanProcessor or BraintrustExporter sends to Braintrust, and in OpenTelemetry compatibility mode.
  • Each record holds only part of the span, so a field can be absent from any single call. Check for a field before you change it.
  • The SDK restores protected fields, such as id, span_id, root_span_id, and project_id, after every call.
If a customizer throws an error or returns an invalid value, such as a promise, the SDK uploads that record with only its protected fields, timestamps, and context.customizer_error set to true (v3.38.0 or later). Earlier versions drop the record. To keep the record’s other fields, catch errors inside onSpanExport() and return a safe result, such as the record with the sensitive field removed. See Customizer failures.

Evaluations

An evaluation runs your task over a set of cases, scores each output, and logs the results to an experiment, which is how you measure quality and catch regressions as you change prompts or models. Use Eval() to run most evaluations. The other APIs here run workflow evaluations and summarize and report results.

Eval()

Runs an evaluation from your data, a task, and scorers or classifiers: it runs the task over every case, scores the outputs, logs each row to an experiment, and returns a result with a summary you can compare across runs.
Returns: Promise<EvalResultWithSummary> Eval(project, evaluator, options?) takes three arguments.
The project name (a string) to log the experiment to. To identify the project by ID, set projectId on the evaluator.
Defines the evaluation: the data to run against, the task to test, and how to score the results. Its core fields:
  • data (EvalData, required): the evaluation cases. Provide an array of cases, a function or promise that returns an array, an AsyncIterable/AsyncGenerator, or BaseExperiment(...). Each case has:
    • input (required): the value passed to the task.
    • expected: the expected output for this case, if any.
    • metadata / tags: per-case metadata and tags.
    • trialCount: how many times to run the task for this case.
  • task ((input, hooks?) => output, required): the function under test. It receives two arguments:
    • input: the current case’s input value.
    • hooks (optional): a context object the framework passes in for the current evaluation row. Use its fields to read parameters, log to the task’s span, or adjust the row:
      • span: the task’s span. Log extra data or child spans to it.
      • parameters: the validated runtime parameters.
      • metadata / tags: mutate to change the current row’s metadata or tags.
      • expected: the expected output for the current case, if it provided one.
      • trialIndex: zero-based trial index, useful when trialCount is greater than 1.
      • reportProgress: reports task progress for long-running evals.
      • signal: an AbortSignal that aborts when the evaluation times out or its signal aborts. Pass it to the APIs your task calls, or check signal.aborted, to stop work early. Requires v3.37.0 or later.
  • scores (EvalScorer[]): scorer functions, required unless classifiers is set. Each receives the case fields plus output and an optional trace, and returns a number, a Score, an array of scores, or null to skip the row. A bare number is named after the function (or scorer_<index>); return a Score for a custom name or metadata.
    Scorers and classifiers receive each case’s id and post-task tags through EvalScorerArgs, in addition to the other EvalCase fields.
  • classifiers (EvalClassifier[]): like scorers, but return a Classification and write to the classifications field instead of scores (required unless scores is set). id is the machine-readable outcome, label is the display label (defaults to id), and name is the key (defaults to the function name, or classifier_<index>).
  • parameters (EvalParameters | loadParameters()): named, typed settings that make the eval configurable, so you can re-run it with different values (a temperature, a model, a prompt) without editing code. Declare them with defaults here, and the task reads the chosen values from hooks.parameters. Pass runtime values in the options argument (validated against your schema), or load a saved set with loadParameters(), whose defaults merge with any runtime overrides. Supports Zod values, model parameters (exposed as strings), and prompt parameters (exposed as Prompt objects).
The remaining fields are optional:
  • experimentName (string): experiment name.
  • trialCount (number): number of task runs per input.
  • maxConcurrency (number): maximum concurrent task/scorer work.
  • timeout (number): evaluation timeout in milliseconds. 0 times out immediately.
  • signal (AbortSignal): stops the evaluation when it aborts.
  • metadata (Record<string, unknown>): experiment metadata.
  • tags (string[]): experiment tags.
  • baseExperimentName (string): base experiment name for comparison.
  • baseExperimentId (string): base experiment ID, taking precedence over baseExperimentName.
  • summarizeScores (boolean): defaults to true.
  • flushBeforeScoring (boolean): flushes task spans before scorers run.
When the evaluation times out or its signal aborts, it skips the cases that haven’t started and aborts hooks.signal. It then waits for running tasks and scorers to finish before it rejects with Evaluator timed out or Evaluator aborted, so no work the evaluation started keeps running after it. A task that ignores hooks.signal runs to completion and delays the rejection. In versions before v3.37.0, the evaluation rejects right away and running tasks continue in the background.
An optional object of run settings:
  • noSendLogs (boolean): run locally and build a local summary without sending logs.
  • onStart ((summary) => void): called when the experiment starts.
  • stream ((event) => void): receives progress events.
  • parent (string): exported parent span for nested or distributed eval logging.
  • parameters (Record<string, unknown>): runtime parameter values.
  • returnResults (boolean): defaults to true. Set false for large evals to keep only aggregate summary data.
  • enableCache (boolean): defaults to true. Controls the local span cache used by scorers.

defineWorkflowEval()

Defines an evaluation whose task or scorers submit requests to an asynchronous provider API, such as a batch API, and collect the results later. The run saves its progress to a store, so your application can resume it by polling or from a webhook. With a shared store such as Redis, a different process can resume it.
TypeScript workflow evaluations are in public preview and can change before reaching general availability.
Requires TypeScript SDK v3.37.0 or later. Import from the top-level braintrust package. The API is marked experimental in the SDK. See Workflow evaluations for a complete OpenAI example.
This example uses functions from the OpenAI Batch API example, such as submitBatch(), pollBatch(), collectText(), and exactMatch(). It defines an evaluation with a polling batch task:
Returns: an object with the workflow evaluation methods. Defining an evaluation does not start a run. To start one, call start(). defineWorkflowEval(projectName, evaluator) takes two arguments.
The project name (a string) to log the experiment to. Braintrust creates the project if it doesn’t exist. To log to an existing project by ID, also set projectId on the evaluator. The name then only sets the default experiment name, and it must stay the same when you resume the run.
Defines the evaluation, the store used to save progress, and any task or scorer work that completes asynchronously. Data, plain tasks, plain scorers, classifiers, parameters, and optional experiment settings use the same contracts as Eval(). On this page, a workflow task or scorer means a WorkflowTask, WorkflowScorer, WorkflowBatchTask, or WorkflowBatchScorer.
  • store (WorkflowEvalStore, required): persistence backend shared by every process that starts or resumes the run. See WorkflowEvalStore.
  • data (EvalData, required): evaluation cases, using the same formats and case fields as Eval(). When using a workflow task or scorer, each case needs a unique, non-empty id or upsert_id, or a caseId callback that supplies one.
  • task (EvalTask | WorkflowTask | WorkflowBatchTask, required): a plain task function using the same task(input, hooks) contract as Eval(), a WorkflowTask, or a WorkflowBatchTask.
  • scores (Array<EvalScorer | WorkflowScorer | WorkflowBatchScorer>): any mix of plain scorer functions, WorkflowScorer instances, and WorkflowBatchScorer instances. Scorers start as soon as their case’s task output is collected, except that a WorkflowBatchScorer waits to fill a batch.
  • classifiers (EvalClassifier[]): plain classifier functions using the same contract as Eval(). Classifiers start as soon as their case’s task output is collected.
  • caseId ((datum) => string | Promise<string>): returns a stable string ID when a case has neither id nor upsert_id. All trials of a case share the ID.
  • maxConcurrency (number): positive maximum number of submit, getExternalId, poll, and collect callbacks that run at once during each start(), poll(), or processSubmissionResult() call. Defaults to 10. For a batch task or scorer, each submit call submits one batch. When the evaluation uses a workflow task or scorer, plain tasks, scorers, and classifiers aren’t affected, and neither is the number of requests pending at the provider. Without either, start() runs the evaluation like Eval(), and maxConcurrency limits tasks and scorers as it does there.
  • parameters (EvalParameters | loadParameters()): parameter definitions or a saved parameter set, using the same contract as Eval(). Pass runtime values to start({ parameters }).
The remaining fields are optional:
  • baseExperimentId (string): ID of the experiment to compare this run against. Takes precedence over baseExperimentName.
  • baseExperimentName (string): experiment to compare this run against.
  • description (string): experiment description.
  • errorScoreHandler (ErrorScoreHandler): handles missing scores when tasks or scorers fail. Ignored when the evaluation uses a workflow task or scorer.
  • experimentName (string): experiment name. If omitted, a unique name is generated for each run. If set, every run logs to the same experiment.
  • flushBeforeScoring (boolean): whether to flush task spans before running scorers.
  • gitMetadataSettings (GitMetadataSettings): settings for collecting Git metadata.
  • isPublic (boolean): whether the experiment is public.
  • metadata (Record<string, unknown>): experiment metadata.
  • projectId (string): ID of an existing project to log to instead. projectName is still required, sets the default experiment name, and must stay the same when you resume the run.
  • repoInfo (RepoInfo): Git metadata to record for the experiment. Takes precedence over gitMetadataSettings.
  • state (BraintrustState): logger state used to initialize Braintrust objects.
  • summarizeScores (boolean): whether to summarize experiment scores. Defaults to true.
  • tags (string[]): experiment tags.
  • trialCount (number): positive number of trials per case. Defaults to 1. A case’s trialCount overrides this value.
defineWorkflowEval() does not support the timeout, signal, or update evaluator options. When the evaluation uses a workflow task or scorer, its maxConcurrency limits provider callbacks, not task and scorer work as in Eval().Case data, submission data, and collected values must be JSON-serializable.

Workflow evaluation methods

Start and resume runs of a workflow evaluation. defineWorkflowEval() returns an object with these methods.
TypeScript workflow evaluations are in public preview and can change before reaching general availability.
Requires TypeScript SDK v3.37.0 or later. Import from the top-level braintrust package. The API is marked experimental in the SDK. See Workflow evaluations for a complete OpenAI example.
This example starts a run of the evaluation defined in the defineWorkflowEval() example, then polls until the run completes:
Methods (all asynchronous):
  • start(options?): creates a new run, saves the cases, and submits the first requests.
    • options.parameters: runtime values for the evaluation’s parameters.
    • options.noSendLogs: true: builds the summary locally without sending logs to Braintrust.
    • Every call starts a new run and submits every request to the provider again. To continue a run, pass its runId to poll() or processSubmissionResult() instead.
    • Without a workflow task or scorer, start() runs the whole evaluation at once, like Eval().
  • status({ runId }): reads saved progress without contacting the provider or advancing work.
  • poll({ runId }): checks existing polling submissions once, collects completed results, and advances the cases that are ready. Scorer requests submitted during this call are polled on a later call. It also resubmits any submission whose submit callback threw, for both polling and webhook completion.
  • processSubmissionResult({ runId?, submissionId?, externalId? }): tells the SDK that one request finished, so it collects the result and advances the cases in it. Call it from your webhook handler.
    • Identify the request by externalId, the provider ID your getExternalId function returned, or by submissionId, the SDK’s ID for the request. Pass at least one. If you pass both, they must identify the same submission.
    • runId is required with submissionId. With externalId alone, you can omit runId when each provider ID belongs to only one run of the evaluation. If several runs share the externalId, it throws an error and you must pass runId.
    • Throws Error("No submission matches this result") if the ID doesn’t match a request in this run, and an error if the run isn’t in the store. Throws an error if the submission’s submit callback threw. The next poll() resubmits it.
    • Doesn’t check the webhook event. Before calling it, check that the event came from the provider and that the request succeeded.
start(), status(), poll(), and processSubmissionResult() all return the run’s current state. All results have status, runId, and pending, and a completed result also has summary:
  • status ("waiting" | "completed"): the run’s status.
  • runId (string): identifier to save and pass to status(), poll(), and processSubmissionResult().
  • pending ({ poll: number; webhook: number }): number of submitted requests not yet collected, split into poll and webhook counts. A batch counts as one request, and so does a submission waiting to be resubmitted.
  • summary (ExperimentSummary): the experiment’s scores and a link to it.

WorkflowTask and WorkflowScorer

Define a task or scorer that submits one request per case and trial to an asynchronous provider, then collects one result when the request completes. To submit many cases and trials in one provider batch, use WorkflowBatchTask and WorkflowBatchScorer.
TypeScript workflow evaluations are in public preview and can change before reaching general availability.
Requires TypeScript SDK v3.37.0 or later. Import from the top-level braintrust package. The API is marked experimental in the SDK. See Workflow evaluations for a complete OpenAI example.
This example defines a task that sends each case as its own single-request OpenAI batch. It uses the submitBatch(), pollBatch(), and collectText() functions from the OpenAI Batch API example, as in Submit one request per case:
Pass a WorkflowTask as task or a WorkflowScorer in scores when calling defineWorkflowEval(). new WorkflowTask(processor) and new WorkflowScorer(processor) take a processor with these fields:
  • name (string, required for WorkflowScorer): scorer name. Must be unique and non-empty, and must stay the same when you resume a run. WorkflowTask has no name.
  • submit(item, context) (required): called to submit the request. WorkflowScorer calls it after the task output is ready. Returns JSON-serializable submission data, which the SDK saves and passes to the completion and collection callbacks.
  • completion (required): how the SDK learns that the request finished. See completion configuration.
  • collect(submission, context) (required): called after the request completes. WorkflowTask returns one task result, and WorkflowScorer returns one scorer result. Must tolerate replay, including concurrent webhook delivery.
submit, poll, and collect must return a Promise. context has SDK-generated runId and submissionId values, which your integration can use to correlate requests with the provider. Items passed to submit:
  • WorkflowTask: id, input, expected, metadata, tags, parameters, and trialIndex. The id identifies one case and trial, such as "france:trial:0", and trialIndex counts from 0.
  • WorkflowScorer: the same fields except parameters, plus the task’s output.
Results returned from collect:
  • WorkflowTask: { output, metadata?, tags? }, the task output. Returned metadata merges into case metadata. Returned tags replace case tags.
  • WorkflowScorer: { score }, a score in the same formats accepted by plain scorer functions, including a number, a score object, or an array of scores. An unnamed numeric score uses the scorer’s name.
Neither result includes an item ID. The SDK associates the result with the saved submission. If submit throws an error, the SDK saves the submission as failed, and the next poll({ runId }) calls submit again with the same submissionId. If your provider supports idempotency keys, use the submissionId as the key so a retry doesn’t create a duplicate request. When submit throws during start(), start() throws without returning the runId, so save context.runId in your submit callback to resume the run. The SDK runs getExternalId and plain task, scorer, and classifier functions only once per case and trial. If one of them throws an error, or the process exits while one of them or submit runs, that case never completes and the run stays "waiting". Start a new run to recover. Polling and collect callbacks are safe to retry.

WorkflowBatchTask and WorkflowBatchScorer

Define a task or scorer that submits many cases and trials in each asynchronous provider batch, such as an OpenAI batch, then collects one result per item when the batch completes. Use them when a provider limits how many batches you can create.
TypeScript workflow evaluations are in public preview and can change before reaching general availability.
Requires TypeScript SDK v3.37.0 or later. Import from the top-level braintrust package. The API is marked experimental in the SDK. See Workflow evaluations for a complete OpenAI example.
This example defines an LLM-as-a-judge scorer that grades up to 100 answers in each OpenAI batch. It uses the submitBatch(), collectText(), and pollBatch() functions from the OpenAI Batch API example:
Pass a WorkflowBatchTask as task or a WorkflowBatchScorer in scores when calling defineWorkflowEval(). An evaluation can mix them with plain functions, WorkflowTask, and WorkflowScorer. new WorkflowBatchTask(processor) and new WorkflowBatchScorer(processor) take a processor with these fields:
  • name (string, required for WorkflowBatchScorer): scorer name. Must be unique and non-empty, and must stay the same when you resume a run. WorkflowBatchTask has no name.
  • batching (required): how the SDK groups items into batches.
    • maxSize (number, required): the maximum number of items in one batch. Must be a positive integer.
    • maxWaitMs (number, WorkflowBatchScorer only): how long a partial batch waits for more items before the SDK submits it. Must be 0 or greater.
  • submit(items, context) (required): called to submit one batch. Receives up to maxSize items and returns JSON-serializable submission data, which the SDK saves and passes to the completion and collection callbacks.
  • completion (required): how the SDK learns that the batch finished. See completion configuration.
  • collect(submission, context) (required): called after the batch completes. Returns one entry per item, as an array, an iterable, or an async iterable. Must tolerate replay, including concurrent webhook delivery.
Items passed to submit have the same fields as the items a WorkflowTask or WorkflowScorer receives, plus a customId. The customId identifies the item within its batch, such as "item-0", and uses only characters that providers accept in request IDs. Use it as the provider’s request ID, such as OpenAI’s custom_id. Entries returned from collect:
  • { customId, result }: the item’s result. For WorkflowBatchTask, result is { output, metadata?, tags? }. For WorkflowBatchScorer, it’s { score }. Both take the same formats as the results a WorkflowTask or WorkflowScorer returns.
  • { customId, error }: the item failed.
The SDK throws an error if collect returns a customId that isn’t in the batch, or returns the same customId twice. The SDK records an item as failed when collect returns an error for it or returns no entry for it. A failed task item logs the error on its row and skips that case’s scorers and classifiers. A failed scorer item omits that score and records the error in the row’s scorer_errors metadata. The run still completes. To report the items in a batch that expired or was cancelled, return { status: "complete" } from your polling callback for those states. When the SDK submits batches:
  • WorkflowBatchTask: start() submits every case and trial, in batches of up to maxSize items.
  • WorkflowBatchScorer: submits a batch when maxSize items have task outputs, or when no more items can get one. If you set maxWaitMs, it also submits a partial batch that has waited that long. The SDK checks the wait during each start(), poll(), and processSubmissionResult() call and doesn’t start timers, so a partial batch is submitted on the first call after maxWaitMs passes.
If submit throws an error, the next poll({ runId }) resubmits the same items with the same submissionId, as it does for a WorkflowTask. Each case’s metadata.workflow_eval.batch_submission_id records the submissionId of its task batch.

Completion configuration

Configure how a workflow task or scorer learns that its provider request or batch finished: by polling when your application calls poll(), or from a webhook your application receives.
TypeScript workflow evaluations are in public preview and can change before reaching general availability.
Requires TypeScript SDK v3.37.0 or later. Import from the top-level braintrust package. The API is marked experimental in the SDK. See Workflow evaluations for a complete OpenAI example.
This example maps an OpenAI batch status to a polling result, then chooses polling or webhook completion keyed on the batch ID, as createEvaluation() does in the OpenAI Batch API example. It uses that example’s client, Submission type, submitBatch(), and collectText(). pollBatch() reports failed, expired, and cancelled batches as complete, so the SDK records the requests without results as failed and the run can finish:
Set completion to one of these objects:
  • { mode: "poll", poll }: poll(submission, context) is called for each pending submission when your application calls poll({ runId }). It returns { status: "pending" }, { status: "complete" }, or { status: "failed", error }. Completion triggers collection. If a callback fails, poll() still checks the other submissions and advances the run before it throws. With one failure, it throws that error. With several, it throws an AggregateError. The submission stays pending, so the next poll() call checks it again.
  • { mode: "webhook", getExternalId }: getExternalId(submission, context) is called right after submit returns. It synchronously returns a non-empty provider request ID to associate with the saved submission. Pass that ID as externalId to processSubmissionResult() after verifying a completion event. For a batch task or scorer, return the provider’s batch ID.
Each task and scorer chooses its own completion configuration, so one run can use both. The SDK does not schedule polling or host a webhook endpoint.

WorkflowEvalStore

Persists workflow evaluation state so a run can be resumed. Use the same store and evaluation definition across invocations, including project name, experiment name, and scorer names.
TypeScript workflow evaluations are in public preview and can change before reaching general availability.
Requires TypeScript SDK v3.37.0 or later. Import from the top-level braintrust package. The API is marked experimental in the SDK. See Workflow evaluations for a complete OpenAI example.
This example creates a Redis-backed store from a REDIS_URL environment variable. Call await redis.connect() before you start or resume a run:
Built-in stores:
  • new WorkflowEvalMemoryStore(): keeps state in memory for single-process runs. State is lost when the process exits.
  • new WorkflowEvalRedisStore({ client, keyPrefix?, ttlMs? }): accepts a connected client from redis (node-redis), ioredis, or @upstash/redis. keyPrefix defaults to "braintrust-eval:". Records and progress sets expire after seven days by default. Set ttlMs to a positive value longer than the full evaluation and expected resumption delays. Close the client when your application shuts down.
For another backend, implement the WorkflowEvalStore interface:
  • read(key: string): Promise<Uint8Array | undefined>: read the saved value, or return undefined if absent.
  • write(key: string, value: Uint8Array): Promise<void>: save a value.
  • getOrSet(key: string, value: Uint8Array): Promise<{ value: Uint8Array; created: boolean }>: atomically insert a value only when the key is absent. Return the stored bytes as value and whether this call inserted them as created.
  • addToSet(key: string, member: string): Promise<void>: atomically add a unique member to a set.
  • getSetSize(key: string): Promise<number>: return the number of unique members.
Keep progress sets for at least as long as run records. Atomic insertion and set operations are required for concurrent resumption.

agentAssertionScorer()

A built-in trace scorer that evaluates an agent through a declarative list of assertions, so you can score tool usage and outputs without writing span-fetching boilerplate. It reads tool call spans from the trace automatically. The score is the fraction of assertions that passed, or 1 when there are no assertions. Score metadata includes each assertion’s name and pass/fail state, plus failure messages for failing assertions.
Returns: an eval scorer.
Tool-call assertions (calledTool, notCalledTool, toolOrder, usedNoTools, maxToolCalls) read your agent’s tool calls from the tool spans in the eval trace, so your task’s tool calls must be traced (through auto-instrumentation or tools wrapped in traced) for these assertions to find them. The output assertions (equals, notEquals, contains, matches) inspect the task’s return value directly and don’t need this.
The assert helper passed to your callback exposes these assertion methods:

buildLocalSummary()

Builds an ExperimentSummary from local eval results. The SDK uses this when an eval runs without a remote experiment, such as Eval(..., { noSendLogs: true }).
Returns: ExperimentSummary Parameters:
  • evaluatorDef (EvaluatorDef, required): your Eval() evaluator object plus the SDK-populated projectName and evalName fields.
  • results (EvalResult[], required): the row-level eval results to summarize.
  • precomputedScores (ScoreAccumulator, optional): score totals and counts to use instead of deriving them from results. Pass it when you ran with returnResults: false (so per-row results aren’t available) or you’ve already accumulated scores yourself. It maps each score’s name to a running total and count:
Computes average scores from the results or the precomputed accumulator.

reportFailures()

Prints failing eval rows to the console in the same format the default reporter uses. Use it when you run evals with a custom reporter but still want readable failure output.
Returns: void Parameters:
  • evaluatorDef (EvaluatorDef, required): evaluator metadata used in error output.
  • failingResults (EvalResult[], required): results whose error field is set.
  • options ({ verbose: boolean; jsonl: boolean }, required): verbose prints full errors. jsonl emits a JSON line containing evaluator name and error strings.

BaseExperiment()

Uses a previous experiment as evaluation data. The previous experiment’s output becomes the current eval’s expected value. This is useful if you want to test, for example, a new prompt for regressions.
Returns: BaseExperiment If name is provided, the SDK uses that experiment both as the comparison base for the new experiment and as the read-only dataset for eval rows. If name is omitted, the SDK derives the base experiment from git metadata:
  1. During experiment registration, the SDK sends ancestor_commits when no explicit baseExperimentId or baseExperimentName is set.
  2. ancestor_commits contains up to 1,000 commit hashes from the current branch, starting at the merge base with the default remote base branch and ending at HEAD. For a clean working tree, the merge base is computed from HEAD^; for a dirty working tree, it is computed from HEAD.
  3. Braintrust chooses the newest experiment in the same project on the nearest commit in that ancestor list that you can read.
  4. The chosen experiment ID is stored as the new experiment’s base experiment and then opened as dataset data for BaseExperiment().
The SDK chooses the default remote base branch from the local main, master, or develop branch when exactly one exists, otherwise from the remote HEAD branch, and falls back to main if the remote HEAD cannot be read. If no experiment matches the ancestor commits, later base lookup can use a project-configured baseline experiment or the nearest earlier experiment in the same project by creation time. If no base experiment can be found, BaseExperiment() fails.

Experiments

An experiment is a single evaluation run logged to a project. Use these APIs when you want to create an experiment and log rows yourself, instead of letting Eval() manage one for you.

initExperiment()

Initializes an experiment in a project. Use it when you want to log experiment rows manually.
Returns: Experiment Options:
  • project (string): project name. Required unless projectId is set.
  • projectId (string): project ID. Takes precedence over project.
  • experiment (string): experiment name. Generated automatically if omitted.
  • description (string): experiment description.
  • dataset (string | Dataset): dataset to associate with the experiment.
  • metadata (Record<string, unknown>): experiment metadata.
  • tags (string[]): experiment tags.
  • baseExperiment (string): base experiment name for comparison.
  • baseExperimentId (string): base experiment ID. Takes precedence over baseExperiment.
  • update (boolean): continue logging to an existing experiment with the same name.
  • open (boolean): open an existing experiment in read-only mode.
  • isPublic (boolean): whether links are public. Defaults to private.
  • setCurrent (boolean): defaults to true. Controls whether global log() uses this experiment.

Datasets

A dataset is a versioned collection of cases you manage in Braintrust and reuse across experiments and evals. Use initDataset() to create a dataset or open an existing one.

initDataset()

Creates or opens a dataset in a project.
Returns: Dataset Options:
  • project (string): project name. Required unless projectId is set.
  • projectId (string): project ID. Takes precedence over project.
  • dataset (string): dataset name. Generated automatically if omitted.
  • description (string): dataset description.
  • metadata (Record<string, unknown>): dataset metadata.
  • version (string): when fetching or iterating rows, read the dataset at this transaction ID. Takes precedence over snapshotName and environment.
  • snapshotName (string): when fetching or iterating rows, read the dataset version captured by this named snapshot. Takes precedence over environment.
  • environment (string): when fetching or iterating rows, read the dataset version assigned to this environment slug.
  • useOutput (boolean): deprecated legacy mode that maps expected to output when fetching rows.
version, snapshotName, and environment select the committed dataset version used for reads. Calls such as insert() and flush() still write new rows to the dataset.

Prompts and functions

In Braintrust, functions are units of logic you define and version in the UI, then load or invoke from your code. A prompt is a function whose job is to call a model with a templated set of messages. Other functions include scorers, tools, and code you deploy. Load and render a saved prompt with loadPrompt(), or call a function directly with invoke().

loadPrompt()

Loads a saved prompt from Braintrust. Use the returned Prompt object’s build() method to render model parameters, messages, tools, or completion text with runtime variables.
Returns: Promise<Prompt> Options:
  • projectName (string): project containing the prompt. Required unless projectId or id is set.
  • projectId (string): project ID. Takes precedence over projectName.
  • slug (string): prompt slug. Required unless id is set.
  • id (string): prompt ID. Takes precedence over project and slug.
  • version (string): prompt version. Takes precedence over environment.
  • environment (string): environment assignment such as production or staging.
  • defaults (Record<string, unknown>): default model, parameter, message, or completion fields used by build(). Saved prompt fields override these defaults.
  • noTrace (boolean): if true, built prompt metadata is not attached to traces.
If neither version nor environment is set, the SDK loads the latest version and can fall back to the local prompt cache. build(args, options?) renders the prompt. Parameters:
  • args (object, required): the template variables. Object keys become variables, and the whole value is available as input. Rendered with Mustache by default, with non-string values JSON-stringified.
  • options (optional):
    • flavor ("chat" | "completion"): defaults to "chat". Use "completion" for completion prompts.
    • messages (Message[]): additional chat messages to append. If the prompt already has a system message, extra system messages are omitted.
    • strict (boolean): validates that referenced template variables are present.
    • templateFormat ("mustache" | "nunjucks" | "none"): overrides the prompt’s template format. Nunjucks requires @braintrust/template-nunjucks. none leaves template strings unrendered.
Use buildWithAttachments() instead of build() when prompt variables contain Braintrust attachment references that need to be resolved before rendering.

getPromptVersions()

Lists the version IDs for a saved prompt, one for each change recorded when the prompt was created or updated. Use it to find an earlier version to load or pin.
Returns: a promise of the prompt’s version IDs Parameters:
  • projectId (string, required): the project’s ID.
  • promptId (string, required): the prompt’s ID.
The returned strings can be passed to loadPrompt({ version }) to load a specific historical prompt version. getPromptVersions() logs in internally with the global SDK state. If BRAINTRUST_API_KEY is set, or if a previous SDK call already logged in, you can call it directly. Call login() first when you need to provide apiKey, orgName, appUrl, or a custom fetch, because getPromptVersions() does not accept those options itself.

loadParameters()

Loads a set of parameters you’ve saved in Braintrust, so an eval or application can run with configuration managed in the UI instead of hardcoded values. The example below passes them to Eval().
Returns: a promise of the resolved parameters Use projectName with slug, or projectId with slug, or id. version takes precedence over environment.

invoke()

Invokes a Braintrust function, prompt, scorer, or tool.
Returns: the function’s output (JSON), or a BraintrustStream when stream: true Identification options. Provide one of these: a function_id, a projectName or projectId plus a slug, or a globalFunction.
  • function_id (string): function ID.
  • projectName (string): project containing the function.
  • projectId (string): ID of the project containing the function. Can be used instead of projectName.
  • slug (string): function slug.
  • globalFunction (string): global function name. See Global Functions.
  • functionType (FunctionType): global function type. Defaults to scorer for global functions.
  • version (string): function version.
Execution options:
  • input (Input, required): logged as the span input.
  • messages (Message[]): additional OpenAI-style messages for LLM functions.
  • metadata (Record<string, unknown>): logged as span metadata and available to the function.
  • tags (string[]): logged as span tags.
  • parent (Exportable | string): parent span, logger, experiment, or exported parent string.
  • stream (boolean): returns a BraintrustStream when true.
  • mode (StreamingMode): function streaming mode.
  • strict (boolean): throws when prompt variable names do not match input keys.
  • schema (z.ZodSchema): validates non-streaming output and returns the typed value.

initFunction()

Creates a callable wrapper around a Braintrust function for use as an eval task or scorer.
Returns: a function (input) => Promise<output> Options:
  • projectName (string, required): project containing the function.
  • slug (string, required): function slug.
  • version (string): function version.
  • state (BraintrustState): SDK state override.

Attachments

Attachments let you log files or large payloads without storing the full bytes inline in the span. This is useful to circumvent the 6 MB request limit to Braintrust. When you trace AI calls, Braintrust automatically converts base64 attachments in provider messages into uploaded attachments, so you rarely need the APIs below for instrumented calls. Reach for them when you’re attaching binary content to a span yourself.

Attachment

Uploads local or in-memory file data and replaces it with an AttachmentReference during logging.
Constructor fields are data (string, Blob, or ArrayBuffer), filename, contentType, and optional state.

ExternalAttachment

References a file that already exists in an external object store.
ExternalAttachment.upload() is a no-op because the file already exists externally.

JSONAttachment

Serializes JSON and uploads it as an application/json attachment. Use it for large JSON objects that should be viewable but do not need to be indexed for search.
Options are filename, pretty, and optional state.

ReadonlyAttachment

Reads an already-uploaded attachment from a dataset, experiment, or raw AttachmentReference.
Useful methods:
  • data() → Promise<Blob>: downloads the attachment as a Blob.
  • asBase64Url() → Promise<string>: returns a data:<content-type>;base64,... URL for prompts.
  • metadata() → Promise<AttachmentMetadata>: fetches download URL and upload status.
  • status() → Promise<AttachmentStatus>: fetches current upload status.

Wrappers

Each wrapper returns the same client or module you pass in, with its methods traced, so the return type always matches the argument type. If Braintrust logging is not configured, wrapper calls are effectively no-ops. Initialize a logger before wrapped calls:

OpenAI

  • wrapOpenAI(openai): wraps OpenAI SDK clients and supports current v4, v5, and v6 style clients.
  • wrapOpenAIv4(openai): lower-level OpenAI wrapper used by wrapOpenAI(). Use wrapOpenAI() unless you know you need this compatibility entry point.
Traced OpenAI surfaces include chat completions, beta chat helpers, responses, embeddings, and moderations where present on the client.

Anthropic

wrapAnthropic() traces messages.create, beta messages.create, and beta tool runner calls when available.

Vercel AI SDK

  • wrapAISDK(ai, options?): wraps AI SDK namespace functions such as generateText, streamText, generateObject, streamObject, embed, embedMany, rerank, and agent constructors.
  • wrapAgentClass(AgentClass, options?): wraps an AI SDK agent class directly.
wrapAISDK() accepts denyOutputPaths?: string[] to omit selected output paths from logged output. Pass the @ai-sdk/code-mode module to wrapAISDK() to trace experimental_runCodeMode() calls.
  • startAISDKBatchTrace({ batch, requests, startTime? }) → Promise<string | undefined>: records the requests of an AI SDK text batch after you submit it with experimental_startBatch(), and returns a context string to store with the batch. Returns undefined if the batch or requests aren’t supported or AI SDK instrumentation is disabled. startTime is a Unix timestamp in seconds and defaults to the batch’s createdAt, or the current time. Doesn’t call the provider.
  • completeAISDKBatchTrace({ batch, requests, status, results, context?, endTime?, denyOutputPaths? }) → Promise<void>: records collected batch results and ends the batch spans. Pass the context from startAISDKBatchTrace(), including from another process. endTime is a Unix timestamp in seconds.
See Trace batch requests and Trace code mode.

Agent SDKs

  • wrapClaudeAgentSDK(sdk): wraps the Claude Agent SDK module, including query, tool, and createSdkMcpServer integration points.
  • wrapOpenRouterAgent(agent): wraps @openrouter/agent clients.
  • wrapGoogleADK(adkModule): wraps Google ADK modules, including runner, agent, and tool execution methods.
  • wrapLiveKit(module): wraps the @livekit/agents module (v1.9.x). Sessions created with the returned module’s voice.AgentSession are traced. See LiveKit Agents.
  • wrapMCPServer(server): traces the requests and notifications that an McpServer or low-level Server from @modelcontextprotocol/sdk or @modelcontextprotocol/server handles, and returns the same instance. You can wrap a server before or after you connect it to a transport. Requires v3.42.0 or later. See MCP SDK.

Model provider SDKs

  • wrapGoogleGenAI(): wraps the entire @google/genai package export (similar to the AI SDK wrapper). Traces models.generateContent, models.generateContentStream, and models.embedContent.
  • wrapOpenRouter(): pass an OpenRouter client. Traces chat, responses, embeddings, rerank, and callModel() where available.
  • wrapMistral(): pass a Mistral client. Traces chat, FIM (fill-in-the-middle), agents, and embeddings.
  • wrapCohere(): pass a Cohere client. Traces chat, chat streaming, embed, and rerank.
  • wrapGroq(): pass a Groq client. Traces chat completions and embeddings.
  • wrapHuggingFace(): pass a Hugging Face Inference module or client. Traces chat completion, text generation, streaming variants, and feature extraction.
  • wrapWorkersAI(): pass a Cloudflare Workers AI binding, such as env.AI. Traces run() calls to the Clef decision models and the Clairic extraction model. Other models, and streaming or raw-response calls, pass through unchanged. See Cloudflare Workers AI.

Testing

Run Braintrust evaluations inside your test runner, so eval cases live alongside your unit tests and your suite fails when scores regress.

wrapVitest()

Wraps Vitest test APIs so tests can create Braintrust experiment rows with inputs, expected values, scorer results, and pass/fail status.
Returns: the wrapped Vitest APIs (test, it, expect, describe, lifecycle hooks, and Braintrust helpers) wrapVitest() returns wrapped test, it, expect, describe, lifecycle hooks, logOutputs, logFeedback, getCurrentSpan, and flushExperiment().

initNodeTestSuite()

Creates a Braintrust-backed suite for Node’s built-in node:test runner.
Returns: a suite with eval() and flush() The suite exposes eval(config, fn) and flush(). If you pass Node’s after hook, flush() is registered automatically.

Configuration

Most configuration is passed per call, such as apiKey and projectName on initLogger(). You can also authenticate once with login(), or set credentials and deployment options through environment variables.

login()

Authenticates the SDK to Braintrust and stores the credentials in its global state, where every later SDK call reads them. Most SDK APIs log in automatically when they first need credentials.
Returns: Promise<BraintrustState> Options (all optional):
  • apiKey (string): API key. Defaults to BRAINTRUST_API_KEY.
  • appUrl (string): Braintrust app URL. Defaults to https://www.braintrust.dev.
  • orgName (string): organization name, useful when credentials can access multiple orgs.
  • fetch (typeof fetch): custom fetch implementation for SDK requests.
  • forceLogin (boolean): log in again even if the SDK already has credentials.
  • noExitFlush (boolean): disables the process exit handler that flushes pending writes.
  • onFlushError ((error) => void): handles errors from the background flusher.
  • disableSpanCache (boolean): disables the local span cache used by eval scorers.
  • debugLogLevel ("error" | "warn" | "info" | "debug" | false): enables SDK troubleshooting output. Set false to also silence the SDK’s default warnings.
In most cases you don’t need to call login() yourself. When BRAINTRUST_API_KEY is set, APIs like initLogger(), initExperiment(), initDataset(), loadPrompt(), and loadParameters() authenticate automatically using it. Call login() yourself when you want to authenticate with something other than that environment variable, such as a specific API key, organization, or custom fetch. Logging in stores those credentials in the SDK’s global state, so every later SDK call uses them, including APIs like getPromptVersions() that take no auth options of their own.

Environment variables

  • BRAINTRUST_API_KEY: API key used to authenticate. Same as the apiKey option.
  • BRAINTRUST_API_URL: Braintrust API URL. Set this for self-hosted or data plane deployments.
  • BRAINTRUST_APP_URL: Braintrust app URL, used for permalinks. Defaults to https://www.braintrust.dev. Same as the appUrl option.
  • BRAINTRUST_APP_PUBLIC_URL: public Braintrust app URL used when generating permalinks. Defaults to the app URL.
  • BRAINTRUST_PROXY_URL: AI proxy URL. Overrides the proxy URL returned for your organization.
  • BRAINTRUST_ORG_NAME: organization name, useful when credentials can access multiple orgs. Same as the orgName option.
  • BRAINTRUST_DISABLE_INSTRUMENTATION: comma-separated list of integrations to skip during auto-instrumentation, for example openai,anthropic.
  • BRAINTRUST_CAPTURE_ATTACHMENTS: set to 1 or true to upload files from OpenAI image and audio calls, base64 image and file inputs to OpenAI Chat Completions calls, and images and resource blobs in MCP server results, as attachments. Off by default, which records the file contents as <omitted>. In v3.41.0 and later, it doesn’t record LiveKit Agents call audio. Use the two variables that follow instead.
  • BRAINTRUST_CAPTURE_USER_AUDIO_ATTACHMENTS: set to 1 or true to record the caller’s audio in LiveKit Agents sessions as attachments. Off by default. Requires v3.41.0 or later.
  • BRAINTRUST_CAPTURE_AGENT_AUDIO_ATTACHMENTS: set to 1 or true to record the agent’s audio in LiveKit Agents sessions as attachments. Off by default. Requires v3.41.0 or later.
  • BRAINTRUST_DEBUG_LOG_LEVEL: SDK troubleshooting output: error, warn, info, or debug. When unset, the SDK prints only warnings that need your attention, such as a client it can’t wrap. Same as the debugLogLevel option.
  • BRAINTRUST_VERBOSE: set to a truthy value to enable verbose evaluation logging.
  • BRAINTRUST_ENVIRONMENT_TYPE: environment type for span-origin provenance (for example, ci or server). Detected automatically from common CI and server runtimes when unset.
  • BRAINTRUST_ENVIRONMENT_NAME: environment name for span-origin provenance (for example, github_actions or aws_lambda). Detected automatically when unset.
The following variables tune the background log flusher. The defaults are suitable for most workloads; adjust them only for high-throughput or self-hosted deployments.
  • BRAINTRUST_SYNC_FLUSH: set to a truthy value to flush logs synchronously instead of in the background.
  • BRAINTRUST_FLUSH_DELAY_MS: maximum time, in milliseconds, that a logged row waits so nearby rows can be sent in one upload request. A full batch of BRAINTRUST_DEFAULT_BATCH_SIZE rows is sent right away. Defaults to 1000 in long-lived Node.js processes, and to 0 (send right away) in other runtimes and in serverless environments such as AWS Lambda, Vercel, Netlify, Google Cloud Run and Cloud Functions, App Engine standard, and Azure Functions. Requires v3.40.0 or later.
  • BRAINTRUST_DEFAULT_BATCH_SIZE: number of log events sent per upload request.
  • BRAINTRUST_MAX_REQUEST_SIZE: override the maximum upload request size, in bytes.
  • BRAINTRUST_NUM_RETRIES: number of times to retry a failed upload.
  • BRAINTRUST_MAX_GENERATOR_ITEMS: maximum number of items pulled from a generator when tracing. Defaults to 1000; 0 disables the limit.
The following variables configure the local caches for prompts and parameters.
  • BRAINTRUST_CACHE_LOCATION: where prompt and parameters caches are stored: mixed, memory, disk, or none. Defaults to mixed.
  • BRAINTRUST_PROMPT_CACHE_DIR: directory for the on-disk prompt cache. Defaults to ~/.braintrust/prompt_cache.
  • BRAINTRUST_PROMPT_CACHE_MEMORY_MAX: maximum number of entries in the in-memory prompt cache.
  • BRAINTRUST_PROMPT_CACHE_DISK_MAX: maximum number of entries in the on-disk prompt cache.
  • BRAINTRUST_PARAMETERS_CACHE_DIR: directory for the on-disk parameters cache. Defaults to ~/.braintrust/parameters_cache.
  • BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX: maximum number of entries in the in-memory parameters cache.
  • BRAINTRUST_PARAMETERS_CACHE_DISK_MAX: maximum number of entries in the on-disk parameters cache.