Quickstart
From zero to your first tracked AI dollar in a few minutes. No proxy, no gateway and nothing to rewrite: you wrap the client you already have.
Install
Run this in your project folder:
npx tokmetry initDetect your project
The CLI detects your runtime, your package manager and the AI SDKs you already use. It only reads dependency names from
package.json: it never opens your code or reads a provider key.Sign in from the browser
It opens your browser to authorize this machine. The CLI never asks for your email or your password.
Pick an organization and a project
Choose where the spend is attributed. The CLI creates a project API key (shown once) and writes
.tokmetry.json, which has no secrets, and your.env. Your.envis added to.gitignore.Install the SDK and test it
It installs
@tokmetry/sdkwith your package manager and sends one synthetic event to confirm the key works.
Useful options
--yes- Take every default and ask nothing. It is also the mode in non-interactive terminals.
--no-install- Print the install command instead of running it.
--no-browser- Show the authorization link and code instead of opening a browser (SSH, CI).
--project <id|slug>- Pick the project without being asked.
--environment <name>development,stagingorproduction. By default it followsNODE_ENV.
Wrap your client
One line around the OpenAI, Anthropic or Gemini client you already have. Your calls stay exactly the same and each one is measured on its own, streaming included.
import OpenAI from "openai";
import { wrapOpenAI } from "@tokmetry/sdk/openai";
const openai = wrapOpenAI(new OpenAI());
const completion = await openai.chat.completions.create({
model: "gpt-4.1-mini",
messages: [{ role: "user", content: "Hello" }],
});In your dashboard (example)gpt-4.1-mini · 1,240 in · 310 out · 812 ms · $0.00099
import Anthropic from "@anthropic-ai/sdk";
import { wrapAnthropic } from "@tokmetry/sdk/anthropic";
const anthropic = wrapAnthropic(new Anthropic());
const message = await anthropic.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});In your dashboard (example)claude-sonnet-5 · 1,240 in · 310 out · 1,140 ms · $0.00558
import { GoogleGenAI } from "@google/genai";
import { wrapGemini } from "@tokmetry/sdk/gemini";
const ai = wrapGemini(new GoogleGenAI({}));
const response = await ai.models.generateContent({
model: "gemini-3.5-flash",
contents: "Hello",
});In your dashboard (example)gemini-3.5-flash · 1,240 in · 310 out · 690 ms · $0.00465
Another provider? Report usage by hand
Pass what your provider already returned in its usage payload to tokmetry.track(). It is synchronous and never throws.
import { tokmetry } from "@tokmetry/sdk";
tokmetry.track({
provider: "openai",
model: "gpt-4.1-mini",
usage: { inputTokens: 1_200, outputTokens: 340 },
latencyMs: 812,
statusCode: 200,
});Configuration
The CLI writes these variables for you. Everything is optional except the key.
| Variable | What it does | Default |
|---|---|---|
TOKMETRY_API_KEY | Your project API key. Without it the SDK is disabled: it makes no HTTP calls and raises no errors. | None |
TOKMETRY_PROJECT_ID | Informational. The backend derives the real project from the key. | None |
TOKMETRY_ENVIRONMENT | development, staging or production. | From NODE_ENV |
TOKMETRY_API_URL | Send events to a different API URL. | The Tokmetry API |
TOKMETRY_DEBUG | Log SDK activity to the console. Accepts 1, true, yes or on. | Off |
Options passed in code to init() win over environment variables, and those win over the defaults. An invalid value never throws: it falls back to the default.
How events are sent
Built so Tokmetry can never get in the way of your application.
Batched, never one request per call
Events wait in memory and go out in batches: every 100 events, every 5 seconds and when the process exits.
Fail-open
If Tokmetry is unreachable, your AI calls keep working exactly as before and the usage data is dropped silently. The SDK never throws into your code.
Retries without double counting
Network errors, timeouts and 408, 429 and 5xx responses are retried with backoff. Every event carries a unique id, so a retry is never counted twice. Other 4xx errors, like a revoked key, are dropped instead of retried forever.
Streaming included
Streamed responses are measured when the stream ends, using the usage the provider reports.
What leaves your app
Only technical and financial metadata: provider, model, token counts, cost, latency, status code and environment. Prompts, responses and provider API keys are never read, sent or stored.
Ready to see your spend?
Create a free account, run the CLI and your first events show up in the dashboard within minutes.
Start Free