Skip to main content

Crash Detection

SwiftPatch monitors app launches after every OTA update. If the new bundle crashes repeatedly before stabilizing, the SDK automatically rolls back to the last stable bundle.

info

If you use withSwiftPatch or SwiftPatchProvider, crash detection is already active. Nothing to enable.

How the 10-Second Window Works

After an update installs, every launch enters a crash detection window (10 seconds by default). The SDK watches for one signal: did the app render?

Step 1: Update lands in NEW_SLOT -- staged but not yet trusted.

Step 2: App launches with new bundle -- native module starts a countdown timer.

Step 3: Provider renders -- SwiftPatchProvider calls markMounted() to signal a healthy launch.

Step 4: Timer stops -- after several healthy launches, the bundle promotes to STABLE_SLOT.

If the app crashes before markMounted(), the native module increments a crash counter. After reaching the threshold (default: 2), SwiftPatch rolls back on the next launch.

Launch 1 with new bundle
[--- 10-second window ---]
App crashes at 3s -> crashCount = 1

Launch 2 with new bundle
[--- 10-second window ---]
App crashes at 1s -> crashCount = 2 (threshold reached)

Launch 3 -> Rollback to STABLE_SLOT

Integration

withSwiftPatch calls markMounted() automatically when it renders:

import { withSwiftPatch } from '@swiftpatch/react-native';

function App() {
return <YourApp />;
}

export default withSwiftPatch(App);

Custom Mount Timing

If your app has heavy initialization that should succeed before the app is considered healthy:

import { useSwiftPatch } from '@swiftpatch/react-native';

function App() {
const { markMounted } = useSwiftPatch();

useEffect(() => {
async function init() {
await loadCriticalData();
await setupServices();
markMounted();
}
init();
}, []);

return <YourApp />;
}
note

Delaying markMounted() gives better crash coverage but increases the chance of incorrectly treating a slow startup as a crash. Balance coverage with startup time.

Configuration

export default withSwiftPatch(App, {
crashDetectionWindowMs: 15000, // 15s window (default: 10000)
maxCrashesBeforeRollback: 3, // 3 crashes before rollback (default: 2)
});
OptionDefaultDescription
crashDetectionWindowMs10000Time window after launch for crash detection
maxCrashesBeforeRollback2Consecutive crashes before rollback
tip

Apps with heavy initialization (Firebase, Sentry, large data loading) may need a longer window. If your app takes more than 10 seconds to fully render, increase crashDetectionWindowMs.

warning

Setting maxCrashesBeforeRollback to 1 means a single crash triggers rollback. This may cause false positives from transient issues. Use 2 or 3 for most apps. Reserve 1 for safety-critical applications.

Dashboard Metrics

Crash Groups

Filter by project, status, and severity. SwiftPatch groups related crashes and provides AI-powered analysis.

Crash analytics

Per-Project Crashlytics

View crash data from Firebase at the project level. Connect Firebase in Settings > Integrations.

Project crashlytics

Key metrics:

  • Crash-free rate per release -- Compare stability across versions
  • Rollback count -- Devices rolled back, by release and channel
  • Crash-to-rollback time -- How quickly SwiftPatch protected users
  • Affected devices -- Total devices that crashed before rollback

Error Tracking Integration

Forward rollback events to your error tracking service:

import { onRollback } from '@swiftpatch/react-native';
import * as Sentry from '@sentry/react-native';

useEffect(() => {
const unsubscribe = onRollback((reason) => {
Sentry.captureMessage('SwiftPatch rollback triggered', {
extra: { reason },
});
});

return unsubscribe;
}, []);

Works with Sentry, Bugsnag, Datadog, or any custom endpoint.

Next Steps

  • Rollbacks -- Automatic and manual rollback strategies
  • Rollouts -- Limit blast radius before crash detection kicks in