Back to Knowledge Hub
Platform

Compute Pressure API: Privacy-Safe Adaptive Workloads

Use Compute Pressure as a coarse, optional signal for reversible workload choices without turning runtime pressure into device identity.

BotBrowser Team

Documentation

Want the structured docs for Platform?

This article lives in the editorial library. For step-by-step setup, reference material, and ongoing updates, jump into the docs section.

The Compute Pressure API exposes a coarse view of pressure affecting a browser workload. It can help an application choose a lighter rendering path, defer optional work, or restore quality after a transition. It is not a CPU meter, a device fingerprint, or a diagnosis of the host. BotBrowser controlled contexts can run an authorized fixture that feature-detects PressureObserver and records visible outcomes when the runtime exposes the API; BotBrowser cannot manufacture a pressure source, force support, or guarantee identical transitions on every host. For adjacent hints, compare Device Memory and web performance, hardware concurrency and worker planning, and PerformanceObserver for application health.

TL;DR

  • Treat PressureObserver as an optional, coarse signal for a reversible workload decision.
  • Keep observer ownership, callback cleanup, and adaptation state inside the component that owns the work.
  • Do not turn nominal, fair, serious, or critical into a device, person, or account label.
  • Keep the baseline path useful when the API is missing, rejected, delayed, or unavailable in a worker.
  • Record a bounded outcome such as reduced, restored, or unavailable, not a long-lived pressure history.

Contents

A PressureObserver capability check leads to a coarse state, a reversible workload choice, or an unavailable fallback.

Read pressure as a coarse capability signal

The Compute Pressure specification defines a browser-facing observation model rather than a promise about a physical processor. An application creates a PressureObserver, supplies a callback, and asks it to observe a pressure source such as cpu. The callback receives PressureRecord values with a state and timestamp. The state vocabulary is intentionally coarse: nominal, fair, serious, and critical describe a pressure band, not a percentage that another system can compare directly.

The MDN Compute Pressure API reference describes the API surface and its availability. Feature-detect the constructor and the methods you use. A missing PressureObserver means that this runtime cannot provide the optional signal through that path. It does not mean that the host is idle, overloaded, fast, or unsafe. A permission-policy decision, a browser release, a worker type, or a platform privacy choice can all explain the absence.

The Chrome Compute Pressure guidance presents adaptation as a way to keep work responsive. Treat that guidance as a model for a user-facing decision, not as a compatibility promise for every embedded browser. The source and the browser release determine which states and sources are exposed. A page should have a useful baseline before it asks whether a richer observation path exists.

Pressure is not equivalent to navigator.hardwareConcurrency, navigator.deviceMemory, or a performance entry. A browser may coarsen or delay pressure changes, and two pages can observe different states while sharing a host. The state also does not identify which tab, process, extension, system task, or thermal condition contributed to it. Keep those questions out of the application record unless a separate, authorized diagnostic answers them.

Use a state record that names the owner and the decision, not the presumed cause:

const pressureState = {
  source: 'cpu',
  state: 'unavailable',
  policy: 'baseline',
  sequence: 0,
};

source, state, and policy are bounded labels. sequence lets the component discard an old callback after teardown or replacement. Do not append raw records forever, export timestamps with a user identifier, or use the state as a join key with account data. If a product needs a performance investigation, create a separate, consented measurement with its own retention rule.

Choose a reversible workload policy

Adaptation should change optional work while preserving the task the user came to complete. A serious state might pause a background preview, reduce a particle count, or postpone an index build. It should not silently discard an edit, lower a required security check, or make a control inaccessible. The policy owns the decision; the pressure observer only supplies a hint.

Write the policy as an explicit state machine. The baseline is available before observation, and every transition has a return path:

Observed outcomeWorkload actionUser-visible contractRecovery condition
unavailableKeep the baseline budget and skip optional observationCore task remains usableRe-evaluate only after a declared runtime change
nominalPermit the normal optional budgetQuality and controls remain availableApply the same limits as the baseline
fairDefer nonessential work and reduce concurrency within an app-owned capTell the user when a preview is delayedRestore after a later observed state, not a timer alone
seriousPause background work and select a bounded lightweight pathKeep input, focus, and cancellation visibleResume only from a newer record owned by this component
criticalStop optional work and preserve the committed resultExplain that optional processing is pausedRequire a fresh state and a safe budget before resuming

The labels are policy outcomes, not measurements of CPU utilization. Avoid a rule such as “critical means the machine has 90% load.” The API does not establish that conversion, and a limit copied from another runtime can cause oscillation. Keep hysteresis in the policy if a transition would otherwise flicker: for example, require one newer record before restoring optional work, while still allowing a user-initiated action to override a preview pause.

Use separate budgets for foreground work, background work, and retained data. A pressure response must not become permission to grow an unbounded queue. Cap pending tasks, cancel obsolete work, and make every worker or scheduler path report whether it committed, was superseded, or was cancelled. When the user changes a document during a pressure transition, the newest task owns the visible result even if an older task finishes later.

The policy should be reversible in both directions. A reduced image size can return to the previous size only after the component verifies that the source still exists and the user has not changed the view. A paused worker can resume only after its inputs remain valid. Keep the previous committed result visible while optional work catches up; replacing it with a blank placeholder makes pressure look like data loss.

Choose the budgets from the work the application owns. A document editor might allow one foreground validation, two queued thumbnails, and no more than one background index task. A map preview might keep the current tile set and stop prefetching neighbors. The numbers are application limits, not Compute Pressure values. Keep them in configuration that can be reviewed with the feature, and expose a bounded “try again” action when the user explicitly requests optional work.

Separate a pressure transition from a failed operation. If a parser rejects input while the policy is reduced, record parse-error and keep the pressure state as context; do not relabel the parser failure as critical. If a worker is cancelled because a newer edit arrived, record superseded, even when the observer callback arrived at the same time. This vocabulary lets support staff distinguish a workload choice from a correctness defect without retaining the source document.

Restoration needs a quiet path as well as a fast path. When a newer record returns to nominal, schedule one small recovery step, verify that the view is still mounted, and then restore the next optional unit. Do not start every paused task at once. If another serious record arrives, cancel the recovery task and leave the committed result intact. A bounded recovery queue prevents the application from creating a new pressure spike while responding to the previous one.

The same policy can serve a page and a worker when the message contract is explicit. The page owns the visible preview and the worker owns its computation. The worker reports sequence, policy, and outcome; the page decides whether the report belongs to its current route. If the page navigates away, it rejects the old sequence and closes the worker. This keeps lifecycle ownership clear without sending raw pressure records between contexts.

Accessibility belongs in the transition contract. Announce a meaningful mode change without repeating every callback, retain keyboard focus, preserve a text alternative, and expose a retry or restore action when optional work is paused. A “lighter mode” must not remove labels, keyboard affordances, or a required validation message. The pressure signal is allowed to change computation, not the user's ability to understand and control the task.

Own observation and privacy boundaries

The component that starts PressureObserver owns the observer, the callback, the policy state, and cleanup. Constructing an observer in a shared utility and forgetting which page owns it makes teardown unreliable. Store the observer in the component that can call disconnect() when the route changes, the worker closes, or the feature is disabled.

The callback should be short. Copy only the state and a local sequence into the policy queue, then return. Do not perform a network request, synchronous layout scan, or large serialization from the callback. If adaptation requires asynchronous work, schedule one bounded task and cancel or supersede it when a newer pressure record arrives. This keeps the observer from becoming the source of the workload it is meant to protect.

The browser may deliver records at a privacy-preserving cadence. Do not infer a hidden high-resolution timeline from the spacing of callbacks. A timestamp can order records for the component, but it is not evidence of a user action, a core count, or a thermal event. Round or omit timestamps in product telemetry unless a documented investigation needs ordering, and retain them only for the shortest useful window.

Keep pressure records out of identity and analytics joins. A state sequence combined with URL, account, locale, or device data can become a persistent behavioral signal even when each field looks harmless. Prefer a single aggregate such as policy=paused for a bounded session. If the product needs fleet health, aggregate after removing account identifiers and document the sampling and retention policy. A dashboard that retains every transition is a different product decision from an adaptive UI.

Workers and frames introduce another owner boundary. A worker may observe its own source, but the page decides whether the result is still relevant to the current route. Send a small message such as workload-reduced with a local sequence, not the entire record history. An iframe should not receive pressure data merely because it shares a page; pass the minimum policy outcome required by an explicit contract. Validate message origin and schema when a boundary crosses documents.

The absence path deserves the same privacy review. A browser that lacks the API should not be labelled “low capability” in an account profile. Use unavailable for the local decision, keep the baseline task usable, and avoid asking for a different identifier to compensate. If a browser permission or policy blocks observation, report that fact only to the owner who can act on it.

BotBrowser can exercise an authorized page and compare visible adaptation outcomes in a controlled context when the selected runtime exposes PressureObserver. It cannot create pressure, control another tab's workload, identify a host-level cause, or certify that a production page will receive the same cadence. Keep that product boundary beside the fixture result rather than presenting a controlled observation as a host benchmark.

Verify transitions with a bounded fixture

Use a synthetic page with one optional workload and one committed result. The fixture should expose a feature-detection outcome, install one observer, apply one bounded policy transition, and disconnect. It must not collect real account data, enumerate unrelated pages, or retain a pressure history. A test that cannot run the API should still produce an explicit unavailable row.

The smallest useful implementation makes ownership visible:

const record = { source: 'cpu', state: 'unavailable', policy: 'baseline', sequence: 0 };
let observer;

if ('PressureObserver' in globalThis) {
  observer = new PressureObserver(records => {
    const latest = records.at(-1);
    record.sequence += 1;
    record.state = latest?.state ?? 'unavailable';
    record.policy = record.state === 'serious' || record.state === 'critical' ? 'reduced' : 'normal';
  });
  await observer.observe('cpu');
}

try {
  await runBoundedFixture({ limit: 8, signal });
} finally {
  observer?.disconnect();
}

The fixture does not pretend to force a state; it records the state the runtime makes visible. In a browser test harness, inject a declared test seam only when the harness documents that seam. Do not monkey-patch production APIs and call the result a platform observation. A synthetic unavailable run is still valuable because it checks that the baseline and cleanup work without the optional feature.

Capture a compact decision table for each run:

Fixture caseExpected recordWhat it provesWhat it does not prove
Constructor missingunavailable, baselineFeature detection and fallback are safeThat the host is idle or unsupported in general
Observer attachesnominal or another visible state, normal or reduced policyThe owner can receive a bounded recordA physical CPU percentage or root cause
New serious or critical recordreduced with a newer sequenceOptional work can pause without losing the committed resultThat every tab or worker shares the state
Route or worker teardownNo later policy commit after disconnect()Cleanup prevents stale callbacksThat the browser will never queue a prior callback
User restores optional workA new bounded task with current inputsRecovery is explicit and reversibleThat pressure has disappeared globally

Record browserVersion, runtimePath, source, state, policy, sequence, fixtureId, and outcome only as synthetic, bounded fields. Keep the fixture identifier unrelated to an account or URL. If the observer rejects a source, classify unsupported-source separately from unavailable; a rejection is a capability result, not a host diagnosis. If the callback never arrives, retain observer-attached and a bounded timeout outcome rather than inventing nominal.

Keep one reviewer-facing note with the fixture date, selected browser release, and the policy version. That note lets a later run distinguish a changed implementation from a changed browser surface while avoiding a permanent history of user pressure states.

Repeat the rows after a browser release, worker change, workload change, or privacy-policy change. Compare the first differing field: constructor availability, observer attachment, state cadence, policy transition, or cleanup. A changed first field narrows the investigation without claiming that the API caused the product regression. Keep a previous committed result in the fixture so a paused optional path cannot masquerade as a failed transaction.

Do not use this fixture to rank devices or tune a universal limit. Pressure observations are contextual and coarse. A result that is useful for deciding whether to defer a preview cannot establish that one customer has fewer cores, that another account is responsible for the pressure, or that a server-side slowdown has the same cause. Route those questions to separate evidence with explicit authorization.

Public sources

Practical conclusion

Feature-detect PressureObserver, keep the baseline usable, and let a bounded policy decide which optional work can pause or resume. Assign one owner to the observer and its cleanup, keep records coarse and short-lived, and preserve committed user results during transitions. Re-run the synthetic fixture after browser, worker, workload, or privacy-policy changes; decide from the first observable state that moved, not from a theory about the host.

#Compute Pressure API#Adaptive Workloads#Web Privacy#Browser Performance

This article is part of the guide: Web Platform Surfaces: A Consistency Review Map

Take BotBrowser from research to production

The guides cover the model first, then move into cross-platform validation, isolated contexts, and scale-ready browser deployment.