Nilguard — Python SDK
Server-side error tracking for ASGI apps (FastAPI, Starlette) and WSGI apps (Flask, Django-WSGI). Mirrors the browser SDK's wire format so the dashboard, ticketing and agent-run pipeline work unchanged.
Install
pip install nilguard
For local development, install the package in editable mode from this directory:
uv pip install -e .
You can also pull it directly as a [tool.uv.sources] path entry from another
project during local testing.
Quick start
from fastapi import FastAPI
import nilguard
nilguard.init(
service="billing-api", # human-readable identifier
framework="fastapi", # dashboard renders the right icon
ingest_key="ng_srv_...", # shown once at mint time
backend_url="https://nilguard.example.com",
environment="production",
release="2026-05-23-a1b2c3d",
)
app = FastAPI()
app.add_middleware(nilguard.NilguardASGIMiddleware)
@app.get("/healthy")
async def healthy():
return {"ok": True}
@app.get("/boom")
async def boom():
1 / 0 # raises ZeroDivisionError; middleware sends a crash bundle, then re-raises
Try the FastAPI example without installing anything
The examples/fastapi_demo.py script uses PEP 723 inline metadata so
uv will install FastAPI + uvicorn + this SDK (via a local path source)
for you on first run:
cd examples/python-fastapi
NILGUARD_INGEST_KEY="ng_srv_..." uv run fastapi_demo.py
WSGI / Flask quick start
For synchronous WSGI frameworks, wrap the WSGI app with
NilguardWSGIMiddleware as the outermost layer. It behaves identically to the
ASGI middleware (clean requests send nothing; unhandled exceptions — including
ones raised mid-stream while iterating the response body — send one crash
bundle, then re-raise) but uses the synchronous HTTP client.
from flask import Flask
import nilguard
nilguard.init(
service="billing-api",
framework="flask",
ingest_key="ng_srv_...",
backend_url="https://nilguard.example.com",
environment="production",
)
app = Flask(__name__)
app.wsgi_app = nilguard.NilguardWSGIMiddleware(app.wsgi_app)
@app.get("/boom")
def boom():
1 / 0 # middleware sends a crash bundle, then re-raises
A runnable demo lives in examples/python-flask/flask_demo.py (PEP 723
inline-deps, same style as the FastAPI demo):
cd examples/python-flask
NILGUARD_INGEST_KEY="ng_srv_..." uv run flask_demo.py
Manual capture
try:
risky()
except Exception as exc:
nilguard.capture_exception(exc, context={"job_id": job.id})
raise
What gets sent
- Clean requests send nothing. The middleware stays on the request path only long enough to observe exceptions.
- Crash bundle on unhandled exception. Includes a
networkevent describing the inbound request plus acrashobject withsignal=server_exceptionand a redacted traceback inmetadata. - Headers, cookies, query values, and anything matching the redaction
denylist (
authorization|cookie|token|secret|password|session|credential|auth) are scrubbed client-side before the POST. The backend re-applies the same rules — it remains the source of truth.
Auth
All ingest requests carry Authorization: Bearer <ingest_key>. No
Origin/CORS dance: the token is the only thing the backend trusts for the
server-ingest path.
Release files for nilguard 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nilguard-0.1.2.tar.gz | 42.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nilguard-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.6 kB
Release files / nilguard-0.1.2.tar.gz
| Download URL | nilguard-0.1.2.tar.gz |
|---|---|
| Size | 42.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4cb23bcc02f6fa419b450d0a616130e3880f60d1493521079d9a50940423d0c6
|
|
BLAKE2b-256 checksum How to use checksums |
cbe6c7e4ea03e543daf21b4fe01debae04ff4beb5f2d6f70e80f65ccccbaf33a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 13, 2026.
Transparency logRelease files / nilguard-0.1.2-py3-none-any.whl
| Download URL | nilguard-0.1.2-py3-none-any.whl |
|---|---|
| Size | 16.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
48c86f00297370d6b81145900c5e140e4aad052e31b3fce8e4cf57bd9dea56d9
|
|
BLAKE2b-256 checksum How to use checksums |
b7611f78011bd427012e48e0f4c78bd3b8f6ae047f5c9af8defd6d3097007d35
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 13, 2026.
Transparency log