Sending Push Notifications from Kontent
Sending push notifications is a great way to let your customers know about promotions, items they may be interested in, things they left in their shopping cart, and so much more! But, if an editor wants to send a push notification, they’ll need a simple way to accomplish this without needing to know any code.
In this post, we’ll be setting up a content type in Kentico Kontent, which editors can use to create new push notifications. When those items are published, your application will automatically send push notifications to all your visitors. What’s more, you can use the content scheduling feature to have the push notifications sent at a specific time in the future!
Setting Up Your Application
With the web push installed, generate the VAPID keys your application will need to send push notifications. VAPID keys are used to identify your application with a push service and without them, we won’t be able to use the web push. Save these keys in a file somewhere—we’ll use them later in the article.
As I mentioned above, we’ll be sending push notifications in reaction to a webhook from Kontent. Webhooks are messages that can be sent to your application when something changes, such as a content item being published. The process looks like this:
When your application receives the webhook POST, you will need to verify that the request is coming from Kontent using the signature. Install body parser at this time as we need it receive the raw JSON body of the webhook and verify the signature:
To ensure that Express uses this parser for JSON data, modify app.js:
Allowing Visitors to Subscribe to Notifications
The first step to getting permission is to check whether the browser is capable of sending push notifications. It’s important to note that push notifications are only supported over secure SSL connections, so your application needs to be running on HTTPS. The following line will run immediately when the script loads to see if the serviceWorker is available in the browser and will call our own run function if so:
Now, we define our run function which will register our script with the serviceWorker asynchronously and pass our own callback method:
Note that we’re registering our own service worker file worker.js in the /public/scripts directory. This is the file that will be called when the push notification is sent by the server. You can create the file now, but leave it blank. We need to make sure the registration is complete before we ask the visitor’s permission. Our waitRegistration function waits until the serviceWorker’s state is "activated" using an event listener, then calls our subscribeForPush function:
Now, we can use it in our subscribeForPush function:
When the visitor subscribes, we receive important information about the subscription which we need to store somewhere:
- endpoint - a randomized URL pointing to the push service, e.g. https://fcm.googleapis.com/fcm/send/csI_R3I7MN[...]
- p256dh - subscription key
- auth - subscription secret
In the Express project, we’re POSTing the data to the /subscribe endpoint and saving it to an SQLite database here, but you can store this information anywhere you’d like (for example, application memory for testing, a text file on your server, etc.).
Configuring the Project in Kontent
Now that we’ve built a list of visitors who’d like notifications, we can design the notifications themselves. Our push notifications will be triggered whenever a certain content item is published in Kontent, so go to your project and create a new content type called "Push notification".
This content type will contain the elements required to send the push notification. You can see in the documentation for sending push notifications that we should at least have a title, body, and icon. We can also optionally vibrate the device and open a URL when the notification is clicked, so here are the elements to create in the content type:
- title: Text
- body: Text
- icon: Asset
- vibrate: Multiple choice (checkbox with single value "Yes")
- url: Text
Since we want the push notification to be sent when an item of this type is published, we can go to the Webhooks page and create a new webhook called "Push notifications". In the Url address field, enter your website’s URL, including the endpoint that will intercept the POST request, e.g., https://mysite.com/push (we will create it in the next section). Also, copy the Secret to be used later. In the Content item events to watch drop-down, select "Publish", then save the webhook.
Validating the Webhook
Create an endpoint that will receive the webhook’s POST request in your application. In Express, we register the /push endpoint in app.js:
Then we create the push route to respond to POST requests:
To validate the signature in the header of the POST request, you will need to add the webhook secret we copied earlier as a const in your /push endpoint, or use an environment variable. Create a new function to validate the signature:
In the /push handler, call your hasValidSignature function by passing the body and signature of the req.headers object:
You can now test your webhook to ensure that you receive a successful 200 response. Publish any content item in Kontent and wait for the POST request to be sent to your application. In Kontent’s Webhooks page, you should see a green dot next to the webhook indicating that it’s successful:
Once the webhook is properly validated, we can move on to reading the data that Kontent sent in the body of the webhook notification.
Processing the Webhook
We want to use the waitForLoadingNewContent option here so that we can get the latest data from Delivery and avoid anything that might be cached. Let’s take a look at the information given to us in the webhook notification and determine what we need to get the values from our content item. The body of the workflow webhook notification differs from previous non-workflow webhooks. It will look something like this:
The Item object contains the ID of the content item that was published. Since this webhook triggers only for that workflow step, we don’t need to worry about the transition_from or transition_to values. To send our push notification with the values from the published content item, we will only need to extract the content item’s ID from this response.
To begin this process, create a new function to contain the logic and call it after the signature has been verified:
In our new processWebhook function, we can get the item ID from the JSON body of the response:
With the content item ID, we can use the filtering options available in the Delivery API to find the exact content item we’re looking for. Create an Observable from the request, subscribe to it, then unsubscribe when we receive the result:
Let’s make sure we retrieved the correct content item before continuing. The items function will return an array of items, but there should be only one item in this case. We’ll check the result.items array to make sure there’s at least one item, then only continue if that item is our "push_notification" content type:
If everything looks good, we pass the content item to a new function sendPush which we’ll create in the next section.
Sending the Push Notification
Now that we have the required information, let’s define our sendPush function to actually send the push notification. You can see an example of what a content item object might look like in our documentation here. We’ll start off by creating the payload for the push notification which is used later by our worker.js file:
To use the web push, first set the VAPID credentials using the public and private keys generated earlier:
Now, we need to call the web push’s sendNotification() function for each visitor that subscribed to the notifications. Get all of your subscribers, then loop through the list. In the Express application, we get all subscriptions from the SQLite database, then construct the required sub object for the web push from the records:
After we construct the subscription object, we can call the web push’s sendNotification and pass the subscription and payload:
If the request returns a 410 status, the subscription has expired or was manually revoked and should be removed from the database.
Finishing the Service Worker File
We’re almost done! Remember the worker.js file we created? This is the actual service worker itself, which is responsible for displaying the notification. In the section above, we sent our worker.js file the JSON payload of the push notification, so now this file needs to "catch" the payload and display the notification. Open the file and add the script that will call showNotification:
Here, we’re consuming the payload sent from the web push and displaying the notification. If a URL has been passed, the notification will display a button to open the address, and mobile devices will vibrate if the "Yes" checkbox was checked on the content item.
Now you can test the notification! Access the site and subscribe to notifications. In Kontent, create a new item with the Push notification content type and publish it. When the webhook fires, you will see your notification appear!
Push Them, but Not Too Often
In this article, we implemented push notifications from the start to the end. We created a content type, configured webhooks, received data in an Express application, and broadcasted them as push notifications. Editors can now easily inform website visitors about the latest news and it only takes them a few clicks. However, be advised that you should only send these notifications sporadically and within the right context to ensure your visitors are paying attention to them.
You can view the fully-implemented code of the Express application here.