npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tokenworth

v0.2.0

Published

LLM cost calculator powered by LiteLLM pricing — 2400+ models, auto-cost on API calls

Readme

tokenworth

One function to estimate LLM cost. Pass a model name + your input and output (raw text or exact token counts). Get back the token usage and estimated USD cost.

Pricing data sourced from LiteLLM — automatically covers 2400+ models across OpenAI, Anthropic, Google, Mistral, Cohere, and more.

No external API calls. No sign-up. All pricing is built into the package — works fully offline.


Install

npm install tokenworth

Quick start

import cost from "tokenworth";

// With exact token counts (pass numbers)
cost("gpt-4o", 1000, 500);
// → { model: "gpt-4o", inputTokens: 1000, outputTokens: 500, totalTokens: 1500, estimatedCost: 0.0075 }

// With raw text (auto-counts tokens)
cost("gpt-4o", "Write a greeting email.", "Hello! Great to hear from you.");
// → { model: "gpt-4o", inputTokens: 6, outputTokens: 8, totalTokens: 14, estimatedCost: 0.000095 }

// Unknown model → null
cost("unknown/fake-model", 100, 50);
// → null

That's it. One import, one call.


Usage examples

1. Pass token counts (numbers)

import cost from "tokenworth";

const result = cost("gpt-4o-mini", 2000, 1000);
//                              ↑      ↑
//                     input tokens   output tokens

console.log(result.estimatedCost); // 0.0009

2. Pass raw text (auto-counts tokens)

import cost from "tokenworth";

const result = cost(
  "gpt-4o",
  "Explain quantum computing in simple terms.",  // input text
  "Quantum computing uses qubits...",            // output / response text
);

console.log(result);
// {
//   model: "gpt-4o",
//   inputTokens: 8,
//   outputTokens: 5,
//   totalTokens: 13,
//   estimatedCost: 0.00007
// }

3. Call an AI model and get the cost automatically

The callModel function makes the actual API call and returns the response + cost. Uses the OpenAI-compatible endpoint.

import { callModel } from "tokenworth";

const { data, cost } = await callModel({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Hello world" }],
  apiKey: process.env.OPENAI_API_KEY,
});

console.log(data.choices[0].message.content);  // ← normal AI response
console.log(cost.estimatedCost);                 // ← auto-calculated cost

Works with any OpenAI-compatible provider — just set baseUrl:

// Azure OpenAI
callModel({ model: "gpt-4o", messages, apiKey, baseUrl: "https://my-resource.openai.azure.com" });

// LiteLLM proxy
callModel({ model: "gpt-4o", messages, apiKey, baseUrl: "http://localhost:4000" });

// Ollama (no API key needed)
callModel({ model: "llama3", messages, baseUrl: "http://localhost:11434" });

4. Wrap your existing AI SDK call

Auto-extracts the output text and counts tokens from the real API response.

import { trackCost } from "tokenworth";
import OpenAI from "openai";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

const { data, cost } = await trackCost({
  model: "gpt-4o",
  input: "Hello world",
  fn: () => openai.chat.completions.create({
    model: "gpt-4o",
    messages: [{ role: "user", content: "Hello world" }],
  }),
});

console.log(data.choices[0].message.content);  // ← normal response, unchanged
console.log(cost.estimatedCost);                 // ← auto-calculated

Also works with Anthropic SDK, raw fetch, or any async function.

5. Custom pricing for models not in the catalog

import cost from "tokenworth";

cost("my-private-model", 1000, 500, {
  pricing: {
    "my-private-model": { input: 0.005 / 1000, output: 0.02 / 1000 },
  },
});
// → { model: "my-private-model", inputTokens: 1000, outputTokens: 500, ... }

6. Use the lower-level functions directly

import { calculateCost, countTokens, getPricing, isLocalModel } from "tokenworth";

countTokens("Hello world");                           // 2
calculateCost("gpt-4o", 1000, 500);                   // 0.0075
getPricing("claude-3-sonnet");                       // { input: 0.000003, output: 0.000015 }
isLocalModel("ollama");                              // true

// Models only in LiteLLM (not in manual list) work too:
getPricing("gemini-2.0-flash-001");                  // { input: 0.00000015, output: 0.0000006 }
getPricing("mistral-large-latest");                   // { input: 0.000008, output: 0.000024 }

What you get back

cost() returns CostResult | null:

type CostResult = {
  model: string;         // the model name you passed in
  inputTokens: number;   // token count for input
  outputTokens: number;  // token count for output
  totalTokens: number;   // inputTokens + outputTokens
  estimatedCost: number; // USD cost
};

Returns null when the model is not found in the pricing catalog and no custom pricing is provided.

callModel() returns CallModelResult:

type CallModelResult = {
  data: Record<string, unknown>;  // raw API response (OpenAI ChatCompletion format)
  cost: CostInfo;                 // cost breakdown
};

trackCost() returns TrackCostResult<T>:

type TrackCostResult<T> = {
  data: T;     // your original SDK response, unchanged
  cost: CostInfo;
};

CostInfo:

type CostInfo = {
  model: string;
  inputTokens: number;
  outputTokens: number;
  totalTokens: number;
  estimatedCost: number;
  inputChars: number;
  outputChars: number;
  durationMs: number;
};

Pricing data

This package embeds LiteLLM's comprehensive pricing database, covering 2400+ models:

  • OpenAI: GPT-4o, GPT-4o-mini, GPT-4-turbo, GPT-4, GPT-3.5-turbo, o1, o3, etc.
  • Anthropic: Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Haiku, Claude 4, etc.
  • Google: Gemini 1.5/2.0 Flash/Pro, etc.
  • Mistral: Mistral Large, Small, Nemo, etc.
  • Cohere: Command R, Command R+, etc.
  • Meta: Llama 3.x (through providers)
  • Amazon Bedrock, Azure, GCP Vertex AI hosted models
  • Local models (Ollama, etc.) are detected automatically and priced at $0

Refresh the pricing data at any time:

npm run refresh-pricing

Full API reference

cost(model, input, output, options?)

| Param | Type | Description | |-----------|-----------------------------|--------------------------------------------------| | model | string | Model name. Vendor prefixes auto-resolved. | | input | string \| number | Raw text (auto-tokenized) or exact token count. | | output | string \| number | Raw text (auto-tokenized) or exact token count. | | options | { pricing?: Record<string, { input: number, output: number }> } | Custom pricing overrides (optional). |

Returns CostResult \| null.

callModel(options)

| Option | Type | Description | |-----------------|-----------------------------------|-----------------------------------------------| | model | string | Model name. | | messages | { role: string; content: string }[] | Chat messages. | | apiKey? | string | API key (default: ""). | | baseUrl? | string | API base URL (default: https://api.openai.com). | | temperature? | number | Sampling temperature. | | maxTokens? | number | Max output tokens. | | topP? | number | Nucleus sampling. | | onCost? | (info: CostInfo) => void | Callback when cost is calculated. |

Returns Promise<CallModelResult>.

trackCost(options)

| Option | Type | Description | |-----------|-----------------------------------|---------------------------------------------| | model | string | Model name. | | input | string | Input text sent to the AI. | | fn | () => Promise<T> | Your AI SDK call. | | onCost? | (info: CostInfo) => void | Callback when cost is calculated. | | pricing?| Record<string, ModelPricing> | Custom pricing overrides. |

Returns { data: T, cost: CostInfo }.

Other named exports

| Function | Description | |-----------------------|----------------------------------------------| | calculateCost(model, inTokens, outTokens, pricing?) | Cost from token counts. | | countTokens(text, model?) | Count tokens in text. | | getPricing(model, custom?) | Look up model pricing. | | isLocalModel(model) | Check if model is free/local. | | extractResponseText(response) | Extract text from AI SDK response. | | estimateCost({ model, inputTokens, outputTokens, pricing? }) | Build full CostInfo. | | resolveModel(name) | Resolve alias/vendor-prefixed name. |


How it works

  1. Pricing catalog is compiled from LiteLLM's open-source pricing database at build time — 2400+ models, no network requests at runtime
  2. Token counting uses @dqbd/tiktoken (OpenAI's open-source encoding, runs locally)
  3. Vendor prefixes (openai/, anthropic/) are auto-stripped before lookup
  4. Dated model names (e.g. claude-sonnet-4-20250514) are aliased to base models
  5. callModel makes the actual API call and returns both response and cost
  6. The original SDK response passes through unmodifiedtrackCost just reads it

Requirements

  • Node.js 18+ (ESM)

License

MIT