Right‑sizing experiences with the Device Memory API

Emotional intelligence. Side view of an elderly man thoughtful, thinking, finding solution with gear mechanism, question, lightbulb.
Use the Device Memory API to bucket users by RAM and serve right‑sized images and effects. It’s a coarse, privacy‑friendly hint for progressive enhancement.

If you’ve ever shipped one “hero” image to every visitor, you’ve probably over-served low‑end phones and under‑served high‑end laptops. The Device Memory API gives you a simple hint about a device’s RAM so you can tune quality without building a full capability profiler.

What it is

Why it helps

Leading practices

Support and caveats

Support is good in Chromium‑based browsers; other engines may return undefined. Always code defensive paths and serve over HTTPS.

				
					<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Device Memory API Demo</title>
    <link data-wphbdelayedstyle="style.css" rel="stylesheet" />
    <script type="wphb-delay-type" src="deviceMemoryAPI.js" defer></script>
</head>

<body>
    <h1>Device Memory API — Quick demo</h1>
    
    <div class="card">
        <div id="info">
            <div class="status" id="device-memory">Device memory: <em>detecting…</em></div>
            <div id="tier">Quality tier: <em>—</em></div>
            <div class="note" id="compat-note"></div>
    
            <!-- demo image — we'll swap a lower/higher-quality source based on memory -->
            <img decoding="async" id="hero" class="demo" src="" alt="Demo image (quality tuned by Device Memory API)" />
    
            <button id="refresh">Re-check device memory</button>
            <div class="note">This demo reads navigator.deviceMemory (approx. GB) and picks a content-quality tier. Must run
                on HTTPS or localhost.</div>
        </div>
    </div>
<script type="text/javascript" id="wphb-delayed-styles-js">
			(function () {
				const events = ["keydown", "mousemove", "wheel", "touchmove", "touchstart", "touchend"];
				function wphb_load_delayed_stylesheets() {
					document.querySelectorAll("link[data-wphbdelayedstyle]").forEach(function (element) {
						element.setAttribute("href", element.getAttribute("data-wphbdelayedstyle"));
					}),
						 events.forEach(function (event) {
						  window.removeEventListener(event, wphb_load_delayed_stylesheets, { passive: true });
						});
				}
			   events.forEach(function (event) {
				window.addEventListener(event, wphb_load_delayed_stylesheets, { passive: true });
			  });
			})();
		</script></body>

</html>
				
			
				
					/* style.css */
body {
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    padding: 24px;
}

.card {
    border: 1px solid #ddd;
    padding: 16px;
    border-radius: 8px;
    max-width: 720px;
}

.status {
    margin: 8px 0;
    font-weight: 600;
}

img.demo {
    width: 100%;
    max-width: 600px;
    height: auto;
    border-radius: 6px;
    display: block;
    margin-top: 12px;
}

.note {
    color: #666;
    margin-top: 10px;
    font-size: 0.9rem;
}

button {
    margin-top: 12px;
}
				
			
				
					// Utility: pick a tier name from the numeric RAM value (GB)
const memoryToTier = (ramValue) => {
	// Common values are 0.25, 0.5, 1, 2, 4, 8 but the API is coarse and intentionally privacy-preserving.
	if (ramValue === undefined || ramValue === null) return 'unknown';
	// Choose thresholds (tweak to suit your app)
	if (ramValue < 1) return 'low';
	if (ramValue >= 1 && ramValue < 4) return 'medium';
	return 'high';
};

// Set the image src depending on quality tier.
const applyQualityTier = (tier) => {
	const hero = document.querySelector('#hero');
	if (tier === 'low') {
		// smaller image, faster to download
		hero.src = 'https://picsum.photos/600/320?grayscale&random=1';
		hero.alt = 'Low-quality image (grayscale, smaller)';
	} else if (tier === 'medium') {
		hero.src = 'https://picsum.photos/900/480?random=2';
		hero.alt = 'Medium-quality image';
	} else if (tier === 'high') {
		// larger, high-res image
		hero.src = 'https://picsum.photos/1400/700?random=3';
		hero.alt = 'High-quality image';
	} else {
		hero.src = 'https://picsum.photos/900/480?random=99';
		hero.alt = 'Default image';
	}
};

// Helper function to safely update an element with a label and an emphasized value.
const updateElementWithEmphasis = (element, label, value) => {
	// Clear any previous content to prevent duplicating nodes on refresh.
	element.textContent = '';

	// Create the <em> element that will contain the dynamic value.
	const em = document.createElement('em');
	em.textContent = value;

	// Append the static text label and the new <em> element to the parent.
	element.appendChild(document.createTextNode(label));
	element.appendChild(em);
};

// Update UI with memory and tier info, now using secure DOM methods instead of innerHTML.
const updateUI = (memValue) => {
	const memEl = document.querySelector('#device-memory');
	const tierEl = document.querySelector('#tier');
	const compatEl = document.querySelector('#compat-note');

	if (memValue === undefined) {
		updateElementWithEmphasis(memEl, 'Device memory: ', 'not available');
		compatEl.textContent =
			'Device Memory API not supported in this browser. See MDN for compatibility (open in a secure context).';
		updateElementWithEmphasis(tierEl, 'Quality tier: ', 'fallback');
		applyQualityTier('medium'); // app-level fallback
	} else {
		const tier = memoryToTier(memValue);
		updateElementWithEmphasis(
			memEl,
			'Device memory: ',
			`${memValue} GB (approx.)`
		);
		updateElementWithEmphasis(tierEl, 'Quality tier: ', tier);
		compatEl.textContent =
			'Value provided by navigator.deviceMemory (approximate & coarse).';
		applyQualityTier(tier);
	}
};

// Try to start a worker and show WorkerNavigator.deviceMemory usage
const startWorkerAndReport = (memValue) => {
	if (!window.Worker) return;
	try {
		const w = new Worker('worker.js');
		// send main-thread value to worker (worker can also read self.navigator.deviceMemory)
		w.postMessage({ mainMemory: memValue });
		w.onmessage = (ev) => {
			// worker will send back a message with its observation
			console.log('Worker says:', ev.data);
			const compatEl = document.getElementById('compat-note');
			compatEl.textContent += ` Worker reported deviceMemory: ${ev.data.workerMemory}`;
		};
	} catch (e) {
		console.warn('Could not start worker:', e);
	}
};

// Main detection function
const detectAndApply = () => {
	// navigator.deviceMemory is the API (available in secure contexts)
	// It's intentionally coarse to avoid fine-grained fingerprinting.
	const mem = navigator.deviceMemory; // may be undefined
	updateUI(mem);
	startWorkerAndReport(mem);
};

// --- Event Listeners and Initial Run ---

// Wire up UI
document.querySelector('#refresh').addEventListener('click', detectAndApply);

// Initial run (works on https or localhost; otherwise deviceMemory likely undefined)
detectAndApply();

// Extra: show a friendly compatibility tip if not secure context
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
	const compatEl = document.getElementById('compat-note');
	compatEl.textContent =
		'Tip: serve this page over HTTPS or run via http://localhost to allow secure-context-only APIs.';
}

				
			

Bottom line

 The Device Memory API is a tiny hint that unlocks right‑sized experiences. Use it to tailor media and effects by tier, not to exclude users—your sites will feel faster on low‑end hardware and look better on powerful machines.

More To Explore

Acronym DOM on wood planks
Code

A Friendly Introduction to the Document Object Model (DOM) API

The Document Object Model (DOM) is the browser’s in-memory representation of your HTML, letting JavaScript select elements (querySelector), listen to events (addEventListener), update content (textContent), toggle styles (classList), and create/insert nodes (createElement, insertAdjacentElement). With it, a button can change a box’s text, toggle a highlight class, set a data attribute, or insert a new paragraph right after the box—no page reload required—illustrating the simple flow: select, listen, update.

Share This Post

small_c_popup.png

Need help?

Let's have a chat...


Login

Jump Back In!

Here at Webolution Designs, we love to learn. This includes sharing things we have learned with you. 

Register

Begin Your Learning Journey Today!

Come back inside to continue your learning journey.