Skip to content

Cap-go/capacitor-webview-crash

@capgo/capacitor-webview-crash

Capgo - Instant updates for Capacitor

Detect recovered Capacitor WebView crashes, restart dead WebViews natively, and optionally recycle long-running WebViews on a fixed interval before memory pressure turns into an OOM.

What It Does

  • Stores a native crash marker when Android reports onRenderProcessGone.
  • Hooks the iOS WebView termination callback and persists equivalent crash metadata.
  • Restarts the WebView natively after crashes so recovery does not depend on a still-running JavaScript runtime.
  • Can restart the WebView on a fixed native interval for kiosk, POS, signage, telemetry, and other always-on apps.
  • Lets JavaScript request a native WebView restart with restartWebView() when the app wants to proactively recycle memory.
  • Exposes the marker through an event, a polling method, and a simulation helper for testing recovery flows.
  • Ships a web implementation that simulates the same recovery flow with local storage.

What It Does Not Do

  • Prevent the underlying WebView crash from happening.
  • Restore lost in-memory JavaScript state automatically.
  • Replace application-level state persistence. Persist critical state before enabling scheduled restarts.

Compatibility

Plugin version Capacitor compatibility Maintained
v8.*.* v8.*.*
v7.*.* v7.*.* On demand
v6.*.* v6.*.* On demand

Policy:

  • New plugins start at version 8.0.0 (Capacitor 8 baseline).
  • Backward compatibility for older Capacitor majors is supported on demand.

Install

npm install @capgo/capacitor-webview-crash
npx cap sync

Usage

import { WebViewCrash } from '@capgo/capacitor-webview-crash';

await WebViewCrash.addListener('webViewRestoredAfterCrash', async (info) => {
  console.log('Recovered after a WebView crash', info);
  await WebViewCrash.clearPendingCrashInfo();
});

await WebViewCrash.addListener('webViewRestoredAfterRestart', async (info) => {
  console.log('Recovered after a native WebView restart', info);
  await WebViewCrash.clearPendingCrashInfo();
});

const pending = await WebViewCrash.getPendingCrashInfo();
if (pending.value) {
  console.log('Pending crash or restart marker', pending.value);
}

Use simulateCrashRecovery() in development or automated tests to exercise your recovery UI without forcing a real native WebView crash.

Call restartWebView() when the current JavaScript runtime decides the native WebView should be replaced:

await WebViewCrash.restartWebView();

The call writes a pending marker with reason: 'manualRestart', then native code restarts the WebView. Android recreates the host Activity. iOS rebuilds the Capacitor bridge view so a new WKWebView is created instead of reloading the current page.

Native Auto Restart

Configure the plugin in capacitor.config.ts so restart decisions happen in native code, even when the JavaScript runtime is unavailable:

import type { CapacitorConfig } from '@capacitor/cli';
import type { WebViewCrashPluginConfig } from '@capgo/capacitor-webview-crash';

const webViewCrash: WebViewCrashPluginConfig = {
  // Keep native crash recovery enabled. This is the default.
  restartOnCrash: true,

  // Use a 5-field cron schedule in the device local timezone.
  // Do not combine restartCron with an active restartIntervalMs.
  restartCron: '0 3 * * *',

  // Optional delay before restarting after a crash.
  restartAfterCrashDelayMs: 0,
};

const config: CapacitorConfig = {
  plugins: {
    WebViewCrash: webViewCrash,
  },
};

export default config;

Use scheduled restarts for apps that stay open for days: kiosk screens, control-room dashboards, point-of-sale terminals, warehouse scanners, vehicle tablets, or any Capacitor app that cannot rely on users force-closing it. The restart is native, writes a pending marker with reason: 'periodicRestart', and then creates a fresh WebView.

Set restartIntervalMs to a maintenance window that your product can tolerate, or set restartCron for a wall-clock schedule such as 0 3 * * * for a daily 03:00 restart. restartCron uses 5-field cron syntax in the device local timezone and supports *, lists, ranges, and steps. Do not configure both schedules at once: native initialization throws a fatal config error when restartCron is set and restartIntervalMs is greater than 0. The user will get a fresh JavaScript runtime, so persist unsaved form state, queued events, and in-progress work before enabling a short interval or cron schedule.

Config Type

export interface WebViewCrashPluginConfig {
  restartOnCrash?: boolean;
  restartIntervalMs?: number;
  restartCron?: string;
  restartAfterCrashDelayMs?: number;
}

Platform Notes

  • iOS: Uses method swizzling on Capacitor's WebViewDelegationHandler to persist crash metadata before Capacitor reloads the WebView. Manual and scheduled restarts rebuild the Capacitor bridge view so a new WKWebView instance is created. No extra permissions are required.
  • Android: Registers a Capacitor WebViewListener and persists crash metadata from onRenderProcessGone. Crash and scheduled restarts reset the bridge and recreate the host activity, giving the app a fresh WebView. No extra permissions are required.
  • Web: There is no real browser crash detection. The web implementation only simulates the recovery flow with local storage.

Documentation

API

Capacitor API for recovered WebView crash and restart detection.

getPendingCrashInfo()

getPendingCrashInfo() => Promise<PendingCrashInfoResult>

Returns the pending native crash or restart marker, if one exists.

Returns: Promise<PendingCrashInfoResult>


clearPendingCrashInfo()

clearPendingCrashInfo() => Promise<void>

Clears the stored marker after the app has handled recovery.


simulateCrashRecovery()

simulateCrashRecovery() => Promise<PendingCrashInfoResult>

Creates a fake crash marker so recovery flows can be tested locally.

Returns: Promise<PendingCrashInfoResult>


restartWebView()

restartWebView() => Promise<PendingCrashInfoResult>

Stores a manual restart marker and asks native code to create a fresh WebView.

On Android this recreates the host Activity. On iOS this rebuilds the Capacitor bridge view so a new WKWebView instance is created instead of reloading the current page.

Returns: Promise<PendingCrashInfoResult>


addListener('webViewRestoredAfterCrash' | 'webViewRestoredAfterRestart', ...)

addListener(eventName: 'webViewRestoredAfterCrash' | 'webViewRestoredAfterRestart', listenerFunc: (info: WebViewCrashInfo) => void) => Promise<PluginListenerHandle>

Fires after a new JavaScript runtime attaches a listener and a matching marker is still pending.

Param Type
eventName 'webViewRestoredAfterCrash' | 'webViewRestoredAfterRestart'
listenerFunc (info: WebViewCrashInfo) => void

Returns: Promise<PluginListenerHandle>


removeAllListeners()

removeAllListeners() => Promise<void>

Removes all plugin listeners.


Interfaces

PendingCrashInfoResult

Pending crash or restart marker returned to JavaScript.

Prop Type Description
value WebViewCrashInfo | null Stored crash or restart metadata, or null when no marker is pending.

WebViewCrashInfo

Metadata captured natively after the previous WebView process died or was restarted.

Prop Type Description
platform WebViewCrashPlatform Platform that detected and stored the marker.
timestamp number Unix timestamp in milliseconds for when the marker was written.
timestampISO string ISO-8601 version of timestamp.
reason WebViewCrashReason Platform-specific reason for the crash or restart marker.
url string Last known WebView URL when the marker was written.
didCrash boolean Android-only hint from RenderProcessGoneDetail.didCrash().
rendererPriorityAtExit number Android-only renderer priority reported at exit.
appState WebViewCrashAppState iOS-only application state captured when the marker was written.

PluginListenerHandle

Prop Type
remove () => Promise<void>

Type Aliases

WebViewCrashPlatform

Platform that produced the stored marker.

'android' | 'ios' | 'web'

WebViewCrashReason

Native reason reported for the previous WebView failure or restart.

'renderProcessGone' | 'webContentProcessDidTerminate' | 'periodicRestart' | 'manualRestart' | 'simulated'

WebViewCrashAppState

Best-effort application state captured on iOS when the WebView process died.

'active' | 'inactive' | 'background' | 'unknown'

About

Capacitor plugin for detecting recovered WebView crashes.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors