> ## Documentation Index
> Fetch the complete documentation index at: https://docs.withboundary.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Production Observability

> Send contract runs to the Boundary dashboard when local logs are not enough

Local logging helps while you are building. The hosted SDK helps after real traffic starts.

Use `@withboundary/sdk` when you need to answer production questions without reading application logs:

* Which contracts are rejecting most often?
* Which rule is causing retries?
* Did a prompt or model change reduce acceptance rate?
* Are failures isolated to one environment?
* Which runs need human review?

## Install the SDK

<CodeGroup>
  ```bash npm theme={null}
  npm install @withboundary/sdk
  ```

  ```bash pnpm theme={null}
  pnpm add @withboundary/sdk
  ```

  ```bash yarn theme={null}
  yarn add @withboundary/sdk
  ```
</CodeGroup>

`@withboundary/sdk` is separate from `@withboundary/contract`. Installing the local contract package never enables cloud telemetry by itself.

## Add a Boundary logger

```typescript theme={null}
import { defineContract } from "@withboundary/contract";
import { createBoundaryLogger } from "@withboundary/sdk";

const boundaryLogger = createBoundaryLogger({
  apiKey: process.env.BOUNDARY_API_KEY,
  environment: "production",
});

export const leadContract = defineContract({
  name: "lead-scoring",
  schema,
  rules,
  logger: boundaryLogger,
});
```

If `BOUNDARY_API_KEY` is missing and no custom `write` sink is configured, `createBoundaryLogger()` returns `null`. Passing that to `defineContract` is safe. The contract still runs; it just sends no events.

## Keep raw data off by default

The SDK's defaults are conservative:

```typescript theme={null}
createBoundaryLogger({
  apiKey: process.env.BOUNDARY_API_KEY,
  environment: "production",
  capture: {
    inputs: false,
    outputs: false,
    repairs: true,
  },
});
```

With these defaults, Boundary receives run metadata, failure categories, failing rule names, repair messages, duration, attempt count, model label, and SDK/runtime attribution. Raw prompts and raw model outputs stay in your process unless you opt in.

## Opt into raw payloads only when needed

Raw inputs and outputs are useful for staging or short debugging windows:

```typescript theme={null}
const boundaryLogger = createBoundaryLogger({
  apiKey: process.env.BOUNDARY_API_KEY,
  environment: "staging",
  capture: {
    inputs: true,
    outputs: true,
    repairs: true,
  },
  redact: {
    fields: ["email", "phone", "ssn", "apiKey"],
    patterns: [/\b\d{3}-\d{2}-\d{4}\b/],
  },
});
```

Do not turn raw capture on just to make the dashboard useful. Rule failures, categories, repairs, and acceptance rates are enough for most production monitoring.

## Flush in short-lived runtimes

Long-running Node servers can rely on normal batching. Serverless and edge runtimes need an explicit flush near the end of the request:

```typescript theme={null}
try {
  return await handler(req);
} finally {
  await boundaryLogger?.flush();
}
```

See the runtime guides for exact patterns:

<CardGroup cols={2}>
  <Card title="Node.js" icon="server" href="/sdk/platforms/node">
    Long-running processes
  </Card>

  <Card title="Next.js" icon="code" href="/sdk/platforms/nextjs">
    Route handlers, server actions, and edge runtime
  </Card>

  <Card title="Vercel & Lambda" icon="cloud" href="/sdk/platforms/vercel-aws-lambda">
    Per-invocation flushing
  </Card>

  <Card title="Workers & Edge" icon="bolt" href="/sdk/platforms/cloudflare-workers-edge">
    `waitUntil` and timer constraints
  </Card>
</CardGroup>

## What to watch first

Start with a small dashboard checklist:

* acceptance rate by contract
* top failing rules
* failures by category
* p95 duration and average attempt count
* recent rejected runs with repair messages

If acceptance drops, inspect the top rule failures first. If format failures rise, inspect provider output, schema instructions, max tokens, and prompt changes.

## See also

<CardGroup cols={2}>
  <Card title="SDK quickstart" icon="rocket" href="/sdk/quickstart">
    Minimal hosted setup
  </Card>

  <Card title="Capture policy" icon="filter" href="/sdk/capture-policy">
    Exact data buckets and defaults
  </Card>

  <Card title="Redaction" icon="eye-slash" href="/sdk/redaction">
    Scrub data before transmission
  </Card>

  <Card title="Security & data handling" icon="shield" href="/concepts/security">
    Network behavior and trust boundaries
  </Card>
</CardGroup>
