Track Every LLM Token in Node.js with all-llm-token-tracker
If you build with OpenAI, Anthropic, or any LLM API, you've probably wondered: How many tokens did that request actually use? Token usage drives cost, performance, and scaling. But in many Node.js apps, response.usage gets logged once and forgotten.
I built all-llm-token-tracker - a small npm package that tracks input and output tokens for every LLM call, with pluggable storage and built-in provider extractors.
- npm: https://www.npmjs.com/package/all-llm-token-tracker
- GitHub: https://github.com/rkanumetta/all-llm-token-tracker
The problem
Most integrations look like this:
const response = await openai.chat.completions.create({ ... });
console.log(response.usage); // logged, rarely stored
That works for debugging - not for production. You usually need:
- Per-call input and output token counts
- Persistent storage you can query later
- Summaries by model, provider, or user
- Something that works in dev and production
Many existing tools bundle pricing engines, MCP servers, or heavy infra. Sometimes you just want clean token tracking.
The solution
all-llm-token-tracker does one job well:
| Feature | Supported |
|---|---|
| Manual token recording | โ |
| Auto-wrap LLM calls | โ |
| OpenAI extractor | โ |
| Anthropic extractor | โ |
| Memory storage | โ |
| File (JSON) storage | โ |
| MongoDB storage | โ |
| Query & summarize | โ |
| Browser dashboard | โ |
| Zero required deps | โ |
Requirements: Node.js 18+
License: MIT
Install
npm install all-llm-token-tracker
MongoDB storage (optional):
npm install all-llm-token-tracker mongodb
Quick start: manual recording
import { createTracker } from 'all-llm-token-tracker';
const tracker = createTracker({ storage: 'memory' });
const record = await tracker.record({
provider: 'openai',
model: 'gpt-4o-mini',
inputTokens: 120,
outputTokens: 45,
metadata: { userId: 'user-123' },
});
console.log(record.totalTokens); // 165
Each record gets a UUID, timestamp, and optional metadata.
Auto-track LLM calls (recommended)
Wrap your existing function - usage is recorded automatically:
import { createTracker, extractOpenAiUsage } from 'all-llm-token-tracker';
import OpenAI from 'openai';
const tracker = createTracker({
storage: 'file',
file: { filePath: './.llm-usage/usage.json' },
});
const openai = new OpenAI();
const { result, record } = await tracker.track(
() => openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Hello!' }],
}),
{
provider: 'openai',
model: 'gpt-4o-mini',
extractUsage: extractOpenAiUsage,
metadata: { feature: 'chat' },
}
);
console.log(result.choices[0].message.content);
console.log(record.inputTokens, record.outputTokens);
What happens:
- Timer starts
- Your LLM function runs
- Usage is extracted from the response
- Record is saved to storage
- You get
{ result, record }back
No changes to your core LLM logic - just a wrapper.
Anthropic support
import { extractAnthropicUsage } from 'all-llm-token-tracker';
await tracker.track(
() => anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello!' }],
}),
{
provider: 'anthropic',
model: 'claude-3-5-sonnet-20241022',
extractUsage: extractAnthropicUsage,
}
);
Storage options
Memory - tests & scripts
const tracker = createTracker({ storage: 'memory' });
File - local JSON
const tracker = createTracker({
storage: 'file',
file: { filePath: './.llm-usage/usage.json' },
});
MongoDB - production
const tracker = createTracker({
storage: 'mongodb',
mongodb: {
uri: process.env.MONGODB_URI,
database: 'my_app',
collection: 'llm_token_usage',
},
});
// on shutdown
await tracker.close();
Query & summarize
const calls = await tracker.getCalls({
provider: 'openai',
from: '2026-07-01',
limit: 100,
});
const summary = await tracker.getSummary();
/*
{
totalCalls: 42,
totalInputTokens: 12500,
totalOutputTokens: 3200,
totalTokens: 15700,
averageInputTokens: 297.6,
averageOutputTokens: 76.2,
averageTotalTokens: 373.8
}
*/
const byModel = await tracker.getSummaryByModel();
const byProvider = await tracker.getSummaryByProvider();
Record shape
Every call is stored like this:
{
"id": "uuid",
"provider": "openai",
"model": "gpt-4o-mini",
"inputTokens": 120,
"outputTokens": 45,
"totalTokens": 165,
"timestamp": "2026-07-10T06:00:00.000Z",
"durationMs": 842,
"metadata": { "userId": "user-123" }
}
Custom providers
import { createUsageExtractor } from 'all-llm-token-tracker';
const extractMyProvider = createUsageExtractor((response) => ({
inputTokens: response.tokens.in,
outputTokens: response.tokens.out,
}));
Or plug in your own storage (Postgres, Redis, etc.):
import { createTracker, type StorageAdapter, type LlmCallRecord } from 'all-llm-token-tracker';
class PostgresStorage implements StorageAdapter {
async save(record: LlmCallRecord) { /* ... */ }
async find(query) { /* ... */ }
async count(query) { /* ... */ }
}
const tracker = createTracker({ storage: new PostgresStorage() });
Bonus: browser dashboard
The repo includes a simple dashboard to visualize input vs output tokens:
git clone https://github.com/rkanumetta/all-llm-token-tracker.git
cd all-llm-token-tracker
npm install
npm run example
npm run dashboard
You'll see:
- Total calls, input tokens, output tokens
- Bar chart per call
- Breakdown by model
- Filterable table with metadata
Real-world use cases
- Cost monitoring - track tokens per feature or user
- Debugging - find which prompts burn the most tokens
- A/B testing - compare models side by side
- SaaS billing - feed data into your own pricing logic
- Compliance - audit trail with timestamps + metadata
Why I built it this way
- Small surface area - one responsibility: track tokens
- Storage flexibility - file in dev, MongoDB in prod
- Provider-agnostic - extend with custom extractors
- TypeScript-first - full types included
- Lightweight - MongoDB is optional, zero required runtime deps
Try it
npm install all-llm-token-tracker
Links:
- ๐ฆ npm: https://www.npmjs.com/package/all-llm-token-tracker
- ๐ GitHub: https://github.com/rkanumetta/all-llm-token-tracker
- ๐ Issues: https://github.com/rkanumetta/all-llm-token-tracker/issues
If you find it useful, star the repo โญ and open an issue if you want support for another provider (Gemini, Mistral, etc.).
Wrapping up
LLM token tracking doesn't need to be complicated. Wrap your API calls, store consistent records, query when you need insights. Track input. Track output. Store it. Query it. Done.
What storage backend do you use for LLM observability - file, MongoDB, or something else? Drop a comment below.
Comments
No comments yet. Start the discussion.