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

# OpenRouter

> Trace OpenRouter SDK calls in Braintrust to debug prompts, evaluate models, and monitor production usage

[OpenRouter](https://openrouter.ai/) lets you call models from many providers through a single API. Braintrust traces OpenRouter SDK calls, including streaming chat completions, embeddings, and the Responses API.

**TypeScript**

> [!TIP]
>
> If you're using OpenRouter's agent toolkit package (`@openrouter/agent`), see [OpenRouter Agent](https://docs.braintrust.dev/integrations/agent-frameworks/openrouter-agent.md).

## Setup

Install the Braintrust and `@openrouter/sdk` packages, then set your API keys.

**1. Install packages**

```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
pnpm add braintrust @openrouter/sdk
```

```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
npm install braintrust @openrouter/sdk
```

**2. Set environment variables**

```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
OPENROUTER_API_KEY=<your-openrouter-api-key>
BRAINTRUST_API_KEY=<your-braintrust-api-key>

# If you are self-hosting Braintrust, set the URL of your hosted dataplane
# BRAINTRUST_API_URL=<your-braintrust-api-url>
```

## Auto-instrumentation

To trace OpenRouter SDK calls without modifying your application code, initialize Braintrust normally, then run your app with Braintrust's import hook to patch the OpenRouter SDK at runtime.

**1. Initialize Braintrust and call OpenRouter**

```javascript title="app.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { initLogger } from "braintrust";
import { OpenRouter } from "@openrouter/sdk";

initLogger({
  projectName: "My Project",
  apiKey: process.env.BRAINTRUST_API_KEY,
});

const client = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });

const response = await client.chat.send({
  chatRequest: {
    model: "openai/gpt-5-mini",
    messages: [{ role: "user", content: "What is observability?" }],
  },
});
```

**2. Run with the import hook**

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
node --import braintrust/hook.mjs app.js
```

The auto-instrumentation example uses plain JavaScript so `node --import` can run the file directly. The Braintrust APIs work the same in TypeScript projects. Compile your TypeScript to JavaScript and run the compiled file with the import hook, or [run TypeScript directly](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) with a TypeScript loader.

> [!NOTE]
>
> If you're using a bundler, see [Trace LLM calls](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) for plugin and loader setup.

## Manual instrumentation

To trace OpenRouter clients manually, wrap them yourself with `wrapOpenRouter`. Use this when you want to instrument specific clients individually rather than all of them globally.

```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { initLogger, wrapOpenRouter } from "braintrust";
import { OpenRouter } from "@openrouter/sdk";

initLogger({
  projectName: "My Project",
  apiKey: process.env.BRAINTRUST_API_KEY,
});

const client = wrapOpenRouter(
  new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY }),
);

const response = await client.chat.send({
  chatRequest: {
    model: "openai/gpt-5-mini",
    messages: [{ role: "user", content: "What is observability?" }],
  },
});
```

## What Braintrust traces

Braintrust instruments the `@openrouter/sdk` client and creates an LLM-typed span per call:

* Chat completion spans (`openrouter.chat.send`), capturing messages as input, request parameters as metadata, and the response choices plus token usage as output. Streaming responses are aggregated (including reasoning and tool calls) and record first-token timing.
* Embedding spans (`openrouter.embeddings.generate`), capturing input texts as input and the first embedding's vector length as output.
* Rerank spans (`openrouter.rerank.rerank`), capturing the query and documents as input, document count and request parameters as metadata, and results as a list of `{ index, relevance_score }` items.
* Response spans (`openrouter.beta.responses.send`), capturing input and request parameters as metadata and the response output plus token usage as output, including streaming.
* Request metadata (model and provider parsed from the OpenRouter `provider/model` ID) and token usage metrics (prompt, completion, and total).

## Resources

* [OpenRouter TypeScript SDK](https://www.npmjs.com/package/@openrouter/sdk)
* [OpenRouter API reference](https://openrouter.ai/docs)

**Python**

## Setup

Install the Braintrust and OpenRouter packages, then set your API keys.

**1. Install packages**

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
pip install braintrust openrouter
```

**2. Set environment variables**

```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
OPENROUTER_API_KEY=<your-openrouter-api-key>
BRAINTRUST_API_KEY=<your-braintrust-api-key>
```

## Auto-instrumentation

To trace OpenRouter SDK calls without modifying your application code, call `braintrust.auto_instrument()` before creating your OpenRouter client.

```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import os

import braintrust

braintrust.auto_instrument()
braintrust.init_logger(project="My Project")

from openrouter import OpenRouter

client = OpenRouter(api_key=os.environ["OPENROUTER_API_KEY"])

response = client.chat.send(
    model="openai/gpt-5-mini",
    messages=[{"role": "user", "content": "What is observability?"}],
)
```

## Manual instrumentation

To trace OpenRouter clients manually, wrap them yourself with `wrap_openrouter()`. Use this when you want to instrument specific clients individually rather than all of them globally.

```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import os

from braintrust import init_logger, wrap_openrouter
from openrouter import OpenRouter

init_logger(project="My Project")

client = wrap_openrouter(OpenRouter(api_key=os.environ["OPENROUTER_API_KEY"]))

response = client.beta.responses.send(
    model="openai/gpt-5-mini",
    input="Summarize tracing in one sentence.",
)

# Response shape varies; adjust indexing for your model and request.
print(response.output[1].content[0].text)
```

### OpenAI-compatible endpoint

If your app already uses the OpenAI Python SDK with OpenRouter's OpenAI-compatible endpoint, keep that setup and use `wrap_openai()`.

```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import os

from braintrust import init_logger, wrap_openai
from openai import OpenAI

init_logger(project="My Project")

client = wrap_openai(
    OpenAI(
        base_url="https://openrouter.ai/api/v1",
        api_key=os.environ["OPENROUTER_API_KEY"],
    )
)

response = client.responses.create(
    model="openai/gpt-5-mini",
    input="Explain routing in one sentence.",
)

print(response.output_text)
```

## What Braintrust traces

Braintrust patches the `openrouter` client and creates an LLM-typed span per call:

* Chat completion spans (`openrouter.chat.send`), capturing messages as input, request parameters as metadata, and the response choices plus token usage as output. Streaming responses are aggregated and record first-token timing. Covers sync (`chat.send()`) and async (`chat.send_async()`) calls.
* Embedding spans (`openrouter.embeddings.generate`), capturing input texts as input and the embedding count plus the first embedding's vector length as output. Covers sync and async calls.
* Responses API spans, capturing input as input, request parameters as metadata, the response output as output, and token usage as metrics, including streaming. Covers sync (`send()`) and async (`send_async()`) calls on both namespaces:
  * `client.responses` creates `openrouter.responses.send` spans. Requires `openrouter` v1.1.0 or later.
  * `client.beta.responses` creates `openrouter.beta.responses.send` spans.
* Request metadata (model and provider parsed from the OpenRouter `provider/model` ID, plus provider routing) and response metadata (response ID and service tier) when present. When a request enables OpenRouter's Armor or alignment plugins, the response metadata also includes `safeguard_results` and `alignment`, including on streamed chat completions.
* Token usage metrics (prompt, completion, and total, plus prompt, completion, and cost detail breakdowns when reported).
* Errors captured on every call.

## Resources

* [OpenRouter Python SDK](https://pypi.org/project/openrouter/)
* [OpenRouter API reference](https://openrouter.ai/docs)
* [OpenAI integration](https://docs.braintrust.dev/integrations/ai-providers/openai.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.