[GH-ISSUE #346] Support Web Push + PWA, for background notifications #269

Closed
opened 2026-05-07 00:22:29 +02:00 by BreizhHardware · 13 comments

Originally created by @Mikaela on GitHub (Jun 28, 2022).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/346

I am not sure what running as progressive web app requires, but I understand they should be able to support receiving notifications in the background even without the tab/app open as long as browser is running.

I think currently at least webapp manifest is missing.

Somewhat unrelatedly, iOS is also receiving support for web push sometime next year, https://webventures.rejh.nl/blog/2022/06/25/the-biggest-thing-from-wwdc22/

Update 2023-04-02: iOS 16.4 supports web push when the PWA has been added to the homescreen.

Originally created by @Mikaela on GitHub (Jun 28, 2022). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/346 I am not sure what running as progressive web app requires, but I understand they should be able to support receiving notifications in the background even without the tab/app open as long as browser is running. I think currently at least webapp manifest is missing. * https://developer.mozilla.org/docs/Web/Manifest * https://developer.mozilla.org/docs/Web/Progressive_web_apps * https://caniuse.com/web-app-manifest (add to homescreen) ~~Somewhat unrelatedly, iOS is also receiving support for web push sometime next year, https://webventures.rejh.nl/blog/2022/06/25/the-biggest-thing-from-wwdc22/~~ Update 2023-04-02: iOS 16.4 supports web push when the PWA has been added to the homescreen.
BreizhHardware 2026-05-07 00:22:29 +02:00
Author
Owner

@wunter8 commented on GitHub (Jun 29, 2022):

I've thought about trying to make this work. I think it might solve #199, too

<!-- gh-comment-id:1169479603 --> @wunter8 commented on GitHub (Jun 29, 2022): I've thought about trying to make this work. I think it might solve #199, too
Author
Owner

@WebKenth commented on GitHub (Jul 13, 2022):

Just thought i would leave my 2 cents

You can create a shortcut with chrome and have it opened as a separate window
image
image

This will give it a sorta PWA like feel, although it is still a chrome instance just running in a separate window

image

<!-- gh-comment-id:1182790265 --> @WebKenth commented on GitHub (Jul 13, 2022): Just thought i would leave my 2 cents You can create a shortcut with chrome and have it opened as a separate window ![image](https://user-images.githubusercontent.com/13419123/178659286-8eda0e78-db7c-4f2e-8f84-ab54336d4304.png) ![image](https://user-images.githubusercontent.com/13419123/178659317-3fa2243c-9c87-4f5f-ad00-63e887ba8922.png) This will give it a sorta PWA like feel, although it is still a chrome instance just running in a separate window ![image](https://user-images.githubusercontent.com/13419123/178659441-b13e91d4-408f-4678-862d-bc0cb941d2e3.png)
Author
Owner

@MaximilianGaedig commented on GitHub (Aug 18, 2022):

The browser asks me if I want to receive notifications, it works in the foreground but after closing the page it does not work anymore. Service workers need to be implemented.

<!-- gh-comment-id:1219300040 --> @MaximilianGaedig commented on GitHub (Aug 18, 2022): The browser asks me if I want to receive notifications, it works in the foreground but after closing the page it does not work anymore. Service workers need to be implemented.
Author
Owner

@liamstojanovic commented on GitHub (Nov 9, 2022):

Made progress in making the react web app fulfill install-ability requirements on the pwa-background-push branch of my forked repo.

No custom service workers are hooked up yet, nor have I managed to successfully install the PWA version so far.

Next steps...

  • Request permission,
  • Generate notification,
  • Push.

Lighthouse PWA report

<!-- gh-comment-id:1309006801 --> @liamstojanovic commented on GitHub (Nov 9, 2022): Made progress in making the react web app fulfill install-ability requirements on the `pwa-background-push` [branch](https://github.com/liamstojanovic/ntfy-webApp/tree/pwa-background-push) of my forked repo. No custom service workers are hooked up yet, nor have I managed to successfully install the PWA version so far. [Next steps...](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Re-engageable_Notifications_Push) - Request permission, - Generate notification, - Push. ![Lighthouse PWA report](https://f002.backblazeb2.com/file/share-liam/lighthouse_pwa_report.png)
Author
Owner

@BuckarooBanzay commented on GitHub (Nov 11, 2022):

Made progress in making the react web app fulfill install-ability requirements on the pwa-background-push branch of my forked repo.

Where are you planning to store the subscriptions from the client? Those have to be somewhere on the backend side 🤔

<!-- gh-comment-id:1312063214 --> @BuckarooBanzay commented on GitHub (Nov 11, 2022): > Made progress in making the react web app fulfill install-ability requirements on the pwa-background-push [branch](https://github.com/liamstojanovic/ntfy-webApp/tree/pwa-background-push) of my forked repo. Where are you planning to store the subscriptions from the client? Those have to be somewhere on the backend side :thinking:
Author
Owner

@liamstojanovic commented on GitHub (Nov 15, 2022):

I've hit a blocker with this endeavor.

I've made the web app install-able, and added appropriate views / preferences for enabling background notifications, but am lost when it comes to actually delivering notifications from the service worker itself, or how to go about listening for events that trigger a notification.

None of the classes in the app/ directory can be imported into the service worker. Additionally, all of the examples I have seen online for enabling push notifications to be delivered from the service worker seem to leverage PushManager / web push protocol. I do not know how to configure / incorporate this server logic into the existing web app code; plus, all the class instances in app/ will cease to run once the PWA is closed.

<!-- gh-comment-id:1315877783 --> @liamstojanovic commented on GitHub (Nov 15, 2022): I've hit a blocker with this endeavor. I've made the web app install-able, and added appropriate views / preferences for enabling background notifications, but am lost when it comes to actually delivering notifications from the service worker itself, or how to go about listening for events that trigger a notification. None of the classes in the `app/` directory can be imported into the service worker. Additionally, all of the examples I have seen online for enabling push notifications to be delivered from the service worker seem to leverage [PushManager](https://web.dev/push-notifications-subscribing-a-user/#subscribe-a-user-with-pushmanager) / [web push protocol](https://web.dev/push-notifications-web-push-protocol/). I do not know how to configure / incorporate this server logic into the existing web app code; plus, all the class instances in `app/` will cease to run once the PWA is closed.
Author
Owner

@binwiederhier commented on GitHub (Nov 16, 2022):

So I know nothing about PWA, but I looked at web push and the service worker stuff for a while (not sure if that's the same thing), and the more I looked, the more confused I got.

It's been a while, so my memory is fuzzy, but luckily I can ping some experts, that can hopefully shed some light :-D

Pretty please, @p1gp1g @karmanyaahm (sorry for pinging you on two tickets :-))

<!-- gh-comment-id:1316220191 --> @binwiederhier commented on GitHub (Nov 16, 2022): So I know nothing about PWA, but I looked at web push and the service worker stuff for a while (not sure if that's the same thing), and the more I looked, the more confused I got. It's been a while, so my memory is fuzzy, but luckily I can ping some experts, that can hopefully shed some light :-D Pretty please, @p1gp1g @karmanyaahm (sorry for pinging you on two tickets :-))
Author
Owner

@BuckarooBanzay commented on GitHub (Nov 16, 2022):

It's been a while, so my memory is fuzzy, but luckily I can ping some experts, that can hopefully shed some light :-D

(background: i've done this before and switched from my own webpush-spaghetty-app to ntfy, it is an awesome tool btw 😉 )

For webpush to work you need to generate a keypair, the public key is for the frontend and the private key is backend-only.
You also need to save the subscriptions from the frontend in the backend (somewhere in a database usually)
A subscription can be obtained by the pushManager in the browser.

This is a rough overview how a subscription is obtained on the frontend/browser side:

if (navigator.serviceWorker){
	// service-worker registration (snippet below)
	navigator.serviceWorker.register('service-worker.js');

	// ready event
	navigator.serviceWorker.ready
	.then(function(registration){
		return registration.pushManager.getSubscription()
		.then(function(subscription){
			if (subscription)
				// already subscribed
				return subscription;

			// new subscription
			// public key from the backend
			return fetch("api/push/pubkey")
			.then(function(res){ return res.text(); })
			.then(function(vapidPublicKey){
				return registration.pushManager.subscribe({
					userVisibleOnly: true,
					applicationServerKey: vapidPublicKey
				});
			});
		});
	})
	.then(function(subscription){
		// TODO: store subscription object in the backend for later notification
	});

} else {
	//no push
}

A subscription looks like this:

{
 "endpoint": "https://browser-dependent-url.com/xy",
 "keys": {
    "auth": "abcde--",
    "p256dh": "efgh=="
}

For the sending part in the backend you should really use a library, i can suggest this: https://www.npmjs.com/package/web-push EDIT: sorry i was somewhere else my my head https://github.com/SherClockHolmes/webpush-go

Sent notifications arrive in the service-worker.js and get dispatched to the user here:

self.addEventListener('push', function(event){
	var payload = event.data ? event.data.text() : null;
	if (!payload)
		return;

	var data = JSON.parse(payload);
	event.waitUntil(
		self.registration.showNotification(data.label, {
			body: data.text
		})
	);
});

Side-note: pwa != webpush, both can be developed independently

<!-- gh-comment-id:1316466052 --> @BuckarooBanzay commented on GitHub (Nov 16, 2022): > It's been a while, so my memory is fuzzy, but luckily I can ping some experts, that can hopefully shed some light :-D (background: i've done this before and switched from my own webpush-~~spaghetty~~-app to ntfy, it is an awesome tool btw 😉 ) For webpush to work you need to generate a keypair, the public key is for the frontend and the private key is backend-only. You also need to save the `subscriptions` from the frontend in the backend (somewhere in a database usually) A subscription can be obtained by the `pushManager` in the browser. This is a rough overview how a `subscription` is obtained on the frontend/browser side: ```js if (navigator.serviceWorker){ // service-worker registration (snippet below) navigator.serviceWorker.register('service-worker.js'); // ready event navigator.serviceWorker.ready .then(function(registration){ return registration.pushManager.getSubscription() .then(function(subscription){ if (subscription) // already subscribed return subscription; // new subscription // public key from the backend return fetch("api/push/pubkey") .then(function(res){ return res.text(); }) .then(function(vapidPublicKey){ return registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: vapidPublicKey }); }); }); }) .then(function(subscription){ // TODO: store subscription object in the backend for later notification }); } else { //no push } ``` A `subscription` looks like this: ```json { "endpoint": "https://browser-dependent-url.com/xy", "keys": { "auth": "abcde--", "p256dh": "efgh==" } ``` For the sending part in the backend you should really use a library, i can suggest this: ~~https://www.npmjs.com/package/web-push **EDIT:** sorry i was somewhere else my my head~~ https://github.com/SherClockHolmes/webpush-go Sent notifications arrive in the `service-worker.js` and get dispatched to the user here: ```js self.addEventListener('push', function(event){ var payload = event.data ? event.data.text() : null; if (!payload) return; var data = JSON.parse(payload); event.waitUntil( self.registration.showNotification(data.label, { body: data.text }) ); }); ``` Side-note: pwa != webpush, both can be developed independently
Author
Owner

@karmanyaahm commented on GitHub (Nov 17, 2022):

hopefully shed some light

PWAs and WebPush are related but separate. One does not require the other.
I agree with @BuckarooBanzay's comment. The frontend is simple, an extra JS file that handles push, notifies, and stores it into the indexed DB.

The backend could get complicated, however. First, you need a way to register. Perhaps POST ntfy.sh/mytopic,topic2/push with the subscription:

{"endpoint": "https://browser-dependent-url.com/xy", "keys": {"auth": "abcde==","p256dh": "efgh=="}}

Then, ntfy needs to store mytopic:subscription, topic2:subscription in the database.

Just like there's a sendToFirebase function, there will have to be a sendToPush function. On every message, sendToPush will look up the subscriptions associated with that topic, and then run the WebPush library on each of those.

The library encrypts the payload and POSTs it to the endpoint.

Details:

  1. I'd recommend allowing ignoring encryption when keys is null (POST raw notification to the server).
  2. The ntfy server will have to generate VAPID keys. It can be saved to the DB on the first run. (https://pkg.go.dev/github.com/AbdullahDiaa/govapid#GenerateVAPID). The client needs to know the public VAPID key.
  3. There needs to be a config option for the email of the server host or something similar (for VAPID).
  4. Make sure the endpoint cannot point to the ntfy server itself, preventing loops.
  5. Subscriptions should expire, perhaps weekly, to prevent dead clients. Clients that are still notifying should reregister every few days.

Feel free to ping me if you need more info about any of this.

<!-- gh-comment-id:1319011262 --> @karmanyaahm commented on GitHub (Nov 17, 2022): > hopefully shed some light PWAs and WebPush are related but separate. One does not require the other. I agree with @BuckarooBanzay's comment. The frontend is simple, an extra JS file that handles push, notifies, and stores it into the indexed DB. The backend could get complicated, however. First, you need a way to register. Perhaps `POST ntfy.sh/mytopic,topic2/push` with the subscription: ```json {"endpoint": "https://browser-dependent-url.com/xy", "keys": {"auth": "abcde==","p256dh": "efgh=="}} ``` Then, ntfy needs to store `mytopic:subscription, topic2:subscription` in the database. Just like there's a `sendToFirebase` function, there will have to be a `sendToPush` function. On every message, `sendToPush` will look up the subscriptions associated with that topic, and then run the WebPush [library](https://github.com/SherClockHolmes/webpush-go) on each of those. The library encrypts the payload and POSTs it to the endpoint. Details: 1. I'd recommend allowing ignoring encryption when `keys` is `null` (POST raw notification to the server). 3. The ntfy server will have to generate VAPID keys. It can be saved to the DB on the first run. (https://pkg.go.dev/github.com/AbdullahDiaa/govapid#GenerateVAPID). The client needs to know the public VAPID key. 4. There needs to be a config option for the email of the server host or something similar (for VAPID). 5. Make sure the endpoint cannot point to the ntfy server itself, preventing loops. 6. Subscriptions should expire, perhaps weekly, to prevent dead clients. Clients that are still notifying should reregister every few days. Feel free to ping me if you need more info about any of this.
Author
Owner

@pinpox commented on GitHub (Jun 26, 2023):

Any plans for when this will be released?

<!-- gh-comment-id:1607443712 --> @pinpox commented on GitHub (Jun 26, 2023): Any plans for when this will be released?
Author
Owner

@binwiederhier commented on GitHub (Jun 26, 2023):

@gedw99 @pinpox You can help test it. It's deployed on https://staging.ntfy.sh https://staging.ntfy.sh/app -- Docs are here: https://docs.ntfy.sh/subscribe/pwa/

We found some small issues, but nothing major. It's almost ready for prime time. The code is already in the main branch.

<!-- gh-comment-id:1607447094 --> @binwiederhier commented on GitHub (Jun 26, 2023): @gedw99 @pinpox You can help test it. It's deployed on ~https://staging.ntfy.sh~ https://staging.ntfy.sh/app -- Docs are here: https://docs.ntfy.sh/subscribe/pwa/ We found some small issues, but nothing major. It's almost ready for prime time. The code is already in the `main` branch.
Author
Owner

@nimbleghost commented on GitHub (Jun 26, 2023):

specifically here: https://staging.ntfy.sh/app :D

and the self-hosting config docs are here: https://docs.ntfy.sh/config/#web-push

<!-- gh-comment-id:1607455712 --> @nimbleghost commented on GitHub (Jun 26, 2023): specifically here: https://staging.ntfy.sh/app :D and the self-hosting config docs are here: https://docs.ntfy.sh/config/#web-push
Author
Owner

@binwiederhier commented on GitHub (Jun 27, 2023):

📢 Request for testing:

The next ntfy server release will contain a progressive web app (PWA) with Web Push support, which means you'll be able to install the ntfy web app on your desktop or phone similar to a native app (even iOS! 🥳), and get basic push notification support (without any battery drain).

Installing the PWA gives ntfy web its own launcher (e.g. shortcut on Windows, app on macOS, launcher shortcut on Linux, home screen icon on iOS, and launcher icon on Android), a standalone window, push notifications, and an app badge with the unread notification count.

The (hopefully) production ready version of the PWA is currently deployed on https://staging.ntfy.sh/app -- Install instructions with screenshots can be found in the docs (https://docs.ntfy.sh/subscribe/pwa/).

Please report bugs or issues on Discord/Matrix/Lemmy. PLEASE HELP TEST

Huuuuge thanks goes to @nimbleghost for developing this entire feature top to bottom. If you throw donations my way, I'll share them with him. He certainly deserves it for all this great work. 👏

<!-- gh-comment-id:1608601239 --> @binwiederhier commented on GitHub (Jun 27, 2023): :loudspeaker: **Request for testing:** The next ntfy server release will contain a **progressive web app (PWA) with Web Push support**, which means you'll be able to **install the ntfy web app on your desktop or phone** similar to a native app (__even iOS!__ :partying_face:), and get basic push notification support (without any battery drain). Installing the PWA gives ntfy web its own launcher (e.g. shortcut on Windows, app on macOS, launcher shortcut on Linux, home screen icon on iOS, and launcher icon on Android), a standalone window, push notifications, and an app badge with the unread notification count. The (hopefully) production ready version of the PWA is currently deployed on https://staging.ntfy.sh/app -- Install instructions with screenshots can be found in the docs (https://docs.ntfy.sh/subscribe/pwa/). Please report bugs or issues on Discord/Matrix/Lemmy. **PLEASE HELP TEST** Huuuuge thanks goes to @nimbleghost for developing this entire feature top to bottom. If you throw donations my way, I'll share them with him. He certainly deserves it for all this great work. :clap:
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ntfy#269
No description provided.