Back to Blog

Firebase Cloud Messaging in 2026: Web Push Notifications with Vue 3 & SDK v10

FirebaseFCMVue.jsPush NotificationsWeb PushFrontendTypeScriptNode.js
Firebase Cloud Messaging web push notifications in a Vue 3 application

Firebase Cloud Messaging (FCM) is the standard for delivering web push notifications. The legacy CDN-based setup (Firebase v7) is deprecated. This guide uses the v10 modular SDK with Vue 3, smaller bundles, full TypeScript support, and the correct service worker pattern for 2026.

Project Setup

bash
pnpm add firebase # Or: npm install firebase

Create src/lib/firebase.ts:

typescript
import { initializeApp } from 'firebase/app'; import { getMessaging } from 'firebase/messaging'; const firebaseConfig = { apiKey: import.meta.env.VITE_FIREBASE_API_KEY, authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN, projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID, storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET, messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID, appId: import.meta.env.VITE_FIREBASE_APP_ID, }; export const app = initializeApp(firebaseConfig); export const messaging = getMessaging(app);

Store all values in .env.local, never hardcode Firebase credentials in source.

Step 1: Get a VAPID Key

  1. Firebase Console → Project Settings → Cloud Messaging
  2. Under Web configuration, click Generate key pair
  3. Copy the public key, you’ll use it as VITE_FIREBASE_VAPID_KEY

Step 2: Request Permission & Get FCM Token (Vue 3 Composable)

Create src/composables/usePushNotifications.ts:

typescript
import { ref } from 'vue'; import { getToken, onMessage, type MessagePayload } from 'firebase/messaging'; import { messaging } from '@/lib/firebase'; export function usePushNotifications() { const token = ref<string | null>(null); const notification = ref<MessagePayload | null>(null); const error = ref<string | null>(null); async function requestPermissionAndGetToken() { try { const permission = await Notification.requestPermission(); if (permission !== 'granted') { error.value = 'Notification permission denied'; return; } // Register the service worker first const registration = await navigator.serviceWorker.register( '/firebase-messaging-sw.js' ); token.value = await getToken(messaging, { vapidKey: import.meta.env.VITE_FIREBASE_VAPID_KEY, serviceWorkerRegistration: registration, }); console.log('FCM token:', token.value); // TODO: send token.value to your backend for storage } catch (err) { error.value = err instanceof Error ? err.message : 'Unknown error'; } } // Handle foreground messages (when the app tab is open) function listenForMessages() { onMessage(messaging, (payload) => { console.log('Foreground message received:', payload); notification.value = payload; }); } return { token, notification, error, requestPermissionAndGetToken, listenForMessages }; }

Use it in a component:

vue
<script setup lang="ts"> import { onMounted } from 'vue'; import { usePushNotifications } from '@/composables/usePushNotifications'; const { token, notification, error, requestPermissionAndGetToken, listenForMessages } = usePushNotifications(); onMounted(() => { listenForMessages(); }); </script> <template> <div> <button @click="requestPermissionAndGetToken">Enable Notifications</button> <p v-if="error" class="text-red-500">{{ error }}</p> <p v-if="notification">{{ notification.notification?.title }}</p> </div> </template>

Step 3: Create the Service Worker

Create public/firebase-messaging-sw.js (must be at the web root):

javascript
// public/firebase-messaging-sw.js import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js'; import { getMessaging, onBackgroundMessage, } from 'https://www.gstatic.com/firebasejs/10.12.0/firebase-messaging-sw.js'; const firebaseConfig = { apiKey: 'YOUR_API_KEY', authDomain: 'YOUR_AUTH_DOMAIN', projectId: 'YOUR_PROJECT_ID', storageBucket: 'YOUR_STORAGE_BUCKET', messagingSenderId: 'YOUR_MESSAGING_SENDER_ID', appId: 'YOUR_APP_ID', }; const app = initializeApp(firebaseConfig); const messaging = getMessaging(app); onBackgroundMessage(messaging, (payload) => { console.log('Background message received:', payload); const { title = 'New message', body = '' } = payload.notification ?? {}; self.registration.showNotification(title, { body, icon: '/icon-192x192.png', badge: '/badge-72x72.png', data: payload.data, }); });

Note: Service workers cannot use Vite environment variables. Inline the Firebase config here directly or use a build step to inject them at deploy time.

Step 4: Send a Notification from Node.js (Backend)

Install the Admin SDK:

bash
npm install firebase-admin
typescript
// server/send-notification.ts import { initializeApp, cert } from 'firebase-admin/app'; import { getMessaging } from 'firebase-admin/messaging'; initializeApp({ credential: cert('./service-account.json'), }); const messaging = getMessaging(); async function sendPushToUser(fcmToken: string) { const messageId = await messaging.send({ token: fcmToken, notification: { title: 'Your order shipped! 📦', body: 'Estimated delivery: tomorrow between 2–5 PM', }, webpush: { fcmOptions: { link: 'https://yourapp.com/orders', }, }, }); console.log('Sent message:', messageId); }

For sending to a topic or user segment, use messaging.sendEachForMulticast() with an array of tokens.

Update manifest.json

Add the FCM sender ID to your web app manifest:

json
{ "name": "My App", "gcm_sender_id": "YOUR_MESSAGING_SENDER_ID" }

Summary

StepWhat it does
initializeApp()Connects to your Firebase project
Notification.requestPermission()Prompts the browser permission dialog
getToken(messaging, { vapidKey })Returns the FCM registration token
onMessage()Handles foreground notifications
firebase-messaging-sw.jsHandles background/closed-tab notifications
messaging.send() (Admin SDK)Sends notifications from your server

The token returned by getToken() is what your server sends to. Store it per-user in your database and refresh it whenever the user revisits the app.

X / Twitter
LinkedIn
Facebook
WhatsApp
Telegram

About Pooya Golchian

Common questions about Pooya's work, AI services, and how to start a project together.

Get practical AI and engineering playbooks

Weekly field notes on private AI, automation, and high-performance Next.js builds. Each edition is concise, implementation-ready, and tested in production work.

Open full subscription page

Get the latest insights on AI and full-stack development.