Skip to main content

Quickstart

Adding Observra to an existing application takes three lines. This page walks through exactly which three, and where they go.

1. Install

npm i observra-sdk-node @opentelemetry/api

The SDK is ESM-only, so your package.json needs "type": "module" (or use an .mjs file).

2. Get a gateway key

In the Observra Dashboard, under Gateway Keys, create a key for the Application and Environment these calls should be attributed to. It starts with obs_.

OBSERVRA_GATEWAY_KEY=obs_your_key_here

That's the only Observra credential you need. Your provider key stays exactly where it is — you keep sending it yourself, and Observra forwards it without storing it.

3. Add three lines to your app

Here is an ordinary application that calls Groq. Nothing Observra-specific:

app.ts — before
import Groq from "groq-sdk";

const groq = new Groq({ apiKey: process.env.GROQ_API_KEY });

export async function ask(question: string) {
const res = await groq.chat.completions.create({
model: "llama-3.3-70b-versatile",
messages: [{ role: "user", content: question }],
});
return res.choices[0].message.content;
}

And the same application with Observra. The highlighted lines are the entire change:

app.ts — after
import * as observra from "observra-sdk-node";
import Groq from "groq-sdk";

observra.configure({ serviceName: "my-app" });
await observra.instrument();

const groq = new Groq({ apiKey: process.env.GROQ_API_KEY });

export async function ask(question: string) {
const res = await groq.chat.completions.create({
model: "llama-3.3-70b-versatile",
messages: [{ role: "user", content: question }],
});
return res.choices[0].message.content;
}

Your Groq client didn't change. Your call site didn't change. No baseURL, no wrapper class, no custom headers. Every call this application makes from now on is routed through the Observra Gateway and traced.

What those lines do

observra.configure() reads OBSERVRA_GATEWAY_KEY from the environment and points at Observra's hosted gateway. serviceName is optional — it labels this application in your trace data, which matters once you run more than one.

observra.instrument() patches the global fetch, which is how a stock provider SDK ends up talking to your gateway without knowing anything about Observra. It's async, so await it.

Where to put them

Before you construct any provider client, once per process. In a real application that usually means the top of your entry point:

main.ts
import * as observra from "observra-sdk-node";

observra.configure({ serviceName: "my-app" });
await observra.instrument();

// Everything imported after this point is instrumented.
const { startServer } = await import("./server.js");
startServer();

If your entry point can't use top-level await, wrap it:

main.ts
async function main() {
const observra = await import("observra-sdk-node");
observra.configure({ serviceName: "my-app" });
await observra.instrument();

const { startServer } = await import("./server.js");
startServer();
}

main();

4. See it

Open the dashboard, go to Observations, and set the range to the last hour. Your calls are there with model, token counts, cost, and latency. Click one and choose Request flow to see it as a tree.

That's the whole integration

Everything else in these docs is optional:

  • Guardrails — catch PII in prompts before they leave
  • Tracing — group multi-step operations into one trace
  • Agents and tools — trace an agent run as one flow
  • Providers — the other 14 supported provider SDKs

Nothing showing up?

Check the request actually reached the gateway. Log the URL your provider SDK requested — after instrument() it should point at your gateway, not the provider:

const realFetch = globalThis.fetch;
globalThis.fetch = async (input, init) => {
console.log("→", typeof input === "string" ? input : input.url);
return realFetch(input, init);
};

await observra.instrument(); // install the logger BEFORE this line

The order matters. A logger installed after instrument() records the original URL, before the SDK rewrote it — which looks like a routing failure on a perfectly working setup.

Check your provider is one the SDK reroutes. See the supported list. Anything not on it passes straight through to its own API, untraced.

Check instrument() ran first. A call made before it completes goes direct to the provider. If you forgot the await, that's the likely cause.

Check the key. An invalid or revoked gateway key gets a 401, which surfaces as whatever error your provider SDK raises for that status.