JavaScript Compute Pressure Table

PieceWhat it doesField note
new PressureObserver(cb)The watchercallback receives PressureRecord lists; construction behind a feature detect - unsupported engines keep current quality forever
observer.observe(source, opts)The startsource is cpu in the current spec; thresholds option maps utilization into your own buckets
PressureRecord {state}The signalnominal / fair / serious / critical - whole-system CPU pressure, not your tab share
transition-only deliveryThe contractfires on state CHANGE, rate-limited by the browser - no polling, no getCurrentPressure, telemetry-firehose designs are forbidden by design
the state ladderThe policynominal/fair go, serious trims (resolution, effects, prefetch), critical stops discretionary work - one state to one action, monotonic
hysteresisThe damperdrop fast, restore slow - dwell timers prevent oscillation when the system sits at a boundary
weightless callbackThe disciplinequeue records, decide on the next frame - heavy work in the callback adds the pressure it reports
lifecycle releaseThe hygieneunobserve/disconnect on hide and teardown - observing while hidden spends battery for decisions nobody watches
Reference: the MDN Compute Pressure API. The machine telling your page how hard it is working: coarse, transition-driven CPU pressure states with privacy shaping on purpose - the input that makes quality adaptation graceful instead of guesswork.
Bottom line: wire the states into your existing quality controller as a ceiling next to network throughput (the min of the two wins), drop fast and restore slow with dwell-based hysteresis, and keep the callback weightless. The API reports the whole system, cpu only, transition-only - feedback-loop probing is designed out, graceful degradation is designed in.
Related tools: the web workers table (the load whose pressure you watch), the observer table (the observer pattern family), the event loop table (the congestion pressure reflects), the performance timing table (the numbers you defer under load), and the idle detection table (the user-idle sibling signal).

The Compute Pressure API answers a question pages have always guessed at: how hard is the machine working right now? A PressureObserver watches the system's CPU pressure and delivers states - nominal, fair, serious, critical - whenever the level changes, so your page can spend or save compute accordingly: drop video resolution when the machine is drowning, pause fancy particle effects, defer analytics work, and climb back when the pressure lifts.

Bottom line: the shape is observer-plus-callback. const observer = new PressureObserver(records => {...}); observer.observe('cpu') starts watching (the source is the only one in the current spec); callback records are PressureRecord objects carrying {source, state, time} and arrive ONLY on state transitions, not on a timer - nominal-to-fair fires once, not repeatedly. Unobserve or disconnect stops the flow. The delivery model is deliberately unhurried: transitions are rate-limited by the browser so the API itself does not become load - treat the callback as an advisory signal for quality decisions, not a telemetry firehose.

The boundary that shapes every design: this is a local, coarse signal with privacy shaping on purpose. It reports the WHOLE system's pressure (not your tab's share), it says nothing about memory, network, temperature or battery, and browsers rate-limit and quantize it so it cannot fingerprint the machine or time side-channels precisely. The pattern it enables is graceful degradation - your page reacting like a good citizen on a loaded machine - and the pattern it forbids is probing (measuring your own workload's effect on the system).

How to use

  1. Feature-detect, then observe: if ('PressureObserver' in window) { const po = new PressureObserver(onPressure); po.observe('cpu', {thresholds: [...]}) } - unsupported platforms keep their current quality level forever, which is the correct default.
  2. Branch on states: nominal and fair mean go (full quality); serious means trim (lower resolution, fewer effects); critical means stop (pause non-essential work entirely) - write the ladder before the observer, one state to one action, so the callback stays dumb.
  3. Use thresholds deliberately: observe('cpu', {thresholds: [0.25, 0.5, 0.85]}) lets the browser map raw utilization into your buckets and only notify on crossing - fewer, more meaningful transitions than the default bands.
  4. Keep the callback weightless: append the record to a queue and decide on your next frame or timer tick - heavy work in the pressure callback adds pressure and risks re-triggering the very signal you are watching.
  5. Release on lifecycle: po.unobserve('cpu') or po.disconnect() on page hide (visibilitychange) and on teardown - observing while hidden spends trust and battery for decisions nobody is watching; re-observe on return.

Frequently asked questions

What do the four states actually measure, and what is the right action for each?

The states quantify whole-system CPU pressure, and each maps to a different class of action. Nominal: the machine is comfortable - run full quality, schedule background work freely (this is also the state to catch up on deferred analytics or sync). Fair: noticeable utilization, headroom exists - hold quality, stop ADDING background load, and let thresholds guide you if you defined custom bands. Serious: the system is struggling - shed optional compute: drop video to the next-lower rendition, halve particle counts, pause prefetch and speculation (prerender/speculation-rules are exactly the kind of work to cancel here). Critical: the machine is drowning - stop discretionary work outright: pause non-visible video processing, kill all non-essential timers and observers, show the user nothing but the core experience. Two design notes that separate good implementations: the ladder must be monotonic and sticky (quality returns more slowly than it drops - hysteresis prevents oscillation when the system sits near a boundary), and actions must be reversible state machines, not one-way switches, because pressure comes and goes and users notice when effects never return.

Why does the callback only fire on transitions, and how do thresholds change that?

The delivery model is transition-driven and rate-limited by design - the API refuses to become the load it reports. A plain observe gives you a callback per state CHANGE (crossing between the browser's default bands), which is exactly the event quality adaptation needs and nothing more. The thresholds option reshapes the bands: your array of utilization cut-points (0 to 1) becomes the boundaries, so states fire when your buckets are crossed rather than the browser's - lower the count and you get fewer, coarser signals; place them around YOUR quality ladder's decision points and every callback becomes actionable. What you never get, deliberately: periodic readings, current-state polling on demand (there is no getCurrentPressure()), or sub-band detail. If you need time-series telemetry, this API is the wrong tool by privacy design - it quantizes precisely so the machine's load profile cannot be exfiltrated. The pattern that works with the grain: on each transition record, apply your ladder action and ALSO stamp a log line locally; over a session you reconstruct a pressure timeline from transitions, which is enough for tuning thresholds without any polling.

How does this fit a video-call or streaming quality ladder in practice?

This is the API's flagship pattern, and the integration has a clean seam. The seam: your player already has a quality ladder (renditions, effects, camera resolution) and a controller that decides the current rung - Compute Pressure becomes one more input to that controller, joining network throughput (the classic input) and device class. The priority ordering matters: network still leads (bandwidth swings are bigger and faster than CPU states), pressure acts as the ceiling - the network may allow 1080p while a serious CPU state caps you at 720p, and the controller takes the min. The concrete wins reported by early integrations: video calls that drop camera resolution instead of stuttering when a screenshare or a background build hogs the CPU; streaming pages that pause speculation and preloads at serious; effect-heavy pages that degrade gracefully instead of dropping frames. The two adjustments that make it production-grade: hysteresis (drop at serious, restore only after nominal persists for a few seconds - the state API gives you transition records, your controller adds the dwell timer) and user-visible honesty (a quiet quality badge beats silent flapping; users forgive quality, not instability).

What are the API's hard limits, and what do I do about the dimensions it does not cover?

The limits are deliberate and knowing them prevents misdesign. Source coverage: the spec ships with 'cpu' only - no GPU pressure, no memory, no network, no temperature; GPU-adaptive rendering still keys off frame timing (requestAnimationFrame deltas), memory pressure off allocation failures and performance.memory where present, network off the Network Information API and throughput probes. System-wide scope: the signal is the machine's load, not your page's contribution - your tab cannot learn what its own work did to the CPU, which kills feedback-loop designs (measure-act-measure) but is precisely what makes cross-page coordination safe. Rate limiting and quantization: transitions arrive late and coarse enough to resist fingerprinting and side channels - do not build timing-sensitive logic on record timestamps. Browser scoping: Chromium-first shipping; unsupported engines throw on construction - the feature detect returns your current behavior, which must be a working (if unadaptive) page. And the honest architectural conclusion: Compute Pressure covers one input of an adaptive system; the production pattern composes it with the network, memory and frame-timing signals behind one quality controller, because real machines are constrained along several axes at once and users experience the worst one, not the average.

Related tools