Enable push notifications for Capacitor progressive web apps (PWA) using Firebase as a cloud messaging service
This is a Capacitor Web plugin that enables Push Notifications for Web apps. Read the guide to set up Push Notifications with Firebase first, then proceed with the setup instructions.
Capacitor Minimum Version: currently waiting on pull request in Capacitor project. If you can't wait, the parts of setup instructions below that ask for npx cap copy web
, you can manually run the npm script for this plugin by doing npm explore capacitor-pwa-firebase-msg -- npm run precapcopyweb
in the command line in the root directory of your Capacitor project. Then you will have to integrate the generated service-worker capacitor-pwa-firebase-msg-sw.js that is written to the www folder on your own.
Go to Project Settings in the Firebase console. In the General section, copy the web app's Firebase config from Firebase SDK snippet and paste it as plugins.PWAFirebaseMsg
in capacitor.config.json. Under the Cloud Messaging section, generate a new VAPID Key Pair under Web configuration, and provide the value to plugins.PWAFirebaseMsg.vapidKey
. See example capacitor.config.json below:
{
"appId": "app.capacitor.my",
"appName": "My Capacitor App",
"serviceWorker": {
"name": "capacitor-sw.js",
"combineWorkers": ["capacitor-pwa-firebase-msg-sw.js", "ngsw-worker.js"],
},
"plugins": {
"PWAFirebaseMsg": {
"apiKey": "ABC123def456-GHI789jkl012-MNO345pqr678",
"authDomain": "mycapacitorapp-abc123.firebaseapp.com",
"databaseURL": "https://mycapacitorapp-abc123.firebaseio.com",
"projectId": "mycapacitorapp-abc123",
"storageBucket": "mycapacitorapp-abc123.appspot.com",
"messagingSenderId": "1234567890",
"appId": "1:1234567890:web:abcdef123456",
"vapidKey": "ABC123def456-GHI789jkl012-MNO345pqr678"
}
},
"npmClient": "npm",
"webDir": "www"
}
Add capacitor-pwa-firebase-msg-sw.js
to Capacitor's aggregate service worker. If the app uses other service workers, provide their locations (relative to webDir
, that is the "www" folder) to serviceWorker.combineWorkers
in capacitor.config.json.
Important: If you are using the Angular service worker, make sure capacitor-pwa-firebase-msg-sw.js
precedes ngsw-worker.js
in the aggregate service worker capacitor-sw.js
. If Angular's service worker handles notifications first, this plugin won't work. See above example for appropriate configuration of serviceWorker.combineWorkers
.
After production builds of the app, run npx cap copy web
from the command line. This will copy Capacitor's aggregate service worker to the webDir
. npx cap copy web
will also copy all the supporting files to webDir
(very specifically, firebase.config.json, firebase-messaging.js, firebase-app.js and capacitor-pwa-firebase-msg-sw.js will be copied to the webDir
).
Ensure that your app uses capacitor-sw.js
as its service worker. The service worker filename generated by npx cap copy web
can be overridden with serviceWorker.name
in capacitor.config.json
. See above example again.
In an Angular PWA, for example, the following code in app.module.ts
will use capacitor-sw.js
as a service worker:
import { ServiceWorkerModule } from '@angular/service-worker';
/* ... */
@NgModule({
imports: [
ServiceWorkerModule.register('capacitor-sw.js', { enabled: true })
/* ... */
After setup, in your app code, import the plugin so that it can register itself with Capacitor:
import "capacitor-pwa-firebase-msg";
Now you can use it using the same PushNotification
Capacitor plugin name. You may already have code for this if you already handled push notifications for Android or iOS platforms using Capacitor's built-in PushNotification API:
import { Plugins } from '@capacitor/core';
const { PushNotifications } = Plugins;
PushNotifications.register();
PushNotifications.addListener('registration', /* ... */);
PushNotifications.addListener('pushNotificationReceived', /* ... */);
PushNotifications.addListener('pushNotificationActionPerformed', , /* ... */);
This plugin is currently using v6.4 of the Firebase libraries (check package.json if this has changed without the README being changed). For Firebase messages received in background, it is necessary to populate the notification
in the payload with click_action
, where click_action
is the absolute URL to the PWA page expected to be open when pushNotificationActionPerformed
is handled. Even though the Firebase spec implies that we could override click_action
via webpush
in the payload instead, in my experience I could never get background push notifications to work properly (i.e. restoring the PWA from background on click or spawning a new instance if not running) using webpush
. This means that on the back-end, the push payloads need to know whether it is pushing to PWA or Android or iOS so that the click_action
is tailored to the correct platform.