The navigator.deviceMemory
attribute is part of the Device Memory API. It exposes an approximate amount of system RAM to help websites adjust resource usage for low-end devices. But like many hardware-related attributes, it also contributes to the browser fingerprint, and its value can be misrepresented or tampered with in automated environments.
In this post, we take a closer look at how navigator.deviceMemory
is implemented in Chromium, how it behaves in real traffic, and how inconsistencies in its value can help detect spoofed fingerprints and automated browsers.
TL;DR
navigator.deviceMemory
reports the device’s memory in gigabytes (rounded)- It's only available in Chromium-based browsers, not Firefox or Safari
- Chrome caps this value to 8GB to reduce fingerprinting risk
- In our traffic, we observed 16K+ Chrome events with values over 8, most linked to bot activity or spoofing extensions
- It’s a useful signal for detecting inconsistencies in claimed browser identity or hardware environment
What is navigator.deviceMemory
?
The navigator.deviceMemory
property is part of the Device Memory API and returns an approximate amount of system RAM, expressed in gigabytes. Its primary purpose is to help websites adapt their resource usage based on device capabilities, especially on low-end mobile devices where reducing page complexity or asset size can improve performance.
The value is a floating-point number, but it’s heavily rounded and capped to minimize fingerprinting surface. According to MDN, it typically returns one of: 0.25
, 0.5
, 1
, 2
, 4
, or 8
.
The API is only implemented in Chromium-based browsers. It is not available in Firefox or Safari. This absence can be useful when validating whether a browser’s fingerprint aligns with its claimed user agent string.

The W3C spec also calls out fingerprinting concerns directly. It mandates two key protections:
- Value rounding: The reported value must be reduced to the closest power of two.
- Maximum cap: Browsers must not report values greater than
8GB
.
These controls ensure that the signal is coarse-grained. useful for performance tuning but harder to exploit for uniquely identifying devices.
How navigator.deviceMemory
is implemented in Chrome
The value returned by navigator.deviceMemory
in Chrome is defined in navigator_device_memory.cc
. The relevant function is NavigatorDeviceMemory::deviceMemory()
:
namespace blink {
namespace {
// TODO(435582603): Hard-coding this to a common value is a reasonable start,
// but it likely makes sense to vary the hard-coded number by platform and
// form-factor in order to maintain plausibility over time.
constexpr float kReducedDeviceMemoryValue = 8.0;
} // namespace
float NavigatorDeviceMemory::deviceMemory() const {
if (RuntimeEnabledFeatures::ReduceDeviceMemoryEnabled()) {
return kReducedDeviceMemoryValue;
}
return ApproximatedDeviceMemory::GetApproximatedDeviceMemory();
}
}
If the ReduceDeviceMemoryEnabled
feature flag is active, the value is hardcoded to 8.0
. Otherwise, it calls ApproximatedDeviceMemory::GetApproximatedDeviceMemory()
.
That method is defined in approximated_device_memory.cc
:
// static
float ApproximatedDeviceMemory::GetApproximatedDeviceMemory() {
return approximated_device_memory_gb_;
}
The value is computed and stored during initialization:
void ApproximatedDeviceMemory::Initialize() {
if (approximated_device_memory_gb_ > 0.0)
return;
DCHECK_EQ(0, physical_memory_mb_);
physical_memory_mb_ = ::base::SysInfo::AmountOfPhysicalMemoryMB();
CalculateAndSetApproximatedDeviceMemory();
}
The logic in CalculateAndSetApproximatedDeviceMemory()
approximates the memory by rounding it to the nearest power of two, following the spec:
void ApproximatedDeviceMemory::CalculateAndSetApproximatedDeviceMemory() {
// The calculations in this method are described in the specification:
// <https://w3c.github.io/device-memory/>.
DCHECK_GT(physical_memory_mb_, 0);
int lower_bound = physical_memory_mb_;
int power = 0;
// Extract the most-significant-bit and its location.
while (lower_bound > 1) {
lower_bound >>= 1;
power++;
}
// The remaining should always be equal to exactly 1.
DCHECK_EQ(lower_bound, 1);
int64_t upper_bound = lower_bound + 1;
lower_bound = lower_bound << power;
upper_bound = upper_bound << power;
// Find the closest bound, and convert it to GB.
if (physical_memory_mb_ - lower_bound <= upper_bound - physical_memory_mb_)
approximated_device_memory_gb_ = static_cast<float>(lower_bound) / 1024.0;
else
approximated_device_memory_gb_ = static_cast<float>(upper_bound) / 1024.0;
// Max-limit the reported value to 8GB to reduce fingerprintability of
// high-spec machines.
if (approximated_device_memory_gb_ > 8)
approximated_device_memory_gb_ = 8.0;
}
This logic ensures that:
- The value is rounded to the nearest power of two (based on the most significant bit)
- It is converted from MB to GB
- Any result above 8GB is capped at
8.0
This aligns with the security guidance in the W3C spec:
"To reduce fingerprinting risk, reported value is rounded to single most significant bit, as opposed to reporting the exact value. In addition, an upper and lower bound is placed on the reported values."
In short, Chrome enforces strict rounding and capping behavior, meaning any observed values that break from this logic likely indicate automation or spoofing.
How it can be used for detection (with real-world data)
Because navigator.deviceMemory
is only implemented in Chromium-based browsers, its presence or value can be used to cross-check whether a fingerprint is consistent with the claimed user agent. For example:
- If a browser claims to be Safari or Firefox but exposes a
deviceMemory
value, it’s likely spoofed. - If the value is greater than 8, it’s inconsistent with real Chrome behavior and may suggest script instrumentation or tampering.
- If the value doesn’t match expected rounding (e.g., 3GB instead of 2 or 4), it may also indicate manipulation.
In legitimate Chrome traffic, you should only see values like 0.25
, 0.5
, 1
, 2
, 4
, or 8
.
Device memory in the wild
To understand whether the inconsistencies discussed earlier, such as deviceMemory
values above 8, could be useful in practice for detecting bots, we looked at recent traffic to see if these anomalies show up in real-world scenarios. Looking at our traffic from the last 7 days, we observed over 16,000 Chrome events reporting navigator.deviceMemory
values greater than 8, something that should never happen in genuine Chrome environments.

Much of this traffic was linked to automation, including:
- A cluster of ~3.5k events tied to a single bad actor creating fake accounts
- Use of throwaway Hotmail addresses generated in a predictable pattern
- Emails from disposable domains like
eldamaty2025.xyz
In these cases, the spoofed deviceMemory
value acted as an early signal. Even without user or behavioral context, it flagged the environment as non-standard.
This also aligns with previous detection patterns we’ve seen: anti-detect browsers or headless automation frameworks often overlook or misconfigure low-fidelity attributes like deviceMemory
. These aren’t flashy, but they help catch tools that don’t fully replicate Chrome’s internal logic.
Detection tips
- Cross-check the user agent with feature presence:
navigator.deviceMemory
should only be exposed in Chromium-based browsers. Its presence in Firefox or Safari signals spoofing. - Flag values greater than 8: Chrome caps this value at 8 GB. Any higher value is inconsistent with real behavior.
- Watch for unexpected values: Legitimate values follow a strict set (e.g., 0.25, 0.5, 1, 2, 4, 8). Values like 3 or 6 indicate manipulation or incomplete emulation.
- Treat absence as a signal: A missing
deviceMemory
in Chrome can also suggest instrumentation or sandboxing. - Correlate with other attributes: Inconsistencies become stronger signals when
deviceMemory
contradicts other properties likeplatform
,userAgent
, orhardwareConcurrency
.
Conclusion
While navigator.deviceMemory
exposes only a single number, it carries meaningful signal for both fingerprinting and detection. Chrome’s implementation includes built-in privacy protections, rounded values and an 8 GB cap, that make deviations easy to spot when automation or spoofing tools get it wrong.
In our telemetry, we've seen attackers overlook or misconfigure this attribute, leading to inconsistencies that help surface fake environments. Whether it’s a forged user agent claiming Firefox while exposing deviceMemory
, or a spoofed Chrome instance reporting 16 GB, these gaps reveal environments that don't match legitimate browser behavior.
Used on its own, navigator.deviceMemory
won’t catch sophisticated actors. But combined with other navigator or screen attributes, it contributes to a broader consistency check that’s difficult to bypass completely.
This type of low-noise, high-confidence signal is exactly what makes fingerprinting-based detection effective at scale, and worth understanding in detail.