> ## Documentation Index
> Fetch the complete documentation index at: https://braintrust.dev/docs/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

If you are a coding agent, prefer the Braintrust [`bt` CLI](/docs/reference/cli/quickstart) for repeatable, scriptable work: running evals, instrumenting code, querying logs, syncing data, managing functions, and configuring coding agents. Use the MCP server for reasoning over Braintrust data in conversation, such as ad-hoc lookups and exploration from your IDE.

[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.

<View title="TypeScript" icon="https://img.logo.dev/typescriptlang.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <Tip>
    If you're using OpenRouter's agent toolkit package (`@openrouter/agent`), see [OpenRouter Agent](/docs/integrations/agent-frameworks/openrouter-agent).
  </Tip>

  <h2 id="setup-typescript">
    Setup
  </h2>

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

  <Steps>
    <Step title="Install packages">
      <CodeGroup>
        ```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
        ```
      </CodeGroup>
    </Step>

    <Step title="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>
      ```
    </Step>
  </Steps>

  <h2 id="auto-instrumentation-typescript">
    Auto-instrumentation
  </h2>

  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.

  <Steps>
    <Step title="Initialize Braintrust and call OpenRouter">
      <CodeGroup>
        ```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?" }],
          },
        });
        ```
      </CodeGroup>
    </Step>

    <Step title="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, then run the compiled file with the import hook.

      <Note>
        If you're using a bundler, see [Trace LLM calls](/docs/instrument/trace-llm-calls#auto-instrumentation) for plugin and loader setup.
      </Note>
    </Step>
  </Steps>

  <h2 id="manual-instrumentation-typescript">
    Manual instrumentation
  </h2>

  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.

  <CodeGroup>
    ```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?" }],
      },
    });
    ```
  </CodeGroup>

  <h2 id="what-traced-typescript">
    What Braintrust traces
  </h2>

  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).

  <h2 id="resources-typescript">
    Resources
  </h2>

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

<View title="Python" icon="https://img.logo.dev/python.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <h2 id="setup-python">
    Setup
  </h2>

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

  <Steps>
    <Step title="Install packages">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      pip install braintrust openrouter
      ```
    </Step>

    <Step title="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>
      ```
    </Step>
  </Steps>

  <h2 id="auto-instrumentation-python">
    Auto-instrumentation
  </h2>

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

  <CodeGroup>
    ```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?"}],
    )
    ```
  </CodeGroup>

  <h2 id="manual-instrumentation-python">
    Manual instrumentation
  </h2>

  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.

  <CodeGroup>
    ```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)
    ```
  </CodeGroup>

  <h3 id="openai-compatible-python">
    OpenAI-compatible endpoint
  </h3>

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

  <CodeGroup>
    ```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)
    ```
  </CodeGroup>

  <h2 id="what-traced-python">
    What Braintrust traces
  </h2>

  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.
  * Response spans (`openrouter.beta.responses.send`), capturing input and request parameters as metadata and the response output plus token usage as output, including streaming. Covers sync and async calls.
  * 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.
  * Token usage metrics (prompt, completion, and total, plus prompt, completion, and cost detail breakdowns when reported).
  * Errors captured on every call.

  <h2 id="resources-python">
    Resources
  </h2>

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