App Hangs

Learn about how to add app hang detection reporting.

We recommend disabling this feature for Widgets and Live Activities because it might detect false positives.

Furthermore, the Cocoa SDK might report app hangs when the OS opens a system dialog asking for specific permissions, such as whether the user wants to allow your app to paste from the clipboard. As we can't reliably detect these scenarios, we advise you to pause and resume tracking app hangs to circumvent this problem.

This integration tracks app hangs. This feature is available on iOS, tvOS, and macOS.

Trying to use an unresponsive app is extremely frustrating for users. There are many reasons why an app may become unresponsive, such as long- running code, infinite loop bugs, and so on. With app hang tracking you can detect and fix them.

The app hang detection integration has a default timeout of two (2) seconds, but with version 7.24.0, we’ve improved the algorithm to detect app hangs sooner, decreasing from appHangTimeoutInterval * 2 to appHangTimeoutInterval * 1.2.

To detect app hangs, the SDK launches a dedicated watchdog thread called io.sentry.AppHangTracker, which periodically enqueues work items on the main thread, and checks if the main thread is executing them within the timeout. If the app is unresponsive for two seconds or more, it creates an error event. This thread is also used by Watchdog Terminations and will be launched even if enableAppHangTracking is disabled.

Recording the stack trace precisely when the app hang occurs works reliably if the app is completely stuck, but if the main thread is extremely busy with different code spots, the app hang detection might fire a bit too late. If this happens, the SDK may record a stack trace that isn’t 100% related to the code, causing the app to hang. Each event has a stack trace of all running threads so you can easily detect where the problem occurred.

The SDK reports an app hang immediately, but doesn’t report the exact duration because the watchdog could kill the app anytime if it's blocking the main thread.

Because the app hang detection integration uses SentryCrashIntegration to capture the stack trace when creating app hang events, SentryCrashIntegration has to be enabled for the integration to work.

You can filter and modify app hang events in beforeSend by checking the event exception type:

Copied
import Sentry

SentrySDK.start { options in
    options.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0"
    options.beforeSend = { event in
        if (event.exceptions?.first?.type == "App Hanging") {
          // modify event here or return nil to discard the event
        }
        return event
    }
}

Starting with version 8.0.0, this feature has been enabled by default. To disable it:

Copied
import Sentry

SentrySDK.start { options in
    options.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0"
    options.enableAppHangTracking = false
}

You can change the timeout by changing the appHangTimeoutInterval option:

Copied
import Sentry

SentrySDK.start { options in
    options.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0"
    options.appHangTimeoutInterval = 1
}

Starting with version 8.30.0, you can pause and resume app hang tracking at runtime with SentrySDK.pauseAppHangTracking() and SentrySDK.resumeAppHangTracking(). These methods don't stop the MetricKit integration from reporting MXHangDiagnostic.

Copied
import Sentry

SentrySDK.pauseAppHangTracking()

// Do something that might cause the app to hang,
// and you don't want the Cocoa SDK to report it.

SentrySDK.resumeAppHangTracking()

This feature is experimental and may have bugs.

As of version 8.39.0-beta.1, you can enable AppHangsV2, which is available on iOS and tvOS. The main difference is that AppHangsV2 differentiates between fully-blocking and non-fully-blocking app hangs, which you might choose to ignore. A fully-blocking app hang is when the main thread is stuck completely, and the app can't render a single frame. A non-fully-blocking app hang is when the app appears stuck to the user, but can still render a few frames. Fully-blocking app hangs are more actionable because the stacktrace shows the exact blocking location on the main thread. Non-fully-blocking app hangs can have a stacktrace that doesn't highlight the exact blocking location, since the main thread isn't completely blocked.

To enable the feature:

Copied
import Sentry

SentrySDK.start { options in
    options.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0"
    options.enableAppHangTrackingV2 = true
}

As stacktraces might not be 100% accurate for non-fully-blocking app hangs, you can disable them with the option enableReportNonFullyBlockingAppHangs:

Copied
import Sentry

SentrySDK.start { options in
    options.dsn = "https://examplePublicKey@o0.ingest.sentry.io/0"
    options.enableReportNonFullyBlockingAppHangs = false
}
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").