Plugin API

Import from @otakit/capacitor-updater. The default 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

Hosted OtaKit keeps the config small. The default automatic behavior is runtime catch-up on cold start, staged activation on later cold starts, and background checks on resume.

plugins: {
  OtaKit: {
    appId: "YOUR_OTAKIT_APP_ID",
    // Optional:
    // channel: "production",
    // runtimeVersion: "2026.04",
    // launchPolicy: "apply-staged",
    // resumePolicy: "shadow",
    // runtimePolicy: "immediate",
    // checkInterval: 600000,
  }
}
appId
string
OtaKit app ID for manifest fetches and event ingest.
channel
string
Named release track to check. Omit it to use the base channel.
runtimeVersion
string
Optional native compatibility lane. Set it when a new store build must stop receiving older OTA bundles.
launchPolicy
"off" | "shadow" | "apply-staged" | "immediate"
Cold-start policy after the current runtime lane is already resolved. Default: apply-staged.
resumePolicy
"off" | "shadow" | "apply-staged" | "immediate"
Foreground resume policy. Default: shadow.
runtimePolicy
"off" | "shadow" | "apply-staged" | "immediate"
Cold-start policy used when runtimeVersion changes or resolves for the first time. Default: immediate.
checkInterval
number
Milliseconds between automatic background resume checks. Applies to `resumePolicy: "shadow"` and `resumePolicy: "apply-staged"` when no staged bundle is already waiting. Default: 600000. Set to 0 or a negative value to disable resume throttling.
appReadyTimeout
number
Milliseconds to wait for notifyAppReady(). Default: 10000.
cdnUrl
string
Optional CDN base URL for static manifest and bundle delivery. Leave unset for the hosted default.
ingestUrl
string
Optional event ingest base URL. Leave unset for the hosted default.
serverUrl
string
Optional control-plane API base URL used by self-host tooling such as the CLI. The native runtime uses cdnUrl and ingestUrl instead.
manifestKeys
array
Optional public verification keys for custom or self-hosted manifest signing.
allowInsecureUrls
boolean
Allow HTTP only for localhost development. Default: false.

Hosted OtaKit points at the managed CDN and ingest service automatically. Do not set cdnUrl, ingestUrl, or manifestKeys unless you intentionally want custom hosting or verification behavior.

Policies

Policies are the only automatic behaviors. The same policy logic runs no matter which event triggered it. launchPolicy, resumePolicy, and runtimePolicy only decide when to invoke that policy.

off
policy
Do nothing automatically.
shadow
policy
Check for the latest update and stage it locally, but never apply it in that flow.
apply-staged
policy
Apply an already staged bundle if one exists. If nothing is staged, fall back to shadow.
immediate
policy
Check, stage, and immediately apply the newest update when one is available.

The hosted defaults are usually the right production baseline: runtimePolicy: "immediate", launchPolicy: "apply-staged", and resumePolicy: "shadow".

Compatibility lanes

channel is for rollout audience. runtimeVersion is for native compatibility.

If you ship a new store build and do not want it to keep consuming older OTA bundles, bump runtimeVersion in the plugin config before uploading the next OTA bundle.

The CLI reads that same value automatically during upload, so releases stay inside the correct runtime lane without extra flags.

When runtimeVersion changes, or when the app resolves a runtime lane for the first time, OtaKit runs runtimePolicy on cold start. By default that policy is immediate, so fresh installs and new native shells catch up before that lane is marked resolved.

Automatic Flow (Default)

The hosted default is equivalent to this configuration:

plugins: {
  OtaKit: {
    appId: "YOUR_OTAKIT_APP_ID",
    runtimePolicy: "immediate",
    launchPolicy: "apply-staged",
    resumePolicy: "shadow",
    appReadyTimeout: 10000,
  }
}

In this mode, your app code usually only needs to call notifyAppReady().

Resume throttling is intentionally narrow: checkInterval only affects resume background checks. Cold-start runtime handling, cold-start launch handling, and all manual APIs always act immediately.

Set checkInterval to 0 or a negative value if you want resume checks to run every time instead of being throttled.

notifyAppReady() void

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)

If you want no automatic checks at all, turn every automatic policy off and drive the update lifecycle yourself.

plugins: {
  OtaKit: {
    appId: "YOUR_OTAKIT_APP_ID",
    launchPolicy: "off",
    resumePolicy: "off",
    runtimePolicy: "off",
  }
}
getState() OtaKitState

Inspect the current updater state: current bundle, fallback bundle, staged bundle, and builtin version.

check() CheckResult

Check the configured channel for a newer bundle without downloading it. Returns no_update, already_staged, or update_available.

download() DownloadResult

Ensure the latest bundle is staged for later activation. Returns no_update or staged.

update() void

Convenience helper for manual flows. It runs the same native immediate-flow operation used by automatic immediate policies. Terminal operation: if an update is applied, it does not resolve back into the old JS context.

apply() void

Activate the currently staged bundle and reload the WebView. Terminal operation: on success it does not resolve back into the old JS context.

notifyAppReady() void

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.

getLastFailure() BundleInfo | null

Returns information about the most recent failed update (rollback). Useful for diagnostics and crash reporting. Returns null if no failure has occurred.

There is no listener API in the current plugin surface. If you want custom update UI, use check(), getState(), download(), and apply() directly.

After a successful apply() or an update() that installs a new bundle, the app reloads immediately. Call notifyAppReady() from the reloaded app startup, not in the same JS flow that triggered the activation.

The simplest manual pattern is: check for updates, show your own prompt, then call update() if the user accepts.

const latest = await OtaKit.check();

if (latest.kind === "no_update") {
  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.kind === "no_update") {
  return;
}

const accepted = window.confirm("Update available. Download now?");
if (!accepted) {
  return;
}

const result = await OtaKit.download();
if (result.kind === "no_update") {
  return;
}

// Later, after another user action:
await OtaKit.apply();

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
    // cdnUrl: "https://cdn.your-domain.com",
    // ingestUrl: "https://ingest.your-domain.com/v1",
    // serverUrl: "https://your-domain.com/api/v1",
    // allowInsecureUrls: false,
    // manifestKeys: [
    //   { kid: "key-2026-01", key: "MFkwEwYH..." }
    // ]
  }
}
cdnUrl
string
Custom CDN base URL for static manifest and bundle delivery.
ingestUrl
string
Custom event ingest base URL used for device telemetry.
serverUrl
string
Control-plane API URL used by self-host tooling such as the CLI. The native runtime does not read it.
allowInsecureUrls
boolean
Allow HTTP for localhost development only. Default: false.
manifestKeys
array
Public verification keys for manifest signature verification on custom/self-hosted setups.

Types

type OtaKitPolicy = "off" | "shadow" | "apply-staged" | "immediate";

interface BundleInfo {
  id: string;
  version: string;
  runtimeVersion?: string;
  status: "builtin" | "pending" | "trial" | "success" | "error";
  downloadedAt?: string;
  sha256?: string;
  channel?: string;
  releaseId?: string;
}

interface OtaKitState {
  current: BundleInfo;
  fallback: BundleInfo;
  staged: BundleInfo | null;
  builtinVersion: string;
}

interface LatestVersion {
  version: string;
  runtimeVersion?: string;
  url: string;
  sha256: string;
  size: number;
  releaseId: string;
}

type CheckResult =
  | { kind: "no_update" }
  | { kind: "already_staged"; latest: LatestVersion }
  | { kind: "update_available"; latest: LatestVersion };

type DownloadResult =
  | { kind: "no_update" }
  | { kind: "staged"; bundle: BundleInfo };