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:
- Firebase config values to initialize the SDK.
- your public VAPID key from the Firebase dashboard to generate a push token.
- the ID of your Knock FCM channel to store channel data
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.
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:
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.