Node & ESM
Pass your provider modules to init() via instrumentModules — the full key list, which import form each takes, and when it's required.
instrumentModules hands TokenPolice the provider modules your app already imported, so it
patches your copy instead of hunting for one. It's Node-only, and it's the fix for every
"the calls run but nothing shows up" shape.
When you need it
- Native ESM (
"type": "module",.mjs, Next.js, Vite, Bun, Deno). ESM freezes a module's bindings at import time, so a provider client imported beforetp.init()runs can't be patched. It fails open — your app is fine, the calls are just invisible. openai7.x, on any module system. Without it, chat completions report 0 tokens. See Supported versions.- Some CommonJS trees too:
pnpm, afile:/link:dependency, npm/yarn/pnpmworkspaces, or more than one copy of a provider package. There, metering can look healthy while enforcement never attaches.
If you're on plain CommonJS with a single flat node_modules, import order genuinely doesn't
matter and you can skip this page.
The SDK tells you when it's needed: at startup it names any provider package it can see
installed but couldn't attach enforcement to. Watch your boot output the first time you run
with logErrors: true.
The fix
import * as tp from "token-police";
import OpenAI from "openai";
tp.init({
apiKey: process.env.TOKENPOLICE_API_KEY,
baseUrl: "https://collect.tokenpolice.ai",
instrumentModules: { openAI: OpenAI },
});
const client = new OpenAI();Pass only the libraries your app actually uses — a provider you don't name simply isn't hooked by this route.
The keys
openAI, anthropic, cohere, bedrock, googleGenAI, openRouter, cerebras,
together, groq, mistral, huggingFace, xai, llamaIndex,
aiSdkProviders, langChain.
Three of them aren't a plain module reference:
| Key | Shape |
|---|---|
llamaIndex | An object: { openaiModule, anthropicModule, geminiModule } — the namespaces of whichever @llamaindex/* providers you use. |
aiSdkProviders | An array. Needed only for community or custom Vercel AI SDK providers, which bundle their own nested @ai-sdk/* copy. Pass provider factories, constructed model instances, or package namespaces. First-party @ai-sdk/* providers and the AI Gateway are found on their own. |
langChain | Exists, but it isn't the supported path. For LangChain, install the token-police-langchain companion instead — there's nothing to call, the base SDK detects it. |
Which import form to pass
For openAI and anthropic, either the default export or a namespace import works.
Every other key takes a namespace import.
import OpenAI from "openai"; // ✅ default export
import * as OpenAINs from "openai"; // ✅ namespace import
import * as Anthropic from "@anthropic-ai/sdk"; // ✅ preferred
import AnthropicDefault from "@anthropic-ai/sdk"; // ⚠️ works, but see below
import * as cohere from "cohere-ai"; // namespace — as for every other keyFor anthropic, use the namespace import. The default export is the Anthropic class
alone, and it leaves out an export the streaming path needs. With it, streamed
messages.create and beta.messages.create still meter through a fallback — but the older
completions.create surface is metered by nothing at all. import * as Anthropic from "@anthropic-ai/sdk" avoids the whole question.

