Tutorials
Send web push with FCM

Sending web push notifications with Firebase Cloud Messaging (FCM)

Learn how to use FCM and Knock to deliver web push messages to a React application.

In this tutorial, we'll walk through how to configure Knock and Firebase Cloud Messaging (FCM) to send web push notifications and customize their display using the Firebase SDK. This tutorial assumes you are using a React application and have already implemented other Knock-specific components, like the KnockProvider. Examples in this tutorial have been written using the Next.js framework.

Configuring FCM resources

#

Knock does not have a first-party web push channel. Instead, you'll use FCM to send messages to a user's browser. There are multiple steps to this configuration, both within Knock and inside your application.

Add FCM as a push channel

#

The first step is to add FCM as a push channel integration in the Knock dashboard using the default instructions. Once you have this channel configured, keep track of the channel_id for use in subsequent steps.

Install the Firebase SDK

#

Many of the steps you'll need to take to successfully register for and receive web push messages will happen inside your application.

The Firebase SDK is responsible for generating a token that registers the user's browser and displaying certain types of notifications to the user.

Run the following command to install the SDK in your client-side application:

You will use both the app and messaging modules of the firebase package in the following steps.

Create environment variables in your application

#

You'll need several environment variables for this integration. Here's a quick breakdown of what you'll need and why:

The environment variables for the Firebase config will also be needed inside of a service worker file, which may not have access to your application or framework's public variables. You may choose to hard-code those values, which you can see in this example of the Firebase config object.

Add Firebase to your app

#

In the following steps, we'll use the Firebase SDK inside your application to register for and receive web push messages.

Create a service worker file

#

First, let's create a service worker file. FCM requires a service worker file to handle displaying push notifications. Create a file called firebase-messaging-sw.js in your public directory and include the following contents:

This file loads the Firebase client libraries and adds some debugging logs to indicate its status.

The important part of this file is that a new Firebase app is initialized and a new instance of messaging is created to automatically handle background notifications. Since service workers run in their own thread, separate from the JavaScript that powers your app, you'll need to bring Firebase into your application as well and pass a reference to this service worker.

Create a FirebaseProvider component

#

In the next step, we'll create a React component that initializes the Firebase SDK in the app and registers the service worker, providing both the messaging instance and the service worker to other components through React context.

You can use the code in the following component as a starting point, but we'll walk through what's happening here step-by-step below:

Now, let's break down what's happening.

1

Create FirebaseContext

First, we define the firebaseConfig values needed to create a new app and messaging instance. Then we create a new context object called FirebaseContext and create an interface to define its properties. This context object is what we'll pass down to other components so they can access the values from the messaging package and the serviceWorkerRegistration.

2

Initialize `app` and register service worker

Inside the body of the FirebaseProvider component, we'll create useState variables to store the messaging object and service worker registration before running a series of useEffect calls to ensure that our code is loading correctly on the client and the browser context supports service workers.

Inside of the initializeFirebase function we'll create a new app and messaging instance and store that messaging value in state:

Next, we'll register the service worker we created in the previous step and store that in state as well:

3

Handling foreground notifications

The FirebaseProvider component is also a great place to centralize your logic for handling foreground messages if you want to use them. In this file, you'll see an onMessage callback that handles showing foreground notifications using browser APIs. We'll revisit this section of code later when discussing the default behavior of push notifications, e.g. foreground vs. background.

4

Return and use context

Next, we'll return FirebaseContext.Provider from FirebaseProvider with values for messaging and serviceWorkerRegistration so we can use them in the following steps:

Finally, you'll also need to implement this provider component in your app and should consider locating it close to where you have implemented the KnockProvider or any other providers that you may need:

Next, we'll register the user's browser to receive web push notifications and store the token in Knock.

Registering for web push notifications

#

Browser push notifications require user consent for registration, so you'll typically want to create UI in your app to trigger the browser's default notification permission UI based on user input.

For this section, we'll create two UI buttons that subscribe and unsubscribe a user from web push notifications.

Retrieve and save a push token

#

The first component will be responsible for retrieving a push token from the browser using the Firebase SDK and then storing that push token on the current user's Knock profile as channel data.

Here is the full code for an example PushSubscribeButton component. We'll break this down in the next step:

1

Requesting permission to send notifications

After making some checks to see what type of device we're on and ensuring that the Firebase SDK has loaded, this component uses browser APIs to enable push notifications in the browser.

The Notification.requestPermission method will trigger the browser's default UI to let you allow or deny notifications for this domain.

2

Get Firebase push token

Once the browser has notifications enabled for this host, we can use the Firebase SDK to request a token specific to this browser. We call the getToken method, and pass in the Firebase context messaging and serviceWorkerRegistration values, as well as the process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY as parameters:

The return value will be a token that we can use to send this user push messages on this device and browser.

3

Store push token in Knock

Next we need to store this token as channel data on a user in Knock so that we can use it inside of workflows.

To do this, we'll use the Knock JavaScript client directly using the useKnockClient React hook. The KnockProvider exposes this hook to all child components, so it's important that your UI components are nested inside of that provider.

Here's an abbreviated code sample showing just the Knock-specific code needed to create a new client and save a user's channel data:

With this channel data successfully stored you should be ready to use an FCM channel step inside of a workflow.

Revoking notification permission

#

If a user wants to unsubscribe from push notifications, they generally need to use the UI contained in the browser to do so. Accessing this behavior with JavaScript directly is not allowed for security reasons.

However, you can offer users the ability to remove a browser push token from Knock, so that any FCM channel steps they encounter during workflows will be skipped:

Here, we'll use the knock.user.setChannelData method to overwrite the channel data for the FCM channel to an empty array.

Test a push workflow

#

Before proceeding any further with this guide, you should test your push channel by triggering a workflow with an FCM channel step for the recipient with valid channel data.

Customizing push notification display

#

Using the Firebase SDK and Knock payload overrides, there are a number of different ways to customize the behavior of your web push notifications.

Data vs. notification message types

#

One of the common differences you'll see in web push messages is data vs. notification messages.

Notification messages

#

By default, Knock sends notification message type payloads to FCM, which already contain a set of predefined key/value pairs. All notification messages will contain a top-level notification key, but may also contain an optional data payload.

With notification messages, the FCM SDK and the browser automatically handle displaying messages when the web app is in the background, e.g. not in the current tab, window is minimized, etc. Developers can customize the foreground behavior of web push messages using the Firebase SDK.

You can also use payload overrides to send web push platform-specific customization options. Using the webpush key in your FCM payload, you can override options on the Notification browser API or send any other values allowed by the WebPushConfig object.

Here's an example of a payload override JSON object using the default merge strategy:

Data messages

#

In contrast, data messages allow the client application to handle the processing and display of all incoming messages, both in the foreground and background. Unlike notification type messages, the key/value pairs for data messages are entirely customizable. These key/value pairs are then mapped to Notification properties in your code.

To send a data message in Knock, you'll need to use a payload override using the __replace__ strategy to override the default notification values:

As you can see in this JSON sample, you can still use Liquid to generate dynamic or personalized content, but this payload override is not automatically connected to the live preview functionality in the template editor. Just be aware that it's easy for messaging to drift when using data messages.

Custom foreground and background handling

#

The Firebase SDK provides methods for manually handling both foreground and background messages depending on the type of message you're using.

Handling foreground messages

#

To handle foreground messages of any type, you'll need to use the onMessage handler to show a notification using browser APIs. This code needs access to both the firebase.messaging module and your service worker registration:

Handling background messages

#

Messages with the notification type will be handled in the background automatically by the browser and the FCM SDK. Messages with the data type can be handled using the onBackgroundMessage handler in the service worker.

Frequently asked questions

#

Yes, FCM web push is supported in all major modern browsers.

This notification is displayed by the browser to let a user know that a site has received a push notification. You may need to update how you handle background messages.