puter.notifications.onPush()Handles the notifications your app sends with channel: key in notify(). While your app is open and connected, the handler runs in the page as each one arrives. While it isn't, Puter sends a browser push instead, and the handler runs in your site's service worker to decide what the notification shows.
Puter picks the route: a notification never goes both ways. The user turns pushes on once with enable(); after that, onPush() keeps this browser's subscription current on every page load without asking again. Different keys share that one permission.
On a website, pushes reach your own origin, so your site has to serve a service worker that loads Puter's push script. Put this in /puter-sw.js at the root of your site:
importScripts('https://js.puter.com/v2/push-sw.js');
If your site already has a service worker, add that line to it instead and pass its path as serviceWorker. Inside the Puter desktop, pushes go through Puter itself and no worker is needed.
puter.notifications.onPush(key, handler)
puter.notifications.onPush(key, handler, options)
key (String) (required)
The channel your notifications are sent with: 1 to 32 lowercase letters, digits or -.
handler (Function) (required)
Called with the notification (the same shape onNotification() delivers). It may return, or resolve to, an object that changes what the browser shows:
title, body, icon, badge, image, tag: strings, as in the browser's showNotification().url: a path or URL on your origin, opened when the notification is tapped. Defaults to the notification's target. Other origins are replaced with your site's root.Returning nothing shows the notification's own title and text. In the page, the result is only shown when the tab is hidden.
options (Object) (optional)
serviceWorker (String): path of the worker that imports push-sw.js. Default /puter-sw.js.onError (Function): called when the handler throws, the live listener stops, or keeping the subscription current fails. Without it, errors go to the console. A server without a push service (push_unavailable) and an app the user turned off in Puter (push_revoked) are not reported here, since enable() rejects with them when called.On a website, the handler is saved as source and run again in your service worker when a push arrives with no page open. There it follows the Web Push rules:
window, document or localStorage. fetch, indexedDB and caches are available.data at most 1 KB. Send IDs and fetch the rest if you need it.eval. It is re-created with new Function, so if your worker is served with a Content-Security-Policy it must allow 'unsafe-eval'.A handler that needs more, such as imported code, can be registered in the worker itself, where it wins over the saved one:
importScripts('https://js.puter.com/v2/push-sw.js', '/my-formatting.js');
puterPush.onPush('chat', (n) => ({ title: formatTitle(n) }));
A Promise that resolves to { off }. off() stops the handler in this page and, when no other handler for key is left, removes the saved one.
Chat messages
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<button id="enable">Turn on notifications</button>
<script>
puter.notifications.onPush('chat', (n) => ({
title: `${n.app?.name ?? 'Chat'}: ${n.title}`,
url: n.target ?? '/',
}));
document.getElementById('enable').addEventListener('click', async () => {
const on = await puter.notifications.enable();
puter.print(on ? 'Notifications are on<br>' : 'Notifications are off<br>');
});
</script>
</body>
</html>