A quick look at the Compute Pressure API: smarter performance under load

Businesswomen tick mark an assessment, questionnaire, evaluation
The Compute Pressure API lets web apps sense system strain (CPU and thermals) and adapt in real time—preventing throttling, stutter, and battery drain.

Modern web apps increasingly juggle heavy, real‑time workloads—think video conferencing, collaborative editors, and 3D games—all competing with other apps for the same device resources. The Compute Pressure API is an experimental Web API that helps your app sense when the system is under strain and adapt proactively, preserving a smooth user experience.

What it does

Where to use it

Key concepts

Why it matters

Traditional performance tuning often reacts after glitches happen—dropping animation frames or throttling tasks when stutters are already visible. The Compute Pressure API encourages proactive adaptation, helping you prevent device overheating, fan noise escalation, or battery drain while keeping your app responsive and pleasant to use.

Getting started tips

Caveats

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

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Compute Pressure API Demo</title>

    <!-- Minimal styling for the demo UI -->
    <link rel="stylesheet" data-wphbdelayedstyle="styles.css" />

        <script type="wphb-delay-type" src="computePressureApi.js" defer></script>

    <!-- Important: The Compute Pressure API is experimental and requires HTTPS. -->
    <!-- Reference: https://developer.mozilla.org/en-US/docs/Web/API/Compute_Pressure_API -->
</head>

<body>
    <main class="container">
        <header class="header">
            <h1>Compute Pressure API Demo</h1>
            <p class="subtle">
                Experimental API. Requires HTTPS. See MDN:
                <a href="https://developer.mozilla.org/en-US/docs/Web/API/Compute_Pressure_API" target="_blank"
                    rel="noreferrer noopener">
                    Compute Pressure API
                </a>
            </p>
        </header>

        <!-- Support and environment status -->
        <section class="card">
            <h2>Environment & Support</h2>
            <ul class="status-list">
                <li>
                    Secure context (HTTPS):
                    <strong id="secureStatus">checking…</strong>
                </li>
                <li>
                    PressureObserver available:
                    <strong id="poStatus">checking…</strong>
                </li>
                <li>
                    Supported sources:
                    <strong id="sources">checking…</strong>
                </li>
                <li>
                    Current observation:
                    <strong id="obsStatus">stopped</strong>
                </li>
            </ul>
            <p class="note" id="supportNote"></p>
        </section>

        <!-- Controls to start/stop observing and a visual indicator for state -->
        <section class="card">
            <h2>Observer Controls</h2>
            <div class="row">
                <label for="sourceSel">
                    Source:
                    <!-- The API commonly supports 'cpu' (we’ll query dynamically) -->
                    <select id="sourceSel"></select>
                </label>

                <button id="btnStart" class="btn primary">Start observing</button>
                <button id="btnStop" class="btn" disabled>Stop observing</button>
            </div>

            <!-- Current state indicator with color coding -->
            <div class="state">
                <div class="state-indicator" id="stateDot" title="No data"></div>
                <div>
                    <div>Latest state: <strong id="stateText">—</strong></div>
                    <div class="muted" id="stateMeta">time: —</div>
                </div>
            </div>
        </section>

        <!-- Optional CPU stress tool to help provoke state changes (if supported) -->
        <section class="card">
            <h2>CPU Stress Tool (optional)</h2>
            <p class="muted">
                Starts a Web Worker that performs CPU-intensive work to increase system pressure.
                Use carefully and stop when done.
            </p>
            <div class="row">
                <label for="intensity">
                    Intensity:
                    <input id="intensity" type="range" min="0" max="100" value="50" />
                    <span id="intensityVal">50%</span>
                </label>
                <button id="btnStressStart" class="btn">Start stress</button>
                <button id="btnStressStop" class="btn" disabled>Stop stress</button>
            </div>
        </section>

        <!-- Log of PressureRecord changes -->
        <section class="card">
            <h2>Change Log</h2>
            <div id="log" class="log" aria-live="polite"></div>
        </section>
    </main>
<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>
				
			
				
					/* Layout helpers */
.full-width {
    width: 100%;
}

.grid-gap {
    display: grid;
    gap: 0.5rem;
}

.mt-05 {
    margin-top: 0.5rem;
}

.my-025 {
    margin: 0.25rem 0;
}

/* Replaces the inline pre/box styling used for results and previews */
.pre-box {
    white-space: pre-wrap;
    background: #f6f8fa;
    padding: 0.75rem;
    border-radius: 6px;
}

/* Optional: small base styles (add/remove as you prefer) */
/*
body {
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
  line-height: 1.4;
  max-width: 800px;
  margin: 2rem auto;
  padding: 0 1rem;
}
*/
				
			
				
					/*
  Compute Pressure API Demo
  -------------------------
  - Observes system resource pressure (e.g., CPU) and reports high-level states.
  - Experimental: requires HTTPS and limited browser support.
  - Reference: https://developer.mozilla.org/en-US/docs/Web/API/Compute_Pressure_API

  This script:
  1) Detects API support and secure context.
  2) Queries supported sources (commonly ['cpu']) and populates a selector.
  3) Starts/stops a PressureObserver and updates UI with the latest PressureRecord.
  4) Includes an optional CPU stress tool (Web Worker via Blob URL) to help provoke state changes.
*/

/* --------------- DOM elements --------------- */
const secureStatusEl = document.querySelector('#secureStatus');
const poStatusEl = document.querySelector('#poStatus');
const sourcesEl = document.querySelector('#sources');
const obsStatusEl = document.querySelector('#obsStatus');
const supportNoteEl = document.querySelector('#supportNote');

const sourceSel = document.querySelector('#sourceSel');
const btnStart = document.querySelector('#btnStart');
const btnStop = document.querySelector('#btnStop');

const stateDot = document.querySelector('#stateDot');
const stateText = document.querySelector('#stateText');
const stateMeta = document.querySelector('#stateMeta');

const intensityRange = document.querySelector('#intensity');
const intensityVal = document.querySelector('#intensityVal');
const btnStressStart = document.querySelector('#btnStressStart');
const btnStressStop = document.querySelector('#btnStressStop');

const logEl = document.querySelector('#log');

/* --------------- Utilities --------------- */

/**
 * Append a line to the log.
 * @param {string} msg
 * @param {string} [state] - one of nominal|fair|serious|critical to colorize
 */
const log = (msg, state) => {
	const p = document.createElement('div');
	p.className = 'line';
	if (state) {
		const tag = document.createElement('span');
		tag.className = `tag ${state}`;
		tag.textContent = state.toUpperCase();
		p.appendChild(tag);
	}
	p.append(document.createTextNode(msg));
	logEl.appendChild(p);
	logEl.scrollTop = logEl.scrollHeight;
};

/** Format DOMHighResTimeStamp to wall clock */
const formatTimeStamp = (ts) => {
	// record.time is DOMHighResTimeStamp relative to timeOrigin (if provided by the UA)
	const wall = performance.timeOrigin
		? new Date(performance.timeOrigin + ts)
		: new Date();
	return wall.toLocaleTimeString();
};

/** Update the state indicator dot + labels */
const updateStateUI = (state, time) => {
	stateDot.classList.remove(
		'state-nominal',
		'state-fair',
		'state-serious',
		'state-critical'
	);
	if (state) {
		const safe = ['nominal', 'fair', 'serious', 'critical'].includes(state)
			? state
			: 'nominal';
		stateDot.classList.add(`state-${safe}`);
		stateText.textContent = safe;
		stateMeta.textContent = time ? `time: ${formatTimeStamp(time)}` : 'time: —';
		stateDot.title = `Latest state: ${safe}`;
	} else {
		stateText.textContent = '—';
		stateMeta.textContent = 'time: —';
		stateDot.title = 'No data';
	}
};

/* --------------- CPU Stress Worker (optional) --------------- */
/*
  We create a Web Worker from a Blob URL so this demo remains a single JS file.
  The worker busy-waits in short slices, controlled by an "intensity" percentage (0–100).
  - At 0% it sleeps (no significant CPU).
  - At 100% it busy-waits nearly constantly.
  This can help provoke pressure state changes on supported browsers/devices.
*/
let stressWorker = null;

const createStressWorker = () => {
	const workerCode = `
    let running = false;
    let intensity = 50; // 0..100 (% of each 50ms slice spent busy-waiting)

    function busyWait(ms) {
      const end = performance.now() + ms;
      while (performance.now() < end) {
        // Do some meaningless math to keep CPU busy
        let x = 0;
        for (let i = 0; i < 1000; i++) x += Math.sqrt(i) % 3;
      }
    }

    function loop() {
      if (!running) return;
      const slice = 50; // ms per slice
      const busy  = (intensity / 100) * slice;
      if (busy > 1) busyWait(busy);
      // Sleep the remainder of the slice
      setTimeout(loop, Math.max(0, slice - busy));
    }

    self.onmessage = (e) => {
      const { cmd, value } = e.data || {};
      if (cmd === 'start') {
        running = true;
        loop();
      } else if (cmd === 'stop') {
        running = false;
      } else if (cmd === 'intensity') {
        // clamp 0..100
        intensity = Math.max(0, Math.min(100, Number(value) || 0));
      }
    };
  `;
	const blob = new Blob([workerCode], { type: 'application/javascript' });
	return new Worker(URL.createObjectURL(blob));
};

const startStress = () => {
	if (!stressWorker) stressWorker = createStressWorker();
	stressWorker.postMessage({ cmd: 'intensity', value: intensityRange.value });
	stressWorker.postMessage({ cmd: 'start' });
	btnStressStart.disabled = true;
	btnStressStop.disabled = false;
	log('CPU stress worker: started');
};

const stopStress = () => {
	if (stressWorker) stressWorker.postMessage({ cmd: 'stop' });
	btnStressStart.disabled = false;
	btnStressStop.disabled = true;
	log('CPU stress worker: stopped');
};

/* --------------- Pressure Observer --------------- */

let observer = null;
let observingSource = null;

/**
 * Initialize a PressureObserver with a callback to handle PressureRecord arrays.
 * Note: Options (like sampleRate) may vary by implementation; we omit them for broadest compatibility.
 */
const createObserver = () => {
	// The callback receives an array of PressureRecord(s). Each has:
	// - record.source (e.g., 'cpu')
	// - record.state  ('nominal'|'fair'|'serious'|'critical')
	// - record.time   (DOMHighResTimeStamp)
	observer = new PressureObserver((records) => {
		for (const rec of records) {
			const msg = `[${rec.source}] state=${rec.state} at ${formatTimeStamp(
				rec.time
			)}`;
			log(msg, rec.state);
			// Update the UI to reflect the latest record for the currently observed source
			if (rec.source === observingSource) {
				updateStateUI(rec.state, rec.time);
			}
		}
	});
};

/** Start observing the selected source */
const startObserving = async () => {
	if (!('PressureObserver' in window)) return;
	if (!observer) createObserver();

	const source = sourceSel.value || 'cpu';
	try {
		// Observe the given source (e.g., 'cpu').
		await observer.observe(source);
		observingSource = source;
		obsStatusEl.textContent = `observing '${source}'`;
		btnStart.disabled = true;
		btnStop.disabled = false;
		log(`Observer: now observing '${source}'`);
	} catch (err) {
		log(`Observer error: ${err?.message || err}`, 'serious');
	}
};

/** Stop observing the current source */
const stopObserving = async () => {
	if (!observer || !observingSource) return;
	try {
		await observer.unobserve(observingSource);
	} catch (e) {
		// Some implementations may not throw; ignore failures here.
	}
	log(`Observer: stopped observing '${observingSource}'`);
	observingSource = null;
	obsStatusEl.textContent = 'stopped';
	btnStart.disabled = false;
	btnStop.disabled = true;
	updateStateUI(null, null);
};

/* --------------- Setup & Feature Detection --------------- */

(init = async () => {
	// Secure context check
	secureStatusEl.textContent = window.isSecureContext ? 'yes' : 'no';
	if (!window.isSecureContext) {
		supportNoteEl.textContent = 'This API requires a secure context (HTTPS).';
	}

	// API feature detection
	const supported = 'PressureObserver' in window;
	poStatusEl.textContent = supported ? 'yes' : 'no';
	if (!supported) {
		supportNoteEl.textContent =
			'PressureObserver is not available in this browser. Try a recent Chromium-based browser, enable flags, or check MDN for updates.';
	}

	// Populate supported sources (commonly ['cpu']). Fallback to 'cpu' if not available.
	let sources = ['cpu'];
	if (supported && typeof PressureObserver.supportedSources === 'function') {
		try {
			const s = await PressureObserver.supportedSources();
			if (Array.isArray(s) && s.length) sources = s;
		} catch {
			// Ignore errors, keep default
		}
	}
	sourcesEl.textContent = sources.join(', ');
	sourceSel.innerHTML = sources
		.map((s) => `<option value="${s}">${s}</option>`)
		.join('');

	// Hook up UI events
	btnStart.addEventListener('click', startObserving);
	btnStop.addEventListener('click', stopObserving);

	intensityRange.addEventListener('input', () => {
		intensityVal.textContent = `${intensityRange.value}%`;
		if (stressWorker)
			stressWorker.postMessage({
				cmd: 'intensity',
				value: intensityRange.value
			});
	});
	btnStressStart.addEventListener('click', startStress);
	btnStressStop.addEventListener('click', stopStress);

	// If supported, prepare the observer
	if (supported) {
		createObserver();
		log('Observer ready. Click "Start observing" to begin.');
	} else {
		log(
			'Compute Pressure API not supported. UI will not receive real updates.',
			'fair'
		);
	}
})();

				
			

Bottom line

The Compute Pressure API gives the web a vocabulary for device strain and a way to act before users feel pain. If your app’s quality hinges on consistent performance under variable load, integrating these signals can make your experience more resilient—just be sure to gate it behind capability checks and maintain graceful fallbacks.

More To Explore

Crisis. Concept of reducing costs. Bag with dollars money in vise.
Code

Compression Streams API: Native gzip/deflate for the web

The Compression Streams API brings native, streaming gzip and deflate to the web platform. With built‑in CompressionStream and DecompressionStream, you can compress or decompress data on the fly—no third‑party libraries required. It integrates cleanly with Fetch/Response to turn streams into ArrayBuffer, Blob, Uint8Array, String, or JSON, works in Web Workers, and is part of the 2023 Baseline. Use it to shrink uploads, store compressed data offline, and streamline real‑time pipelines while keeping bundles lean.

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.