Metadata-only usage tracking for Anthropic and OpenAI — swap one import line.
Project description
Tokenwise Python SDK
Metadata-only usage tracking for Anthropic and OpenAI. Swap one import line and every API call's token counts and latency flow to your Tokenwise dashboard — with zero access to your prompts or responses.
- from anthropic import Anthropic
+ from tokenwise import Anthropic
Your code is otherwise unchanged: the wrapper exposes the identical interface, forwards every call to the official SDK, and returns its response untouched.
Why it's safe
- Metadata only. The SDK reads exactly:
model,input_tokens,output_tokens,cache_read_input_tokens,cache_creation_input_tokens,latency_ms,timestamp,endpoint. It never reads or transmits prompt text, response text, system prompts, or tool definitions. (Contrast with proxy-based tools, which see all your traffic.) - Non-blocking. Events are queued and sent on a background daemon thread. If Tokenwise is slow or down, your AI calls complete normally.
- Fail-silent + bounded. Up to 1,000 events buffer when offline; the oldest drop silently if the buffer fills. Capture never raises, never waits.
Install
pip install tokenwise-sdk[anthropic] # if you use Anthropic
pip install tokenwise-sdk[openai] # if you use OpenAI
pip install tokenwise-sdk[anthropic,openai]
anthropic and openai are optional extras — install only what you use.
Configure
Set your Tokenwise key (from the dashboard, looks like tw_...):
export TOKENWISE_API_KEY=tw_your_key
# optional:
export TOKENWISE_API_URL=https://tokenwise-production-aa59.up.railway.app # default
export TOKENWISE_DISABLED=true # emergency kill switch
Precedence for every setting: constructor argument > environment variable > default. If no key is configured the SDK runs disabled and your AI calls behave exactly as the official SDK.
Usage
# Pattern 1 — key from environment
import os
os.environ["TOKENWISE_API_KEY"] = "tw_abc123"
from tokenwise import Anthropic
client = Anthropic(api_key="sk-ant-...")
msg = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=256,
messages=[{"role": "user", "content": "Hello"}],
)
# Pattern 2 — key passed explicitly
from tokenwise import Anthropic
client = Anthropic(api_key="sk-ant-...", tokenwise_key="tw_abc123")
# Pattern 3 — OpenAI
from tokenwise import OpenAI
client = OpenAI(api_key="sk-...", tokenwise_key="tw_abc123")
client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}],
)
Streaming and async work the same way:
# Streaming (sync) — usage captured on stream completion
with client.messages.create(..., stream=True) as stream:
for event in stream:
...
# Async
from tokenwise import AsyncAnthropic
client = AsyncAnthropic(api_key="sk-ant-...", tokenwise_key="tw_abc123")
msg = await client.messages.create(...)
What's instrumented (v1)
| Provider | Method | Streaming |
|---|---|---|
| Anthropic | messages.create |
✅ usage read from the event stream (request unchanged) |
| OpenAI | chat.completions.create |
✅ see note below |
Other methods pass through and work, but aren't yet recorded. (OpenAI Responses API and legacy completions are planned.)
Note on OpenAI streaming
OpenAI only returns token usage on a streamed response when the request includes
stream_options={"include_usage": True}. When you stream without supplying
your own stream_options, Tokenwise injects it for you so usage can be captured.
This adds one final usage-only chunk (with an empty choices list) to the
stream. If you already pass stream_options, Tokenwise respects yours and does
not modify the request (in that case usage is captured only if you enabled it).
Latency semantics
For non-streaming calls, latency_ms is the wall-clock time of the call. For
streaming calls it is the total stream duration (until the last chunk is
consumed), which includes time your code spends between chunks — events from
streaming calls carry streamed: true so this is distinguishable.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tokenwise_sdk-0.1.1.tar.gz.
File metadata
- Download URL: tokenwise_sdk-0.1.1.tar.gz
- Upload date:
- Size: 17.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
32a4edc44f95d8c27c7daf89524861b1441e8cde51e156e2647a2dcb22d73307
|
|
| MD5 |
2aa74db982efbd45250ee41dae28d855
|
|
| BLAKE2b-256 |
0387aa1e2cab44ac2f69276dd277488caef6bb376cd9c6c0ff89ac3e3c38c425
|
File details
Details for the file tokenwise_sdk-0.1.1-py3-none-any.whl.
File metadata
- Download URL: tokenwise_sdk-0.1.1-py3-none-any.whl
- Upload date:
- Size: 13.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1055960088bc6a2d26a79753affb2b1d35f67e137d2967a5f0aaa085b29e4509
|
|
| MD5 |
2dfb8c04afa06ca951d17c5ae2d4d141
|
|
| BLAKE2b-256 |
caefea1a74df04c1520b97ba73799da25463145a404bdb03dbd8cc0c3d3eb6d9
|