Guide Errors ~9 min read Updated June 23, 2026

Python Error Tracking with the Sentry SDK: The 2026 Setup Guide

Python error tracking with sentry-sdk is a two-line setup: install the package and call sentry_sdk.init() with a DSN. The DSN is the only variable between pointing at Sentry cloud and a self-hosted backend like urgentry.

TL;DR

20 seconds. Python error tracking with sentry-sdk is a two-step install: pip install sentry-sdk then sentry_sdk.init(dsn=...). Every unhandled exception ships automatically from that point. urgentry covers 218 of 218 Sentry SDK operations, so the SDK code is the same whether the DSN points at Sentry cloud or a self-hosted urgentry instance.

60 seconds. The SDK posts events to the backend URL encoded in the DSN, filing them under the project ID also encoded there. Three production settings matter before real traffic: traces_sample_rate at 0.1 (not 1.0), a before_send callback to drop health-check noise, and a release string from your CI pipeline. The OTLP path on port 4318 is an alternative for services already using the OpenTelemetry Python SDK that want a single pipeline for both traces and errors. The critical footgun on the OTLP path: OTEL_EXPORTER_OTLP_ENDPOINT must be the base URL only; include the path and the SDK doubles it, silently dropping events. urgentry runs as a single 52 MB binary and achieved 2.2× the throughput of self-hosted Sentry in the April 2026 benchmark.

This guide covers Step 1: Install sentry-sdk, Step 2: Get your DSN, Step 3: Initialize the SDK, Step 4: Send a test event, Step 5: Verify the event arrived, production configuration, the OTLP-native path, framework integrations, common failure modes, and frequently asked questions.

Python error tracking with sentry-sdk takes two lines of code. Install the package, call sentry_sdk.init() with a DSN that points at your backend, and every unhandled exception ships automatically. The setup is identical whether you’re pointing at Sentry cloud or a self-hosted backend like urgentry. The only variable is the DSN string.

This guide covers the base Python setup (no framework), the configuration options that matter in production, the OTLP-native path as an alternative to the Sentry envelope protocol, and the failure modes that eat debugging hours. If you’re using Django or FastAPI, the base setup here still applies; framework-specific integrations are covered in the Django error tracking guide and the FastAPI error tracking guide.

Prerequisites: Python 3.8 or later, pip, and a running error-tracking backend (Sentry cloud, urgentry, or another Sentry-compatible server) that will give you a DSN.

Step 1: Install sentry-sdk

pip install --upgrade "sentry-sdk"

The sentry-sdk package is the official Sentry Python SDK and works with any Sentry-compatible backend. It has no mandatory runtime dependencies beyond the Python standard library. If you need framework-specific integrations (Django, FastAPI, Flask), the extras install them:

pip install --upgrade "sentry-sdk[django]"
pip install --upgrade "sentry-sdk[fastapi]"

What "done" looks like: pip show sentry-sdk returns a version string (1.x or 2.x as of 2026). No import errors.

Step 2: Get your DSN

A DSN (data source name) is the URL the SDK uses to route events to your backend. What a DSN is is covered in detail in the fundamentals guide, but the shape you need is:

https://<public_key>@<your-host>/<project_id>

If you’re using Sentry cloud: copy the DSN from Project Settings → Client Keys (DSN). It looks like https://abc123@o12345.ingest.sentry.io/678901.

If you’re using urgentry self-hosted: copy the DSN from your project settings. It follows the same format:

https://<public_key>@errors.example.com/<project_id>

For a local urgentry instance (dev/test):

http://your-key@localhost:8080/1

Store it as an environment variable. Never hardcode it in source:

export SENTRY_DSN="https://<public_key>@errors.example.com/<project_id>"

What "done" looks like: echo $SENTRY_DSN returns your DSN string with no trailing slash.

Step 3: Initialize the SDK

Call sentry_sdk.init() once, at your application’s entry point, before any other application code runs. The earliest possible call is the safest.

import os
import sentry_sdk

sentry_sdk.init(
    dsn=os.environ.get("SENTRY_DSN"),
    environment=os.environ.get("APP_ENV", "production"),
    release=os.environ.get("APP_VERSION"),
    traces_sample_rate=0.1,
    send_default_pii=False,
)

The SENTRY_DSN environment variable is also read automatically by the SDK if you don’t pass dsn= explicitly. Both work. Explicit is clearer.

Parameter notes:

  • traces_sample_rate=0.1: captures 10% of transactions as performance traces. Set to 1.0 during initial setup to confirm traces arrive, then reduce before production load. Do not leave it at 1.0 under real traffic unless you intend to capture everything.
  • send_default_pii=False: suppresses user IP addresses, email addresses, and HTTP headers that can contain credentials. Turn this on only if you’ve confirmed your backend’s PII scrubbing configuration and you understand what you’re collecting.
  • environment and release are optional but worth setting from the start. They let you filter errors by deploy stage and tie issues to specific versions in the dashboard.

What "done" looks like: No exception on import, no sentry_sdk.Hub.current.client is None warning in logs.

Step 4: Send a test event

After initialization, send one event deliberately to confirm the pipeline works end to end.

import sentry_sdk

# Option 1: capture a real exception
try:
    result = 1 / 0
except ZeroDivisionError:
    sentry_sdk.capture_exception()

# Option 2: send a message (no exception needed)
sentry_sdk.capture_message("Python error tracking initialized", level="info")

Both methods flush the event to the backend before the process exits. For scripts that exit immediately, call sentry_sdk.flush(timeout=5) explicitly to ensure the background sender thread finishes:

sentry_sdk.flush(timeout=5)

What "done" looks like: the call returns without error.

Step 5: Verify the event arrived

Open your backend’s issue list within 30 seconds. In urgentry, go to Issues in the project where your DSN lives. In Sentry cloud, go to Issues in your project.

If the event doesn’t appear:

  • Check the DSN: the public key and project ID must match the backend’s records exactly.
  • Check network: confirm the host in the DSN is reachable from your machine (curl https://errors.example.com/ should return something, not time out).
  • Check the backend’s ingest endpoint: the SDK posts to /api/<project_id>/store/. The backend must be running and accepting POST requests on that path.

What "done" looks like: one new issue or message in the project’s issue list, with the stack trace or message you sent.

Production configuration

Once the first event lands, three configuration changes reduce noise and improve signal before you route real traffic through the tracker.

1. Set traces_sample_rate to a production value

Full trace capture (1.0) generates a lot of data at real traffic volumes. Start at 0.1 (10%) or lower. You can always increase it during a debug session.

2. Use before_send to filter noise

before_send runs on every event before it leaves the SDK. Return None to drop the event, return the modified event to send it. Use this to filter health-check errors, known-benign exceptions, or events from specific paths:

def before_send(event, hint):
    # Drop health check errors
    if "request" in event:
        url = event["request"].get("url", "")
        if "/health" in url or "/ping" in url:
            return None
    return event

sentry_sdk.init(
    dsn=os.environ.get("SENTRY_DSN"),
    before_send=before_send,
    traces_sample_rate=0.1,
    send_default_pii=False,
)

3. Set release from your CI pipeline

Tying errors to releases lets you know whether a new deploy introduced a regression. The value can be any string (a git SHA works well):

export APP_VERSION=$(git rev-parse --short HEAD)

OTLP-native path

The Sentry SDK sends events over the Sentry envelope protocol. urgentry also accepts OTLP/HTTP on port 4318 (the standard OpenTelemetry port), and both paths run on the same urgentry instance at the same time. You do not need to choose one or the other; the OTLP for error tracking guide covers the full picture.

The OTLP path uses the OpenTelemetry Python SDK instead of sentry-sdk. The pattern for recording an exception as a span event:

from opentelemetry import trace
from opentelemetry.trace import StatusCode

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("process-payment") as span:
    try:
        charge_card(order)
    except Exception as exc:
        span.record_exception(exc)
        span.set_status(StatusCode.ERROR, str(exc))
        raise

Configure the exporter with environment variables:

export OTEL_EXPORTER_OTLP_ENDPOINT="https://errors.example.com"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/json"
export OTEL_SERVICE_NAME="payment-service"

One footgun: set OTEL_EXPORTER_OTLP_ENDPOINT to the base URL only. The SDK appends /v1/traces (and /v1/logs) automatically. If you include the path in the env var, the SDK doubles it: https://errors.example.com/v1/traces/v1/traces. That path returns 404 and your events are silently dropped. No error appears in the logs because the exporter swallows failed exports by default.

When to use OTLP vs the Sentry SDK: the Sentry SDK path is simpler and requires zero OpenTelemetry configuration. The OTLP path makes sense if you’re already using the OpenTelemetry Python SDK for traces and want errors to flow through the same pipeline without running two separate SDKs.

Framework integrations

The sentry_sdk.init() call above works in any Python process. Framework integrations add middleware-level error capture, request context (URL, method, user), and performance tracing for the specific framework’s request/response cycle. They’re installed as extras and passed to integrations=[].

Django covers request errors, database queries, template renders, and Celery tasks. See the Django error tracking guide for the full DjangoIntegration() configuration.

FastAPI / Starlette covers ASGI request errors and async background tasks. One ordering constraint applies: call sentry_sdk.init() before app = FastAPI(). The SDK patches Starlette’s middleware chain at import time; if FastAPI() runs first, the middleware is not installed and HTTP request errors are not captured. See the FastAPI error tracking guide for the ordering and StarletteIntegration config.

Other integrations (Flask, Celery, SQLAlchemy, Redis, aiohttp) follow the same pattern: import the integration class, pass an instance to integrations=[] in sentry_sdk.init(). The full list is in the Sentry Python SDK documentation.

Common failure modes

Events not appearing in the dashboard

Check three things in order. First, does sentry_sdk.Hub.current.client exist? If sentry_sdk.init() raised an exception on startup (bad DSN, import error), the client is None and all capture calls silently no-op. Second, is the backend reachable? The SDK POSTs to https://<your-host>/api/<project_id>/store/; confirm that path returns 200 for a valid payload. Third, is your process exiting before the background sender flushes? Short scripts must call sentry_sdk.flush(timeout=5) or events queued in the buffer never go out.

DSN mismatch errors

The backend validates the public key and project ID in the DSN against its database. A key from one project used against a different project’s endpoint returns a 403 and events are rejected. Copy the DSN from the project settings, not from another project or from documentation examples.

traces_sample_rate set to 0 by accident

traces_sample_rate=0 disables performance tracing entirely. It also silently disables some integrations’ transaction instrumentation. If you don’t need traces, omit the parameter rather than setting it to 0 explicitly. The default in SDK 2.x is to capture errors without traces.

OTLP double-path (silent event loss)

Described in the OTLP section above. OTEL_EXPORTER_OTLP_ENDPOINT must be the base URL with no trailing path. https://errors.example.com works; https://errors.example.com/v1/traces does not.

send_default_pii=True in production without scrubbing configured

Enabling PII collection and then discovering it in an issue report later is more expensive than configuring scrubbing upfront. The urgentry PII scrubbing guide covers server-side scrubbing rules for production deployments.

Frequently asked questions

How do I add error tracking to a Python app?

Install sentry-sdk with pip, then call sentry_sdk.init(dsn="...") once at application startup. After that, all unhandled exceptions are captured automatically. Handled exceptions can be sent with sentry_sdk.capture_exception().

What is a DSN in Python error tracking?

A DSN (data source name) is a URL that tells the SDK where to send events. It contains a public key, the backend host, and a project ID. What a DSN is is covered in detail in the fundamentals guide.

Does the Sentry Python SDK work with urgentry?

Yes. urgentry covers 218 of 218 Sentry SDK operations. The only change is the DSN: replace the Sentry cloud or self-hosted Sentry DSN with your urgentry instance’s DSN. No code changes, no re-instrumentation. urgentry runs as a single binary and accepts the Sentry envelope protocol on its main port alongside OTLP/HTTP on port 4318.

How do I test that error tracking is working in Python?

After calling sentry_sdk.init(), execute sentry_sdk.capture_message("test") and check your backend’s issue list within 30 seconds. For exception capture, wrap a deliberate 1/0 in a try/except and call sentry_sdk.capture_exception(). In short-lived scripts, call sentry_sdk.flush(timeout=5) before exit to ensure the event is sent.

Can I self-host Sentry-compatible error tracking for Python?

Yes. Any backend that implements the Sentry envelope protocol works with sentry-sdk: change the DSN and keep all existing instrumentation. urgentry is a single Go binary that runs on a $5–$20/month VPS, accepts Python SDK events without modification, and in the April 2026 benchmark achieved 2.2× the throughput of Sentry self-hosted on identical hardware with ~52 MB peak memory instead of ~8 GB.

What is traces_sample_rate and what should I set it to?

traces_sample_rate controls what fraction of requests are traced as performance transactions. 1.0 captures everything; 0.1 captures 10%. Set it to 1.0 during initial setup to confirm traces arrive, then reduce to 0.1 or lower before production traffic. Error capture (not trace capture) is not affected by this parameter.

What is send_default_pii in the Sentry SDK?

send_default_pii=True allows the SDK to include user-identifying data in events: IP addresses, email addresses, username fields, and some HTTP headers. The default is False. Set it to True only if you’ve reviewed what your backend stores and configured appropriate server-side scrubbing.

Sources

  1. urgentry docs: Python SDK setup — urgentry’s reference for initializing the Sentry-compatible Python SDK against a self-hosted backend.
  2. urgentry guide: Django error tracking — full DjangoIntegration() configuration and middleware ordering for Django projects.
  3. urgentry guide: FastAPI error tracking — ASGI ordering constraint and StarletteIntegration config for FastAPI and Starlette projects.
  4. urgentry guide: OTLP for error tracking — the full picture on routing exceptions through the OTLP pipeline alongside the Sentry envelope path.
  5. urgentry April 2026 benchmark — throughput and memory comparison between urgentry and Sentry self-hosted on identical hardware.
  6. Sentry Python SDK documentation — canonical reference for all integrations, configuration parameters, and the full list of supported frameworks.

Python error tracking on a backend you own.

The same sentry-sdk code, the same DSN format, only the host changes. urgentry accepts the Sentry envelope protocol and OTLP/HTTP on a single binary that runs on a $5 VPS.