The deviceready Event

If there is one concept in this entire track worth over-explaining, it's deviceready. Nearly every confusing "why doesn't my plugin work" bug a Cordova beginner hits traces back to calling a native API before Cordova has finished setting itself up. This page goes deep on why the event exists, the correct pattern for using it, what breaks if you skip it, and the related events for handling your app moving to the background and back.

Why deviceready Exists

When a Cordova app launches, the native shell starts a WebView and points it at your www/index.html — but the WebView loading and rendering your HTML/CSS/JS is only half the story. Underneath, Cordova also needs to initialize its native bridge (the communication channel between your JavaScript and native code) and let every installed plugin finish its own startup work before any plugin API can be safely called. That initialization takes a small but nonzero amount of time after the page begins loading. The deviceready event is Cordova's way of telling your JavaScript, unambiguously, "the bridge and all plugins are now ready — it's safe to call native APIs starting now."

The regular browser event you might reach for instead, window.onload (or jQuery's $(document).ready()), only tells you that the DOM and its referenced assets have finished loading — it says nothing about whether Cordova's native bridge is initialized. Those two things usually finish at different times, which is exactly why Cordova ships its own, separate event instead of overloading the standard page-load events.

The Correct Pattern

The standard, correct way to wait for Cordova is to attach a listener for deviceready and put all of your Cordova/plugin-dependent startup code inside the handler function:

document.addEventListener('deviceready', onDeviceReady, false);

function onDeviceReady() {
    // Safe to call Cordova plugin APIs starting here
    console.log('Running cordova-' + device.cordova);
    console.log('Platform: ' + device.platform + ', model: ' + device.model);

    navigator.geolocation.getCurrentPosition(function(position) {
        console.log('Lat: ' + position.coords.latitude);
    });
}

The third argument to addEventListener, false, is the standard "useCapture" parameter from the DOM event API — you'll almost always see it passed as false in Cordova examples, matching normal JavaScript event-listener conventions.

The Wrong Way — and Why It Fails

Compare that to code that calls a plugin API immediately, at the top level of a script, with no event listener at all:

// WRONG: no deviceready listener — this runs immediately on page load
console.log('Platform: ' + device.platform);

navigator.geolocation.getCurrentPosition(function(position) {
    console.log(position.coords.latitude);
});

This script runs the instant the browser parses it — which, in a Cordova app, can easily be before the native bridge has finished initializing. The result is typically one of a few failure modes: device is undefined (throwing a "Cannot read property 'platform' of undefined" error), navigator.geolocation silently falls back to a plain browser geolocation implementation that doesn't match Cordova's plugin behavior, or the call simply does nothing because the plugin's native side hasn't registered its message handler yet. These bugs are especially frustrating because they can appear to work sometimes (on a fast device, if the bridge happens to initialize quickly) and fail other times — a classic race condition.

What's Safe Before deviceready vs. What Must Wait

Safe Before devicereadyMust Wait for deviceready
  • Regular DOM manipulation (querySelector, changing text/classes, showing/hiding elements)
  • Attaching click/input/form event listeners
  • Plain JavaScript logic, math, string/array processing
  • Rendering your initial UI layout and styling
  • Fetching data over the network with fetch/AJAX from a regular web API
  • Camera access (cordova-plugin-camera)
  • Geolocation (navigator.geolocation via cordova-plugin-geolocation)
  • File system access (cordova-plugin-file)
  • Reading device info (device.platform, device.model, device.uuid)
  • Any other plugin-provided API (push notifications, network info, in-app browser, etc.)

The simple rule of thumb: if the API you're calling is part of plain JavaScript or the DOM, it's safe any time. If it's provided by a Cordova plugin — which almost always means it hangs off device, navigator (for plugin-provided extensions like geolocation and camera), or a global object a plugin registers — it must wait for deviceready.

deviceready Only Fires Once

deviceready fires exactly one time per app load/launch — it marks the one-time transition from "still initializing" to "fully ready," not a repeating readiness check. If you need code to run every time the user returns to your app (rather than only on the very first launch), deviceready is the wrong event to reach for; that's what the pause and resume events below are for.

Related Lifecycle Events: pause and resume

Two related events let your app react to the user switching away from it and back, which is common on mobile — the user might get a phone call, switch to another app, or lock the screen:

document.addEventListener('pause', onPause, false);
document.addEventListener('resume', onResume, false);

function onPause() {
    // App is moving to the background — good place to pause timers, save state
}

function onResume() {
    // App is coming back to the foreground
}

pause fires when the app is sent to the background (for example, the user presses the home button), and resume fires when it comes back to the foreground. These are commonly used to pause things like media playback, timers, or animations while the app is hidden, and to refresh time-sensitive data (like re-checking geolocation) when the user returns.

Next: With the deviceready lifecycle solidly understood, move on to Plugins Overview to see how the plugin ecosystem itself is organized and managed.