Execute best practices for using Sentry SDK in TypeScript and Python.
Use when implementing error handling patterns, structuring Sentry code,
or optimizing SDK usage.
Trigger with phrases like "sentry best practices", "sentry patterns",
"sentry sdk usage", "sentry code structure".
Production patterns for @sentry/node (v8+) and sentry-sdk (Python 2.x+) covering scoped error context, breadcrumb strategies, event filtering with beforeSend, custom fingerprinting for issue grouping, and performance instrumentation with spans. All examples use real Sentry SDK APIs.
Prerequisites
Sentry SDK v8+ installed (@sentry/node, @sentry/react, or sentry-sdk)
SENTRY_DSN environment variable configured
Familiarity with async/await (TypeScript) or context managers (Python)
Instructions
Step 1 -- Structured Error Context with Scopes
Use Sentry.withScope() (TypeScript) or (Python) to attach context to individual events without leaking state across requests.
import sentry_sdk
def capture_error(error, severity="error", tags=None, context=None, user=None):
"""Capture exception with isolated scope context."""
with sentry_sdk.new_scope() as scope:
scope.set_level(severity)
if tags:
for key, value in tags.items():
scope.set_tag(key, value)
if context:
scope.set_context("app", context)
if user:
scope.set_user(user)
sentry_sdk.capture_exception(error)
Key rule: Never call Sentry.setTag() or sentry_sdk.set_tag() at the module level inside request handlers. Those mutate the global scope and leak between concurrent requests. Always use withScope() or new_scope().
Step 2 -- Breadcrumbs, Filtering, and Fingerprints
Sentry.init({
dsn: process.env.SENTRY_DSN,
beforeSend(event, hint) {
const error = hint?.originalException;
// Drop non-actionable errors
if (error instanceof Error) {
if (error.message.includes('ResizeObserver loop')) return null;
if (error.message.includes('Network request failed')) return null;
}
// Scrub PII from user context
if (event.user) {
delete event.user.ip_address;
delete event.user.email;
}
return event;
},
});
Python beforeSend:
def before_send(event, hint):
if "exc_info" in hint:
exc_type, exc_value, tb = hint["exc_info"]
if isinstance(exc_value, (KeyboardInterrupt, SystemExit)):
return None
if "user" in event:
event["user"].pop("email", None)
event["user"].pop("ip_address", None)
return event
sentry_sdk.init(dsn=os.environ["SENTRY_DSN"], before_send=before_send)
beforeBreadcrumb -- Filter noisy breadcrumbs
Sentry.init({
dsn: process.env.SENTRY_DSN,
beforeBreadcrumb(breadcrumb, hint) {
// Drop console.log breadcrumbs in production
if (breadcrumb.category === 'console' && breadcrumb.level === 'log') {
return null;
}
// Redact auth tokens from HTTP breadcrumbs
if (breadcrumb.category === 'fetch' && breadcrumb.data?.url) {
const url = new URL(breadcrumb.data.url);
url.searchParams.delete('token');
breadcrumb.data.url = url.toString();
}
return breadcrumb;
},
});
Custom fingerprints for issue grouping
Override default stack-trace grouping when the same root cause produces different stacks:
Sentry.withScope((scope) => {
// Group all payment gateway timeouts together
scope.setFingerprint(['payment-gateway-timeout', gatewayName]);
Sentry.captureException(error);
});
with sentry_sdk.new_scope() as scope:
scope.fingerprint = ["payment-gateway-timeout", gateway_name]
sentry_sdk.capture_exception(error)
Step 3 -- Framework Integration and Performance Spans
See implementation.md for Django middleware, test mocking patterns, and additional framework examples.
Output
After applying these patterns you will have:
Centralized error handler module with typed severity and scoped context
Structured breadcrumb helpers for auth, db, and http events
beforeSend filter that drops noise and scrubs PII
beforeBreadcrumb callback that redacts sensitive query parameters
Custom fingerprinting for accurate issue grouping
Framework error boundaries for Express and React
Performance spans for tracing critical code paths
Error Handling
Error
Cause
Solution
Scope leaking between requests
Global scope mutations in async handlers
Use withScope() / new_scope() for per-event context
Duplicate events
Error caught and re-thrown at two layers
Capture at one level only -- middleware or handler, not both
Missing breadcrumbs
Cleared after max count (default 100)
Set maxBreadcrumbs in Sentry.init()
beforeSend returns undefined
Missing return statement
Always return event or null explicitly
Events grouped incorrectly
Default stack-trace fingerprinting
Use scope.setFingerprint() with semantic keys
Sentry is not defined
SDK not imported
Verify import * as Sentry from '@sentry/node'
Spans not appearing
Missing tracing config
Set tracesSampleRate in Sentry.init()
Examples
Centralized error handler: Create lib/error-handler.ts wrapping Sentry.withScope() with typed severity, tags, context, user, and fingerprint support.
Breadcrumb trail for checkout: Add breadcrumb.auth('login'), breadcrumb.db('SELECT', 'orders'), breadcrumb.http('POST', '/api/payments', 201) before critical operations so errors include full context timeline.
Noise filtering: Configure beforeSend to drop ResizeObserver loop and Network request failed, scrub PII from user context and cookies.
Fix issue grouping: Add scope.setFingerprint(['payment-gateway-timeout', gatewayName]) to group all payment timeouts by gateway.
See examples.md for full worked scenarios with Python context managers and async wrappers.