How to add @deploy-your-app/capacitor-update-manager to a Capacitor app and get the first update check working.
Automated setup
The CLI does the whole installation interactively:
dya setup
dya setup logs you in, picks or creates the app, generates RSA keys, installs the plugin with your package manager, writes the plugins.DeployYourApp block into capacitor.config.json (or prints a snippet for .ts / .js configs), and runs npx cap sync. It requires a TTY, so it is not usable in CI. See dya setup.
The rest of this page covers the same steps by hand.
Requirements
| Requirement | Value |
|---|---|
@capacitor/core |
>=6.0.0 (peer dependency) |
| iOS deployment target | 13.0 |
Android minSdkVersion |
22 |
Android compileSdkVersion |
34 |
| Android JDK / Kotlin | Java 17, Kotlin 1.9.25 |
The Android minSdkVersion, compileSdkVersion, and targetSdkVersion are read from your root project's ext block when you define them, so the plugin follows your app's values.
Install
npm install @deploy-your-app/capacitor-update-manager
npx cap sync
npx cap sync registers the plugin with both native projects and pulls in the iOS ZIP dependency. No manual class registration is needed on either platform.
Configure
Add a DeployYourApp block under plugins in capacitor.config.json:
{
"appId": "com.yourcompany.yourapp",
"webDir": "dist",
"plugins": {
"DeployYourApp": {
"appId": "com.yourcompany.yourapp",
"channel": "production"
}
}
}
plugins.DeployYourApp.appId is the app ID from the DeployYourApp dashboard. It is separate from the top-level Capacitor appId, even when the two happen to match. When it is unset the plugin falls back to the platform's own identifier — the bundle identifier on iOS, the application package name on Android — and logs a warning to the Xcode console or logcat. Unless that identifier happens to be your dashboard app ID, every update check will return "no update". Set it explicitly.
That is the minimum. Every other option has a default — see Configuration for the full list.
Confirm each launch
The plugin rolls a newly served bundle back unless your app confirms it booted. Call notifyAppReady() once, as early as your app can honestly say it is working:
import { DeployYourApp } from '@deploy-your-app/capacitor-update-manager';
await DeployYourApp.notifyAppReady();
If a new bundle does not call this within appReadyTimeout (10 seconds by default), the plugin restores the previous bundle. See Update lifecycle.
With the default autoUpdate: true, that is the whole integration. The plugin checks for updates on launch and every checkInterval seconds, downloads new bundles, verifies them, and activates them on the next launch.
iOS
npx cap sync is the only step. Specifics worth knowing:
- ZIP extraction uses ZIPFoundation
~> 0.9.19. CocoaPods installs it from the plugin's podspec; Swift Package Manager resolves it fromPackage.swift. - The plugin ships an Apple privacy manifest (
PrivacyInfo.xcprivacy) as a resource bundle. It is included automatically in the CocoaPods integration. - Bundles are stored under
Application Support/dya-bundles/<bundleId>/. Plugin state (device ID, channel, bundle metadata) lives inUserDefaultsunderdya_*keys. - The plugin writes Capacitor's own
serverBasePathkey inUserDefaultsso a cold start serves the active bundle before plugins load.
Android
npx cap sync is the only step. Specifics worth knowing:
- The plugin's
AndroidManifest.xmlis empty — it declares no permissions, activities, or services. Your app still needs the internet permission it already has for any network access. - ZIP extraction uses
java.util.zip, so there is no extra Gradle dependency beyondcapacitor-android,androidx.appcompat, and the Kotlin standard library. - Bundles are stored under the app's internal
files/dya-bundles/<bundleId>/. Plugin state lives in thedya_prefsanddya_configSharedPreferencesfiles. - The plugin writes Capacitor's
serverBasePathkey in theCapWebViewSettingspreferences so a cold start serves the active bundle before plugins load.
Verify the installation
Build and run on a device or emulator, then confirm the plugin answers and reaches the server:
import { DeployYourApp, DYA_EVENTS } from '@deploy-your-app/capacitor-update-manager';
DeployYourApp.addListener(DYA_EVENTS.UPDATE_AVAILABLE, ({ version }) => {
console.log('Update available:', version);
});
const { version } = await DeployYourApp.getPluginVersion();
console.log('Plugin version:', version);
const { deviceId } = await DeployYourApp.getDeviceId();
console.log('Device ID:', deviceId);
const result = await DeployYourApp.checkForUpdate();
console.log('Update available?', result.available);
A successful check registers the device against your app. The device then appears in the dashboard, which confirms appId and updateUrl are correct. available: false on a fresh app is expected until you deploy a bundle with dya deploy.
Pointing at another environment
Skip this. By default the plugin talks to deployyour.app and neither URL needs setting. These options exist for testing an app against a different DeployYourApp API, such as a local server during development.
Both are base URLs — the plugin appends /api/update and /api/stats itself. Because bundles are served from object storage rather than the API host, that host must also be listed in allowedDownloadHosts; downloads from anywhere else are refused, and https is required except from localhost:
{
"plugins": {
"DeployYourApp": {
"appId": "com.yourcompany.yourapp",
"updateUrl": "http://localhost:3000",
"statsUrl": "http://localhost:3000",
"allowedDownloadHosts": ["localhost"]
}
}
}
Troubleshooting
The plugin is not found at runtime. Run npx cap sync again. It must run after every install and after any change to capacitor.config.json.
Every check returns no update. Confirm plugins.DeployYourApp.appId matches the app ID in the dashboard, that the channel name exists on that app, and that you have deployed a bundle to it. An unset appId produces this exact symptom; look for the DeployYourApp warning in logcat or the Xcode console, which names the identifier that was substituted.
The device never appears in the dashboard. The device only registers once an update check reaches the server. Check that the device has network access to your updateUrl.
Next steps
- Configuration — every option and its default.
- Update lifecycle — how a bundle goes from download to active, and how rollback works.
- API reference — every method, event, and error code.
- CLI commands —
dya deployand key management.