npx skills add ...
npx skills add cap-go/capgo-skills --skill debugging-capacitor
Comprehensive debugging guide for Capacitor applications. Covers WebView debugging, native debugging, crash analysis, network inspection, and common issues. Use this skill when users report bugs, crashes, or need help diagnosing issues.
npx skills add cap-go/capgo-skills --skill debugging-capacitor
Complete guide to debugging Capacitor apps on iOS and Android.
| Platform | WebView Debug | Native Debug | Logs |
|---|---|---|---|
| iOS | Safari Web Inspector | Xcode Debugger | Console.app |
| Android | Chrome DevTools | Android Studio | adb logcat |
Enable on device:
Enable in Xcode (capacitor.config.ts):
Connect Safari:
Debug:
Connect Chrome:
chrome://inspectDebug features:
Install "Debugger for Chrome" extension:
Set breakpoints:
breakpoint set --name methodName in LLDBRun with debugger:
LLDB Console commands:
Attach debugger:
Set breakpoints:
Debug console:
package:com.yourappDiagnosis:
Common causes:
Solution checklist:
npx cap synccd ios/App && pod installError: Error: "MyPlugin" plugin is not implemented on ios/android
Diagnosis:
Solutions:
npm install @capgo/plugin-namenpx cap syncDiagnosis:
Common causes:
Diagnosis:
iOS: Check Info.plist has usage descriptions:
Android: Check AndroidManifest.xml:
Diagnosis:
dist/ folder existswebDir in capacitor.config.tsSolutions:
Diagnosis:
iOS: Check Associated Domains entitlement and apple-app-site-association file.
Android: Check intent filters in AndroidManifest.xml.
Use Chrome DevTools Memory tab:
Add to build.gradle:
When debugging issues:
rm -rf node_modules && npm install)const config: CapacitorConfig = {
android: {
webContentsDebuggingEnabled: true,
},
};// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "attach",
"name": "Attach to Android WebView",
"port": 9222,
"webRoot": "${workspaceFolder}/dist"
}
]
}npx cap open ios# Print variable
po myVariable
# Print object description
p myObject
# Continue execution
continue
# Step over
next
# Step into
step
# Print backtrace
btnpx cap open android# Evaluate expression
myVariable
# Run method
myObject.toString()// Basic logging
console.log('Debug info:', data);
console.warn('Warning:', issue);
console.error('Error:', error);
// Grouped logs
console.group('API Call');
console.log('URL:', url);
console.log('Response:', response);
console.groupEnd();
// Table format
console.table(arrayOfObjects);
// Timing
console.time('operation');
// ... operation
console.timeEnd('operation');import os.log
let logger = Logger(subsystem: "com.yourapp", category: "MyPlugin")
// Log levels
logger.debug("Debug message")
logger.info("Info message")
logger.warning("Warning message")
logger.error("Error message")
// With data
logger.info("User ID: \(userId)")
// Legacy NSLog (shows in Console.app)
NSLog("Legacy log: %@", message)import android.util.Log
// Log levels
Log.v("MyPlugin", "Verbose message")
Log.d("MyPlugin", "Debug message")
Log.i("MyPlugin", "Info message")
Log.w("MyPlugin", "Warning message")
Log.e("MyPlugin", "Error message")
// With exception
Log.e("MyPlugin", "Error occurred", exception)# iOS - Check crash logs
xcrun simctl spawn booted log stream --level debug | grep -i crash
# Android - Check logcat
adb logcat *:E | grep -i "fatal\|crash"import { Capacitor } from '@capacitor/core';
// Check if plugin exists
console.log('Plugins:', Capacitor.Plugins);
console.log('MyPlugin available:', !!Capacitor.Plugins.MyPlugin);// Add request interceptor
const originalFetch = window.fetch;
window.fetch = async (...args) => {
console.log('Fetch:', args[0]);
try {
const response = await originalFetch(...args);
console.log('Response status:', response.status);
return response;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
};<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>server: {
cleartext: true, // Only for development!
}import { CapacitorHttp } from '@capacitor/core';
const response = await CapacitorHttp.request({
method: 'GET',
url: 'https://api.example.com/data',
});import { Permissions } from '@capacitor/core';
// Check permission status
const status = await Permissions.query({ name: 'camera' });
console.log('Camera permission:', status.state);<key>NSCameraUsageDescription</key>
<string>We need camera access to scan documents</string><uses-permission android:name="android.permission.CAMERA" /># Rebuild web assets
npm run build
# Sync to native
npx cap sync
# Check config
cat capacitor.config.tsimport { App } from '@capacitor/app';
App.addListener('appUrlOpen', (event) => {
console.log('Deep link:', event.url);
});// Mark performance
performance.mark('start');
// ... operation
performance.mark('end');
performance.measure('operation', 'start', 'end');
const measures = performance.getEntriesByName('operation');
console.log('Duration:', measures[0].duration);# Run with Leaks instrument
xcrun instruments -t Leaks -D output.trace YourApp.appdebugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'