O

OpenRouter

Wrap the official OpenRouter SDK in TypeScript or Python. Chat, Responses, streams, and embeddings traced with tokens, provider-reported cost, and latency.

Built by

telemetry.dev

Language

TypeScript + Python

Packages

@telemetry-dev/openrouter · telemetry-dev-openrouter

Category

Model providers

About the OpenRouter integration

@telemetry-dev/openrouter (TypeScript) and telemetry-dev-openrouter (Python) instrument the official OpenRouter SDKs. Chat, Responses, and embedding calls become OpenTelemetry GenAI spans with the request model and input, response metadata, finish reasons, token usage, provider-reported cost, and latency. Every span records the provider as openrouter, regardless of which model OpenRouter routes the request to.

Before you start

You need two API keys:

  1. A project API key from the API Keys page in your telemetry.dev project.
  2. An API key from your OpenRouter account.

Set both keys in the environment where your application runs:

export TELEMETRY_DEV_API_KEY="td_live_..."
export OPENROUTER_API_KEY="sk-or-v1-..."

Keep these values out of source control. Your framework or deployment platform may provide its own environment-variable settings.

TypeScript quickstart

  1. Install the core SDK, the OpenRouter integration, and the official OpenRouter SDK:

    npm install @telemetry-dev/sdk @telemetry-dev/openrouter @openrouter/sdk
  2. Initialize telemetry.dev, wrap your OpenRouter client, and make a request:

import { OpenRouter } from "@openrouter/sdk";
import { init, shutdown } from "@telemetry-dev/sdk";
import { wrapOpenRouter } from "@telemetry-dev/openrouter";

const telemetryApiKey = process.env.TELEMETRY_DEV_API_KEY;
const openRouterApiKey = process.env.OPENROUTER_API_KEY;
if (!telemetryApiKey || !openRouterApiKey) {
  throw new Error("Set TELEMETRY_DEV_API_KEY and OPENROUTER_API_KEY");
}

init({ apiKey: telemetryApiKey, serviceName: "openrouter-example" });

const openRouter = wrapOpenRouter(new OpenRouter({ apiKey: openRouterApiKey }));

try {
  await openRouter.chat.send({
    chatRequest: {
      model: "openai/gpt-4o-mini",
      messages: [{ role: "user", content: "Say hello" }],
    },
  });
} finally {
  await shutdown();
}
  1. Run the application, then open Traces in your telemetry.dev project. You should see a chat openai/gpt-4o-mini span with provider openrouter.

For a long-running server, call shutdown() during graceful shutdown rather than after every request.

Python quickstart

  1. Install the integration. It includes compatible versions of the telemetry.dev core SDK and official OpenRouter SDK:

    pip install telemetry-dev-openrouter
  2. Initialize telemetry.dev, wrap your client, and make a request:

import os

import telemetry_dev
from openrouter import OpenRouter
from telemetry_dev_openrouter import wrap_open_router

telemetry_dev.init(
    api_key=os.environ["TELEMETRY_DEV_API_KEY"],
    service_name="openrouter-example",
)

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

try:
    client.chat.send(
        model="openai/gpt-4o-mini",
        messages=[{"role": "user", "content": "Say hello"}],
    )
finally:
    telemetry_dev.shutdown()
  1. Run the application, then open Traces in your telemetry.dev project. You should see the same chat openai/gpt-4o-mini span.

For a long-running server, call telemetry_dev.shutdown() during graceful shutdown rather than after every request.

What gets captured

  • Chat, Responses, and embeddings: Instruments chat.send, responses.send, and embeddings.generate, including synchronous and asynchronous Python methods.
  • Streaming with TTFT: Chat and Responses streams accumulate consumed output and record time to first response, terminal usage, cost, errors, and partial output when cancelled early.
  • Provider-reported cost: Uses OpenRouter's response cost when available, with upstream inference cost as a fallback. No cost is invented when neither field is present.
  • Safe request handling: Instrumentation never injects stream_options or mutates a request. Embedding vectors are never captured as output.

Instrument every client

The quickstarts wrap one client explicitly. To instrument all official OpenRouter clients created by your application, call instrumentOpenRouter() in TypeScript or instrument_openrouter() in Python once during startup. Repeated instrumentation is safe, and the matching uninstrumentOpenRouter() or uninstrument_openrouter() function restores the original SDK methods.

If telemetry.dev has not been initialized, instrumentation becomes a no-op and OpenRouter requests continue normally.

Using the OpenAI-compatible API

If your application uses an official OpenAI client with https://openrouter.ai/api/v1 as its base URL, the telemetry.dev OpenAI integrations detect the OpenRouter host automatically and record gen_ai.provider.name as openrouter. Use the first-class OpenRouter packages above when your application uses the official OpenRouter SDK.