Back

Using the Battery Status API in Web Apps

Using the Battery Status API in Web Apps

Most web apps have no idea whether the person using them is at 8% battery on a train with no charger in sight. The Battery Status API changes that — at least in some browsers. It lets your JavaScript read the device’s battery level, charging state, and estimated time remaining, so you can adapt your app’s behavior accordingly.

This article explains how the API works, what you can realistically do with it, and why you need to be careful about where and how you use it.

Key Takeaways

  • The Battery Status API exposes battery level, charging state, and time estimates through navigator.getBattery(), returning a BatteryManager object with four readable properties and four corresponding change events.
  • Always use feature detection and error handling before calling the API, since it is only available in secure contexts (HTTPS) and only in Chromium-based browsers.
  • Firefox removed the API over fingerprinting concerns, and Safari never implemented it, so treat battery-aware behavior strictly as a progressive improvement — never as a core feature.
  • Practical applications include pausing background sync, reducing animations, and prompting users to save work when battery is low.

What Is the Battery Status API?

The Battery Status API exposes battery information through the navigator.getBattery() method, which returns a Promise that resolves to a BatteryManager object. That object gives you four properties:

  • level — a number between 0 and 1 (e.g., 0.72 means 72%)
  • chargingtrue if the device is plugged in, false if not
  • chargingTime — estimated seconds until fully charged
  • dischargingTime — estimated seconds until battery is empty

Both time properties can return Infinity — when the device is a desktop with no battery, when the estimate isn’t ready yet, or when the browser deliberately withholds precision to limit fingerprinting risk.

How to Use navigator.getBattery() Safely

Always check for support before calling the API. It is only available in secure contexts (HTTPS), and even then, only in browsers that expose it.

In embedded contexts, access can also be restricted by the battery Permissions Policy.

async function initBatteryMonitor() {
  // Feature detection — don't assume the API exists
  if (!('getBattery' in navigator)) {
    console.warn('Battery Status API not supported in this browser.')
    return
  }

  let battery

  try {
    battery = await navigator.getBattery()
  } catch (err) {
    console.error('Failed to access battery information:', err)
    return
  }

  // Read initial values
  console.log(`Level: ${battery.level * 100}%`)
  console.log(`Charging: ${battery.charging}`)

  // Handle Infinity gracefully before displaying
  const formatTime = (seconds) =>
    seconds === Infinity ? 'Unknown' : `${Math.round(seconds / 60)} min`

  console.log(`Charging time: ${formatTime(battery.chargingTime)}`)
  console.log(`Discharging time: ${formatTime(battery.dischargingTime)}`)

  // Listen for changes
  battery.addEventListener('levelchange', () => {
    console.log(`Battery level updated: ${battery.level * 100}%`)
  })

  battery.addEventListener('chargingchange', () => {
    console.log(`Charging state changed: ${battery.charging}`)
  })
}

initBatteryMonitor()

The four events you can listen to are levelchange, chargingchange, chargingtimechange, and dischargingtimechange. Each fires when its corresponding value changes.

Practical Use Cases

The API is most useful when you want to reduce resource consumption for users on low battery:

  • Pause background sync or polling when battery.level drops below a threshold like 0.2
  • Reduce animation complexity or disable auto-playing video
  • Prompt users to save their work before the battery runs out
  • Adjust PWA behavior — for example, deferring non-critical network requests

These are progressive improvements. Your app should work fine without them.

Browser Support and Privacy Concerns

This is where the Battery Status API gets complicated.

BrowserSupportNotes
Chromium-based browsersSupported with limited availabilityHTTPS only; values may be reduced, rounded, or replaced with default values
FirefoxNoRemoved due to privacy concerns
SafariNoNever implemented

Current browser support is narrow. Firefox removed the API because researchers demonstrated it could be used as a fingerprinting vector — the combination of battery level and time values was specific enough to help track users across sites. In response, Chromium-based browsers may reduce precision or expose default values to limit that risk.

This means you should never rely on the Battery API as a primary feature. Treat it as a nice-to-have improvement, and always write fallback behavior for when it returns nothing.

Testing the Battery API in Development

Chrome DevTools does not currently provide a built-in battery simulator under Sensors. To test battery-related behavior during development, you have a few practical options:

  • Use a real mobile device connected via USB remote debugging, and observe actual battery state changes.
  • Mock the API in your code by replacing navigator.getBattery with a function that returns a fake BatteryManager object with the properties and events you need to test.
  • Use browser overrides or testing libraries such as Sinon or Jest to stub navigator.getBattery() in your test suite.

Here is a minimal mock you can drop into your dev environment:

function mockBattery({ level = 0.15, charging = false } = {}) {
  const fake = {
    level,
    charging,
    chargingTime: charging ? 3600 : Infinity,
    dischargingTime: charging ? Infinity : 1800,
    addEventListener: () => {},
  }

  navigator.getBattery = () => Promise.resolve(fake)
}

// Simulate a low-battery, unplugged device
mockBattery({ level: 0.08, charging: false })

This approach gives you full control over the values your code receives, without depending on browser-specific tooling.

Conclusion

The Battery Status API is a niche tool with real limitations. Browser support is narrow, values are intentionally imprecise, and the privacy implications mean its future is uncertain. But in controlled environments — internal tools, PWAs targeting known Chromium-based browsers, or kiosk-style applications — it can meaningfully improve the user experience.

Use feature detection, handle Infinity values explicitly, clean up your event listeners when they’re no longer needed, and never build a critical feature on top of it.

FAQs

Only on Chromium-based mobile browsers such as Chrome for Android, and even there availability can vary by environment. Safari on iOS has never implemented it, and Firefox removed support entirely. Always use feature detection to check for availability before calling navigator.getBattery(), and provide fallback behavior for unsupported browsers.

It can be. Researchers showed that the combination of battery level and discharge time values was precise enough to fingerprint users across websites. This led Firefox to remove the API completely. Chromium-based browsers may reduce precision or expose default values to limit that risk, but the concern remains a reason some browsers avoid implementing it.

Store references to your handler functions and call removeEventListener when they are no longer needed, such as when a component unmounts. Since the BatteryManager object persists, failing to remove listeners can cause memory leaks or unexpected behavior if your app re-initializes the monitor multiple times.

It works in supported Chromium-based desktop browsers, but the values may not be meaningful. Desktops without batteries often report a level of 1 and a charging state of true, with both time properties set to Infinity. The API is most useful on laptops and mobile devices where battery state actually fluctuates.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay