Skip to content

Notifications · Concept

Notification actions and badge options

Published Updated

In one line: actions adds up to Notification.maxActions clickable buttons to a notification, and badge is a separate option — a small image URL the OS shows “when there is not enough space to display the notification itself,” per MDN, such as the Android notification bar. Both are options on service-worker-driven notifications, not the app-icon Badging API.

  • actions — a read-only array MDN describes as objects with action (an identifying string), title (button label text), an optional icon URL, and an optional navigate URL. Per MDN, “browsers typically limit the maximum number of actions they will display,” and that limit is exposed as the static Notification.maxActions property.
  • badge — per MDN, “a string containing the URL of an image” shown in place of the full notification when space is tight; MDN’s Android guidance sizes it “about 96 by 96 px,” noting the image “will be automatically masked.”
const permission = await Notification.requestPermission();
if (permission === 'granted') {
const registration = await navigator.serviceWorker.ready;
await registration.showNotification('New message', {
body: 'Ada sent you a message.',
badge: '/icons/badge-96.png',
actions: [
{ action: 'reply', title: 'Reply' },
{ action: 'dismiss', title: 'Dismiss' },
],
});
}

Per MDN, actions is available “only for persistent notifications” — those shown via ServiceWorkerRegistration.showNotification() — not for a plain new Notification(). MDN states passing a non-null actions option to the Notification() constructor “throws a TypeError.”

What happens when an action button is clicked depends on whether that action set a navigate URL. Per MDN’s actions documentation, if navigate is set the browser navigates to that URL directly and does not dispatch notificationclick. Only when an action has no navigate URL does the click reach the service worker’s notificationclick event, where event.action holds the clicked button’s action string.

Per the linked browser-compat-data:

Browser actions badge
Chrome (Desktop) yes, since 53 yes, since 53
Edge (Desktop) yes, since 18 yes, since 18
Opera (Desktop) yes, since 39 yes, since 39
Firefox (Desktop) yes, since 152 not supported
Safari not supported not supported

Both options require a secure context, per MDN.

function canShowActionsAndBadge() {
if (!('serviceWorker' in navigator) || !('Notification' in window)) {
return { actions: false, badge: false }; // no persistent notifications here at all
}
return {
actions: 'actions' in Notification.prototype,
badge: 'badge' in Notification.prototype,
};
}
async function notifyNewMessage(registration) {
const { actions, badge } = canShowActionsAndBadge();
const options = { body: 'Ada sent you a message.' };
if (badge) {
options.badge = '/icons/badge-96.png';
}
if (actions) {
options.actions = [
{ action: 'reply', title: 'Reply' },
{ action: 'dismiss', title: 'Dismiss' },
];
}
// When actions/badge are unsupported, this sends a body-only notification
// instead — the options above are simply omitted rather than causing an error.
await registration.showNotification('New message', options);
}
  • Never pass an actions option to new Notification() — per MDN it throws a TypeError outside a persistent (service-worker) notification.
  • Read Notification.maxActions instead of hardcoding a button count; browsers cap it differently.
  • Do not confuse the badge option’s small tray image with the separate app-icon Badging API (navigator.setAppBadge()) — they solve different problems.
  • For actions with a navigate URL, expect a direct browser navigation instead of a notificationclick event; only actions without navigate reach the service worker’s notificationclick event, where you read event.action.
  • Check the support table above before relying on actions in Firefox or on either option in Safari.
  • The Notifications API — the base permission model and page-vs-service-worker distinction these options build on.
  • App icon badging — the separate Badging API for setting a count on the installed app’s icon.

Specifications

SpecificationStatus
None.