(NodeJS) Web Push Notifications Extension

Hi. Created an extension with web-push to send push notifications to users!


Below the explanation on how to set it up, apologies for the many steps.

Let me know if you have any issues, ideas or optimisations as I’m still very new in extension development.

Download

Functionality

Allows to send push notifications to users from server connect api’s, you can set it up to only send a notification if user is not active in the tab / page.

This means that the notification will also work when your page is closed, great way to remind users to check something on your app!

Requirements

  • Node JS server model
  • Set your generated public and private keys in settings (Explained below)
  • Create a flow in server connect to handle user subscription data
  • Please follow steps below exactly with names etc as otherwise it won’t work

Installation

1. Add files from package

  • In your project folder, create /extensions/server_connect/modules (if it does not yet exist)

  • Add the “web_push.hjson” and “web_push.js” files into /extensions/server_connect/modules
    Screenshot 2022-09-08 at 18.02.39

  • Refresh the Server Actions panel (restarting Wappler is also an option)

  • The required libraries will be installed automatically upon use and next deployment

  • Add the files “client.js” and “worker.js” folder in the public folder (Directly inside the public folder, not in a sub-folder)

  • You should now have a Web Push Notification group in your available actions list for server workflows

2. Add this script tag in your layout page before closing body tag

<script src="/client.js"></script>

3. Generate Vapid Public & Private Keys

Generate the keys with the “Generate Vapid Keys” action from a temporary server connect api. Click on open in browser to copy the generated keys

Keep the page open for now as you will copy and paste these keys below, you can delete this server connect api once the steps below are completed

4. Open web_push.js (Added in step 1), paste the public & private keys

5. Open client.js (Added in step 1), paste ONLY public key

Paste the public key in the area.

Below that, you can see that the “show_only_when_tab_not_active” is set on true, this means that the user will only get notifications when your page is not active / open in the user’s tab. If you always want to push the notification, even when user is active on the page, you can set this setting to false

6. Set up server connect api to get subscriber object

The script sends the user’s subscription object to /api/web_push/subscribe, this means that you must create a folder in your api’s called “web_push” and add an action named “subscribe” in this folder

Screenshot 2022-09-08 at 18.41.02

This “subscribe” action will receive the subscription data with POST.
This subscription object must be connected to the user, to send this user notifications later on. This subscription object will update often so you will need to create a flow to update this.

What I did for the subscription flow:

  1. Create a database table called “push_subscriptions” with a user_id reference field and a json field for the subscription object
    Screenshot 2022-09-08 at 18.48.44

  2. In the newly created “subscribe” API action, add a security provider “identity” action to get the user’s id

  3. Add a database query to check if this user has a subscription in the newly created “push_subscriptions” table

  4. Add a condition action, if the query returns a result (when it’s true), create an update action to update this user’s subscription object in the “push_subscriptions” table, use the whole “$_POST” as a value (This contains the whole subscription object that is needed)

  5. Add an else action to this condition, to insert a new record in the “push_subscriptions” with the user_id and the “$_POST” value for the subscription
    Screenshot 2022-09-08 at 19.00.57

7. Send Push Notification!

  1. You can now use the “Send notification” action in any server connect api
  2. You can query the “push_subscriptions” table in the database to get the user subscription object that you’d like to send a notification to (To send a notification to everyone you can simply query the whole table and repeat the records)

    Subscription = Add the subscription object here
    Title = Title text in notification (string)
    Body = Body text in notification (string)
    Icon = Url of image / icon to show (string)

Result:

Additional Comments

  • I’m planning to add additional options in the UI to add buttons / actions to the push notifications
  • I’m planning to add URL option to go on click
19 Likes

Nice! I wish this was available for PHP.

2 Likes

Thank you. That s very interesting!!!

1 Like

Update

Fixed the page visibility event, not using a workaround now so it’s much more efficient.
Push notifications work now when user closes the page / web app

Important change:
The client.js and worker.js files must be directly in the public folder

Explanations and download link above are updated

In the next update I will add the options to create custom buttons in the notification and url redirect links on click

2 Likes

Great work. Thanks for sharing. :+1:
We have been thinking about building our own notification solution for a project in near future - now it would be really easy and fast with this.

2 Likes

Thanks for this, great extension, this is a must have inside Wappler, the team should have to considere it.

But unfortunatly, I get a error:

image

Following the exact same steps, same names, at least, that’s what I think;).

Aditional, in page where reside script “/client.js” doing a control+F5 (win) or Cmd+F5 (mac) to clear caché in browser I get a different error:
image

The database do not get update by the script, At this point I don’t know if I missing something.

Hi Alexander, in which browser are you testing? I only have that issue in Brave as they block push notifications etc

Hi, thanks for reply, you are right, I’m using Brave. but now in Google Chrome I get this error:
Error: ER_BAD_FIELD_ERROR: Unknown column 'expirationTime' in 'field list':

Don’t really understand what goes wrong from only that

When you try it in Chrome, does it update your db table with the subscription details? If no, maybe the server action isn’t set up correctly

In Chrome I see that the script updates the DB, but when I’m try to send notification following the step above I get nothing, I don’t know if it’s because the missing expirationTime or not. But no Push message at all. This is my API that is trigger after clic in button in html.

The Database single query: “query” search in “push_subscriptions” table where user_id == identity, but nothing.

I’m missing something maybe?

Really appreciate your help.

What do you mean by user_id == identity? As I don’t see any identity step before your query. Can you try to add a static id condition for the user id that has the subscription, and then can you click on “open in browser” to test the server action directly

I use identity in globals.

Can you click on “open in browser” to see if it gets the subscription object correctly

I just tested it again and it works for me:

Screenshot 2023-02-24 at 19.48.19

Screenshot 2023-02-24 at 19.50.09

Edit: I see in the picture you sent about your error, that the subscription object looks fine, so right now I’m not sure what the problem is…

Right, the object is correctly query from API, but none push message at all. It’s like if the “Send Notification” step in API is not loading, I don’t know.

Ahh ok there you go, it’s a string, not an object. You probably added the db field as a string/text field instead of a json/jsonb field. So you should JSON.parse that string before adding it to the subscription field. Tomorrow I could add a type check in the extension if you’d like, to parse the string to JSON if the type is string

MariaDB use LONGTEXT for json, and you are right, the subscription field need to be output as parseJSON.

This works now:

image

Really appreciate your help.

1 Like

Works in brave too, only is need to be enable Google Push Messaging Services:

After that notificactions works. No more Onesignal or similar services :smiley:

2 Likes

Hi @htatd

Maybe not universal, but If someone else need it here are a few changes in original steps. I hope this is not a bother.

If user change of browser the script send a new object, and in Wappler we are able to perform a DB update, if not, just not perform any action.

This fix this problem, because in the “endpoint” the browsers not sent the expirationTime and is null, so, is not possible to perform an direct update.

STEPS

In clien.js file in async function send() I add this new function (this only retrieve desktop browsers):

var browser = (function (agent) {        
     switch (true) {
            case agent.indexOf("edge") > -1: return "MS Edge";
            case agent.indexOf("edg/") > -1: return "Edge";
            case agent.indexOf("opr") > -1 && !!window.opr: return "Opera";
            case agent.indexOf("chrome") > -1 && !!window.chrome: return "Chrome";
            case agent.indexOf("trident") > -1: return "MS IE";
            case agent.indexOf("firefox") > -1: return "Firefox";
            case agent.indexOf("safari") > -1: return "Safari";
            default: return "other";
        }
    })(window.navigator.userAgent.toLowerCase());

Now, inside async function send() in same file change the stringify of body to this {subscription,browser}:

body: JSON.stringify({subscription,browser}),

Following the original steps, the 6.5 in the conditions, I made this changes:

Now the fetch from the script client.js send two objects, we need it from separete, now exist $_POST.subscription and $_POST.browser.

In table “push_subscriptions” I added a new column named “browser” that looks like this:
image

In the above condition steps, if $_POST.browser is different from DB browser it perform a Database deleted and Database Insert, if not, means if both value are equal not perform any action.

And of course in database “insert” and “updates” exists change in “POST” to; for subscription is $_POST.subscription and for browser is $_POST.browser:

In this way if user change of browser it remove the row of the user and create a new one, and of course if not exist create a new one too.

There are too many possibilities, like conver the API into Library and execute it inside for example forms submissions where exist Send Mail. User will receive emails and browser notification. Too using ejs conditions to allow embbeded the script only if user have some kind of dashboard where explicity allow to receive this kind of notifications beyond of the same browser authorization to allow that, just to avoid unnecesary script on load. But, is only an example.

Thanks.

1 Like

Forgive my ignorance, I’m new to NodeJS so just learning. Will these notifications be sent on users phones if they have the app installed as a PWA? And if so, will they send when the app is closed?
Thanks!

Hi. Sorry don’t really now, never tried that