The Badging API is a proposed Web Platform API allowing web applications to set a taskbar or home screen icon badge.
- w3c/manifest#663 (related discussion)
- crbug.com/719176 (Chrome implementation bug)
Badging API
Home Page: https://w3c.github.io/badging/
License: Other
The Badging API is a proposed Web Platform API allowing web applications to set a taskbar or home screen icon badge.
First of all, this is really cool!! I loved reading the proposal and seeing the care that went into coming up with something that was flexible and powerful, but also mapped to a wide variety of hosts.
One aspect that I found surprising was in the goals/non-goals section, about this being specifically an application-wide badge, instead of a per-tab badge. Partially this is because I have a lot of tabs today that implement their own badges using favicons or <title>
changes.
Upon reflection, I think the restriction makes sense. (I can't think of any of the web apps I use which have different badge counts in different tabs; they all synchronize.) Still, it might be worth a dedicated section with a few paragraphs spelling out the problem space here and why being app-wide is the best solution.
I also would wonder if it's worth softening the non-goal
To provide badging for sites in a normal web browsing context. While it will be available to normal websites, user agents will generally not surface the badge unless the app is installed or has some presence in the operating system shelf area.
I think it'd be a bit of a shame for web developers if they had to continue using their favicon/<title>
tricks, in addition to this API, to give users a good experience when used in a tab. It seems like, if you applied the badging to all tabs under a given application, it would be a win for the user and web developer.
If you're worried about collision with existing techniques, it could be opt-in, e.g. set(x, { evenWhenNotInstalled: true })
.
This could greatly reduce the custom code web developers have to write to update their favicons/titles and synchronize across tabs.
Just a start...
A web application could (ab)use the badging API to attempt to display badge numbers, in order to trick user to unnecessarily open the application. By launching the application, the user could unintentionally expose private information.
The spec has some occurrences of "is a service worker client".
Note that document, dedicated workers, and shared workers are always service worker clients, even if there is no service worker registration they are under (see https://w3c.github.io/ServiceWorker/#control-and-use-window-client and https://w3c.github.io/ServiceWorker/#control-and-use-worker-client for when service worker clients are created).
Is this intended, or does the spec mean something like: "if the service worker client's active service worker is not null"?
Thank you for creating this. I've read the google thread about badging PWA and I am wondering after reading the explainer if this is just a proposal of specs on how each OS can implement the badge respectively, or does the badging api also work at the moment if implemented with service worker?
Just wanted to know when we can start using it if not yet :)
Our product has launched PWA to some of our customers.
The major feedback is that people want Badging.
In Mac, Badging is shown on icons in both task bar and launchpad.
However, in windows, the desktop icon is only shown in taskbar. Desktop shortcut doesn't show the badge.
In addition, when you close PWA in mac, it really exit PWA entirely so the badging will disappear which may confuses mac users because the expected behavior of closing a app on mac is only minimizing it.
In the new explainer, we outline a combined API that sets badges at different URL scopes and is expected to appear on either or both the app icon or the tab icon, at the user agent's discretion.
Having drilled down on this, we're now starting to question why these are the same API, because their usage is very different.
Required reading: A Case for Separation section.
Summary:
Two static methods on a non-constructible class is a bit strange. Consider using a Web IDL namespace instead.
The main observable differences would be that typeof Badge === "object"
instead of "function"
, and there would be no empty Badge.prototype
object.
I chose Document because it better fits my mental model of what the badge is attached to. But it might be the case that the Document is actually just a JavaScript-exposed object, whereas internal slots like the badge should be attached to the browsing context instead.
Likely related to #5
Currently, we are proposing that each badge apply to a scope. However, scopes can be complicated and unwieldy. For example, clearing a badge at one scope could cause it to acquire the badge from another, less specific scope, while setting the badge at a scope might affect a number of pages.
There are a number of constraints that lead us to the current proposal:
/app/page1
to set a badge for /app
which would be displayed in the operating system when installed.This problem feels similar to what we're doing with Service Worker Registration Scope and Web App Navigation Scope.
That said, we're open to alternatives that allow the problem to be solved in a less complicated manner.
The API allows set()
ting unsigned long long
types. Presumedly, when the badge is presented, these would then be formatted appropriately based on the user's locale settings.
We should add a note about this...
Raised by @grorg on webkit-dev:
I'd also like to see some specification text describing how the browser should ignore multiple set/clear operations executed in rapid succession (e.g. to create a blinking badge) - maybe the limit is one badge operation per minute or something?
We should address this; it might be a recommendation rather than a requirement, since it relates to the UI of the user agent.
I'd like to see some sort of "eventual consistency" guarantee which says that the final value you write to the badge will eventually be the one displayed to the user. This prevents a situation where you set "3" then 10 seconds later set "12", and due to rate limiting, the "12" never gets set, so the user just sees "3" forever. Instead, the rule should be "If the UI hasn't been updated in > N seconds, update it to the new value. Otherwise, set a timer to update the UI to the new value in N - (however long it has been since the last update) seconds."
Raised by @marcoscaceres on #57. I could go either way on this.
The reason it's currently specified as "fire and forget" and always resolve the promise is that the API is a "best effort". Especially for the app version of the API, you could store the badge state locally, then try to set the badge in 3 places in the OS, some of which succeed and others of which fail. There's no reasonable way to communicate the partial success back to the user.
So it's currently specified as "always report success to the user, even if it failed at the OS level". We could change this.
TPAC will be virtual this year. W3C is finalizing the details but it is likely there will be events for the whole W3C community during between 12-31 October, with WG able to organize their own meetings.
Please post a specification status report when possible, before TPAC.
The specification status report should include:
I know this will require integrating into the platforms, but hey that is supposed to be a features of PWAs :)
But it feels like this should add a badge to the icon on a desktop or the start menu. For Windows this really should be hooked into the Live Tile plumbing. I know IE has this working pre-Edge days, well sort of working at least.
Having a badge update for a pinned icon is rather limiting.
The Badging API was discussed at TPAC 2019-09.
After some discussion a new shape for the API was decided on:
navigator.setAppBadge(number);
navigator.setClientBadge(number, { client });
typedef ClientOrClientId = WindowClient or DOMString;
dictionary ClientBadgeOptions {
ClientOrClientId client = null;
};
partial interface navigator {
Promise<void> setAppBadge(optional integer content);
Promise<void> clearAppBadge();
Promise<void> setClientBadge(optional integer content, optional ClientBadgeOptions options);
Promise<void> clearClientBadge(optional ClientBadgeOptions options);
}
partial interface workernavigator {
Promise<void> setAppBadge(optional integer content);
Promise<void> clearAppBadge();
Promise<void> setClientBadge(optional integer content, optional ClientBadgeOptions options);
Promise<void> clearClientBadge(optional ClientBadgeOptions options);
}
setXXXBadge
methods are exposed on the navigator on the ServiceWorker and Window. Calling setClientBadge
from the window without specifying a client or client id will result in the current client being badged.
calling setAppBadge
from the window will result in the app with the most specific scope containing the current document being badged.
calling setAppBadge
from the ServiceWorker will result in the app whose scope exactly matches the service worker (<-- to be discussed, could be above scope, could be within scope) being badged.
Need to spec that a scope URL outside of the current origin should raise a permission error. (The current Chrome implementation just fails silently.)
Any reason not to use unsigned long
instead of long
? Then WebIDL automatically handles the -N
case.
Excited to see this!
If you do wish to support something other than ints, I was wondering how you would expect to fallback from an arbitrary emoji to something else?
Would a failed Badge.set()
throw?
Would you specify multiple values as an explicit fallback (e.g. Badge.set({rich: '💯', plaintext: 100})
or Badge.set('💔', '零', 0)
?
We want to start out with the minimum viable product. Strings (and the whole associated "single grapheme cluster") add significant complexity to the API since we then get into Unicode issues, as well as display issues on various platforms (e.g., arbitrary characters are not usable in the UWP API).
For now, let's remove the string option from the API and just have "flag" and the integer.
For installed apps, showing badges makes sense, because of the song-and-dance the users have to go through to install a web apps. However, I wonder if we need to gate the API using a permission to mitigate tabs unnecessarily drawing the user's attention?
This could potentially be handled at the UI layer... just putting this here for discussion.
Hello,
At the moment the color of the badge is red, is it possible to pass along the color while setting the badge counter?
thanks
Dirk
Follow-up to Chromium bug 1000968.
The current informal definition of the set()
method has two optional parameters:
Badge.set([contents], [options])
: Sets the badge for the scope in options to contents (an integer), or to "flag" if contents is omitted. If contents is 0, clears the badge for the given scope.
The intention here is that if you pass one argument, if it's an integer, it's contents and the scope is default. If it's a dictionary, it's options and the badge is set to "flag". I think that would feel natural to users and it's unambiguous, but it might be difficult to express that in WebIDL, and/or be considered bad API design.
I can't think of a precedent for this sort of "arity overloading" in the Web platform. The closest thing that comes to my mind is Python's range function, which takes (start, stop)
, but if you only supply one argument, it is accepted as stop (not start).
Edit: Examples of the four different ways you'd be able to supply parameters to this function:
Badge.set()
-- sets badge to "flag" with the default scope.Badge.set(num)
-- sets badge to num with the default scope.Badge.set(num, {scope: url})
-- sets badge to num with scope url.Badge.set({scope: url})
-- (in question): sets badge to "flag" with scope url.The question is whether this is reasonable for the user to understand that if you pass a dictionary as the sole argument that it be treated as options (not content), and also whether this is acceptable from an IDL and implementation perspective.
If the above can't be done, we need another solution, such as being able to pass an explicit value meaning "flag" (e.g., true
or null
) to that first argument.
Currently, due to the declaration of that parameter in WebIDL as unsigned long long
, false
and null
are converted to 0, which clears the badge, and true
is converted to 1 which sets it to "1". There is no way to pass an explicit argument that sets the badge to "flag".
Possibly something to ask TAG about.
I see some discussion about exposing the API to service workers. I honestly think this should be the primary path for badge updates. To me badging is something done in the background, silently, sort of like a push notification.
So how would you trigger a badge update?
Use a push notification, at least it would use an existing channel, but also open it up to silent updates, which would get abused, but I still like.
Create a new channel exclusively for background badge updates. This would require platforms to create a new service to handle badge updates.
Allow the PWA to silently poll an API (this is sort of how IE did live tiles back in the day) to get updated data. This would be similar to the previous option, but require no service infrastructure to be created. It would/could increase network traffic, but you could also allow the consumer to control frequency.
I've created this issue which was spawned from a discussion on #16 (comment). The current proposal explainer says:
The Badge interface is a member object on Window and Worker. It contains two methods:
void set(optional USVString or long)
: Sets the associated app's badge to the given data, or just "flag" if the argument is not given.void clear()
: Sets the associated app's badge to nothing.These can be called from either a foreground page or a service worker (in either case, affecting the whole app, not just the current page).
It seems a little incomplete for the API to have a setter but no way to get badge counts for cases where there are multiple badge setters throughout an application that don't know about each other.
Let's say I have an application that shows both a chat box and email in the same interface. It gets one new unread chat message and shows 1 as badge count and then gets 2 new unread emails.
How would the application know that there was a badge count of one before it adds a 2 to that number? Sure, I could always query or listen in on both the chat message unread number and the email unread numbers, calculate them together and then call set()
with the total number, but that would quickly become unwieldy. Then I would probably have to store both the chat unreads and email unreads on a globally accessible object (perhaps window
) to make it available to both chat and email logic which breaks encapsulation. Why not avoid having to do this and just allow getting the badge number easily?
Be great to publish this spec as FPWD! @mgiuca @fallaciousreasoning, there are a couple of ReSpec issues by the looks of it, but otherwise it should be good to go. WDTY?
Maybe this is just reopening #19 but I think it's a slightly different issue.
We noticed it was quite difficult to write a wrapper around the Badge set methods, like this:
function wrapBadgeSet(contents) {
return navigator.setAppBadge(contents); // BAD
}
This fails because if contents
is omitted in the call to wrapBadgeSet
, it will pass undefined
to setAppBadge
, which has different semantics to passing no argument (specifically: passing no argument will set the badge state to flag, while passing undefined will coerce to 0 which happens to clear the badge).
Instead, to wrap correctly, you must do this:
function wrapBadgeSet(...args) {
return navigator.setAppBadge(...args);
}
Which is non-obvious and a bit hard to read.
As a general rule, I think passing undefined
to an argument should be the same as omitting it. So I propose that we change the IDL to include a "?
" which would make both undefined
(and null
, an unintended but unavoidable side effect) set it to flag, the same as omitting an argument altogether.
This is semi related to #19.
What the behavior of Badge.clear({ scope: '...' })
should be is a little unclear.
Is the badge for that specific scope now clear
or does it display the badge from a parent scope?
Perhaps we should remove separate set/clear
methods in favor of something like this:
Badge.set({
badge: number | boolean | undefined,
scope: string
});
A badge for a scope can be in one of four states:
unset
: The badge from a parent scope will be applied (or none, if there is no badge for a parent scope).cleared
: No badge is displayed for the scope.flag
: A special value indicating a notification dot should be displayed.<number>
A non-zero, positive number: The value will be displayed in the badge.If badge
is undefined or not present then the badge for the scope is unset
If badge
is a boolean false sets the badge to cleared
while true sets it to flag
.
If badge
is a number 0
sets the badge to cleared
while other positive numbers set the badge to that number.
Alternatively, we could introduce separate methods for each value, as in #19.
// 0 sets the badge to cleared, other values set the badge to that value.
Badge.setNumber(<number>, { scope: '...' });
// false sets the badge to cleared, true sets the badge to flag.
Badge.setFlag(boolean, { scope: '...' });
// Unsets the badge.
Badge.unset({ scope: '...' });
I think this second approach is more friendly for polyfilling (though both should be polyfillable) if we add a new type (such as glyphs). However, in the second approach, it's less obvious that there is only one badge value active at any time.
@domenic I know you had some thoughts on this.
@marcoscaceres @mgiuca @raymeskhoury
I'm still not sure we should do the DOMString thing... browsers already show little icons for media playing, etc. I think it might be overstepping a little bit. We should maybe just start with the numbers and then look at adding that later...
During TPAC, IIRC, you mentioned that Windows had a special restricted set of icons that could be shown. I'd prefer we'd go down that route (using an enum, for instance) down the road.
I wasn't present at TPAC where it was decided to move the Badging API methods to Navigator
, so I'm not really sure what the rationale was other than "Navigator is a dumping ground for new APIs".
Trying to write the spec, and digging into the HTML spec's object hierarchy, Navigator feels like a pretty poor fit for Badging, since Badging is about setting state for the current document and/or app, while Navigator seems to be a handle for the browser, independent of the document.
I think some other existing APIs on Navigator make more sense:
All of these examples are about talking to the browser (independent of the current document) or the hardware, via the browser. They don't interact with the current document or origin. A counter-example would be indexedDB, which interacts with a data store tied to the current origin; it lives in Window, not Navigator.
It's telling that I'm trying to associate a badge with a document or browsing context (haven't decided which yet). If the Badge API was on Window, I could say "Set the Window's associated document's badge to X" or perhaps "Set the Window's browsing context's badge to X". But there doesn't appear to be any link from a navigator back to a document. I can't say "Set the Navigator's document's badge to X." And it got me thinking, maybe that's because the Navigator is supposed to represent the browser itself -- it doesn't have an associated document. Maybe we're putting this API in the wrong place.
Thoughts @marcoscaceres @annevk ?
Hello!
I installed the sample demo PWA in my phone and another one and is not showing the badge, or is there some special steps to test it on Android?
Thanks
@annevk suggested it might be good to just attach this as an attribute on navigator
. I think that makes sense to align with other APIs (and given that one can't construct new Badge()
etc).
If the browser is in the control of presenting the badge, it should be possible to define some accessibility guidelines.
The explainer is being updated with our feedback from TAG in #39. The spec should be updated in a separate PR:
When this is done
#1 can be closed (now all badges must specify scope).
#5 can be closed (same reason)
#12 can be closed (badging of installed apps is implicit, based on scope).
#35 can be closed (same as above).
I think we should decouple this entirely from Web Manifest and install. It just happens that if it is an "installed" application, the badge gets displayed in the system tray.
The proposal states:
The Badge interface [...] contains two methods:
void set(optional USVString or long)
: Sets the associated app's badge to the given data, or just "flag" if the argument is not given.void clear()
: Sets the associated app's badge to nothing.
The proposal around the clear()
method seems a bit unclear here 😄 . Is there any particular reason to have a clear()
method? Wouldn't set(undefined)
, set(null)
, or set()
all clear the badge count and hide it? Or is clear()
meant to serve some other purpose? Maybe clear the count, but still show the badge (without a number)?
How long is it expected for a browser to maintain the badge? Are they ever given the ability to reset it without a dev calling clear()
? I.E. if a user resets their data in system settings, but does not uninstall the pwa, would the stale badge still show until the user launches it again?
Because there is much IPC going on when setting a badge, I think this API might need to return promises and only allow setting the badge “one at a time”... so more like a request to set the badge. We might need to retain state, and only allow setting once a setting operation has completed. Clear()ing would probably want to abort ongoing set() operations, then behave as set()ing to 0.
Also, as already stated in another bug, we need to disassociate this API from installation IMO (and “Web Applications”, as that’s fairly meaningless). And we definitely need to restrict this to top level browsing contexts only and same origin iframes. Would third party contexts ever be allowed to set the badge? Do we need a feature policy?
We had an anonymous feature request from the Chrome origin trial feedback:
It would be great to allow a limited set of other characters in the badge - like a + when there is an unknown (not everything yet loaded) or large count to display (e.g. "999+")
Filing an issue to track it, though note that we aren't planning to address this in the first version.
Note that in the original proposal, we allowed any single Unicode character (or, more formally, any grapheme cluster) to be set as the badge value. This feature was dropped because it presented a compatibility risk: some platforms would be able to support certain characters, and others would not. For example, Windows only supports a small set of hand-picked symbols, which do not even necessarily correspond to Unicode characters. There was a risk that browsers implement a hand-picked subset of Unicode characters, and then developers choose to set characters based on that, creating sites that work well on some platforms, and set empty badges on other platforms.
Were we to bring this back, we'd likely hand-pick a small set of symbols that we're sure can be represented on all platforms. Unfortunately, we'd likely be restricted to the lowest common denominator, which is Windows UWP's very restrictive set. It would not be ideal to have a web standard "controlled" by the Windows API. So for the time being, it is probably best to leave this out, until we see a stronger need for it.
Various places in the spec say <b>flag</b>
or <b>nothing</b>
. Instead they should link to the definitions of those terms in https://wicg.github.io/badging/#badge-model. (Although I guess those are not <dfn>
s either, just <b>
s again. But they should be <dfn>
s.)
What I'm looking for (as a user) is the following:
As long as at least 1 open tab in my browser has a badge set, I'd like the browser icon in my toolbar to also show some badge/highlighting which signals that there are unread messages (etc.) even if I have the browser in the background.
In other words: Would app badges only effect PWAs or also "normal" websites + the browser they run in?
Once w3c/manifest#823 lands.
This specification has been proposed for migration to the WebApps WG (which is expected to partly replace the WebPlat WG). For this to happen, we need expressions of interest/intent to commit from at least two implementors.
Please let us know if you plan to implement this specification, or if you can point to any publicly documented expressions of interest from implementors.
The draft WebApps charter will go to the Advisory Committee (AC) within the next two or three weeks, so quick responses may make the difference.
The non-normative note in https://wicg.github.io/badging/#determining-the-set-of-matching-applications seems to uses "service worker context" to mean "service worker client". This is confusing because "service worker context" usually means a service worker thread.
I'd call it "service worker client" or "service worker client context" instead.
Currently the spec only has app badging examples.
Hi!
I think it is a common scenario to increase the badge by 1. To this first we need to get the current value of the badge. Is it possible in the current implementation?
Thanks.
Interestingly, I think the current approach (always badging a specific scope) would also allow badging bookmark icons, if user agents think it's a good idea.
Should this be explicitly called out in the spec @marcoscaceres @mgiuca?
draft of topics to talk about at the WebApps WG.
In order to provide a first class experience for web apps, it should be possible to integrate deeply with native operating system APIs.
The main use case for the badging API is to provide applications (such as a Chat application) a low impact alternative to notifications. For example, in Slack, it might be desirable to not show a notification in a busy room, just update the application's badge count (direct messages and @ mentions could still display a notification).
Explainer: https://github.com/WICG/badging/blob/master/explainer.md
Chrome Tracking Bug: crbug.com/719176
This makes sure that values that can't be represented as an int (such as non-numeric strings and extremely large floats) throw a TypeError rather than converting to 0.
(IMHO [EnforceRange]
should be used on all new integer types. The default behaviour of converting an arbitrary string "foo"
to 0 is very silly, and it's bizarre that this happens for integer types but not for float types.)
I suspect that in some scenarios sites may wish to clear badges for all scopes. It might be useful to expose a function for doing this, especially as sites have no way of retrieving the badges they have currently set (if they forget about a badge they have set, it could conceivably never be cleared).
// Clears all badges on the origin.
Badge.reset();
// Not sure if we need this but clear all badges under a scope.
Badge.reset({ scope: `/app` });
A given domain can have multiple service workers and manifests with different scopes. For example, assume I have a:
/
/my-orders
/deal-of-the-day
Assuming a sync in my service worker like
self.addEventListener('sync', () => {
self.Badge.set(latestOfferEmjoi());
});
Which installed manifest would get that badge?
My assumption would be that the badge inherits the scope of whatever's calling it. i.e. if the service worker is at / so both installed apps at the lower scope get the badge.
Could we have an optional scope
parameter, similar to navigator.serviceWorker.register()
that would allow setting the badge at a narrower scope? This would allow a top-level service worker to set a badge for a lower level installed app without affecting the other.
I think I would also expect any badge set at a higher scope to override any more specific ones.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.