How to Use the HTML5 Battery Status API

If you’re lucky, you’ll get seven or eight hours usage from a smart phone or tablet before the battery dies. Expect around half that on a laptop. Battery technology has not kept pace with advances in mobile computing. A decade ago you could expect your Palm Pilot to last up to a month on a couple of AAA batteries. Now you’re feeding devices every night and your room lights up like a blinking red and green LED version of Las Vegas.

Few of us worry about battery life when developing web applications, but perhaps we should be more considerate now that mobile access has reached one in five users. Fortunately, the W3C Battery Status API has been implemented by both Mozilla and Google — and it’s very simple to use.

What’s Not So Simple…

We can detect when a battery reaches a critical level but what can we do about it? It will depend on your application, but the primary causes of power drainage are…

The screen
Your back-lit screen is the biggest juice glutton. There are a few options you could consider when the battery reaches a critical level:

  • switch to a light-on-dark theme
  • disable non-critical CSS3 and JavaScript animations
  • avoid DOM changes where possible

Network activity
Wi-fi and mobile networks require power-draining radio wave communications. Consider:

Audible and tactile output
Sound and vibration will kill a battery dead; you could use shorter effects or disable it completely.

Processing
Heavy-duty processing has a noticeable impact on battery life and handset heat! Other than fast-action games, few web applications should require complex on-going client-side calculations. I suspect there’s little you can practically do other than suggesting the user plugs-in to continue.

You should also note that many of these options may be applicable to the Page Visibility API. For example, if a game isn’t running in the active tab, it can be paused until the user returns.

Browser Support

At the time of writing, only Firefox desktop and mobile editions offer unprefixed support for the Battery API (versions 10 to 16 used the moz prefix). It is also available in recent editions of Chromium with a webkit prefix.

We can create a cross-browser battery object using:

var battery = navigator.battery || navigator.webkitBattery || navigator.mozBattery || navigator.msBattery;

if (battery) {
	// battery API supported
}

This is used in the Battery API demonstration…

Basic Properties

You can obtain the battery level using the navigator.battery.level property which returns a value between 0 and 1, e.g.

console.log( "battery level: ", Math.floor(battery.level * 100) + "%" );

However, the current level may not be so important if the device is being charged. We can check the status using the navigator.battery.charging property which returns true if charging or false if discharging:

console.log( "device is ", (battery.charging ? "charging" : "discharging") );

Therefore, you probably want to introduce power-boosting options when the battery level drops below, say, 25% and the device is not being charged, e.g.

var enableEffects = (battery.charging || battery.level > 0.25);

// vibrate for one second
if (enableEffects) navigator.vibrate(1000);

There are a couple of other properties you may find useful:

  • navigator.battery.chargingTime — the time, in seconds, until charging reaches 100%.
  • navigator.battery.dischargingTime — the time, in seconds, until the battery is completely discharged and the device will shut down.

Neither of these properties appear to work as you’d expect in current browsers. Firefox returns either zero or Infinity which isn’t particularly helpful.

Battery Status Events

Four events can be fired by the Battery object:

  • chargingchange — the device has changed from being charged to being discharged or vice versa
  • levelchange — the battery level has changed
  • chargingtimechange — the time until the battery is fully charged has changed
  • dischargingtimechange — the time until the battery is fully discharged has changed

For example, using our cross-browser battery object:

battery.onlevelchange = function() {

	var ee = enableEffects;
	enableEffects = (battery.charging || battery.level > 0.25);
	
	if (enableEffects != ee) {
		if (enableEffects) {
			console.log( "Battery power is OK." );
		}
		else {
			console.log( "Battery power is critical!" );
		}
	}

}

Some would say your web app should never needlessly drain the battery. However, the Battery API allows us to make more sophisticated decisions about when we can and cannot depend on animation, effects and Ajax calls.

View the Battery API demonstration… (Firefox and Chromium)

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Jason Peltier

    Great article! Can we rely on polyfills until everyone is on board?

    I have a few apps that change functionality based on battery state, but using the native API would be sweet!

    • James Edwards

      How do you polyfill something which requires system-level access to the hardware?

      • Jason Peltier

        Do you always answer a question with a question? :)

        • James Edwards

          I was asking a question, not answering one.

          You said you have apps that change functionality based on battery state, and I’m asking how you did that.

          Unless by “have” apps you mean, you own apps, rather than you wrote the apps yourself, which is what I’d assumed you’d meant.

          But perhaps not.

          As far as I know it’s impossible to polyfill something which requires system-level access to the hardware.

  • James Edwards

    That would work for native apps, but not for JavaScript.

    You’d have to write an app that sends that data to the browser’s JavaScript runtime, which is probably not possible either (short of writing your own browser!)