capgo-live-updates ยท diff
git:20260318.df79da2 to git:20261011.86834d4
93 added, 456 removed. Audit A to A.
---
name: capgo-live-updates
- description: Complete guide to implementing live updates in Capacitor apps using Capgo. Covers account creation, plugin installation, configuration, update strategies, and CI/CD integration. Use this skill when users want to deploy updates without app store review.
+ description: Sets up and debugs Capgo live (OTA) updates in a Capacitor app with @capgo/capacitor-updater. Use when the user wants to ship web-layer fixes without app store review, install or configure the updater plugin, choose an autoUpdate mode, call notifyAppReady, wire manual download/next/set flows, set channels from the app, or debug updates that never apply, roll back, or report codes such as no_new_version_available, disable_auto_update_to_major, cannot_update_via_private_channel, or on_premise_app. Do not use for CLI-only bundle/channel operations (capgo-release-management), Capgo Cloud native builds (capgo-native-builds), or migrations from another OTA vendor.
---
- # Capgo Live Updates for Capacitor
-
- Deploy updates to your Capacitor app instantly without waiting for app store review.
+ # Capgo Live Updates
- ## When to Use This Skill
+ Wire `@capgo/capacitor-updater` into a Capacitor app, ship the first bundle, and keep rollback safe.
- - User wants live/OTA updates
- - User asks about Capgo
- - User wants to skip app store review
- - User needs to push hotfixes quickly
- - User wants A/B testing or staged rollouts
+ Facts below were checked against `@capgo/capacitor-updater` 8.52 and `@capgo/cli` 8.77 (October 2026).
- ## What is Capgo?
+ ## When to Use
- Capgo is a live update service for Capacitor apps that lets you:
+ TRIGGER when:
- - Push JavaScript/HTML/CSS updates instantly
- - Skip app store review for web layer changes
- - Roll back bad updates automatically
- - A/B test features with channels
- - Monitor update analytics
+ - The user wants OTA / live updates, hotfixes without store review, or "Capgo" in a Capacitor app.
+ - The updater plugin needs installing, upgrading, or configuring in `capacitor.config.*`.
+ - The user asks about `notifyAppReady`, `autoUpdate` modes, `directUpdate`, `autoSplashscreen`, `setChannel`, `getLatest`, `download`, `next`, `set`, or `reset`.
+ - Updates upload fine but devices never get them, roll back, or loop.
- **Note**: Native code changes (Swift/Kotlin/Java) still require app store submission.
+ Do not use when:
- ## Getting Started
+ - The work is only CLI bundle, channel, rollout, or encryption-key commands. Use `capgo-release-management`.
+ - The user needs a signed IPA/APK/AAB from Capgo Cloud. Use `capgo-native-builds`.
+ - The user is moving from Capawesome Cloud (`capawesome-live-update-migration`) or Ionic Appflow (`ionic-appflow-migration`).
+ - The user wants the whole release pipeline (OTA, native builds, and store publishing). Use `capgo-release-workflows`.
+ - The request is about general CLI routing or MCP setup. Use `capgo-cli-usage`.
- ### Step 1: Create a Capgo Account
+ ## Reference Index
- 1. Go to **https://capgo.app**
- 2. Click **"Sign Up"** or **"Get Started"**
- 3. Sign up with GitHub, Google, or email
- 4. Choose a plan:
- - **Free**: 1 app, 500 updates/month
- - **Solo**: $14/mo, unlimited updates
- - **Team**: $49/mo, team features
- - **Enterprise**: Custom pricing
+ Only load a reference when its topic is in play.
- ### Step 2: Install the CLI
+ | File | Load when |
+ | --- | --- |
+ | `references/configuration.md` | Editing `plugins.CapacitorUpdater` in `capacitor.config.*`, choosing `autoUpdate` modes, self-hosted URLs |
+ | `references/js-api.md` | Writing manual update flows, listeners, channel switching, or rollback code |
+ | `references/channels-and-rollouts.md` | Channels, device self-assignment, progressive rollouts, version targeting |
+ | `references/ci-cd.md` | Uploading from GitHub Actions, GitLab CI, or another CI |
+ | `references/troubleshooting.md` | A device does not update, rolls back, or the backend returns an error code |
- ```bash
- npm install -g @capgo/cli
- ```
+ ## Version Rule (read first)
- ### Step 3: Login to Capgo
+ The updater major version follows the Capacitor major version.
- ```bash
- capgo login
- # Opens browser to authenticate
- ```
+ | Capacitor | Install |
+ | --- | --- |
+ | 8.x | `npm install @capgo/capacitor-updater@latest` (8.x line) |
+ | 7.x | `npm install @capgo/capacitor-updater@lts-v7` |
+ | 6.x | `npm install @capgo/capacitor-updater@lts-v6` |
+ | 5.x | `npm install @capgo/capacitor-updater@lts-v5` |
+ | 4.x | `npm install @capgo/capacitor-updater@lts-v4` |
- Or use API key:
- ```bash
- capgo login --apikey YOUR_API_KEY
- ```
+ Capacitor 9 trap: Capacitor 9 is still prerelease (`@capacitor/core@next`). As of October 2026 there is no updater line for Capacitor 9. The 8.x line declares `peerDependencies: @capacitor/core ^8.0.0`. The `@capgo/capacitor-updater@9.0.0` on npm is an old Capacitor 5 release from 2023 and is marked deprecated, so never install it for Capacitor 9. Before you advise on a Capacitor 9 project, check the current tags with `npm view @capgo/capacitor-updater dist-tags`. If no Capacitor 9 line is listed, tell the user that.
- ### Step 4: Initialize Your App
+ ## Procedure
- ```bash
- cd your-capacitor-app
- capgo init
- ```
+ ### 1. Inspect before editing
- This will:
- - Create app in Capgo dashboard
- - Add `@capgo/capacitor-updater` to your project
- - Configure capacitor.config.ts
- - Set up your first channel
+ - Read `package.json` to get the `@capacitor/core` major and any existing `@capgo/capacitor-updater`.
+ - Read `capacitor.config.ts|json` to get `appId`, `webDir`, and any existing `plugins.CapacitorUpdater`.
+ - Find the app entry point (`main.ts`, `main.tsx`, `App.vue` setup, `app.component.ts`, and so on). That is where `notifyAppReady()` goes.
+ - Check for another OTA SDK. If one is present, stop and switch to the matching migration skill.
- ### Step 5: Install the Plugin
+ ### 2. Connect the project (preferred path)
- If not installed automatically:
+ The guided onboarding registers the app, installs the plugin, patches the entry point, builds, uploads, and verifies on a device:
```bash
- npm install @capgo/capacitor-updater
- npx cap sync
+ npx @capgo/cli@latest init YOUR_API_KEY com.example.app
```
- ## Configuration
-
- ### Basic Configuration
-
- ```typescript
- // capacitor.config.ts
- import type { CapacitorConfig } from '@capacitor/cli';
+ API keys live at https://console.capgo.app/dashboard/apikeys. If the user already gave you a key, use it as-is and do not echo it back. In monorepos, add `--package-json`, `--main-file`, and `--capacitor-config`.
- const config: CapacitorConfig = {
- appId: 'com.yourapp.id',
- appName: 'Your App',
- webDir: 'dist',
- plugins: {
- CapacitorUpdater: {
- autoUpdate: true, // Enable automatic updates
- },
- },
- };
+ ### 3. Manual install (when not using `init`)
- export default config;
+ ```bash
+ npm install @capgo/capacitor-updater@latest # pick the tag from the Version Rule table
+ npx cap sync
+ npx @capgo/cli@latest app add com.example.app
```
- ### Advanced Configuration
+ Minimum config (`autoUpdate` defaults to `true`, which equals `"atBackground"`):
```typescript
- // capacitor.config.ts
plugins: {
CapacitorUpdater: {
autoUpdate: true,
- // Update behavior
- resetWhenUpdate: true, // Reset to built-in on native update
- updateUrl: 'https://api.capgo.app/updates', // Default
- statsUrl: 'https://api.capgo.app/stats', // Analytics
-
- // Channels
- defaultChannel: 'production',
-
- // Update timing
- periodCheckDelay: 600, // Check every 10 minutes (seconds)
- delayConditionsFail: false, // Don't delay on condition fail
-
- // Private updates (enterprise)
- privateKey: 'YOUR_PRIVATE_KEY', // For encrypted updates
},
},
```
- ## Implementing Updates
-
- ### Automatic Updates (Recommended)
-
- With `autoUpdate: true`, updates are automatic:
+ ### 4. Call `notifyAppReady()` immediately
```typescript
- // app.ts - Just notify when ready
import { CapacitorUpdater } from '@capgo/capacitor-updater';
- // Tell Capgo the app loaded successfully
- // This MUST be called within 10 seconds of app start
CapacitorUpdater.notifyAppReady();
```
- **Important**: Always call `notifyAppReady()`. If not called within 10 seconds, Capgo assumes the update failed and rolls back.
-
- ### Manual Updates
-
- For more control:
-
- ```typescript
- // capacitor.config.ts
- plugins: {
- CapacitorUpdater: {
- autoUpdate: false, // Disable auto updates
- },
- },
- ```
-
- ```typescript
- // update-service.ts
- import { CapacitorUpdater } from '@capgo/capacitor-updater';
-
- class UpdateService {
- async checkForUpdate() {
- // Check for available update
- const update = await CapacitorUpdater.getLatest();
-
- if (!update.url) {
- console.log('No update available');
- return null;
- }
-
- console.log('Update available:', update.version);
- return update;
- }
-
- async downloadUpdate(update: any) {
- // Download the update bundle
- const bundle = await CapacitorUpdater.download({
- url: update.url,
- version: update.version,
- });
-
- console.log('Downloaded:', bundle.id);
- return bundle;
- }
-
- async installUpdate(bundle: any) {
- // Set as next version (applies on next app start)
- await CapacitorUpdater.set(bundle);
- console.log('Update will apply on next restart');
- }
-
- async installAndReload(bundle: any) {
- // Set and reload immediately
- await CapacitorUpdater.set(bundle);
- await CapacitorUpdater.reload();
- }
- }
- ```
-
- ### Update with User Prompt
-
- ```typescript
- import { CapacitorUpdater } from '@capgo/capacitor-updater';
- import { Dialog } from '@capacitor/dialog';
-
- async function checkUpdate() {
- const update = await CapacitorUpdater.getLatest();
-
- if (!update.url) return;
-
- const { value } = await Dialog.confirm({
- title: 'Update Available',
- message: `Version ${update.version} is available. Update now?`,
- });
-
- if (value) {
- // Show loading indicator
- showLoading('Downloading update...');
-
- const bundle = await CapacitorUpdater.download({
- url: update.url,
- version: update.version,
- });
-
- hideLoading();
-
- // Apply and reload
- await CapacitorUpdater.set(bundle);
- await CapacitorUpdater.reload();
- }
- }
- ```
-
- ### Listen for Update Events
-
- ```typescript
- import { CapacitorUpdater } from '@capgo/capacitor-updater';
-
- // Update downloaded
- CapacitorUpdater.addListener('updateAvailable', (info) => {
- console.log('Update available:', info.bundle.version);
- });
-
- // Download progress
- CapacitorUpdater.addListener('downloadProgress', (progress) => {
- console.log('Download:', progress.percent, '%');
- });
-
- // Update failed
- CapacitorUpdater.addListener('updateFailed', (info) => {
- console.error('Update failed:', info.bundle.version);
- });
-
- // App ready
- CapacitorUpdater.addListener('appReady', () => {
- console.log('App is ready');
- });
- ```
-
- ## Deploying Updates
+ - Call it at the very top of the entry file, before any network call or async init. If it is not called within `appReadyTimeout` (default 10000 ms), the bundle is marked failed and the previous one is restored.
+ - Crashes or API errors after this call do **not** trigger a rollback.
+ - `bundle upload` checks for this call and fails with `notifyAppReady() is missing in the build folder (...)`. Fix the source. Only use `--ignore-notify-app-ready` / `--no-code-check` when the user accepts the rollback risk.
- ### Deploy via CLI
+ ### 5. Ship a bundle
```bash
- # Build your web app
npm run build
-
- # Upload to Capgo
- capgo upload
-
- # Upload to specific channel
- capgo upload --channel beta
-
- # Upload with version
- capgo upload --bundle 1.2.3
- ```
-
- ### Deploy via CI/CD
-
- #### GitHub Actions
-
- ```yaml
- # .github/workflows/deploy.yml
- name: Deploy to Capgo
-
- on:
- push:
- branches: [main]
-
- jobs:
- deploy:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - uses: actions/setup-node@v4
-
- - name: Install dependencies
- run: npm install
-
- - name: Build
- run: npm run build
-
- - name: Deploy to Capgo
- run: npx @capgo/cli bundle upload
- env:
- CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
- ```
-
- #### GitLab CI
-
- ```yaml
- # .gitlab-ci.yml
- deploy:
- stage: deploy
- image: node:20
- script:
- - npm install
- - npm run build
- - npx @capgo/cli bundle upload
- only:
- - main
- variables:
- CAPGO_TOKEN: $CAPGO_TOKEN
- ```
-
- ## Channels and Staged Rollouts
-
- ### Create Channels
-
- ```bash
- # Create beta channel
- capgo channel create beta
-
- # Create staging channel
- capgo channel create staging
- ```
-
- ### Deploy to Channels
-
- ```bash
- # Deploy to beta (internal testing)
- capgo upload --channel beta
-
- # Promote to production
- capgo upload --channel production
- ```
-
- ### Staged Rollout
-
- In Capgo dashboard:
- 1. Go to Channels > production
- 2. Set rollout percentage (e.g., 10%)
- 3. Monitor analytics
- 4. Increase to 50%, then 100%
-
- ### Device-Specific Channels
-
- ```typescript
- // Assign device to channel
- import { CapacitorUpdater } from '@capgo/capacitor-updater';
-
- // For beta testers
- await CapacitorUpdater.setChannel({ channel: 'beta' });
-
- // For production users
- await CapacitorUpdater.setChannel({ channel: 'production' });
- ```
-
- ## Rollback and Version Management
-
- ### Automatic Rollback
-
- If `notifyAppReady()` isn't called within 10 seconds, Capgo automatically rolls back to the previous working version.
-
- ### Manual Rollback
-
- ```bash
- # List available versions
- capgo bundle list
-
- # Rollback to specific version
- capgo bundle revert --bundle 1.2.2 --channel production
- ```
-
- ### In-App Rollback
-
- ```typescript
- // Get list of downloaded bundles
- const bundles = await CapacitorUpdater.list();
-
- // Rollback to built-in version
- await CapacitorUpdater.reset();
-
- // Delete a specific bundle
- await CapacitorUpdater.delete({ id: 'bundle-id' });
- ```
-
- ## Self-Hosted Option
-
- For enterprise or privacy requirements:
-
- ```bash
- # Install self-hosted Capgo
- docker run -d \
- -p 8080:8080 \
- -e DATABASE_URL=postgres://... \
- capgo/capgo-server
- ```
-
- Configure app to use self-hosted:
-
- ```typescript
- // capacitor.config.ts
- plugins: {
- CapacitorUpdater: {
- autoUpdate: true,
- updateUrl: 'https://your-server.com/updates',
- statsUrl: 'https://your-server.com/stats',
- },
- },
- ```
-
- ## Security
-
- ### Encrypted Updates
-
- For sensitive apps, enable encryption:
-
- ```bash
- # Generate key pair
- capgo key create
-
- # Upload with encryption
- capgo upload --key-v2
+ npx @capgo/cli@latest bundle upload com.example.app --path ./dist --channel production
```
- Configure in app:
-
- ```typescript
- // capacitor.config.ts
- plugins: {
- CapacitorUpdater: {
- autoUpdate: true,
- privateKey: 'YOUR_PRIVATE_KEY',
- },
- },
- ```
+ For instant-apply modes (`"atInstall"`, `"onLaunch"`, `"always"`), upload with `--delta` and set `autoSplashscreen: true` with `@capacitor/splash-screen` `launchAutoHide: false`. See `references/configuration.md`.
- ### Code Signing
+ ### 6. Decide OTA vs native before each release
- Verify updates are from trusted source:
+ OTA can only change web assets. A new or upgraded native plugin, a Capacitor bump, or an edit under `ios/`, `android/`, or native config needs a store build. Check with:
```bash
- # Sign bundle
- capgo upload --sign
-
- # Verify signature in app
- capgo key verify
- ```
-
- ## Monitoring and Analytics
-
- ### Dashboard Metrics
-
- In Capgo dashboard, view:
- - Active devices
- - Update success rate
- - Rollback rate
- - Version distribution
- - Error logs
-
- ### Custom Analytics
-
- ```typescript
- // Track custom events
- import { CapacitorUpdater } from '@capgo/capacitor-updater';
-
- // Get current bundle info
- const current = await CapacitorUpdater.current();
- console.log('Current version:', current.bundle.version);
-
- // Get download stats
- const stats = await CapacitorUpdater.getBuiltinVersion();
+ npx @capgo/cli@latest bundle releaseType com.example.app --channel production # prints OTA or native
```
- ## Troubleshooting
-
- ### Issue: Updates Not Applying
+ `releaseType` compares native package metadata only. It cannot see raw edits under `ios/` or `android/`.
- 1. Check `notifyAppReady()` is called
- 2. Verify app ID matches Capgo dashboard
- 3. Check channel assignment
- 4. Review Capgo dashboard logs
+ ## Traps
- ### Issue: Rollback Loop
+ - **Store compliance:** OTA may change only interpreted web code and assets, and must not change the app's primary purpose. This comes from the interpreted-code clause in Apple's Developer Program License Agreement, App Review Guideline 2.5.2, and Google Play's Device and Network Abuse policy. Never use OTA to ship features that need review, and do not force an update to block app usage.
+ - **Privacy manifest:** iOS needs `NSPrivacyAccessedAPICategoryUserDefaults` with reason `CA92.1` in `PrivacyInfo.xcprivacy`.
+ - **Config key is `publicKey`, not `privateKey`.** The private key (`.capgo_key_v2`) stays with the uploader and must never be in the app or the repo.
+ - **`resetWhenUpdate` (default `true`)** clears downloaded bundles when a new native build is installed. If you disable it, a store build older than the OTA bundle can break things.
+ - **Testing on a dev build:** a channel blocks dev, emulator, or prod devices by flag (`disable_dev_build`, `disable_emulator`, ...). Check the channel options before you assume the plugin is broken.
+ - **Live reload (Ionic/Quasar):** the updater does not serve live-reload URLs. Turn live reload off when testing updates.
+ - **`set()` destroys the JS context.** No code after it runs. Prefer `next()` to apply on the next background.
+ - **Encryption is not secrecy:** an unencrypted bundle is a public web asset. Encryption protects storage and delivery, but the public key ships in the app. See `capgo-release-management` for `key create` / `key save`.
- 1. App crashes before `notifyAppReady()`
- 2. Fix: Ensure `notifyAppReady()` is called early
- 3. Temporarily disable updates to debug
+ ## Verification
- ### Issue: Slow Downloads
+ 1. `npx @capgo/cli@latest doctor` shows the installed updater version and flags anything outdated.
+ 2. `grep -rn "notifyAppReady" src/` finds exactly one early call in the entry point.
+ 3. `npx cap sync` succeeds, then build and install the native app once on a real device.
+ 4. Upload a visibly changed bundle. Run `npx @capgo/cli@latest app debug com.example.app` while you background and reopen the app. The log should show the check, the download, and `set`.
+ 5. `npx @capgo/cli@latest probe --platform ios` (or `android`) reports whether the backend would deliver an update to this config and explains why not.
- 1. Enable delta updates (automatic)
- 2. Optimize bundle size
- 3. Use CDN (enterprise)
+ ## Error Handling
- ## Best Practices
+ | Symptom / string | Fix |
+ | --- | --- |
+ | `notifyAppReady() is missing in the build folder` | Add the call to the entry point, rebuild, then upload again |
+ | `index.html is missing in the root folder of <dir>` | `--path` points at the wrong folder. Use the built `webDir` |
+ | `no_new_version_available` | Normal: the device is already current |
+ | `disable_auto_update_to_major` / `_minor` / `_patch` | Channel strategy blocks the jump. Align `CapacitorUpdater.version` or change `--disable-auto-update` |
+ | `cannot_update_via_private_channel` | Enable self-assign on the channel (`channel set <ch> --self-assign`) |
+ | `on_premise_app` (HTTP 429) | The `appId` is not in Capgo, the app is flagged on-prem, or the plan is cancelled |
+ | Update downloads then reverts on next launch | `notifyAppReady()` ran too late or not at all, or the bundle throws before it runs |
- 1. **Always call `notifyAppReady()`** - First thing after app initializes
- 2. **Test updates on beta channel first** - Never push untested to production
- 3. **Use semantic versioning** - Makes rollback easier
- 4. **Monitor rollback rate** - High rate indicates quality issues
- 5. **Implement error boundary** - Catch crashes before rollback
- 6. **Keep native code stable** - Native changes need app store
+ The full code list is in `references/troubleshooting.md`.
## Resources
- - Capgo Documentation: https://capgo.app/docs
- - Capgo Dashboard: https://web.capgo.app
- - Plugin GitHub: https://github.com/Cap-go/capacitor-updater
- - Discord Community: https://discord.gg/capgo
+ - Getting started: https://capgo.app/docs/getting-started/add-an-app/
+ - Plugin settings: https://capgo.app/docs/plugins/updater/settings/
+ - Plugin API: https://capgo.app/docs/plugins/updater/api/
+ - Update behavior: https://capgo.app/docs/live-updates/update-behavior/
+ - Common problems: https://capgo.app/docs/plugins/updater/commonproblems/