Capacitor Apps: Leveraging Ionic Appflow for Live Updates
Anyone who’s shipped a mobile app knows the review cycle problem.
You find a bug. You fix it in an hour. Then you wait. Apple’s review takes two days, sometimes more. Google Play has tightened its review process considerably over the past couple of years — new apps can sit for a week. By the time users get the fix, they’ve either given up, left a one-star review, or both.
Ionic Appflow’s Live Updates solves the specific category of fixes and updates that don’t touch native code. UI changes, logic fixes, content updates, new JavaScript-based features — these can ship directly to users without going through the app store review cycle at all. This guide covers the implementation: SDK setup, configuration options, how the different update strategies actually behave, and the Appflow dashboard setup required to make deploys work end-to-end.
Key Takeaways
- Live Updates works by updating the web layer of a Capacitor app — the HTML, CSS, and JavaScript — without requiring a new binary submission. Native code changes still go through the app stores.
- The SDK offers four auto-update strategies with meaningfully different user experience tradeoffs. Background is the most conservative; Force Update applies immediately on launch. Understanding which one fits your update patterns matters before you pick.
- autoUpdateMethod: ‘none’ combined with programmatic SDK calls gives you full control over when syncs happen and when reloads are triggered. The “always latest” pattern covered here uses this approach.
- Appflow channels are the targeting mechanism — you configure your app binary to listen to a specific channel, and deploying a web build to that channel is what triggers the update distribution.
- Live updates are limited to web layer changes. If your update touches a native plugin, a native module, or any platform-specific configuration, it needs a binary release through the app stores.
Installation and SDK Configuration
Start by installing the Live Updates SDK and syncing the native projects:
npm install @capacitor/live-updates
npx cap syncnpx cap sync copies the updated native bridge files into your iOS and Android projects. Don’t skip it — the native projects need to know about the new plugin.
Next, configure the SDK in your capacitor.config.ts:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
plugins: {
LiveUpdates: {
appId: 'xxxxxx', // Your unique app ID
channel: ‘Production’, // Deployment channel
autoUpdateMethod: ‘none’, // Method for automatic updates
maxVersions: 5 // Maximum number of versions to keep
}
}
};
export default config;export default config;
A few things worth clarifying here.
appId is the identifier from your Appflow dashboard — not your app’s bundle ID. Get it from the app settings page after you’ve set up the app in Appflow.
channel is how you target different user populations. A single Appflow account can have multiple channels: Production, Staging, Beta. The binary you ship to the App Store listens to whichever channel you configure here. Setting it to ‘Production’ means only builds assigned to the Production channel will be delivered to this binary.
autoUpdateMethod: ‘none’ tells the SDK not to handle updates automatically. We’re going to manage the sync and reload logic ourselves, which gives more control over when updates apply relative to the app’s state. The next section explains why this matters.
maxVersions: 5 limits the number of update bundles cached on device. If 5 cached versions seems like too many, 2 or 3 is usually sufficient.
Auto Update Methods
Appflow offers four update strategies. They differ in when the update downloads and when it actually applies — and those are two separate moments that you can control independently.
Background (Recommended for most apps)
The update downloads while the user is actively using the current version. Nothing interrupts them. The next time the app launches, the new version loads. The user never sees a loading state related to the update, and the switch happens at a natural restart point.
This is the least disruptive option and works well for most apps. The tradeoff: there’s a potential lag of one app session before users are on the latest version.
Always Latest
Similar to Background in that the download happens while the app is in use. The difference is the trigger for applying the update — with Always Latest, the reload happens the next time the app comes to the foreground from the background, not just on a full relaunch. This tightens the window between a deploy and users running the updated version.
The risk is that users can experience a reload at an unexpected moment — they switch apps briefly, come back, and the app reloads. Depending on what state the user was in, this can be jarring.
Force Update
Get Sahil Khurana’s stories in your inbox
Join Medium for free to get updates from this writer.
Applies the update immediately on the next app launch. The splash screen stays up while the update installs, then the app starts fresh with the new version. No lag at all between deploy and all users running the update.
The experience cost is a slower perceived launch time on first open after an update. For critical fixes — a security patch, a broken checkout flow — the tradeoff is usually worth it. For routine feature updates, it isn’t.
None
The SDK doesn’t check for or apply updates automatically. All update logic is handled programmatically through the SDK’s API. This is what we’re using in the implementation example below — it gives the most control and lets you make the update behavior context-aware.
Set up and Configuration on AppFlow Dashboard
Before deploys work, the Appflow side needs to be configured.
1. Create an account and app
Go to Appflow and create an account. There’s a free tier suitable for testing. Once logged in, create a new app. You can import from an existing GitHub repository — connect your GitHub account, select the repo, and Appflow handles the rest.
2. Get your App ID
After the app is created, the App ID appears in the app settings. Copy this and put it in capacitor.config.ts as the appId value.
3. Create a web build
Live Updates deploys web builds — the compiled output of your app’s web layer. In the Appflow dashboard, click New Build, select a commit from your repository, and choose Web as the target platform.
4. Assign the build to a channel
After the build finishes, assign it to a deployment channel. If you haven’t created a channel yet, there’s a default Production channel. You can create additional channels (Staging, Beta) from the Channels section of the dashboard.
When a web build is assigned to a channel, any app binary configured to listen to that channel will receive the update on its next sync.
Implement Live Updates in Your App
The programmatic approach gives you control over the sync and reload timing. The implementation below uses the “always latest” pattern: check for updates on app load and on every foreground event, reload as soon as an update has been downloaded and the app is available.
First, install the Capacitor App plugin — you need it for the appStateChange event:
npm install @capacitor/app
npx cap syncThen, in your app’s main component:
import { Component, OnInit } from '@angular/core';
import { App } from '@capacitor/app';
import * as LiveUpdates from '@capacitor/live-updates';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent implements OnInit {
constructor() {}
async ngOnInit() {
await this.initializeApp();
}
async initializeApp() {
try {
// Register an event to fire each time the app resumes
App.addListener('appStateChange', async (state) => {
if (state.isActive && localStorage.getItem('shouldReloadApp') === 'true') {
await LiveUpdates.reload();
} else {
const result = await LiveUpdates.sync();
localStorage.setItem('shouldReloadApp', result.activeApplicationPathChanged.toString());
}
});
// Initial sync on app load
const result = await LiveUpdates.sync();|
localStorage.setItem('shouldReloadApp', result.activeApplicationPathChanged.toString());
} catch (error) {
console.error('Error initializing app', error);
}
}
}How this works:
On every app load, LiveUpdates.sync() checks the configured Appflow channel for a newer web build. If one exists, it downloads it in the background. The activeApplicationPathChanged property on the result tells you whether a new version was downloaded — true means a new build is ready, false means the current version is already the latest.
That value gets stored in localStorage as shouldReloadApp.
The appStateChange listener fires whenever the app moves between foreground and background. When the app comes to the foreground (state.isActive === true), it checks shouldReloadApp. If true, it calls LiveUpdates.reload() — which reloads the web layer with the newly downloaded bundle. If false, it runs another sync to check for updates released since the last check.
The practical result: users are on the latest version within one foreground session of a deploy. They never experience a mid-session reload — the reload only happens when they bring the app to the foreground, at which point they’re expecting the app to respond rather than being in the middle of a flow.
Conclusion
Appflow Live Updates removes the app store review cycle from the critical path for web layer changes. The SDK configuration is lightweight, the programmatic control is flexible, and the update strategies cover the range from maximally conservative to immediately applied.
The implementation above — programmatic sync with foreground-triggered reload — gives a good balance between keeping users current and not interrupting them mid-session. Adjust the strategy based on how frequently your app updates and how important it is that users are always on the latest version.
About Innostax
Innostax specializes in managed engineering teams and was founded in 2014, and is headquartered in Framingham, Massachusetts. We establish engineering teams with accountability as a priority for both startups and enterprises, helping them achieve consistent software velocity with no customer churn.
Read more : Capacitor Apps: Leveraging Ionic Appflow for Live Updates










