Skip to main content
import { createBoundaryLogger } from "@withboundary/sdk";

Signature

function createBoundaryLogger<T = unknown>(
  options?: BoundaryLoggerOptions,
): BoundaryLogger<T> | null;

Returns

  • A BoundaryLogger<T> when either apiKey (or BOUNDARY_API_KEY env var) or write is configured.
  • null otherwise — the dev-safe fallback. Passing null to defineContract({ logger }) is a no-op.

BoundaryLoggerOptions

OptionTypeDefaultDescription
apiKeystringprocess.env.BOUNDARY_API_KEYBoundary ingest credential
environment"production" | "staging" | "development"Bucket events on the dashboard
endpointstring"https://api.withboundary.com"Override the ingest endpoint (self-host, proxy)
modelstringDefault LLM label stamped onto every event; overridable per-call
capturePartial<CapturePolicy>see belowWhich buckets of data to ship
redactRedactionOptionsfields / patterns / custom scrubbing
batch.sizenumber20Flush when queue hits this length
batch.intervalMsnumber5000Periodic flush cadence (0 disables)
batch.maxQueueSizenumber1000Drop-oldest overflow threshold
beforeSend(event) => BoundaryLogEvent | nullLast-chance transform or drop
write(events) => void | Promise<void>Custom sink; fires alongside apiKey
flushOnExitbooleantrueAttach runtime lifecycle drain hooks
onError(err) => voidone-time console.warnPermanent drop callback
fetchtypeof fetchglobalThis.fetchInjected fetch (tests, polyfills)

Default capture policy

{
  inputs: false,
  outputs: false,
  repairs: true,
  errors: true,
  metadata: true,
}
Conservative — raw LLM inputs and outputs are off by default. See Capture policy.

BoundaryLogger<T>

The returned object:
type BoundaryLogger<T = unknown> = ContractLogger<T> & {
  flush: (timeoutMs?: number) => Promise<void>;
  shutdown: (timeoutMs?: number) => Promise<void>;
};
  • Implements every ContractLogger<T> hook (assign it directly to defineContract({ logger })).
  • flush(timeoutMs?) — drain the queue; logger stays active.
  • shutdown(timeoutMs?) — drain, stop the timer, disable further sends. Idempotent.
See Shutdown for timeout semantics and per-platform recipes.

Minimal example

import { createBoundaryLogger } from "@withboundary/sdk";
import { defineContract } from "@withboundary/contract";

const logger = createBoundaryLogger({
  environment: "production",
});

const contract = defineContract({
  name: "lead-scoring",
  schema,
  rules,
  logger,
});

Full example

const logger = createBoundaryLogger({
  apiKey: process.env.BOUNDARY_API_KEY,
  environment: "production",
  model: "gpt-4.1",
  capture: {
    inputs: false,
    outputs: false,
    repairs: true,
    errors: true,
    metadata: true,
  },
  redact: {
    fields: ["ssn", "email"],
    patterns: [/\b\d{3}-\d{2}-\d{4}\b/],
    custom: (value, path) =>
      path.at(-1) === "customerId" && typeof value === "string"
        ? `cust_${hash(value).slice(0, 10)}`
        : value,
  },
  batch: {
    size: 50,
    intervalMs: 2000,
    maxQueueSize: 2000,
  },
  beforeSend(event) {
    return event.contractName === "health-check" ? null : event;
  },
  write(events) {
    for (const e of events) console.log(JSON.stringify(e));
  },
  onError(err) {
    metrics.increment("boundary.drop");
  },
});

See also

SDK Quickstart

Install and wire the logger

Shutdown

flush + shutdown + signal handling