Getting started
Your first trace
Wrap an LLM call in a trace and generation, send token usage, and flush before your process exits.
This is the whole quickstart: create a trace, record a generation inside it, end the generation with token usage, and flush. The SDK batches events in the background and ships them to Currai.
After this code runs, open your Currai workspace and check the traces table for
chat-turn. If the trace does not appear within a few seconds, start with
Troubleshooting: most missing traces come from missing
environment variables, invalid keys, or returning from a serverless handler
before flushAsync() / flush_async() finishes.
TypeScript
import { Currai } from "currai";
const currai = new Currai({
publicKey: process.env.CURRAI_PUBLIC_KEY!,
secretKey: process.env.CURRAI_SECRET_KEY!,
});
const trace = currai.trace({
name: "chat-turn",
sessionId: "sess-1",
userId: "user-1",
input: { messages },
environment: "production",
tags: ["chatbot"],
});
const generation = trace.generation({
name: "openai.chat.completions",
model: "gpt-4o-mini",
input: messages,
modelParameters: { temperature: 0.7 },
});
const completion = await openai.chat.completions.create({ /* … */ });
generation.end({
output: completion.choices[0].message,
usage: {
input: completion.usage.prompt_tokens,
output: completion.usage.completion_tokens,
total: completion.usage.total_tokens,
unit: "TOKENS",
},
});
trace.update({ output: completion.choices[0].message.content });
await currai.flushAsync(); // required on serverless (Vercel, AWS Lambda, etc.)Python
import os
from currai import Currai
currai = Currai(
public_key=os.environ["CURRAI_PUBLIC_KEY"],
secret_key=os.environ["CURRAI_SECRET_KEY"],
)
trace = currai.trace(
name="chat-turn",
session_id="sess-1",
user_id="user-1",
input={"messages": messages},
environment="production",
tags=["chatbot"],
)
generation = trace.generation(
name="openai.chat.completions",
model="gpt-4o-mini",
input=messages,
model_parameters={"temperature": 0.7},
)
completion = openai_client.chat.completions.create(...)
generation.end(
output=completion.choices[0].message.content,
usage={
"input": completion.usage.prompt_tokens,
"output": completion.usage.completion_tokens,
"total": completion.usage.total_tokens,
"unit": "TOKENS",
},
)
trace.update(output=completion.choices[0].message.content)
await currai.flush_async() # required before short-lived processes exitFlush hygiene
The SDK buffers events and flushes them in the background, so instrumentation never blocks a request. But a short-lived process — a serverless function, a CLI, a worker that exits — can die before the buffer is sent.
Always flush before the process can exit. Call flushAsync() (TypeScript) or flush_async() (Python) at the end of a request handler or before shutdown. In Python, a synchronous currai.flush() is also available for non-async call sites. On a long-running server you can rely on the background flush interval and only flush on shutdown.
Provider support
The SDK is provider-agnostic — trace().generation().end({ model, output, usage }) works for any LLM. For OpenAI-compatible providers (OpenAI, Groq, xAI Grok, DeepSeek, Together), point the openai client at their baseURL and instrument the same way. For Anthropic, Gemini, or Bedrock, wrap the call manually — it's the same ~10 lines.
What to check in the dashboard
The first trace should show:
chat-turnas the trace name.productionas the environment.user-1andsess-1on the trace metadata.- One
openai.chat.completionsgeneration nested inside the trace. - Prompt, completion, token usage, latency, and cost on the generation.
If you see the trace but not the generation, make sure generation.end() runs
after the provider call. If you see the generation but cost is empty, make sure
you send usage.input, usage.output, and the model name.
Next, go deeper on generations, or see full runnable apps in the examples repo.
