Python
Track exceptions raised on your backend. Server errors land in the same Nohmo project as your frontend errors, so a 500 in your API sits next to the JS error it caused in the browser — and feeds the same revenue-impact ranking and the same daily digest.
The package has no runtime dependencies. It uses only the standard library, because an error reporter should never be the thing that breaks the app it is watching.
Install
pip install nohmo
You install nohmo but import nohmo_sdk, the same way pip install pillow gives you import PIL. The import name stays out of the way on purpose: a package called nohmo in site-packages would shadow a nohmo package in your own project.
Django
Add your keys to settings, then add the middleware near the top.
# settings.pyNOHMO_PROJECT_ID = "proj_xxx"NOHMO_API_KEY = "pk_xxx"NOHMO_RELEASE = "2.4.1" # optional — ties errors to a deployNOHMO_ENVIRONMENT = "production" # optionalMIDDLEWARE = ["nohmo_sdk.integrations.django.NohmoMiddleware",# ... your other middleware]
Note: Place it high in MIDDLEWARE. It cannot see exceptions raised by middleware listed above it. It uses Django's process_exception hook and returns None, so your error pages, DRF handlers and everything else behave exactly as before.
Flask
import nohmo_sdkfrom nohmo_sdk.integrations.flask import NohmoFlaskapp = Flask(__name__)nohmo_sdk.init(project_id="proj_xxx", api_key="pk_xxx")NohmoFlask(app)
FastAPI
import nohmo_sdkfrom nohmo_sdk.integrations.fastapi import NohmoMiddlewarenohmo_sdk.init(project_id="proj_xxx", api_key="pk_xxx")app = FastAPI()app.add_middleware(NohmoMiddleware)
Starlette applies middleware in reverse registration order, so add this last if you want it outermost.
Any other WSGI app
For Pyramid, Bottle, CherryPy or a hand-rolled WSGI application:
from nohmo_sdk.integrations.wsgi import NohmoWSGIapplication = NohmoWSGI(application)
Capturing manually
Unhandled exceptions are captured automatically. Use these for errors you handle yourself but still want to know about.
import nohmo_sdktry:charge(order)except PaymentError as exc:nohmo_sdk.capture_exception(exc, extra={"order_id": order.id})nohmo_sdk.capture_message("Reconciliation found a mismatch", level="warning")
Short-lived processes
Events are sent on a background thread and flushed on exit. A management command, cron job or Lambda can exit before that happens, so flush explicitly:
nohmo_sdk.flush(timeout=3)
Options
| Option | Default | What it does |
|---|---|---|
| environment | 'production' | Tags every event |
| release | '' | Ties errors to a deploy for the causal narrative |
| server_name | hostname | Groups errors per server instance |
| sample_rate | 1.0 | Fraction of events sent |
| dedup_window | 5.0 | Seconds before an identical error is sent again |
| queue_size | 1000 | Bounded — drops rather than growing without limit |
| batch_size | 50 | Events per request |
| flush_interval | 5.0 | Seconds before a partial batch ships |
| send_default_pii | False | Include headers, query strings and user email |
| debug | False | Verbose logging |
Privacy
Headers, query strings and user email addresses are not sent unless you set send_default_pii=True. Even then, anything that looks like a credential is redacted: Authorization, Cookie, Set-Cookie, X-API-Key, CSRF tokens, and any key containing secret, token, password or private_key. Matching happens after normalising case and hyphens, so X-API-Key and x_api_key are both caught.
How it behaves under load
It will not block your requests. Capturing appends to a queue; all network I/O happens on a background thread, so a slow or unreachable Nohmo is invisible to your latency.
It will not crash your app. Every public entry point swallows its own exceptions, and calling anything before init() is a no-op rather than an error — a missing environment variable cannot break a deploy.
It will not grow without bound. The queue is capped. A crash loop that outruns the network drops events and logs the count rather than consuming memory until the process is killed.
It survives a fork. gunicorn and uWSGI preload your app and then fork worker processes. Threads do not survive fork(), so an SDK that starts its worker in the master silently sends nothing from every child. This one notices the pid change and restarts in the child.
How errors are grouped
Errors group by exception type plus the deepest frame in your code — framework and site-packages frames are skipped. Only the file basename and line number are used, so the same bug groups together across containers, virtualenvs and development machines.
Note: Python tracebacks print "most recent call last", the opposite of a JavaScript stack. Nohmo reads them from the bottom up, so grouping keys off the line that actually raised rather than your WSGI entry point — which would be identical for every error your app ever produces.