Skip to content

Push Notifications

Push Notifications Implementation with Firebase Cloud Messaging

Push notifications are a critical feature for PWAs, enabling real-time user engagement. Firebase Cloud Messaging (FCM) is the recommended service for implementing push notifications in modern web apps. This guide walks through setting up FCM, managing subscriptions, and handling payloads.


1. Firebase Project Setup

Step 1: Create Firebase Project
Use the Firebase Console to create a new project. The firebase projects:create command is used to create a project, not to initialize a web app.

Step 2: Initialize Firebase Web App
In an existing project directory, run:

npm install -g firebase-tools
firebase init
This command initializes a web app within an existing Firebase project. Ensure you select the correct project when prompted.

Step 3: Configure Firebase Web App
In the Firebase Console, add your web app and copy the firebaseConfig object. Store this securely in your app (e.g., environment variables).


2. Client-Side Implementation

Register Service Worker & Initialize Firebase
In your next.config.js or a global script, register the service worker and initialize Firebase:

// firebase-init.js
import { initializeApp } from 'firebase/app';
import { getMessaging, onMessage, getToken } from 'firebase/messaging';

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
  projectId: "YOUR_PROJECT_ID",
  // ...other config
};

const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);

// Request permission and subscribe
getToken(messaging, { vapidKey: "YOUR_VAPID_KEY" })
  .then((currentToken) => {
    if (currentToken) {
      // Send token to your backend
      console.log('FcmToken:', currentToken);
    } else {
      console.warn('No FCM token available');
    }
  })
  .catch((err) => {
    console.error('Failed to get FCM token:', err);
  });

Handle Background Messages
Update your service worker to handle notifications in the background:

// service-worker.js
self.addEventListener('push', (event) => {
  const data = event.data?.json() || {};
  const title = data.title || 'New Notification';
  const options = {
    body: data.body,
    icon: '/icon.png',
    tag: 'notification-tag',
  };
  event.waitUntil(self.registration.showNotification(title, options));
});


3. Subscription Management

Subscribe to Topics
Allow users to subscribe to specific topics (e.g., "news") for targeted notifications:

messaging.subscribeToTopic('news')
  .then(() => console.log('Subscribed to "news" topic'))
  .catch((err) => console.error('Subscription failed:', err));

Unsubscribe
Provide a UI to let users unsubscribe:

messaging.unsubscribeFromTopic('news')
  .then(() => console.log('Unsubscribed from "news"'))
  .catch((err) => console.error('Unsubscribe failed:', err));


4. Payload Handling

Frontend Response to Messages
Use onMessage to handle foreground notifications:

onMessage(messaging, (payload) => {
  console.log('Received foreground message:', payload);
  // Update UI or state based on payload
});

Background Message Handling
The push event in the service worker triggers notifications even when the app is closed. Ensure your service worker is properly registered and has access to the app's assets.


5. Security & Best Practices

  • Validate Server Keys: Never expose your FCM server key in client code. Use a secure backend to send messages.
  • HTTPS Requirement: Ensure your app uses HTTPS for secure communication with FCM.
  • User Consent: Always prompt users for permission before requesting notifications.
  • Token Rotation: Handle token refreshes by listening to the onTokenRefresh event.

Key takeaways

  • Use Firebase Cloud Messaging for reliable push notifications in PWAs.
  • Securely manage subscriptions and handle payloads in both foreground and background contexts.
  • Prioritize user consent and secure communication to avoid privacy issues.
  • Regularly update your service worker and backend logic to align with FCM best practices.