Targeting iOS vs Android with OTA updates
Sometimes a fix only applies to one platform. When and how to ship platform-specific Capacitor live updates for iOS and Android separately using channels and runtime versions.
Most of the time you ship one web bundle to both platforms and it just works — that's the whole appeal of Capacitor. But occasionally a fix or a feature only applies to iOS or only to Android: a platform-specific CSS quirk, a workaround for one WebView, a feature gated to one store. This guide covers when and how to target iOS vs Android with Capacitor live updates using OtaKit.
Reach for platform-specific updates rarely. If you can solve it with a runtime Capacitor.getPlatform() check inside one shared bundle, do that first — it's simpler and keeps both platforms on one release.
Option 1: branch inside one bundle (preferred)
Ship the same bundle everywhere and branch at runtime. This keeps a single release stream and is almost always the right answer for small differences:
import { Capacitor } from '@capacitor/core';
if (Capacitor.getPlatform() === 'ios') {
applyIosWorkaround();
} else if (Capacitor.getPlatform() === 'android') {
applyAndroidWorkaround();
}The change ships over the air to both platforms; each device runs its own branch. No extra channels, no divergence to manage.
Option 2: separate channels per platform
When the platforms genuinely diverge — different feature sets, different release cadences — give each its own channel. Configure iOS builds to follow production-ios and Android builds production-android, then release to each independently:
otakit upload --release production-ios otakit upload --release production-android
This is more to manage — two streams to keep in sync — so use it only when the divergence is real. See Channels & runtime version.
Watch the native compatibility boundary
Platform differences often trace back to different native shells. If your iOS and Android binaries ship different plugin versions, that's a runtime version concern, not just a channel one — a bundle should only reach shells it's compatible with. See semantic versioning for bundles.
The maintenance cost of two channels is the same as the cost of any fork: every future change has to consider both. Merge them back to a single channel as soon as the platform-specific reason goes away.
Where to go next
See targeting users with channels for the broader channel patterns and Plugin API for platform detection.