Sentry installed but crashes never appear? Walk through the real causes, from debugger interference and late initialization to sample rates and background flushing, with concrete fixes in order of likelihood.
The symptom is specific: Sentry is installed, you may even see message events or errors in the dashboard, but deliberate or real crashes never show up as issues. This is different from no events at all, which usually points to a DSN or network problem. When errors arrive but crashes do not, the problem is almost always in how and when crash capture happens on iOS. Native crashes are handled differently from regular errors. A thrown Swift error is caught and sent immediately over the network, but a hard crash, a signal like a bad memory access or an uncaught exception, terminates the process. Sentry cannot send an event from a process that is dying, so instead it writes the crash to disk in its handlers and sends it on the next app launch. Understanding this two-phase behavior is the key to diagnosing the issue, because most causes of missing crashes come down to either the handlers not being installed in time, something else intercepting the crash first, or the app never getting a clean next launch to flush the stored report.
This is by far the most common reason a test crash never reaches Sentry, and it fools nearly everyone at first. When you run your app from Xcode with the Run button, the LLDB debugger is attached to your process. When a crash occurs, the debugger catches the signal before Sentry's handler can, pausing execution at the crash instead of letting Sentry record it. As a result the crash is never written to disk and never sent. The fix is to test crashes without the debugger. Build and run once from Xcode to install the app, then stop the Xcode session and launch the app directly by tapping its icon on the device or simulator. Trigger the crash, then reopen the app; the stored crash report flushes on that next launch and appears in Sentry shortly after. This is not a bug in Sentry and it does not affect real users, who never run under a debugger. Before investigating anything more exotic, always confirm your crash test was run with the debugger detached.
Sentry can only capture crashes that happen after its handlers are installed, and its handlers are installed when SentrySDK.start runs. If you initialize Sentry late, for example after other startup work, after a dependency injection container spins up, or partway through your AppDelegate, then any crash during that earlier work is invisible to Sentry because the handlers did not yet exist. The fix is to move SentrySDK.start to the earliest possible point. In a SwiftUI app that means the init of your App struct, before other setup. In a UIKit app it means the very first lines of application(_:didFinishLaunchingWithOptions:), ahead of everything else. If you have crashes that only happen at cold start, this placement matters enormously. Also make sure you are not conditionally skipping initialization; a guard that only starts Sentry in certain build configurations, or that returns early when a config value is missing, can silently leave crash capture disabled. Confirm with debug logging that SentrySDK.start actually runs on every launch, in the build you are testing, before any code that might crash.
Configuration can suppress crashes even when everything else is correct. Check that you have not set a session or error sample rate that drops events. While tracesSampleRate governs performance transactions and does not affect crashes, other options can. If you have implemented a beforeSend callback, verify it is not accidentally returning nil for crash events, because returning nil from beforeSend discards the event entirely, and a broad filter meant to scrub noise can swallow real crashes. Similarly, an overly aggressive inbound filter configured in the Sentry dashboard, such as filtering by release, environment, or a specific error type, can hide events that did arrive. Review your beforeSend logic line by line and temporarily remove it to see whether crashes appear. Also confirm that any enableCrashHandler or similar option has not been disabled; the crash handler is on by default, but if a teammate turned it off to debug something and never turned it back on, no native crashes will be captured. Rule these out by testing with a minimal configuration containing only the DSN.
Because iOS crash reports are sent on the next launch rather than at crash time, anything that prevents a normal next launch prevents the crash from being delivered. If your app crashes again immediately on relaunch before the SDK can flush, the report may never get sent. If the user deletes the app after it crashes, the stored report is gone. And if the very first thing your app does on launch is crash again, you can get into a loop where reports pile up on disk but never transmit. The fix is to ensure the SDK gets a chance to initialize and flush early in launch, which reinforces why early SentrySDK.start placement matters. If you suspect stored reports are not flushing, launch the app in a stable state, such as on a good network connection, and give it a few seconds foregrounded before doing anything. On a simulator you can also inspect that a crash was recorded. Ensuring a reliable, non-crashing next launch path is essential for the delivery half of crash reporting to work.
Even with a stored crash report and a clean relaunch, the event still has to travel over the network, and timing or connectivity can interfere. If the device has no connection at the moment of relaunch, the SDK holds the event and retries later, so a crash may appear minutes or hours after it happened rather than instantly. If the app is launched and then immediately backgrounded or killed, the SDK may not have finished sending. During testing, keep the app foregrounded on a working network for a little while after the relaunch so the flush completes. Corporate networks, VPNs, or content filters can also block the Sentry ingest endpoint; test on a normal connection to rule that out. If your app enforces App Transport Security exceptions or a custom URLSession configuration, make sure it does not inadvertently block Sentry's outbound requests. These network causes are less common than the debugger and initialization issues, but when crashes appear inconsistently or with long delays rather than not at all, connectivity and flush timing are usually the explanation.
Work through the causes in order of likelihood rather than guessing. First, enable options.debug to true so the SDK logs what it is doing to the Xcode console, and confirm you see it initialize and, after a crash, see it read and send the stored report on the next launch. Second, always test crashes with the debugger detached by launching the app from its icon, not from Xcode. Third, verify SentrySDK.start runs as early as possible and unconditionally. Fourth, strip your configuration down to only the DSN, removing any beforeSend callback and sample-rate options, to rule out filtering. Fifth, ensure a clean, connected next launch and give the app time to flush. If crashes still do not appear after all of this, capture a simple message with SentrySDK.capture to confirm the basic pipeline works, which isolates whether the problem is crash handling specifically or event delivery generally. If even the plain message does not arrive, the problem is general event delivery rather than crash handling, and you should switch to diagnosing your DSN and network path instead. Following this sequence will surface the cause in almost every real case, because the vast majority of missing-crash reports come down to the debugger or late initialization.
Almost always because the Xcode debugger was attached and caught the crash before Sentry could record it. Launch the app directly from its icon with Xcode stopped, trigger the crash, then reopen the app. The stored report flushes on the next launch and appears shortly after.
Not at crash time. A hard crash terminates the process, so Sentry writes the report to disk in its crash handler and sends it on the next app launch. This is why a clean, connected relaunch is required for the crash to be delivered.
Yes. If beforeSend returns nil for an event, that event is discarded entirely. A broad filter meant to scrub noise can accidentally swallow real crashes. Temporarily remove beforeSend and test with a DSN-only configuration to confirm whether it is the cause.
Very much. Sentry only captures crashes that occur after SentrySDK.start installs its handlers. Initialize it as early as possible, in your App struct's init or the first lines of didFinishLaunchingWithOptions, so early startup crashes are covered and stored reports get a chance to flush on launch.
Because the report is sent on the next launch and requires network connectivity. If the device was offline at relaunch, or the app was backgrounded before the flush finished, the SDK retries later, so the event can arrive minutes or hours after the crash occurred.