How to send push notifications with Firebase and React
Tags: firebase, react, javascript, webdev
Published: 2022-02-24 03:29:53

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

{% embed https://www.youtube.com/watch?v=czoOAF4r9KI&ab_channel=JeremyTenjo %}

Get the complete code [here](https://github.com/jeremytenjo/how-to-send-push-notifications-with-firebase-and-react).

## Create Firebase project

1. Add project from the [Firebase Console](https://console.firebase.google.com/)


![setup firebase project step 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytomcfu2uxecs9dp9i83.png)


![setup firebase project step 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ns8h3m7yq7qsr2yqqj5.png)


![setup firebase project step 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aoh425aymruyynm45ti1.png)


![setup firebase project step 4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z25mrkfqs7mgzh1cuw6e.png)


![setup firebase project step 5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/un1j9czebvpxlzylhwwm.png)


2. Add a Web App to your firebase project

![setup firebase project step 6](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pd40f9fj1urfl7tkplcy.png)


![setup firebase project step 7](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u97qkwwnciqnsq1cifom.png)

- Press `Continue to console`

## Add firebase to React app

1. Install Firebase CLI

```sh
npm i -g firebase-tools
```

2. Clone React app tutorial starter

```sh
npx degit https://github.com/jeremytenjo/starter-demo.git firebase-messaging-with-react && cd firebase-messaging-with-react && npm i && npm run dev
```

3. Install dependencies

```sh
npm i firebase @useweb/use-firebase-messaging @useweb/use-firebase
```

4. Setup firebase in app

```sh
firebase init hosting
```

- Click `Use an existing project`
- Click `tut-push-notifications (tut-push-notifications)`
- Select the following options:

```sh
? 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
```

- Firebase initialized 🎉

- Firebase will create `firebase.json` and `.firebaserc`

4. Add `gcm_sender_id` property to `manifest.json` . Insert the value below AS IT IS, without changing.

```json
{
  "gcm_sender_id": "103953800507"
}
```

5. Create a [firebase-messaging-sw.js](https://firebase.google.com/docs/cloud-messaging/js/receive#web-v9_2) file in your public folder. This service worker will receive and display notification when your app is in the background.

```js 
/* 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()
})
```

6. Replace `firebaseConfig = undefined` in `firebase-messaging-sw.js` with your firebase config. Find under `Project settings` in the firebase console.


![firebase config page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxpcnqw89o8w8z9lvzwc.png)

7. 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.

```js
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>
  )
}
```

8. Replace `firebaseConfig = undefined` in `src/services/Firebase/Firebase.tsx` with your firebase config. Find under `Project settings` in the firebase console.

![firebase config page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxpcnqw89o8w8z9lvzwc.png)

9. Generate firebase messaging `vapidKey`

- Open the [Cloud Messaging tab](https://console.firebase.google.com/u/0/project/tut-push-notifications/settings/cloudmessaging) 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.

10. Replace `vapidKey = undefined` in `src/services/Firebase/Firebase.tsx` with your generated `vapidKey`

11. Wrap you app with `Firebase.tsx`

`src/index.tsx`

```js
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'))
```

8. 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`

```js
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>
  )
}
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qojfw8vrmxy1gglnd4li.png)

3. Click on `New campaign` button

4. Click on `Notifications` button


![firebase messaging composer step 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cjimo9yr9poercmu2m3.png)

5. Add `Notification title` and `Notification text`

6. Click `Send test message`

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

8. 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

{% embed https://www.youtube.com/watch?v=czoOAF4r9KI&ab_channel=JeremyTenjo %}

## Send notification from a cloud function (Advanced)

1. Get `FCM registration token` to send cloud messages to.

```js
const messaging = useFirebaseMessaging({
  onFcmRegistrationToken: (fcmRegistrationToken) => {
    console.log(fcmRegistrationToken)
  },
})
```

2. Send message from nodejs function/app

```js
        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)

```

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](https://twitter.com/jeremy_tenjo) ✌️