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.
What each option does
Section titled “What each option does”actions— a read-only array MDN describes as objects withaction(an identifying string),title(button label text), an optionaliconURL, and an optionalnavigateURL. Per MDN, “browsers typically limit the maximum number of actions they will display,” and that limit is exposed as the staticNotification.maxActionsproperty.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' }, ], });}The persistent-notification requirement
Section titled “The persistent-notification requirement”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.
Where it is supported
Section titled “Where it is supported”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.
How to detect it at runtime
Section titled “How to detect it at runtime”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);}Practical checklist
Section titled “Practical checklist”- Never pass an
actionsoption tonew Notification()— per MDN it throws aTypeErroroutside a persistent (service-worker) notification. - Read
Notification.maxActionsinstead of hardcoding a button count; browsers cap it differently. - Do not confuse the
badgeoption’s small tray image with the separate app-icon Badging API (navigator.setAppBadge()) — they solve different problems. - For actions with a
navigateURL, expect a direct browser navigation instead of anotificationclickevent; only actions withoutnavigatereach the service worker’snotificationclickevent, where you readevent.action. - Check the support table above before relying on
actionsin Firefox or on either option in Safari.
Where to go next
Section titled “Where to go next”- 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.