Filtering allows you to control which events, breadcrumbs, and spans are sent to Sentry, helping reduce noise and protect sensitive data.
Event Filtering with beforeSend
The beforeSend hook processes all error events before they’re sent:
import * as Sentry from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event , hint ) {
// Don't send events with specific error messages
if ( event . message ?. includes ( 'Non-Error exception captured' )) {
return null ; // Returning null drops the event
}
return event ; // Returning the event sends it
},
});
Returning null from beforeSend drops the event entirely. Use this carefully to avoid losing important error data.
Event Hint
The hint parameter contains the original error and additional context:
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event , hint ) {
// Access the original error
const error = hint . originalException ;
if ( error instanceof MyCustomError ) {
// Add custom data
event . tags = { ... event . tags , customError: true };
}
// Access the event's ID
console . log ( 'Event ID:' , hint . event_id );
return event ;
},
});
Transaction Filtering with beforeSendSpan
Filter performance data before sending:
Sentry . init ({
dsn: '__DSN__' ,
beforeSendSpan ( span ) {
// Filter out health check spans
if ( span . description ?. includes ( '/health' )) {
// Note: In v9+, you cannot drop spans by returning null
// Instead, use integrations to prevent span creation
return span ;
}
// Remove sensitive query parameters
if ( span . description ?. includes ( '?token=' )) {
span . description = span . description . split ( '?' )[ 0 ];
}
return span ;
},
});
Starting in SDK v9, you cannot drop spans in beforeSendSpan by returning null. This hook is for modifying span data only. To control which spans are created, configure integrations instead.
Filtering with Integrations
Inbound Filters Integration
The inboundFiltersIntegration (enabled by default) filters common noise:
import { inboundFiltersIntegration } from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
inboundFiltersIntegration ({
// Don't send errors from localhost
allowUrls: [
/ ^ https ? : \/\/ ( [ ^ . ] + \. ) ? myapp \. com/ ,
],
// Block errors from specific domains
denyUrls: [
/graph \. facebook \. com/ ,
/connect \. facebook \. net/ ,
],
// Ignore specific error messages
ignoreErrors: [
'ResizeObserver loop limit exceeded' ,
'Non-Error promise rejection captured' ,
],
// Ignore errors from specific transactions
ignoreTransactions: [
'/health' ,
'/metrics' ,
],
}),
],
});
Common Ignore Patterns
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
inboundFiltersIntegration ({
ignoreErrors: [
// Browser extensions
'top.GLOBALS' ,
'originalCreateNotification' ,
'canvas.contentDocument' ,
'MyApp_RemoveAllHighlights' ,
// Network errors
'NetworkError' ,
'Network request failed' ,
// Random plugins/extensions
'atomicFindClose' ,
'conduitPage' ,
// Facebook blocked
'fb_xd_fragment' ,
],
denyUrls: [
// Google Tag Manager
/googletagmanager \. com/ i ,
// Browser extensions
/extensions \/ / i ,
/ ^ chrome: \/\/ / i ,
/ ^ moz-extension: \/\/ / i ,
],
}),
],
});
Breadcrumb Filtering
Filter breadcrumbs before they’re added:
Sentry . init ({
dsn: '__DSN__' ,
beforeBreadcrumb ( breadcrumb , hint ) {
// Don't record console.debug breadcrumbs
if ( breadcrumb . category === 'console' && breadcrumb . level === 'debug' ) {
return null ;
}
// Filter sensitive data from fetch breadcrumbs
if ( breadcrumb . category === 'fetch' ) {
const url = breadcrumb . data ?. url ;
if ( url ?. includes ( 'token=' )) {
breadcrumb . data . url = url . split ( '?' )[ 0 ] + '?[Filtered]' ;
}
}
return breadcrumb ;
},
});
Filtering Sensitive Data
Scrubbing Request Data
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event ) {
// Remove sensitive headers
if ( event . request ?. headers ) {
delete event . request . headers [ 'Authorization' ];
delete event . request . headers [ 'Cookie' ];
delete event . request . headers [ 'X-Api-Key' ];
}
// Scrub query parameters
if ( event . request ?. query_string ) {
const params = new URLSearchParams ( event . request . query_string );
if ( params . has ( 'token' )) {
params . set ( 'token' , '[Filtered]' );
}
if ( params . has ( 'api_key' )) {
params . set ( 'api_key' , '[Filtered]' );
}
event . request . query_string = params . toString ();
}
return event ;
},
});
Scrubbing User Data
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event ) {
// Remove email from user data
if ( event . user ?. email ) {
event . user . email = event . user . email . replace ( / ( . {2} ) . * @/ , '$1***@' );
}
// Remove IP address
if ( event . user ?. ip_address ) {
delete event . user . ip_address ;
}
return event ;
},
});
Use sendDefaultPii: false to prevent the SDK from sending PII by default. Then explicitly set only the user data you want to send.
Filtering by Error Type
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event , hint ) {
const error = hint . originalException ;
// Ignore specific error types
if ( error instanceof TypeError && error . message . includes ( 'undefined' )) {
return null ;
}
// Ignore errors from specific files
if ( event . exception ?. values ?.[ 0 ]?. stacktrace ?. frames ) {
const frames = event . exception . values [ 0 ]. stacktrace . frames ;
if ( frames . some ( frame => frame . filename ?. includes ( 'third-party' ))) {
return null ;
}
}
return event ;
},
});
Filtering by User
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event ) {
// Don't send events from internal users
if ( event . user ?. email ?. endsWith ( '@mycompany.com' )) {
return null ;
}
// Don't send events from test users
if ( event . user ?. username ?. startsWith ( 'test_' )) {
return null ;
}
return event ;
},
});
Filtering by Environment
Sentry . init ({
dsn: '__DSN__' ,
environment: process . env . NODE_ENV ,
beforeSend ( event ) {
// Only send errors in production
if ( event . environment !== 'production' ) {
return null ;
}
return event ;
},
});
It’s usually better to disable Sentry entirely in development rather than filtering in beforeSend: Sentry . init ({
dsn: '__DSN__' ,
enabled: process . env . NODE_ENV === 'production' ,
});
Filtering Network Requests
HTTP Client Integration
Filter outgoing request breadcrumbs:
import { httpClientIntegration } from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
httpClientIntegration ({
failedRequestStatusCodes: [[ 400 , 599 ]], // Only track errors
failedRequestTargets: [
/api \. myapp \. com/ , // Only track API calls
],
}),
],
beforeBreadcrumb ( breadcrumb ) {
// Filter sensitive URLs
if ( breadcrumb . category === 'fetch' || breadcrumb . category === 'xhr' ) {
if ( breadcrumb . data ?. url ?. includes ( '/auth/' )) {
return null ;
}
}
return breadcrumb ;
},
});
Filtering Third-Party Errors
Use the thirdPartyErrorFilterIntegration to filter errors from third-party scripts:
import { thirdPartyErrorFilterIntegration } from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
integrations: [
thirdPartyErrorFilterIntegration ({
// Filter errors from specific domains
filterKeys: [ 'my-app' ],
// Optionally specify behavior
behaviour: 'drop-error-if-contains-third-party-frames' ,
}),
],
});
Advanced Filtering Patterns
Rate Limiting Specific Errors
const errorCounts = new Map ();
const MAX_SAME_ERROR = 5 ;
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event ) {
const fingerprint = event . fingerprint ?.[ 0 ] || event . message || 'unknown' ;
const count = errorCounts . get ( fingerprint ) || 0 ;
if ( count >= MAX_SAME_ERROR ) {
return null ; // Drop after 5 occurrences
}
errorCounts . set ( fingerprint , count + 1 );
return event ;
},
});
Conditional Filtering Based on Context
Sentry . init ({
dsn: '__DSN__' ,
beforeSend ( event ) {
// Get current scope data
const scope = Sentry . getCurrentScope ();
const tags = scope . getScopeData (). tags ;
// Filter based on tags
if ( tags ?. feature === 'experimental' ) {
// Add special tag for experimental features
event . tags = { ... event . tags , experimental: true };
}
// Filter based on extra data
const extras = scope . getScopeData (). extra ;
if ( extras ?. skipSentry ) {
return null ;
}
return event ;
},
});
Best Practices
Use allowlists instead of denylists
When possible, explicitly allow what you want rather than denying what you don’t: // ✅ Good: explicit allowlist
inboundFiltersIntegration ({
allowUrls: [ / ^ https ? : \/\/ myapp \. com/ ],
})
// ❌ Bad: endless denylist
inboundFiltersIntegration ({
denyUrls: [ /facebook/ , /google/ , / ... / ],
})
It’s more efficient to prevent events from being created than to filter them in beforeSend: // ✅ Good: don't create the span
integrations : [
httpIntegration ({
tracing: {
shouldCreateSpanForRequest : ( url ) => {
return ! url . includes ( '/health' );
},
},
}),
]
// ❌ Less efficient: filter after creation
beforeSendSpan ( span ) {
if ( span . description ?. includes ( '/health' )) {
// Can't drop in v9+
}
return span ;
}
In beforeSend and beforeBreadcrumb, always explicitly return or drop: beforeSend ( event ) {
if ( shouldDrop ) {
return null ; // Explicit drop
}
// Modify event...
return event ; // Explicit return
}
Don't filter too aggressively
Overly aggressive filtering can hide important issues. Start conservative and refine based on actual noise.
Log filtered events in development
In development, log what you’re filtering to verify your rules: beforeSend ( event ) {
if ( shouldFilter ) {
if ( process . env . NODE_ENV === 'development' ) {
console . log ( 'Filtered event:' , event );
}
return null ;
}
return event ;
}
Complete Example
import * as Sentry from '@sentry/browser' ;
import {
inboundFiltersIntegration ,
httpClientIntegration ,
thirdPartyErrorFilterIntegration ,
} from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
environment: process . env . NODE_ENV ,
integrations: [
// Filter common noise
inboundFiltersIntegration ({
ignoreErrors: [
'ResizeObserver loop' ,
'Non-Error promise rejection' ,
],
ignoreTransactions: [ '/health' , '/metrics' ],
}),
// Filter third-party errors
thirdPartyErrorFilterIntegration ({
filterKeys: [ 'my-app' ],
}),
// Filter HTTP requests
httpClientIntegration ({
failedRequestStatusCodes: [[ 500 , 599 ]],
}),
],
// Filter events
beforeSend ( event , hint ) {
// Remove sensitive data
if ( event . request ?. headers ) {
delete event . request . headers [ 'Authorization' ];
}
// Don't send from internal users
if ( event . user ?. email ?. endsWith ( '@mycompany.com' )) {
return null ;
}
return event ;
},
// Filter breadcrumbs
beforeBreadcrumb ( breadcrumb ) {
// No console.debug
if ( breadcrumb . category === 'console' && breadcrumb . level === 'debug' ) {
return null ;
}
return breadcrumb ;
},
});
Next Steps
Error Handling Best practices for error handling
Performance Monitoring Optimize performance monitoring