Battery Status API: Privacy, Availability, and Safer Web Decisions
Learn what the Battery Status API exposes, why support is limited, and how to use battery information without turning it into a user profile.
Want the structured docs for Fingerprint?
This article lives in the editorial library. For step-by-step setup, reference material, and ongoing updates, jump into the docs section.
The Battery Status API can report a browser's current charging state, battery level, and estimated charging or discharging time. It is an optional, limited-availability capability signal, not a device identity or a promise about how long a session will last. Applications should feature-detect it, keep a useful default, and use any result only for a reversible, user-visible decision. That distinction matters because a battery signal is transient and policy-dependent: two tabs can observe different moments, and two browsers can expose different precision. Treat it as an optional input to a local policy, never as a hidden prerequisite for rendering. The behavior should remain explainable without mentioning a percentage: the page keeps normal optional work, defers a nonessential enhancement, or asks the person to choose. This keeps the feature understandable when support changes, when a device is plugged in during an operation, or when a person has selected a preference. It also prevents a temporary reading from becoming a durable label attached to an account or session. A product can save power by reducing background activity, batching nonurgent updates, or waiting before preparing a large preview, while keeping the core task immediate and complete. Communicate any meaningful delay, preserve an equivalent way to continue, and return to the ordinary path when the optional work is no longer needed.
What the Battery Status API provides
An application can call navigator.getBattery() when the API is exposed. The returned BatteryManager can expose charging, level, chargingTime, and dischargingTime, together with events for changes. These values describe the browser's current view of power state; they are not a hardware inventory, an exact remaining-runtime guarantee, or a measure of battery health.
The values can change during a visit and may be unavailable, rounded, or otherwise constrained by browser policy. Treat them as hints for the current task. A page might defer an optional animation or reduce background refresh while a device is not charging, but it should not remove required content or infer who is using the page.
The API also has an important scope boundary: it describes the state exposed to this browsing context, not a contract with the operating system. A browser may return a value that is already a little old, may update it only after a platform event, or may intentionally provide less precision. Code should therefore tolerate a value that changes immediately after it was read. Keep the decision local to the component that needs it, and make the default behavior correct before the asynchronous result arrives.
When the page asks for the information, treat a rejected promise, an exception, and an unavailable method as the same product outcome: battery-aware enhancement is not available right now. Do not turn that outcome into a warning that blocks the page. A short-lived local decision can be recalculated when the document becomes visible again, but the page should not repeatedly ask merely to make a missing signal appear.
Availability is a normal compatibility branch
MDN marks the Battery Status API as limited availability, so a production page cannot assume that navigator.getBattery exists or that its promise will resolve successfully. Support can vary by browser, release, context, and user-agent policy. Feature-detect the method, handle rejection, and keep the same baseline when the value is absent.
Do not use a browser name as a substitute for feature detection. Test the behavior your product needs: the page remains usable when the API is missing, a value changes, or a request fails. The browser capability guide describes the same fallback-first approach for another optional API.
Availability is also affected by execution context. A feature that appears during local testing may be disabled in a managed profile, a private context, an embedded frame, or a future browser release. Document the tested behavior rather than promising support for a browser family. A capability check belongs close to the code path that consumes the result, because a cached global flag can outlive the context in which it was obtained.
The baseline should include a clear failure path in the user experience, not just a defensive catch. For example, a reader can load the same article and controls when battery information is absent; only an optional preview or background refresh needs a policy choice. This keeps compatibility work visible in tests and prevents an implementation detail from becoming a hidden dependency of navigation or data entry.
Make a small, reversible product decision
Start with a baseline that works without battery data. If a result is available, use it to choose among a small number of policies, such as normal and reduced background work. Keep essential navigation, forms, media alternatives, and accessibility controls intact. Explain a meaningful change in ordinary product language and let the user choose when the change affects data transfer, quality, or timing.
Battery state should not control authorization, billing, account recovery, or a required request. A server should not depend on a JavaScript battery value that can be unavailable or change between requests. If a person explicitly selects a data-saving or reduced-effects setting, send that choice instead of the raw battery fields. Keep the policy close to the component that owns the work: a document viewer might defer a high-resolution preview while preserving reading and download controls, while a collaboration tool might slow background refresh without delaying edits or an explicit refresh. A media page can postpone an autoplay enhancement while keeping play, captions, and the ordinary page flow available.
Avoid a single global low-power mode that silently changes every feature. Different tasks have different costs and expectations, and a person reading an article may prefer no visible change while someone exporting a large file may appreciate a clear choice to wait. Name policies in product language, make the transition observable, and keep a direct way to request the full experience when the cost is meaningful. A battery hint can inform a default, but it never overrides an explicit request. Essential work such as authentication, payment confirmation, document saves, legal notices, and account controls must remain on the same reliable path whether or not the API is present. Optional work can be queued, cancelled, or resumed, but a missing value should never become an accidental error state.
Use a state machine small enough to explain in a test: baseline, optional enhancement enabled, and optional work deferred or cancelled. A reading should move between those states only when the relevant event occurs or when the person chooses a setting. If several components need a policy, share the policy decision rather than sharing raw readings. This avoids one component interpreting level as a percentage while another treats it as a permission to stop work.
A visible choice is especially important for operations with a cost that the person can judge better than the browser can. A large export, a camera preview, and a long upload can each offer a pause or reduced-quality option while retaining a normal path. State what will happen, preserve already entered data, and make resuming idempotent. A battery hint can suggest the choice, but the person should be able to override it without searching through settings.
Do not let a transient reading create a permanent product mode. If a person changes from charging to discharging, reevaluate only the optional operation that is affected and avoid restarting unrelated work. Likewise, if the device begins charging, do not surprise the person by changing content or quality in the middle of an interaction. A small notification or an explicit refresh action is easier to understand than silent global changes.
Privacy boundaries and data minimization
Battery readings can contribute to fingerprinting when combined with other signals. Keep them local to the decision that needs them, and discard the raw values after the page has selected its policy. Do not add level, charging state, or timing values to account identifiers, URLs, analytics labels, or long-lived support records by default.
Operational logs usually need only the selected policy and outcome, for example power_policy=reduced and whether an optional task completed. If a support case genuinely needs more detail, explain the purpose, restrict access, set a short retention period, and remove the fields when the case closes. The browser privacy basics guide covers broader data-minimization choices.
Treat a battery reading as short-lived state. Read it near the decision, keep the chosen policy in memory, and allow a later state change to trigger a bounded reevaluation. Do not poll continuously when an event is available, and do not retain a history of levels or charging transitions. A page that remains open for hours should not slowly assemble a power profile. If a page returns from a suspended tab or a back-forward cache, recompute the small local decision instead of trusting a stale value. Review third-party monitoring libraries and service workers as well, because either can copy a value into a remote event or a cache without the component author noticing.
If a diagnostic incident genuinely requires raw fields, make that collection a documented, time-limited exception. Explain the purpose when appropriate, restrict the event to the affected flow, limit who can read it, and set an expiration. Remove the field from the schema after the incident instead of leaving a permanent temporary attribute. Keep analytics aggregated at the policy or outcome level, and do not let dashboards sort individual accounts by power state. Removing an unnecessary battery branch is both a privacy improvement and a maintenance improvement.
Consider the full data path, not only the call site. A client-side error reporter, performance beacon, service worker, browser extension hook, or third-party SDK may copy properties that the feature author intended to keep local. Use an allowlist for events leaving the page, review serialization code, and check that cached requests do not contain battery fields. A policy value such as reduced is usually sufficient for operational questions and is less identifying than a sequence of raw readings.
Retention should match the decision's lifetime. If a policy is needed for one tab, keep it in memory; if a person chooses a preference, store that preference as a preference rather than as evidence about a battery state. Avoid putting raw values in query strings or form submissions, where they can enter server logs, referrer headers, screenshots, or copied support links. Data minimization is easier when the value has no path to a durable identifier.
Privacy review should include the negative case. Verify that missing permission, a rejected call, and a rounded value do not trigger extra collection or a more invasive fallback. A product that simply proceeds with its normal experience when the API is absent has fewer opportunities to create a power-state history and fewer compatibility assumptions to maintain. The same principle covers restored tabs, interrupted uploads, and devices that move between charging states while a person is working. Required navigation, saves, and account controls should remain predictable in every case.
Test the fallback, not a particular battery value
Tests should cover an undefined API, a rejected getBattery() call, a changing level or charging state, and a browser that exposes only the baseline path. Assert that required content and controls remain available, that optional work can be cancelled, and that a user can recover after a state change. Do not assert that a particular device returns a particular percentage or time.
Respect user intent and accessibility in every branch. A reduced mode may postpone a preview or lower background frequency, but it must preserve the task's meaning and provide a clear way to continue. Avoid retry loops and avoid asking a person to weaken a browser privacy setting merely to enable an enhancement.
Test lifecycle behavior at inconvenient times: while navigation is in progress, while an upload is waiting, during a background transition, and immediately after a person selects the full experience. Verify that a cancellation does not lose input, that a retry has a visible reason, and that keyboard and assistive-technology users can understand the same choice. If optional work was postponed, provide a way to start it later and show progress. If it was interrupted by navigation, backgrounding, or a state change, cancel cleanly and release temporary resources. A debounce or a user action is preferable to restarting an expensive operation every time a reading changes.
Document the boundary in customer-facing terms: the feature may adjust optional background work or defer an enhancement when power information is available, but support varies and the reading is not used to identify a person, authorize an account, or guarantee runtime. Link to current standards and browser documentation instead of promising that one browser family exposes the same fields everywhere. Assign an owner for the policy, its fallback, and its retention rule, then review that decision when the workload changes. A browser release is evidence about one tested environment, not a promise of identical behavior in every managed context.
The same boundary applies when a page is restored after suspension or when a person changes a power preference. Recompute the small local policy, keep required navigation and saves on their normal path, and make any optional delay visible. Review the behavior with keyboard and assistive technology users as well as with metered connections, because a power-aware choice should not remove an equivalent way to complete the task. A short-lived policy and an explicit user control are more durable than a stored history of readings, especially when browsers expose different levels of support over time.
Include timing and cancellation in automated coverage. Resolve getBattery() after the page has rendered, reject it after a user has started an action, and dispatch a change event while optional work is queued. The expected result is deterministic: required work continues, optional work follows the selected policy, and a cancellation releases temporary resources. Tests should also cover a tab becoming hidden and visible, because a suspended document may resume with a different state and a different browser policy.
For manual checks, use a browser or test harness that can expose the API, one that omits it, and one that returns a promise rejection. Change charging state while a long operation is in progress and confirm that focus, entered values, upload progress, and announcements remain coherent. Check reduced motion, keyboard navigation, screen readers, and a metered connection separately; a battery-aware branch must not become an accessibility or connectivity regression.
Keep customer-facing documentation precise and modest. Say that the feature may adjust optional background work or defer an enhancement when power information is available, that support varies, and that the reading is not used to identify a person, authorize an account, or guarantee runtime. Link to current standards and browser documentation, and assign an owner for reviewing the policy when workload, browser behavior, or privacy expectations change.
Sources
Related Articles
Take BotBrowser from research to production
The guides cover the model first, then move into cross-platform validation, isolated contexts, and scale-ready browser deployment.