Debugging Cordova Apps
Here's the good news: a Cordova app's UI is just HTML, CSS, and JavaScript rendered inside a
WebView, which means you already own the single best tool for debugging it — the browser
developer tools you've been using for ordinary websites all along. You don't need a specialized
"Cordova debugger." What you do need is a way to point those familiar dev tools at the
WebView running inside a real device or emulator, since that's the environment your users will
actually experience, quirks and all. This page walks through remote debugging on Android via
Chrome, remote debugging on iOS via Safari, the humble console.log(), falling back
to native device logs, and a short guide to isolating plugin-specific problems.
Remote Debugging Android with Chrome DevTools
Since Cordova's Android WebView is (on modern devices) backed by Chromium, desktop Chrome can attach to it directly over a USB connection and give you the full DevTools experience — Elements, Console, Network, Sources with breakpoints, all of it — pointed at the exact WebView your app is running. The walkthrough:
| Step | What to do |
|---|---|
| 1 | On the Android device (or emulator), open Settings → About phone and tap "Build number" seven times to unlock Developer options, then open Developer options and enable USB debugging |
| 2 | Connect the device to your development machine with a USB cable (an emulator running in Android Studio is already "connected" and doesn't need a cable) |
| 3 | Run your app on the device, either from Android Studio or with cordova run android |
| 4 | On the same machine, open desktop Chrome and navigate to chrome://inspect#devices |
| 5 | Accept the "Allow USB debugging?" prompt that appears on the device the first time you connect |
| 6 | Your running app's WebView appears in the device list on the chrome://inspect page — click its inspect link to open a full DevTools window attached to it |
Once that DevTools window is open, treat it exactly like inspecting any web page: set breakpoints in the Sources panel, watch network requests, inspect the live DOM, and read whatever your code prints to the console — all reflecting the actual app running on the actual device.
Remote Debugging iOS with Safari's Web Inspector
iOS uses the same idea through Safari instead of Chrome, though the setup requires a Mac (Xcode and Safari's developer tooling aren't available on Windows or Linux). In brief:
| Step | What to do |
|---|---|
| 1 | On the iOS device, go to Settings → Safari → Advanced and enable Web Inspector |
| 2 | On the Mac, open Safari's Develop menu (enable it first via Safari → Preferences → Advanced → Show Develop menu in menu bar if it isn't visible) |
| 3 | Connect the iOS device via USB (or use the iOS Simulator, which appears automatically) and run your Cordova app on it via Xcode or cordova run ios |
| 4 | In Safari's Develop menu, find your device's name, then select the running app's WebView from the submenu that appears underneath it |
| 5 | The Web Inspector opens, attached to that WebView, with the same Elements/Console/Network/Sources tools you'd expect |
console.log() — Your Fastest Tool
Both remote debugging setups above surface anything your code writes with console.log()
in the attached DevTools/Web Inspector console, which makes it the fastest way to sanity-check a
value, confirm a callback actually fired, or trace how far execution got before something broke
— often faster than setting a formal breakpoint.
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
console.log('deviceready fired, platform: ' + device.platform);
navigator.camera.getPicture(onCameraSuccess, onCameraError, { quality: 75 });
}
function onCameraSuccess(imageData) {
// If this never prints, the plugin callback isn't firing at all
console.log('Camera success, data length: ' + imageData.length);
}
function onCameraError(message) {
console.error('Camera error: ' + message);
}
console.log() calls at the boundaries of anything asynchronous — plugin callbacks, network requests, event listeners — so a glance at the console tells you exactly how far execution got before things went wrong.Viewing Native Logs (adb logcat)
Sometimes a problem happens below the WebView entirely — a native crash, a plugin's native
code throwing an exception, or the app failing to even reach the point where a WebView console
exists. For Android, adb logcat reads the device's full native log stream and is
your fallback when the Chrome DevTools inspector isn't enough (or the app crashed before you
could attach it):
adb logcat
That firehose includes every process on the device, so it helps to filter it down to just your app's messages and Cordova's own tag:
adb logcat -s CordovaLog:V chromium:V AndroidRuntime:E
console.log() calls from your JavaScript are actually mirrored into logcat under the
CordovaLog (or chromium) tag, so this same command doubles as a way to
watch your JS console output without Chrome attached at all — handy for a quick check on a
device that isn't near your development machine's USB port.
The "It Only Works in the Browser Platform" Gotcha
Cordova supports a browser platform that runs your www/ app directly in
a desktop browser tab, which is genuinely convenient for rapid UI iteration — no build, no
device, instant reload. The gotcha is that it's a WebView in name only: most Cordova core and
community plugins either don't run there at all or fall back to browser-native stand-ins that
behave differently from the real native plugin. A camera call might just open the desktop's file
picker instead of the actual camera hardware, for example.
browser platform is fine for laying out screens and wiring up non-native logic, but never call a feature "done" until you've run it on a real device or a real Android emulator/iOS simulator. Plugin availability, permission prompts, and WebView rendering quirks are all things the desktop browser simply can't reproduce.Debugging Plugin-Specific Issues
When a plugin misbehaves — a callback never fires, a method throws "undefined is not a function," or results look wrong — work through these checks roughly in order:
| Check | What it tells you |
|---|---|
| Is the plugin actually installed? | Run cordova plugin ls from the project root and confirm the plugin ID and version you expect are actually listed — it's easy to assume a plugin is installed when it was only ever added to a different, abandoned project folder |
Did you call it before deviceready? | The single most common cause of "the plugin function doesn't exist" — see the deviceready lesson |
| Version mismatch? | A plugin version far ahead of (or behind) your installed Cordova platform version can expose a different JS API than the plugin's docs describe — check the plugin's changelog for breaking changes around the version you have |
| Does the native side even get reached? | If a JavaScript callback never fires at all, check adb logcat (Android) for a native exception or permission denial happening below the WebView, which never surfaces in the JS console |
| Permission declared in config.xml / requested at runtime? | Many plugins (camera, geolocation, file) need a permission both declared for the platform and, on newer Android/iOS versions, granted by the user at runtime — a silently failing callback is often a denied permission |