1. Introduction
This section is non-normative.Web Applications have conventionally been able to execute code, make network requests and interact with the user by means of established interaction, usually through a browser tab. This has allowed users to associate the presence of a browser tab with the Web Application’s ability to do work on their behalf.
Following the introduction of the Push API [PUSH-API] and Web Background Synchronization [WEB-BACKGROUND-SYNC], this assumption no longer stands. Web Applications are now able to both trigger and schedule execution of code in the background, outside of the user’s control.
In an effort to mitigate risk to the user, user agents have implemented restrictions such as time limits on executing code in the background, or a requirement for the Web Application to use the Web Notification API [NOTIFICATIONS] to inform the user of the work they’ve done. Those restrictions are often unspecified and left up to the discretion of the user agent. In some cases, user agents will choose to not enforce these restrictions depending on the intensity of the user’s engagement with the Web Application.
This specification describes an API that exposes a budget that can be used by authors to determine their current budget for resource consuming background operations, as well as the cost associated with doing a certain background operation.
Because this API relates to the ability to do work in the background, which is considered a privilege, functionality provided by this API is only available in a secure context.
This specification does not define how user agents establish or store the amount of current budget. It aims to define an API that exposes sufficient information to make the budget useful for authors, while not restricting the implementation details and heuristics specific to a user agent.
1.1. Current budget
There are various use-cases for needing to know the currently available budget:
- Deciding to not show a notification in response to a low priority push message whose primary purpose was to synchronize data.
- Deciding whether the origin can schedule a precise timer using a hypothetical Job Scheduler API.
Determine whether a user visible interaction is required in response to a push message:
self.addEventListener('push', event => { // Execute the application-specific logic depending on the contents of the // received push message, for example by caching the latest content. event.waitUntil( navigator.budget.reserve('silent-push').then(reserved => { if (reserved) return; // No need to show a notification. // Not enough budget is available, must show a notification. return registration.showNotification(...); }) ); });
1.2. Expected budget
There are various use-cases for needing to know the budget in advance:
- Deciding on the frequency of server-initiated cache updates of synchronized data.
- Deciding on the server whether there is sufficient budget available to hide previously shown notifications when the user dismissed them on other devices.
- Deciding to temporarily limit background operations if the budget could be used during an upcoming sporting event instead.
2. Concepts
The user engagement with an origin is defined by the intensity of their interaction with the application by means of navigation, interaction and retention signals.
A background operation is the ability for an origin to execute potentially resource consuming code in the background.
The background operation cost is a non-negative number that describes the cost of executing a background operation on the user’s device.
An origin has an associated budget, which is a non-negative number derived from the user engagement that describes how many background operations the origin is able to do, depending on the associated background operation costs.
An origin has an associated list of budget expectations. This starts with the origin’s currently available budget, followed by zero or more entries indicating the lower bound of available budget at known points in the future.
User agents are not required to maintain future-bound budget expectations, but doing so enables more use-cases for authors.
Part of an origin’s available budget can be reserved. This reduces the origin’s current budget by the given cost.
The reserved cost of certain background operations could be less than the cost
indicated by
when the user’s device is in favorable
conditions, for example because it’s not on battery power. getCost()
3. Security and Privacy Considerations
3.1. Applicability
Applicability of the Budget API is limited to potentially resource consuming background operations— operations that are not sufficiently privacy sensitive to need express user permission for basic usage.
User agents MUST NOT use the Budget API as an alternative to obtaining express user permission for privacy-sensitive operations such as accurate location access [GEOLOCATION-API] and access to the user’s camera and/or microphone [WEBRTC].
Examples include Web Background Sync [WEB-BACKGROUND-SYNC], which may have execution time and retry limitations applied by the user agent, and the Push API [PUSH-API] in situations where the effects of a push message are not immediately visible to the user.
3.1.1. Location Tracking
Fetch requests within background operations may reveal the client’s IP address to the server after the user left the page. The user agent SHOULD limit tracking by capping the duration of background operations.
3.2. Permissions
The Budget API provides an alternative to obtaining express user permission where the user agent believes it can appropriately protect the user for strictly resource consuming background operations.
Both the APIs described in this document, as well as the specifications that depend on this document, MUST NOT limit the user agent’s ability to require express user permission in addition to budget requirements.
User agents that require express user permission for certain background operations MAY lower or eliminate the background operation cost of such an operation, because the user has explicitly allowed the Web Application to engage on their behalf.
4. API
4.1. Navigator and WorkerNavigator extensions
[Exposed=Window] partial interface Navigator { [SameObject] readonly attribute BudgetService budget; };
[Exposed=Worker] partial interface WorkerNavigator { [SameObject] readonly attribute BudgetService budget; };
The budget
attribute’s getter must return a
scoped to the entry settings object’s origin. BudgetService
4.2. The BudgetService
interface
The
interface represents the programmatic interface to the user
agent’s budget service. It is available in both document and worker environments. BudgetService
[Exposed=(Window,Worker)] interface BudgetService { Promise<double> getCost(OperationType operation); Promise<sequence<BudgetState>> getBudget(); Promise<boolean> reserve(OperationType operation); };
The getCost()
method
returns a promise that will be resolved with the worst-case background operation cost of the indicated background operation.
When invoked, it MUST run the following steps:
- Let promise be a new promise.
- Let origin be the entry settings object’s origin.
- If the origin is not a secure context, reject promise with a
and terminate these steps.SecurityError
-
Return promise and run the following step in parallel:
- Resolve the promise with the worst-case background operation cost associated with the given operation.
The getBudget()
method
returns a promise that will be resolved with a sequence of
objects indicating the expected state of the budget at given times in the future. BudgetState
When invoked, it MUST run the following steps:
- Let promise be a new promise.
- Let origin be the entry settings object’s origin.
- If the origin is not a secure context, reject promise with a
and terminate these steps.SecurityError
-
Return promise and run the following step in parallel:
- Let details be a new
.sequence
-
If there are entries in origin’s list of budget expectations, for each entry:
- Let state be a new
instance.BudgetState
- Set state’s
attribute to entry’s budget value.budgetAt
- Set state’s
attribute to thetime
representing the final date of entry’s validity in milliseconds since 00:00:00 UTC on 1 January 1970.DOMTimeStamp
- Add state to details.
Otherwise:
- Let state be a new
instance.BudgetState
- Set state’s
attribute to 0.budgetAt
- Set state’s
attribute to thetime
representing the current time in milliseconds since 00:00:00 UTC on 1 January 1970.DOMTimeStamp
- Add state to details.
- Let state be a new
- Resolve the promise with details.
- Let details be a new
The reserve()
method
returns a promise that will be resolved with a boolean indicating whether the requested
budget for operation could be reserved.
When invoked, it MUST run the following steps:
- Let promise be a new promise.
- Let origin be the entry settings object’s origin.
- If the origin is not a secure context, reject promise with a
and terminate these steps.SecurityError
-
Return promise and run the following step in parallel:
- Let budget be the amount of budget available to origin.
- Let cost be the background operation cost associated with operation.
- If cost is greater than budget, resolve the promise with
the boolean
false
and abort these steps. - Reserve the cost from origin’s budget and resolve the promise with the boolean
true
.
4.3. The BudgetState
interface
The
interface represents the amount of budget available at
a specific point in time. This enables authors to make near-term decisions about how to spend
their budget. BudgetState
[Exposed=(Window,Worker)] interface BudgetState { readonly attribute double budgetAt; readonly attribute DOMTimeStamp time; };
The budgetAt
attribute’s getter must
return the budget at the associated
. time
The time
attribute’s getter must
return the timestamp representing the time, in milliseconds since 00:00:00 UTC on 1 January
1970, at which the
will be valid. budgetAt
4.4. The OperationType
enum
The
enumeration describes the known set of background
operations that the Web Budget API caters for. Authors can use this in combination with OperationType
to interpret their available budget as a
quantifiable set of background operations it can be used for. getCost()
enum OperationType {
"silent-push"
};
The following
values are defined: OperationType
- The
silent-push
value represents a background operation in response to an incoming push message through the Push API that does not result in a user visible action. [PUSH-API]
Specifications are encouraged to extend the
enumeration with
their own values. Naming consistency with the Permission API [PERMISSIONS], where
applicable, is recommended. OperationType