Verify it works
Confirm the SDK is recording calls, and diagnose an empty dashboard in order of how likely each cause is.
The SDK fails silently by design. It will not raise an exception to report that it is misconfigured, so when nothing is recorded there is no error to read. Use the checks below.
Check which providers were patched
capsera.init(api_key=os.environ["CAPSERA_API_KEY"])
print(capsera.get_interception_report())
{'anthropic.messages': 'patched',
'anthropic.messages_async': 'patched',
'openai.chat_completions': 'patched',
'openai.chat_completions_async': 'patched',
'openai.embeddings': 'patched',
'openai.embeddings_async': 'patched',
'google.generativeai': 'not-installed',
'google.genai': 'not-installed',
'mistral.chat_complete': 'not-installed',
'cohere.chat': 'not-installed',
'vertex.generate_content': 'not-installed',
'bedrock.converse': 'not-installed'}
| Value | Meaning |
|---|---|
patched | Calls through that surface are recorded. |
not-installed | The library is not importable. Expected for providers you do not use. |
unpatched | The library is installed but init() has not run yet. |
Assert this at startup to catch a regression:
report = capsera.get_interception_report()
assert report["anthropic.messages"] == "patched", report
Log each intercepted call
debug=True writes one INFO line per recorded call:
capsera.init(api_key=..., debug=True)
capsera: intercepted provider=anthropic model=claude-sonnet-4-6 tokens=412/89
cost_usd=0.002571 agent=drafter routed=False error=False caller=app/draft.py:24
If these lines appear, interception works and the problem is in delivery or configuration. If a call produces no line, the call is not passing through a patched surface.
Causes of an empty dashboard
Listed in the order they usually occur.
1. CAPSERA_API_KEY is not set where the code runs. The most common cause. The
variable being set in your shell says nothing about the container, the worker, or the
CI job. Log whether the key is present (never its value) at startup, and check the
environment you actually deploy.
2. A short-lived process exited before the queue drained. Applies to scripts, cron
jobs, Lambda handlers, and notebook cells. Call capsera.shutdown() before exiting,
or capsera.flush() at a checkpoint.
3. init() ran after the calls. Client construction order does not matter, because
the patch is applied to provider classes. A call that executed before init() ran is
not recorded.
4. The provider or call style is not covered. Google is synchronous only. Mistral, Cohere, Vertex, and Bedrock are synchronous only. See Providers for the matrix and Troubleshooting for the streaming shapes that are not recorded.
5. The backend was unreachable. The emitter retries three times with exponential
backoff, then opens a circuit breaker for 30 seconds and drops events. Pass on_error
to observe this:
capsera.init(
api_key=...,
on_error=lambda exc: logging.warning("capsera delivery failed: %s", exc),
)
6. The monthly event limit was reached. On the free plan the backend returns 429. The SDK stops sending for the rest of the process and the application is unaffected.
Test delivery without a provider call
record() puts an event on the same queue and delivery path as an intercepted call,
so it tests the key, network, and account without spending anything at a provider:
capsera.init(api_key=os.environ["CAPSERA_API_KEY"])
capsera.record(
input_tokens=100,
output_tokens=20,
model="gpt-4o-mini",
provider="openai",
agent_id="wiring-check",
)
capsera.shutdown()
If wiring-check appears in Capsera, delivery works and the problem is interception.
If it does not, the problem is delivery, and on_error will report the reason.