Plugin API
Import from @otakit/capacitor-updater. For normal app code, the normal hosted flow usually only needs notifyAppReady(). The other public methods exist for advanced manual update flows where your app decides when to check, download, and apply an update.
import { OtaKit } from "@otakit/capacitor-updater";Configuration
For hosted OtaKit, keep the plugin config small:
plugins: {
OtaKit: {
appId: "YOUR_OTAKIT_APP_ID",
appReadyTimeout: 10000,
// Optional:
// updateMode: "next-resume",
}
}Hosted OtaKit points at the managed server automatically. Do not set serverUrl or manifestKeys unless you intentionally want custom server or verification behavior.
Update Modes
All automatic modes check for updates on cold start (always) and app resume (throttled by checkInterval, default 10 minutes).
Manifest Verification
Hosted OtaKit verifies manifests automatically. The native plugin ships with built-in trusted public keys for the managed service and uses them by default when you stay on the hosted server.
You only need manifestKeys when you intentionally override trust for a custom or self-hosted server. In that case, also set serverUrl to your own API base URL.
Automatic Flow (Default)
This is the normal OtaKit flow. Leave updateMode unset or set it to next-launch. The plugin checks automatically on startup, downloads in the background, and activates the new bundle on the next cold app launch.
In this mode, your app code usually only needs to call notifyAppReady().
Confirm the current bundle is working. Call this once when your app has fully loaded. If it is not called within appReadyTimeout, the plugin rolls back.
import { OtaKit } from "@otakit/capacitor-updater";
await OtaKit.notifyAppReady();Manual Flow (Advanced)
Use this only when your app wants to control the update UX itself, for example by showing an “Update available” prompt or delaying install until the user confirms. Set updateMode to "manual" first.
plugins: {
OtaKit: {
appId: "YOUR_OTAKIT_APP_ID",
updateMode: "manual",
appReadyTimeout: 10000,
}
}Inspect the current app-facing updater state: current bundle, staged bundle, and builtin version.
Check the configured channel for a newer bundle without downloading it. When downloaded=true, that exact update is already staged locally.
Ensure the latest bundle is staged for later activation. If it is already staged, the staged bundle is returned without re-downloading it.
Recommended one-shot manual helper. Bring the app to the newest available update now. If the newest update is already staged, apply it. Otherwise download it and apply it. Terminal operation.
Activate the currently staged bundle and reload the WebView. Terminal operation.
Still required after the updated bundle launches. Call this once when your app has fully loaded so the plugin can mark the new bundle healthy.
The simplest manual pattern is: check for updates, show your own prompt, then call update() if the user accepts.
If check() returns downloaded: true, the latest update is already staged locally and you can call apply() directly.
const latest = await OtaKit.check();
if (!latest) {
return;
}
const accepted = window.confirm("Update available. Install now?");
if (accepted) {
await OtaKit.update();
}If you want a split flow, download first and apply later:
const state = await OtaKit.getState();
if (state.staged) {
await OtaKit.apply();
return;
}
const latest = await OtaKit.check();
if (!latest) {
return;
}
const accepted = window.confirm("Update available. Download now?");
if (!accepted) {
return;
}
await OtaKit.download();
// Later, after another user action:
await OtaKit.apply();Debug API
Manual inspection and control methods live under OtaKit.debug. These are for diagnostics, support, and test flows, not normal app code.
Check the server for a newer bundle without downloading it. You can optionally pass { channel } for a one-off debug override.
Debug version of download() that ensures the latest bundle is staged for a one-off { channel } override.
Clear active updater state, return to the builtin bundle, clear fallback and last failure state, and reload the WebView. Terminal operation.
List downloaded OTA bundles stored on the device.
Delete a downloaded bundle that is not current, fallback, or staged.
Return the last failed update metadata for diagnostics. The failed bundle files themselves are cleaned up automatically after rollback.
Advanced Overrides
Use these only when you run a custom server or need custom verification behavior.
plugins: {
OtaKit: {
appId: "YOUR_OTAKIT_APP_ID",
// Optional advanced overrides
// serverUrl: "https://your-server.com/api/v1",
// allowInsecureUrls: false,
// manifestKeys: [
// { kid: "key-2026-01", key: "MFkwEwYH..." }
// ]
}
}Events
Listen to update lifecycle events with OtaKit.addListener(event, callback). Returns a handle that can be removed with .remove().
OtaKit.addListener("downloadComplete", (bundle) => {
console.log(`Update staged: ${bundle.version}`);
});
await OtaKit.removeAllListeners();Types
interface BundleInfo {
id: string;
version: string;
status: "builtin" | "pending"
| "trial" | "success" | "error";
downloadedAt?: string;
sha256?: string;
channel?: string;
releaseId?: string;
}
interface OtaKitState {
current: BundleInfo;
staged: BundleInfo | null;
builtinVersion: string;
}
interface LatestVersion {
version: string;
url: string;
sha256: string;
size: number;
downloaded?: boolean;
releaseId?: string;
minNativeBuild?: number;
}