This specification defines an API that allows [=installed web applications=] to set an application badge, which is usually shown alongside the application's icon on the device's home screen or application dock.

This is a work in progress.

Responsible badge usage

Badges can contribute to notification fatigue for some users. As such, authors need to reserve badges for states that truly merit user attention or action; avoid using them for marketing or engagement gimmicks.

Avoid rapidly changing values that increase distraction or cognitive load.

To support users who do not perceive badges, or have disabled them at the system level, authors are encouraged to present the same state within application UI using accessible patterns (e.g., clearly labeled in-app status indicators).

Usage examples

        async function updateMailBadge() {
          // Check if the API is supported.
          if (!navigator.setAppBadge) return;

          const unreadCount = await getUnreadMailCount();

          // Try to set the app badge.
          try {
            await navigator.setAppBadge(unreadCount);
          } catch (e) {
            // The badge is not supported, or the user has prevented the app
            // from setting a badge.
          }
        }
      

The badge might show up on the application's icon in the operating system. If multiple API calls within the same application [=badge/set=] or [=badge/clear=] a badge, the most recent one takes effect, and may continue being seen even after an application is closed.

        async function showPlayerTurn(playerTurnId) {
          if (playerTurnId === localPlayerId)
            await navigator.setAppBadge();
          else
            await navigator.clearAppBadge();
        }
      

On some operating systems [=badge/setting=] a badge can require permission from the user. In this case, a developer need to query the "[=notifications=]" permissions status before [=badge/setting=] a badge. If the permission is not granted, the developer will need to prompt for permission via the {{Notification}}.{{Notification/requestPermission()}}.

        async function checkPermission() {
          permission = await navigator.permissions.query({
            name: "notifications",
          });
          const button = document.getElementById("permission-button");
          if (permission.state === "prompt") {
            // Prompt the user to grant permission.
            button.hidden = false;
            button.addEventListener("click", async () => {
              await Notification.requestPermission();
              checkPermission();
            }, { once: true });
            return;
          }
          button.hidden = true;
        }
      

Model

A badge is intended as a mechanism for [=installed web applications=] to notify the user that there is some new activity that might require their attention, or as a way of indicating a small amount of information, such as an unread count.

A [=badge=] can have one of the following values:

The special value "nothing":
Indicates that there is no badge currently [=badge/set=]. When a [=badge=] has this value, no visual indicator should be displayed to the user.
The special value "flag":
Indicates that the badge is [=badge/set=] and should be displayed to the user, but contains no specific numerical value. This is distinct from [=badge/"nothing"=] in that a visual indicator should be shown to the user to indicate the presence of the badge.
A number value:
Indicates that the badge is [=badge/set=] to a numerical value greater than `0`.

An [=installed web application=] has an associated [=badge=], which is initialized to [=badge/"nothing"=]. The operating system stores and manages the badge value, with the [=user agent=] acting as an intermediary to communicate badge changes to the OS.

The user agent MAY (re)[=set=] an application's badge to [=badge/"nothing"=] at its discretion (for example, following system conventions).

Displaying a badge

When the application's badge is set, the [=user agent=] or operating system SHOULD display the application's [=badge=] alongside the primary iconic representation of the application in the user's operating system (for example, as a small overlay on top of the application's icon on the home screen on a device).

A user agent MAY require [=express permission=] from the user to [=badge/set=] the badge. When a user agent requires such [=permission=], it SHOULD tie the permission grant to the "[=notifications=]" permission.

When the [=badge=] is [=badge/set=] to [=badge/"flag"=], the [=user agent=] or operating system SHOULD display an indicator with a non-specific symbol (for example, a colored circle). If the platform does not support displaying a [=badge/"flag"=] badge, the [=user agent=] SHOULD display the badge using the closest available representation that indicates the presence of a badge (e.g., the value "1"), rather than [=badge/clearing=] the badge entirely.

When a [=badge=]'s value is [=badge/set=] to [=badge/"nothing"=], the [=user agent=] or operating system SHOULD clear the [=badge=] by no longer displaying it.

When the [=badge=] is [=badge/set=] to a [=badge/number=], the [=user agent=] or operating system:

Implementation considerations for platform limitations

Different operating systems have varying capabilities for displaying badges. The ultimate display behavior is controlled by the operating system and might be further modified by user settings or system conventions. When communicating badge information to the operating system, [=user agents=] SHOULD preserve the semantic intent of the badge request:

Extensions to the `Navigator` and `WorkerNavigator` interfaces

        [SecureContext]
        interface mixin NavigatorBadge {
          Promise<undefined> setAppBadge(
            optional [EnforceRange] unsigned long long contents
          );
          Promise<undefined> clearAppBadge();
        };

        Navigator includes NavigatorBadge;
        WorkerNavigator includes NavigatorBadge;
      

User agents that never display application badges SHOULD NOT [=interface/include=] {{NavigatorBadge}}.

setAppBadge() method

When the {{NavigatorBadge/setAppBadge()}} method is called, the user agent MUST [=set the application badge=] of [=this=] to value of the |contents:unsigned long long| argument.

clearAppBadge() method

When the {{NavigatorBadge/clearAppBadge()}} method is called, the user agent MUST [=set the application badge=] of [=this=] to 0.

Setting the application badge

To set the application badge of platform object |context:platform object| to an optional {{unsigned long long}} |contents:unsigned long long| value:

  1. Let |global| be |context|'s [=relevant global object=].
  2. If |global| is a {{Window}} object, then:
    1. Let |document| be |global|'s [=associated `Document`=].
    2. If |document| is not [=Document/fully active=], return [=a promise rejected with=] a {{"InvalidStateError"}} {{DOMException}}.
    3. If |document|'s [=relevant settings object=]'s [=origin=] is not [=same origin-domain=] with [=this=]'s [=relevant settings object=]'s [=environment/top-level origin=], return [=a promise rejected with=] a {{"SecurityError"}} {{DOMException}}.
  3. Let |promise| be [=a new promise=].
  4. [=In parallel=]:
    1. If the [=user agent=] requires [=express permission=] to [=badge/set=] the application badge, then:
      1. Let |permissionState| be the result of [=getting the current permission state=] with "[=notifications=]".
      2. If |permissionState| is not {{PermissionState/"granted"}}, [=queue a global task=] on the [=user interaction task source=] given |global| to [=reject=] |promise| with a {{NotAllowedError}} and terminate this algorithm.
    2. Switching on |contents|, if it happens to be the case that:
      |contents| was not passed:
      [=badge/Set=] |badge| to [=badge/"flag"=].
      |contents| is 0:
      [=badge/Set=] |badge| to [=badge/"nothing"=].
      |contents|:
      [=badge/Set=] |badge| to |contents|.
    3. [=Queue a global task=] on the [=DOM manipulation task source=] given |global| to [=resolve=] |promise| with `undefined`.
  5. Return |promise|.

Privacy considerations

The API is write-only by design. There is no way for a site to read back the value of a badge that was previously set, to ensure that the application badge cannot be used as a storage or fingerprinting mechanism.

Security considerations

The [=user agent=] or operating system MAY [=badge/clear=] a [=badge=] at its discretion, and to follow any system conventions (for example, when the system is reset).

User agents MAY rate-limit badge [=set the application badge|setting=] or [=badge/clear|clearing=] the application badge to prevent distracting animations and reduce resource usage. However, user agents SHOULD generally leave rate limiting to the operating system, as it is in a better position to determine appropriate throttling based on system load, user preferences, and accessibility considerations.

Accessibility considerations

Application badges convey status that can require the user's attention. Because badges are often presented outside the web content area (for example, on an app icon in the dock), user agents need to ensure that the information remains accessible and controllable through platform accessibility features and user preferences.

Screen reader compatibility

User agents SHOULD expose the current [=badge/value=] (including [=badge/"flag"=] vs. [=badge/number=]) through platform accessibility APIs so that assistive technologies can present it on demand (for example, when the user focuses the application icon).

User agents SHOULD NOT automatically announce badge changes; instead, they SHOULD follow platform conventions that avoid unsolicited interruptions.

Visual accessibility

As badges are typically drawn by the underlying platform, visual affordances are typically handled there. Nevertheless, user agents and platforms need to consider:

Platform integration and user preferences

User agents SHOULD integrate with platform accessibility settings and themes.

User agents SHOULD reflect OS-level per-application badge preferences (for example, when the operating system disables badges for an app).