DEV Community

Cover image for How to send push notifications with Firebase and React
Jeremy Tenjo
Jeremy Tenjo

Posted on

How to send push notifications with Firebase and React

Push notifications improve engagement with your app. Firebase provides a way to send them using their Firebase Cloud Messaging service. I'm going to show you how to integrate it in your React app.

What we are building

Get the complete code here.

Create Firebase project

  1. Add project from the Firebase Console

setup firebase project step 1

setup firebase project step 2

setup firebase project step 3

setup firebase project step 4

setup firebase project step 5

  1. Add a Web App to your firebase project

setup firebase project step 6

setup firebase project step 7

  • Press Continue to console

Add firebase to React app

  1. Install Firebase CLI
npm i -g firebase-tools
Enter fullscreen mode Exit fullscreen mode
  1. Clone React app tutorial starter
npx degit https://github.com/jeremytenjo/starter-demo.git firebase-messaging-with-react && cd firebase-messaging-with-react && npm i && npm run dev
Enter fullscreen mode Exit fullscreen mode
  1. Install dependencies
npm i firebase @useweb/use-firebase-messaging @useweb/use-firebase
Enter fullscreen mode Exit fullscreen mode
  1. Setup firebase in app
firebase init hosting
Enter fullscreen mode Exit fullscreen mode
  • Click Use an existing project
  • Click tut-push-notifications (tut-push-notifications)
  • Select the following options:
? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? Set up automatic builds and deploys with GitHub? No
Enter fullscreen mode Exit fullscreen mode
  • Firebase initialized 🎉

  • Firebase will create firebase.json and .firebaserc

  1. Add gcm_sender_id property to manifest.json . Insert the value below AS IT IS, without changing.
{
  "gcm_sender_id": "103953800507"
}
Enter fullscreen mode Exit fullscreen mode
  1. Create a firebase-messaging-sw.js file in your public folder. This service worker will receive and display notification when your app is in the background.
/* eslint-disable no-undef */
importScripts('https://www.gstatic.com/firebasejs/8.6.8/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/8.6.8/firebase-messaging.js')

const firebaseConfig = undefined // firebaseConfig is required

firebase.initializeApp(firebaseConfig)

const messaging = firebase.messaging()

messaging.onBackgroundMessage((payload) => {
  console.log('[firebase-messaging-sw.js] Received background message ', payload)
  const notificationTitle = payload.notification.title
  const notificationOptions = {
    body: payload.notification.body,
    icon: payload.notification.icon || payload.notification.image,
  }

  self.registration.showNotification(notificationTitle, notificationOptions)
})

self.addEventListener('notificationclick', (event) => {
  if (event.action) {
    clients.openWindow(event.action)
  }
  event.notification.close()
})
Enter fullscreen mode Exit fullscreen mode
  1. Replace firebaseConfig = undefined in firebase-messaging-sw.js with your firebase config. Find under Project settings in the firebase console.

firebase config page

  1. Create src/services/Firebase/Firebase.tsx and add the following code. We are using the @useweb/use-firebase package in order to pass necessary data to the @useweb/use-firebase-messaging package we will use later on.
import React from 'react'
import { FirebaseProvider } from '@useweb/use-firebase'
import { initializeApp } from 'firebase/app'
import { getMessaging } from 'firebase/messaging'

const firebaseConfig = undefined // firebaseConfig is required

const firebaseApp = initializeApp(firebaseConfig)
const messaging = getMessaging(firebaseApp)

const envIsDev = process.env.NODE_ENV === 'development'

const vapidKey = undefined // vapidKey is required

export default function Firebase({ children }) {
  return (
    <FirebaseProvider
      firebaseConfig={firebaseConfig}
      firebaseApp={firebaseApp}
      envIsDev={envIsDev}
      messaging={messaging}
      messagingOptions={{
        vapidKey,
      }}
    >
      {children}
    </FirebaseProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode
  1. Replace firebaseConfig = undefined in src/services/Firebase/Firebase.tsx with your firebase config. Find under Project settings in the firebase console.

firebase config page

  1. Generate firebase messaging vapidKey
  • Open the Cloud Messaging tab in the Firebase console Project Settings and scroll to the Web configuration section.
  • In the Web Push certificates tab, click the Generate key pair button.
  1. Replace vapidKey = undefined in src/services/Firebase/Firebase.tsx with your generated vapidKey

  2. Wrap you app with Firebase.tsx

src/index.tsx

import React from 'react'
import ReactDOM from 'react-dom'

import Firebase from './services/firebase/firebase'
import Router from './pages/router'
import Theme from './theme/theme'

function App() {
  return (
    <Firebase>
      <Theme>
        <Router />
      </Theme>
    </Firebase>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
Enter fullscreen mode Exit fullscreen mode
  1. We are going to use @useweb/use-firebase-messaging to retrieve our FCM registration token and handle notifications while the app is in the foreground. Add the following code to pages/HomePage/HomePage.tsx
import React, { useEffect } from 'react'
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import LinearProgress from '@mui/material/LinearProgress'
import useFirebaseMessaging from '@useweb/use-firebase-messaging'

import CopyToClipboard from '../../lib/components/CopyToClipboard/CopyToClipboard'
import Text from '../../lib/components/Text/Text'
import Header from '../../lib/components/_unique/Header/Header'
import useSnackbar from '../../lib/components/Snackbar/Snackbar'

export default function HomePage() {
  const snackbar = useSnackbar()

  const firebaseMessaging = useFirebaseMessaging({
    onMessage: (message) => {
      console.log(`Received foreground message`, message)
      snackbar.show({
        message: message?.notification?.title || message?.data?.title,
      })
    },
  })

  useEffect(() => {
    firebaseMessaging.init()
  }, [])

  return (
    <Box>
      <Header
        title='Firebase Messaging Push Notification Example'
        tutorialLink='how-to-send-push-notifications-with-firebase-and-react'
        repoLink='https://github.com/jeremytenjo/how-to-send-push-notifications-with-firebase-and-react'
      />

      {firebaseMessaging.initializing && (
        <>
          <Text
            text='Initializing Firebase Messaging (enable notifications for this page)'
            sx={{ mb: 2 }}
          />
          <LinearProgress />
        </>
      )}

      {firebaseMessaging.error && (
        <Text text={firebaseMessaging.error.toString()} sx={{ color: 'red' }} />
      )}

      {firebaseMessaging.fcmRegistrationToken && (
        <>
          <Box
            sx={{
              display: 'grid',
              gridAutoFlow: 'column',
              justifyContent: 'start',
              alignItems: 'center',
              mb: 1,
              gridGap: '10px',
            }}
          >
            <Text text='FCM Registration Token:' />
            <CopyToClipboard text={firebaseMessaging.fcmRegistrationToken}>
              <Button>Copy</Button>
            </CopyToClipboard>
          </Box>

          <Text
            text={firebaseMessaging.fcmRegistrationToken}
            sx={{
              width: '100%',
              overflowWrap: 'break-word',
              fontSize: '14px',
              color: 'grey.main',
            }}
          />
        </>
      )}
    </Box>
  )
}
Enter fullscreen mode Exit fullscreen mode

That is it, now lets test push notifications using the generated FCM registration token

  1. Open http://localhost:3001/

  2. Open Firebase message composer

firebase messaging composer step 1

  1. Click on New campaign button

  2. Click on Notifications button

firebase messaging composer step 2

  1. Add Notification title and Notification text

  2. Click Send test message

  3. Add the registration token generated from http://localhost:3001/ and click the plus icon

  4. Click Test

🎉 Your app will show a snackbar if the app is in the foreground or it will show the native notification if the app is in the background

Send notification from a cloud function (Advanced)

  1. Get FCM registration token to send cloud messages to.
const messaging = useFirebaseMessaging({
  onFcmRegistrationToken: (fcmRegistrationToken) => {
    console.log(fcmRegistrationToken)
  },
})
Enter fullscreen mode Exit fullscreen mode
  1. Send message from nodejs function/app
        const message = {
          data: {
            title: `New episodes aired recently!`,
            image: `/images/logo/assets/logo.png`,
            icon: `/images/logo/assets/logo.png`,
            body,
            actions: JSON.stringify(actions),
          },
          tokens: fcmRegistrationToken,
        }

        functions.logger.info('FCM Message', message)

        // https://firebase.google.com/docs/cloud-messaging/send-message#send-messages-to-multiple-devices
        const response = await messaging.sendMulticast(message)

Enter fullscreen mode Exit fullscreen mode

That's all for now. I hope you find this tutorial helpful! Feel free to leave feedback or questions below, I would love to hear and work on them.

For more content, follow me on Twitter ✌️

Top comments (2)

Collapse
 
danielfogacaa profile image
danielfogacaa

I'm having trouble with background notifications, when I click on them nothing happens, would my App.js file be able to see when it was clicked?

Collapse
 
jeremytenjo profile image
Jeremy Tenjo

Hi @danielfoga

Use self.addEventListener('notificationclick', (event) => {} to listen to background notification clicks.

For example:

firebase-messaging-sw.js

...

self.addEventListener('notificationclick', (event) => {
  console.log({ notificationclick: event })
  if (event.action) {
    clients.openWindow(event.action)
  } else {
    // Open tv page
    clients.openWindow(origin + '/tv')
  }
  event.notification.close()
})

Enter fullscreen mode Exit fullscreen mode