Guides10 min read

Debugging Capacitor OTA updates: a practical checklist

Your update did not land — now what? A systematic checklist for debugging Capacitor live updates: notifyAppReady, runtime version mismatches, manifest errors, channel config, and rollback loops.

You released a bundle and the app didn't change. Or it changed, then reverted. Live-update problems almost always trace to one of a handful of causes, and you can work through them in order. This is the checklist for debugging Capacitor OTA updates with OtaKit.

Start here: call getState() and getLastFailure() from the plugin. Together they tell you which bundle is active and why the last attempt was rejected — that answers most questions before you dig further.

1. Is notifyAppReady() being called?

This is the number-one cause. After an update boots, your app must call notifyAppReady() to confirm it started successfully. If it doesn't — because of a crash on boot, or because you never added the call — OtaKit assumes the update is bad and rolls back on the next launch. An update that “keeps reverting” is almost always a missing ready signal. See rollback strategies.

2. Does the runtime version match?

A bundle is only served to native shells it's compatible with. If you shipped a bundle that needs a newer native runtime than the installed binary, compatible devices get it and older ones correctly don't. Check the runtime version on the release against what's installed. See semantic versioning for bundles.

3. Is the device on the channel you released to?

Releasing to staging and testing a device configured for production is a classic. Confirm the channel in your config matches the channel in your release command.

4. Did the download actually complete?

Subscribe to downloadFailed and check getLastFailure(). A large bundle on a flaky network can fail mid-download; the device keeps the old bundle and retries later. Persistent failures are a size problem — enable delta updates.

5. Does the bundle verify?

Every bundle is checked against the SHA-256 in the signed manifest before it activates. A hash mismatch means the served files don't match what was signed — usually a botched upload or a caching artifact. Re-release and confirm the manifest updated.

import { OtaKit } from '@otakit/capacitor-plugin';

const state = await OtaKit.getState();
const failure = await OtaKit.getLastFailure();
console.log('active bundle', state, 'last failure', failure);

Debug on a staging channel against a real device before production. Most “it works on my machine” update bugs are really channel or runtime-version mismatches that a proper staging pass would have caught — see how to test OTA updates.

Where to go next

See Plugin API for the state and failure methods, and monitoring OTA updates to catch these in production automatically.

Related docs