back to overview More blogs

Battery Fingerprinting: Your Charge Level Is a Tracker

Checking battery exposure...

You went incognito. You cleared your cookies. And the site still treated you like the same visitor it saw ten minutes ago. One of the quieter reasons it keeps happening is sitting in the corner of your screen: the battery meter.

For most of the last decade any website could ask your browser exactly how charged your laptop was, to a suspiciously precise number, and how many seconds of life it had left. Read those numbers on two different sites a moment apart and you had enough to decide the two visitors were one person. The panel on this page asks your browser the same question right now and shows you the answer.

The short version: battery fingerprinting runs on two numbers. The Battery Status API hands out your charge level and time-to-empty, and at any given moment that pair is close to unique, so it works as a short-lived key that re-links you across sites and incognito windows without a cookie. Firefox deleted the whole API over it; Chrome still exposes a blunted version.

The four numbers the Battery Status API hands out

Call navigator.getBattery() and you get back an object with four fields: level from 0 to 1, charging true or false, chargingTime in seconds until full, and dischargingTime in seconds until empty. No serial number, nothing that looks like an ID. That is exactly why it walked into browsers in the early 2010s without much of a fight. What could a battery percentage possibly give away?

Entropy, it turns out. dischargingTime on its own lands somewhere in a range thousands of seconds wide. Pair it with a level once reported to many decimal places and you have a value very few other people online are holding at that exact second. It is not a name. It is a number rare enough to act like one for a little while.

How two sites find each other with it

The mechanism was spelled out in 2015 by Olejnik, Acar, Castelluccia and Díaz, in a paper called The leaking battery. The reading is a re-identification handle with a lifespan. Site A records your level and dischargingTime; a moment later Site B records almost the same pair; the two can be joined with no cookie changing hands. It survives a cleared cookie jar and a private-browsing switch, because none of it is stored in the browser. It is read fresh off the hardware every time you ask.

One battery reading, two sites
shop.example
47%
to empty: 2:12
=
news.example
47%
to empty: 2:12
Same handle — the two visits are linked
Both sites read the same charge and time-to-empty, so they can join you into one profile with no cookie involved.
The reading is a join key, not a stored ID. It links two sites that see it close together, and expires as the battery moves — good for roughly thirty seconds to a couple of minutes.

The window is short. The numbers drift as your battery drains, so the match only holds for something like thirty seconds to a couple of minutes. Thirty seconds is plenty to stitch two page loads into one visitor. A year after the paper, a Princeton crawl of a million sites found real tracking scripts already reading the API in the wild, so the attack had already left the lab.

The capacity trick: reading mAh out of thin air

Here is the part the other write-ups skip. The operating system computes level as charge_now / charge_full, two integers in the battery’s own units, microamp-hours on a typical Linux laptop. So the fraction your browser reports is not arbitrary. It is a ratio whose denominator is your battery’s full-charge capacity. Firefox on Linux once handed back the raw ratio at full precision, something like 0.9301926, and from a reading that exact you can run the fraction backwards and recover the denominator underneath it.

Reading capacity out of the decimals
Your browser reports
battery.level = 0.9301926
Smallest fraction that matches
4650963 / 5000000
Capacity recovered: ~5000 mAh
That denominator is the full-charge capacity in microamp-hours. It drops as the battery ages, so it is a signal specific to your physical cell.
The level is charge-now over charge-full, so the fraction hides the capacity in its denominator. Full precision gives it up; rounding to a percent takes it away. The panel at the top of this page runs this on your real battery.

That denominator is your capacity in mAh, and it is a better identifier than the level ever was, because a battery’s full-charge capacity creeps downward as it ages. It is specific to your physical cell, at its current point of wear. Modern Chromium mostly shut this down by rounding level to a whole percent, so the only denominator you can pull back out is 100 and the real capacity disappears. The panel on this page runs the reconstruction on your live reading, and it will almost certainly report the value as quantized. That failure is the mitigation doing its job.

Why Firefox just deleted the whole thing

Mozilla did not patch the battery API. It removed it, in Firefox 52 in 2017, the entire navigator.getBattery surface gone. Apple never shipped it in Safari to begin with. That is a blunt response for a web feature, and it tells you how the standards world came to see this one: a tracking vector with no upside for the person being tracked. Chrome and Edge still carry it, now walled off to secure top-level pages and rounded down, and the specification itself now leads with a privacy warning it did not have in 2012. If you are reading this in Firefox or Safari, the test up top comes back clean, because there is nothing there to answer. The same split holds on phones: Chrome on Android exposes the reading too, while Safari on iOS and Firefox for Android give up nothing.

It was never only the battery

The battery is one line on a longer list your browser will read out to any site that asks, no permission prompt anywhere. navigator.hardwareConcurrency gives up your CPU’s logical core count. navigator.deviceMemory reports your RAM, coarsened to a power of two — long capped at 8 on desktop, though current Chrome now hands out 16 and 32 as well. maxTouchPoints says whether you have a touchscreen. The WebGPU adapter hands over your GPU’s vendor and architecture in plain strings. None of these pins you down alone. Stacked together they cut the crowd you are hiding in down to a handful, the same way canvas rendering and audio processing do in our canvas fingerprinting and audio fingerprinting breakdowns. The Hardware panel in the full browser scan shows the exact values your browser is giving out right now.

What to actually do

  1. See what you leak before you assume you are covered. Run the browser scan and read the battery and hardware panels. Guessing what you leak is not the same as looking.
  2. Incognito does not help here. The re-link runs through hardware, not cookies, so a private window with the same battery and GPU is the same visitor. That is worth remembering wherever you were counting on it.
  3. Firefox and Safari already close the battery vector. If you are on Chrome, staying current is what keeps the level quantized instead of raw.
  4. If you juggle several identities, make the whole hardware story consistent. Spoofing one value while the rest disagree is the contradiction that fingerprinting systems hunt for. Incogniton builds each profile so the battery, GPU, cores and memory it presents line up as one believable machine rather than a pile of contradictions.

The battery meter is a small thing to have given so much away. Point your own browser at the scan and see what yours still says.

Incogniton Logo

Level up your privacy

Arrow