Diagnosing Capacitor Live Reload Failures on Physical iOS and Android Devices
Step-by-step diagnostic guide for Capacitor Live Reload failing on physical iOS/Android devices — covers network, firewall, config, HTTPS, and corporate Wi-Fi isolation with ordered verification commands.
21 Jan 2026, 11:42 UTC

The Problem
You run ionic cap run ios -l --external or ionic cap run android -l --external. The build succeeds, the app installs, but on the physical device you see a blank screen, "connection refused," or "unable to connect to dev server." The same command works fine in the simulator or emulator. This guide walks through the most common causes in order of likelihood, with verification steps you can run from your development machine.
Quick Cause Reference
| Symptom | Likely Cause | Quick Test |
|---|---|---|
| Blank screen / connection refused | Device and dev machine on different LANs or subnets | ping <device-ip> from dev machine and vice versa |
| Timeout on port 8100 | Firewall blocking the dev server port | nc -zv <dev-machine-ip> 8100 from device (via Termux/SSH) or dev machine |
| App loads but no live reload badge | capacitor.config.ts server.url set to localhost | Inspect capacitor.config.ts — value must be LAN IP |
| "Cleartext traffic not permitted" (Android) or cert warning (iOS 17+) | OS enforces HTTPS for live reload; self-signed cert not trusted | Check adb logcat or Safari Web Inspector console |
| Works on home Wi-Fi, fails on office Wi-Fi | AP isolation / client isolation on corporate network | iperf3 -c <dev-machine-ip> -p 8100 or nc test |
Ordered Verification Steps
1. Confirm Both Devices Share a LAN
Run ping <device-ip> from your development machine. Then, from the device (use Termux on Android, or a ping app on iOS), ping your dev machine's LAN IP (e.g., 192.168.1.42). Both must succeed. If either fails, you are on different subnets, a guest network, or a VPN is isolating traffic.
Fix: Join the same Wi-Fi SSID, disable VPN on the dev machine, or use USB tethering (see step 6).
2. Test Port 8100 Reachability
On the dev machine, start the dev server: ionic serve --host=0.0.0.0 --port=8100. Then from the device (or another machine on the same LAN), run:
nc -zv 192.168.1.42 8100Replace 192.168.1.42 with your dev machine's actual LAN IP. You should see succeeded!. If it times out, a firewall is blocking inbound TCP on port 8100.
Fix (Linux/macOS): sudo ufw allow 8100/tcp or sudo firewall-cmd --add-port=8100/tcp --permanent.
Fix (Windows): Create an Inbound Rule in Windows Defender Firewall for TCP port 8100, scoped to your LAN subnet.
3. Ensure capacitor.config.ts Points to LAN IP
Open capacitor.config.ts and locate the server block. It must use your machine's LAN IP, not localhost or 127.0.0.1:
server: {
url: 'http://192.168.1.42:8100',
cleartext: true
}After changing this, run ionic cap copy ios (or android) — cap sync alone does not rewrite the native server.url value. Then rebuild the native project (xcodebuild or ./gradlew assembleDebug).
4. Launch with Explicit Bind Address
Always start the dev server binding to all interfaces:
ionic cap run android -l --external --host=0.0.0.0 --port=8100Omitting --host=0.0.0.0 causes Ionic CLI ≤7.1 to bind only to localhost, making the server unreachable from the device. Ionic CLI 7.2+ defaults to 0.0.0.0 when --external is used, but being explicit avoids version surprises.
5. Handle HTTPS / Cleartext Requirements
iOS 17+: Live reload over plain HTTP is rejected unless you configure NSAllowsArbitraryLoads and NSExceptionDomains in Info.plist. The simpler path: generate a locally trusted certificate with mkcert and run:
mkcert -install
mkcert 192.168.1.42
ionic cap run ios -l --external --ssl --ssl-cert=192.168.1.42.pem --ssl-key=192.168.1.42-key.pemInstall the mkcert root CA on the iOS device (Settings → General → VPN & Device Management → Profile).
Android 13+ (Capacitor 6.1+): cleartext: true in capacitor.config.ts auto-generates android:usesCleartextTraffic="true" in AndroidManifest.xml. For Capacitor ≤6.0, edit android/app/src/main/AndroidManifest.xml manually:
<application
android:usesCleartextTraffic="true"
...>6. USB Tethering Fallback (When Wi-Fi Fails)
If the network cannot be fixed (corporate AP isolation, no shared LAN), tunnel over USB.
Android: Enable USB debugging, then run adb reverse tcp:8100 tcp:8100. The device now reaches the dev server at http://10.0.2.2:8100 (emulator) or http://localhost:8100 (physical device via reverse). Update capacitor.config.ts server.url accordingly and re-copy.
iOS: Requires rvictl (part of Xcode) to create a virtual network interface: rvictl -s <device-udid>. This creates rvi0 with an IP like 192.168.65.x. Bind the dev server to that interface (--host=192.168.65.1) and update server.url. Note: rvictl is fragile on macOS 14+; prefer Wi-Fi when possible.
Escalation Criteria
Engage your platform/infrastructure team when:
- WebSocket upgrade fails —
ionic serve --verboseshowsws://handshake errors despite all checks passing. This often indicates a proxy or load balancer strippingUpgradeheaders. - Corporate AP isolation confirmed —
pingworks butnc/iperf3to port 8100 fails. IT must allow device-to-device traffic on the SSID or provision a dev VLAN. - Capacitor version mismatch —
@capacitor/cliand@capacitor/corediffer by more than one minor version. Runnpm ls @capacitor/cli @capacitor/core, align versions, thenionic cap sync.
Verification Checklist (Run After Each Fix)
ionic cap run android -l --external --host=0.0.0.0 --port=8100→ device shows app with live reload badge (🔄) in corner.adb logcat | grep -E 'Capacitor|LiveReload|WebSocket'→ showsConnected to live reload server.- On iOS, open Safari Web Inspector (Develop → Device → App) → Console shows
[LiveReload] Connectedwithout certificate warnings. - Edit a
.tsxfile → device updates within 2 seconds without full reload. - Confirm
capacitor.config.tsserver.urlmatchesipconfig getifaddr en0(macOS) orip route get 1 | awk '{print $7}'(Linux).
Limitations & Risks
- Exposing dev server to LAN:
--host=0.0.0.0 --externalbinds to all interfaces. Do not use on untrusted networks (coffee shops, open offices). Bind to a specific interface IP (--host=192.168.1.42) instead. - Self-signed certs:
mkcertrequires installing the root CA on every device. Not practical for CI device farms. - iOS USB debugging:
rvictl+ios-webkit-debug-proxybreaks frequently on macOS 14+; treat as last resort. - Config changes require native rebuild: Modifying
server.urlorcleartextneedsionic cap copy <platform>followed by a full native build —cap syncis insufficient.
Version Assumptions
This guide assumes Ionic CLI 7.x, Capacitor 6.x, Node 20 LTS, iOS 16+/Android 13+ physical devices. Behavior differs on older versions: Capacitor ≤6.0 requires manual AndroidManifest.xml edits for cleartext; Ionic CLI ≤7.1 binds to localhost by default even with --external.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.