Debug logging
How to turn debug logging on for the SDK, what gets logged, and why you must turn it off in production.
Debug logging
The SDK has a debug log mode that prints every policy decision, every batched telemetry post, and every control-plane interaction to stderr. It's useful while you're tuning a policy or chasing an intermittent deny — and it's a footgun in production.
This page covers how to enable it, what it actually shows, and the guard rails that keep it off prod by default.
Turning it on
Both SDKs honor the CHECKRD_DEBUG=1 environment variable. This is
the recommended switch because it works identically on both
runtimes and you don't have to change application code:
export CHECKRD_DEBUG=1The JavaScript SDK additionally accepts debug: true as a
constructor option for cases where you want debug enabled per-
client rather than process-wide:
import { Checkrd } from "checkrd";
const client = new Checkrd({
agentId: "my-agent",
apiKey: "ck_live_...",
debug: true,
});The Python SDK does not expose a constructor debug flag —
production deployments routinely audit application code for hot-
path opt-ins, and a process-level env var is the unambiguous
single source of truth. Either path emits a one-time stderr banner
on the first request that flags the PII risk and links here.
What gets logged
With debug=True, every request the SDK touches produces a structured
log record. Approximately:
[checkrd] decision request_id=01HKZ... agent=sales-agent
method=POST url=https://api.openai.com/v1/chat/completions
rule=allow-openai-chat outcome=allow latency_us=187
[checkrd] telemetry batch_id=01HKZ... events=12 signed=true
ingestion=https://api.checkrd.io/v1/telemetry status=204
[checkrd] control sse_event=policy_updated version=42
dsse_verify=ok install_latency_ms=4What's not logged at any level:
- Request bodies, response bodies, prompt content, completion content.
- API keys, agent private keys, OAuth tokens.
- Headers other than
:method,:authority,:path, and the Checkrd signature headers.
The deny-or-allow decision and the metadata that the dashboard already shows are everything that's printed. There is no "verbose" level that ever logs the body.
The PII banner
When debug is enabled, the SDK writes one banner to stderr before the first request:
[checkrd] DEBUG LOGGING IS ON.
Decision metadata, request URLs, and policy reasons will be printed
to stderr. Bodies and prompts are NOT logged.
This is fine for local dev. In production, the URL and matched-rule
fields can still leak operational signal that you may not want in
shared log aggregators.
turn it off. See https://checkrd.io/docs/debug-loggingThe banner is one-shot per process so it doesn't spam your logs. There is no way to silence the banner while keeping debug on — that is intentional. If you want a quiet production deploy, turn debug off.
Why this matters in production
Even though the SDK doesn't log bodies, the structured fields it does log are operational signal:
- URLs can identify which third-party APIs your agent depends on, which is sometimes confidential.
- Rule names can leak the shape of your security posture.
request_idis correlatable across SDK, ingestion, and ClickHouse — useful for triage, useful for log scrapers too.
In a shared log aggregator (Datadog, Splunk, CloudWatch) accessible to a wide audience, that's worth thinking about. The dashboard already gives you the same data with proper RBAC; the debug log is strictly for cases where you can't reach the dashboard.
Production guard
The SDK looks for production signals on init: NODE_ENV=production,
PYTHON_ENV=production, the standard PaaS markers
(KUBERNETES_SERVICE_HOST, LAMBDA_RUNTIME_DIR,
AWS_EXECUTION_ENV, RAILWAY_ENVIRONMENT, RENDER, FLY_APP_NAME,
VERCEL). If any of these are set and debug is on, the banner
escalates to a WARN-level log and the request_id is suppressed
from the structured fields — so debug remains useful for one-off
production triage but won't quietly leak request correlations.
There is no hard refusal in production. The judgment call is yours; the SDK just makes sure you've seen the warning.
Turning it off
unset CHECKRD_DEBUGJS callers who explicitly opted in via the constructor flip it back:
const client = new Checkrd({
agentId: "my-agent",
apiKey: "ck_live_...",
debug: false,
});debug is off by default. If you set it explicitly somewhere and
forgot, grep for CHECKRD_DEBUG and debug: / debug=.
See also
- Error handling — how denies surface even with debug off
- Identity & signing — what's in those structured records
- SECURITY.md — full debug-vs-prod safety posture