Your iOS app crashes without a crash log? Users complain, but Crashlytics stays silent. You've likely encountered Watchdog Termination — a system mechanism that forcibly terminates the app if the main thread hangs beyond a threshold (about 8 seconds on older iOS versions, ~4 seconds on newer ones). We configure detection for such incidents so you get full diagnostics and can eliminate the root cause. Over the years, we've identified dozens of projects where Watchdog Terminations went unnoticed, despite accounting for 2–3% of all sessions. Our basic Sentry setup costs $500–$1,000 with setup in 4–8 hours, and can save up to 5 hours per week on incident analysis. With 6+ years of iOS development experience and over 60 monitoring projects, we guarantee a quality setup.
Why standard crash reporters miss Watchdog Termination
Firebase Crashlytics does not register Watchdog Termination — it's neither an exception nor a signal. Sentry since version 8.0 can detect it via flags in UserDefaults (enable enableWatchdogTerminationTracking). MetricKit provides accurate data but with a delay of up to a day. The choice of method depends on your priorities: speed vs. accuracy. Apple Documentation: MXHangDiagnostic is the only official source for an accurate main thread stack trace at the time of the hang.
| Method | Speed of retrieval | Stack accuracy | Additional costs |
|---|---|---|---|
| MetricKit | up to 24 hours | High (callStackTree) | Free (built into iOS) |
| Sentry | minutes | Medium (flag + main thread stack) | Subscription to sentry.io |
| Custom detector | real-time | High (BSBacktraceLogger) | Development and maintenance |
For effective iOS force termination tracking, combine MetricKit and Sentry to monitor main thread hang.
How to choose a monitoring method?
If you need maximum accuracy for deep analysis, use MetricKit. It's free, but data arrives with a delay, making it unsuitable for quick response. If speed matters, Sentry provides information within minutes with sufficient accuracy. When you need real-time monitoring and a low trigger threshold (2–3 seconds), we build a custom detector based on DispatchQueue.main.async with feedback via BSBacktraceLogger. Sentry is 2 times faster than MetricKit in data retrieval, but stack accuracy is lower due to the absence of callStackTree.
How we set up monitoring: a real-world case
Our client from the fintech sector faced mass Watchdog Terminations after an app update. Engineers connected Sentry with a threshold of appHangTimeoutInterval = 2.5 seconds and discovered that in 70% of cases, the hang occurred in the processTransaction method on the main thread due to a synchronous CoreData write. We moved the write to a background context — the incident frequency dropped by 90%. We additionally configured MetricKit for confirmation — the data matched.
Recommendations for choosing the trigger threshold
For apps with heavy interfaces (e.g., animations), the threshold should be lowered to 2–3 seconds. For financial apps, where every millisecond counts, 1–2 seconds. Use A/B testing before rolling out.
Implementing a custom detector (if you need speed)
final class WatchdogDetector {
private let queue = DispatchQueue(label: "watchdog.monitor", qos: .utility)
private var pingTime: Date = Date()
private let threshold: TimeInterval = 3.0
func start() {
scheduleMainThreadPing()
scheduleBackgroundCheck()
}
private func scheduleMainThreadPing() {
DispatchQueue.main.async { [weak self] in
self?.pingTime = Date()
self?.scheduleMainThreadPing()
}
}
private func scheduleBackgroundCheck() {
queue.asyncAfter(deadline: .now() + 1.0) { [weak self] in
guard let self = self else { return }
let elapsed = Date().timeIntervalSince(self.pingTime)
if elapsed > self.threshold {
self.captureHang(duration: elapsed)
}
self.scheduleBackgroundCheck()
}
}
private func captureHang(duration: TimeInterval) {
// Use BSBacktraceLogger to capture main thread stack trace
BacktraceLogger.backtrace(for: .main) { frames in
SentrySDK.capture(error: NSError(
domain: "WatchdogHang",
code: Int(duration * 1000),
userInfo: [
NSLocalizedDescriptionKey: "Main thread hung for \(duration)s",
"stackFrames": frames
]
))
}
}
}
Thread.callStackSymbols captures the stack trace of only the current thread. For the main thread, use BSBacktraceLogger or PLCrashReporter.
What the setup includes (deliverables)
- Installation and configuration of a MetricKit subscriber to receive MXHangDiagnostic
- Integration of Sentry with
enableWatchdogTerminationTrackingenabled and optimized threshold - If needed, development of a custom detector with a low threshold (from 2 seconds)
- Setting up alerts in Sentry or your monitoring system for a rise in Watchdog Termination Rate
- Analysis of callStackTree and identification of bottlenecks (synchronous operations on the main thread)
- Documentation of the monitoring setup and integration instructions
- Access to monitoring dashboards and configuration
- Training session for your team (up to 2 hours)
- Support for 1 month post-deployment
Typical sources of Watchdog Termination (and what to do about them)
| Problem | Solution |
|---|---|
| Synchronous CoreData fetch in viewDidLoad | Offload the request to a background context |
| DispatchSemaphore.wait() without timeout on the main thread | Use async-await or a timeout |
| Deadlock between @MainActor and synchronous Swift Concurrency code | Avoid blocking the actor |
| Heavy JSON decode in an URLSession closure | Switch thread using dataTask with qos: .userInitiated |
Process of work
- Analysis — we study the current architecture, iOS versions, typical scenarios. We collect metrics via MetricKit (if already used).
- Design — we choose the optimal stack: MetricKit + Sentry / Sentry only / custom + Sentry. We determine trigger thresholds.
- Implementation — we write and integrate code, test on a simulator and real devices with different iOS versions.
- Testing — we simulate hangs (e.g., via
sleep(10)on the main thread) and verify that the detector triggers and sends diagnostics. - Deployment — we roll out via TestFlight, monitor initial data, and adjust thresholds as needed.
Timeline and cost
Basic setup via Sentry: 4–8 hours ($500–$1,000). MetricKit integration with sending diagnostics to your server: 1–2 days ($1,500–$3,000). Full cycle with a custom detector and analysis: from 3 days ($4,000–$7,000). The cost is calculated individually — contact us for a project assessment. Get a consultation — we'll help reduce Watchdog Termination frequency and improve user experience. With 6+ years of iOS development experience and over 60 monitoring projects, we guarantee a quality setup.







