Short answer
Read Notification.permission before calling getToken(), or register() in the newer API. If it is denied, skip FCM and show a short note on turning notifications back on in site settings. If it is default, ask from a button the user clicks, after explaining why. Serve the page over HTTPS, and check that firebase-messaging-sw.js is at the root.
Rather not fix it yourself? App Fix Ticket starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.
Why permission is blocked, and the fix
01
The user blocked notifications for the site
“The user has explicitly denied permission for the current origin to display system notifications.” MDN, Notification.requestPermission()
Once the user clicks Block, or blocks the site in settings, the browser answers denied without showing a prompt. Only the user can change it.
02
Check permission before you register
“When you need to target an app instance with FCM, first request notification permissions from the user with Notification.requestPermission().” Firebase, Set up a JavaScript client
Call FCM only when permission is granted, and ask only when it is still default, so blocked users don’t hit the error on every visit. The error surfaces on the call that fetches the token.
import { getMessaging, getToken } from 'firebase/messaging'; async function enablePush() { if (Notification.permission === 'denied') return showUnblockSteps(); const permission = await Notification.requestPermission(); if (permission !== 'granted') return; const token = await getToken(getMessaging(), { vapidKey: VAPID_KEY }); await saveToken(token); }03
The prompt fires on page load
Asking the moment the page opens gets many users to click Block, and some browsers quiet or hide prompts that come without a click. Ask from a button, after the user sees why.
04
Older code uses getToken()
“If you are using the deprecated token APIs, you should pass the VAPID key to getToken() instead of register().” Firebase, Set up a JavaScript client
Firebase now documents register() and onRegistered() for web apps, and marks the token APIs deprecated. Apps on getToken() still work. Check the permission the same way before either call.
05
The page isn’t on HTTPS
“The FCM SDK is supported only in pages served over HTTPS.” Firebase, Set up a JavaScript client
Service workers need HTTPS, except on localhost. On a plain http preview link, FCM fails before the permission question matters.
Checked against the vendor’s docs on : Firebase docs: Set up a JavaScript Firebase Cloud Messaging client app; MDN: Notification.requestPermission().
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
“Very responsive, attentive to fixing bugs, and completed the project as needed! Thank you!”
Related: FCM registration token not registered · Expo push notifications not working · Firebase Storage object-not-found · Firebase auth/popup-blocked