Pick the log channel that actually carries the message you need, filter to the app, capture to a file, hand off to diagnosis.
When to Use
TRIGGER when:
- User asks how to view, stream, filter, or save device/simulator logs.
console.logoutput or⚡️Capacitor lines are missing on iOS/Android.- User needs a crash report (
.ips, tombstone, ANR) from a device or simulator. - Logcat or the unified log is too noisy; user wants only their app or plugin.
- A log command fails or misbehaves:
--level errorstill shows everything,unable to find utility "devicectl",Error: Unexpected argument 'log',adb: no devices/emulators found.
Do not use:
- Interpreting the error and fixing the app ->
debugging-capacitor. - Production crash/ANR reporting (Sentry, Crashlytics, Datadog) ->
capacitor-native-observability. - AI agent log streaming via MCP servers ->
capacitor-mcp. - CPU/memory profiling ->
capacitor-performance. - UIScene lifecycle migration ->
capacitor-uiscene-migration.
Where Capacitor Output Goes (the main trap)
| Source | iOS | Android |
|---|---|---|
Capacitor bridge messages (⚡️ Loading app at ..., ⚡️ To Native ->, errors) |
stdout only (print) |
logcat tag Capacitor and Capacitor/<Sub> |
JS console.log/warn/error mirrored natively |
stdout as ⚡️ [log] - ... |
logcat tag Capacitor/Console as File: ... - Line N - Msg: ... |
| JS console, full fidelity (objects, stack traces) | Safari Web Inspector | chrome://inspect |
Plugin/app code using os.Logger / NSLog |
unified log (Console.app, log stream) |
n/a |
Plugin code using android.util.Log / Capacitor Logger |
n/a | logcat |
| Native crash | .ips crash report |
FATAL EXCEPTION in logcat + crash buffer; tombstone for native code |
Consequences:
- On iOS, Console.app and
log streamwill not show Capacitor's⚡️lines or mirrored JS console. Use Xcode's console,xcrun simctl launch --console-pty, orxcrun devicectl device process launch --console. - Mirroring obeys
loggingBehavior(none|debug|production, defaultdebug): Release builds produce no Capacitor logs unless set toproduction. - The iOS process name is the executable (
Appin the Capacitor template), not the display name. Filter withprocess == "App".
Quick Commands
# iOS Simulator: Capacitor + JS console (stdout), relaunching the app
xcrun simctl launch --console-pty --terminate-running-process booted com.example.app
# iOS Simulator: unified log for the app (os_log / NSLog / system messages)
xcrun simctl spawn booted log stream --level debug --predicate 'process == "App"'
# iPhone: install + launch with stdout attached (Xcode 15+ devicectl)
xcrun devicectl list devices
xcrun devicectl device process launch --console --terminate-existing --device <id> com.example.app
# iPhone: unified log snapshot of the last 10 minutes
sudo log collect --device-udid <udid> --last 10m --output /tmp/iphone.logarchive
log show /tmp/iphone.logarchive --predicate 'process == "App"' --info --debug
# Android: only this app (re-run after each app restart, PID changes)
adb logcat --pid="$(adb shell pidof -s com.example.app)"
# Android: Capacitor + JS console only
adb logcat -s Capacitor:V Capacitor/Console:V
# Android: crashes only
adb logcat -b crash
Procedure
- Identify target: Simulator/emulator vs physical device; Debug vs Release; which layer emitted the message (table above).
- Check connectivity:
xcrun simctl list devices booted,xcrun devicectl list devices(device must be unlocked, trusted, Developer Mode on),adb devices -l. - Clear and reproduce:
adb logcat -con Android; on iOS start the stream before relaunching the app. - Filter early by process/PID, then by subsystem/tag, then by text. Never paste unfiltered system logs into a conversation.
- Save to a file (
> app.log,.logarchive,adb bugreport) when the user needs to share it; redact tokens, emails, and auth headers before sharing outside the team. - Hand off the relevant lines to
debugging-capacitorfor root-cause work.
Error Handling
| Message | Fix |
|---|---|
--level error still shows every message |
log stream --level only understands default, info, debug (it sets the floor, not a ceiling). Filter errors with --predicate 'messageType == error OR messageType == fault'. |
xcrun: error: unable to find utility "devicectl" |
Active dev dir is Command Line Tools. sudo xcode-select -s /Applications/Xcode.app/Contents/Developer. |
Error: Unexpected argument 'log' (devicectl) |
devicectl has no log streaming subcommand. Use --console for stdout, Console.app or log collect --device-udid for unified logs. |
log collect fails with a permission error |
Run with sudo; device must be unlocked and trusted. |
No devices are booted. (simctl) |
xcrun simctl boot "<device name>" or open Simulator. |
adb: no devices/emulators found / unauthorized |
Enable USB debugging, accept the RSA prompt, adb kill-server && adb start-server. |
adb logcat --pid= prints everything / errors |
App not running so pidof returned nothing. Launch the app first. |
No Capacitor/Console lines on Android |
loggingBehavior: 'none', or Release build with default debug. |
JS logs show but objects print as [object Object] |
Native mirroring stringifies; use the WebView inspector for structured output. |
Verification
- iOS sim: launch with
--console-pty, see⚡️ Loading app at capacitor://localhostand a testconsole.log('log-check')as⚡️ [log] - log-check. - iOS device: same via
devicectl device process launch --console. - Android:
adb logcat -s Capacitor/Console:VshowsMsg: log-check. - Unified log: a plugin
Logger(subsystem: "com.example.app", category: "test").info("log-check")appears with--predicate 'subsystem == "com.example.app"' --level info.
References
Only load a reference when its topic is in play.
| File | Load when |
|---|---|
references/ios-logs.md |
Unified log predicates, Console.app, log collect/log show, iOS crash reports via devicectl/Xcode, adding os.Logger to a plugin |
references/android-logs.md |
logcat buffers/formats/filters, Android Studio Logcat queries, ANRs, tombstones, bugreports, WebView (chromium) noise |