How to add In-App notifications to any web app!
Tags: javascript, react, tutorial
Published: 2023-05-09 14:20:49

## TL;DR
In this article, you'll learn how to add a notification system to any app in just a few simple steps! The primary focus in making this app was to showcase just how simple it is to add notifications to an app.

![Notifications generator homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxhya3tay69e6ixh32i5.png)



![The text entered is sent as a notification](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tch0v30va20ixko6ugjb.png)



If you take [any modern app](https://charming-dieffenbachia-2ae3ea.netlify.app), there's a high chance that it would have notifications functionality baked in. And why not!

Notifications make any app better by providing real-time updates and keeping users engaged. They help increase user retention by providing a medium of communication between an app and its users.

If you're reading this article, chances are that you already understand the importance of having notifications in your app and are looking for a way to add a notification system to your app.

Well, you've come to the right place. In this tutorial, we'll have a look at how we can add notifications to any app. Now, writing a custom solution every time you want to add notifications somewhere is cumbersome, I know. 

But we'll use a magical tool to help make our jobs easier and believe me, this whole thing will be much simpler than you might think, _pinky promise_! 

How, you ask?

**_Enter Novu!_**

Novu helped me solve the biggest problem I had every time I wanted to add notifications to an app - writing a notifications center from scratch. 

And even though, I could re-use parts of what I'd written earlier, the unique use cases of each app ensured, I had to make significant changes to my previous system. 

With Novu, I could simply grab an API key and use the custom component to add notifications to any web app. PERIOD!

## Novu - Open-source notification infrastructure for developers:

Novu is an [open-source notification infrastructure](www.novu.co) for developers. It helps you manage all the product notifications be it an in-app notification (a bell icon like what's there in Facebook), Emails, SMSs, Discord, and what not.

![Novu makes adding notifications a breeze](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gln2um5bb2rc96mv7wkg.gif)




I'll be super happy if you check us out on GitHub and give us a star! ❤️
https://github.com/novuhq/novu


## Let's write some code:
We'll make our app in two stages - backend and front-end. Both will live in separate GitHub repositories and I'll also show you how to deploy both to the web, enabling us to access the app from anywhere.
Let's start with the backend.

## Basic set-up:

We'll start with an empty git repo. Create an empty git repository, enter all the relevant details, and publish it to GitHub. Then open it in your IDE (I'm going to use VS Code):

Our first step here would be to install all the required packages. We'll rely on several packages from npm (Node Package Manager).

To start this process, we'll generate a package.json using the following command:

``` bash
npm init -y
```
This command generates the package.json file and now we can install all the packages we need. Use the following command to install the packages we'll be using:

``` bash
npm i novu body-parser cors dotenv express mongoose nodemon
```

Now, create a '.env' file and a '.gitignore' file in the root of the project. We'll keep sensitive data like our MongoDB connection URL and the Novu API key in the _.env_ file. To stop it from getting staged by git and being pushed onto GitHub, add the .env file to the .gitignore file, as shown below. This way it'll be accessible to us in the app but nobody will be able to see it on Github.


![add novu api key and mongoDB connection URL in .env file and add the .env file to .gitignore](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qt8usaf7wobe392u9wa3.png)

## Connecting to a database:
After completing the basic setup, it is now time for us to connect to a database. 

If you haven't already, create your MongoDB account and sign in.

We'll need to get a connection URL from our database and will plug that into our backend. To get that URL, go to the top left corner and create a new project.

![Creating a new project on MongoDB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ickff9b29slsis3keahi.png)

Give your project a name and then click the 'build a database' button:

![Building a database in MongoDB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dn5f22afsiuw1poz4fe0.png)


After this, choose the free option and leave everything else to default.

![Click the 'build a database' button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kn0f1iqlaulnmc1ue13e.png)


Now, enter the username and password that you want to use for database authentication, and make sure that you've noted down the password (we're going to need it).

![enter username and password](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qmgoqir18f5yn2x1jvin.png)


Now, only the last step is left which is to obtain our connection URL. To get it, click on the 'connect' button


![Click the connect button to get connection URL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7qvt9tk01jz6xs83mnq8.png)

Then choose the 'compass' option.
![Choose the 'compass' option to get the connection URL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mfaubpgr11es0hy12th1.png)

Now, note down the URL (highlighted text in the image):
![copy the connection URL and change your password](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e04pprj2srapsz0jfbyr.png)

In this URL, you'll have to replace '<password>' with your actual password (that you noted down above). That's it!

Store this URL in a variable in your '.env' file as shown below:

![Store the connection URL in '.env' file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jwk1xsidk6l9j24xn68.png)


Obtaining Novu API key:

Getting the Novu API key is quite simple. You just need to head over to [Novu's web platform](web.novu.co)


![Novu web platform](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99ywsq7np81ng1pfb2ey.png)

Then create your account and sign in to it. Then go to _'Settings'_ from the left navigation menu:


![Settings tab in the left menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rkgcy9yjk24cpsvampyt.png)


Now, in the settings, go to the second tab called 'API Keys'. There, you'll see your Novu API key. Copy it and add it to the .env file in your project's root directory:


![env file with connection URL and Novu API Key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygcrcjwgq5c93m7kxtjz.png)


## Let's start coding:

The backend for this app is rather simple and consists of a few key parts:

1. Controller: It contains code for the function that runs when we make server requests from our front-end. It just contains one simple function:

```javascript
import { inAppNotification } from "../Novu/novu.js";
import Notif from "../models/notif.js";

export const createNotif = async (req, res) => {
    const { description } = req.body
    const newNotif = new Notif({
        description
    });
    try {
        await newNotif.save();
        await inAppNotification(description, "Sumit");
        res.status(201).json(newNotif);
    } catch (error) {
        res.status(409).json({ message: error });
    }
}
```

The function starts by destructuring the description property from the req.body object, which is passed in as a parameter when the function is called from the front-end.

Next, a new instance of the _'Notif'_ model is created using the description value, which is then saved to a database using the _'save()'_ method.

After the notification is saved to the database, an in-app notification is sent using the _'inAppNotification'_ function, which is imported from the "../Novu/novu.js" module. 

This function takes two arguments:
- The description of the notification, and 
- The name of the user who triggered the notification, in this case, it is my name: "Sumit".

If everything is successful, the function sends an HTTP status code of 201 along with the new notification object in the response. 

On the contrary, if an error occurs during the process, the function sends an HTTP status code of 409 along with an error message in the response.

## Database Schema:

In MongoDB, data is stored in things called _'Collections'_. Collections are like boxes within which we store data. A database in this case is the room. So the database contains entities called 'collections' and we store data within those collections.

The schema for notifications is as follows:

```javascript
import mongoose from "mongoose";

const notifSchema = mongoose.Schema(
  {
    description: { type: String, required: true }
  },
  {
    collection: "notif",
  }
);

export default mongoose.model("Notif", notifSchema);
```


Here, we're defining a _'notif'_ collection in our database. We're using the _'Mongoose'_ library to connect to the database.

Using _'mongoose.Schema'_ method, we're creating a new schema object for the "notif" collection. The object passed as the first parameter is defining the shape of the documents in the collection. 

In this case, the schema is defining a single field called "description", which is of type String and is required (i.e., it must be present in every document).

The second parameter being passed to mongoose.Schema is an optional _'options'_ object. In this case, it is setting the name of the collection to "notif".

Finally, we're using _'mongoose.model'_ method to create a model based on the schema. This model is being exported as the default export of this module.

The benefit of exporting it is that we can now use it to interact with the "notif" collection in the MongoDB database. 

Now, off to the sweet part!

## Setting up Novu notification template:

We're now left with two tasks in the backend:
- Configuring Novu, and
- Starting the server

To configure Novu, go the the [web platform](web.novu.co) again and go to _'Notifications'_ from the left menu bar:

![Notifications button on the left meny](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ucpjnpp9nljfbsfk7osm.png)

Now, create a new workflow, give it a name, and go to the workflow editor:



![Workflow editor in Novu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0wddn77pwtxl2gxmqx0d.png)




Since we'll be using just one functionality - In-app notifications, we'll set only that one up. But with Novu, you can send notifications through pretty much every channel out there, be it email, sms, push, or chat.

To setup the in-app channel, drag the button called 'in-app' from the right options menu and click on it to edit it.

Because we're using _'description'_ in the backend, we'll have to plug that in here as shown below:


![Using 'description' in Novu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c90o0uhap9r4hvpoz141.png)



Now, back to the code:

In the controller above, we had used a function called `inAppNotification` but we never defined it. Now is the time to do so:

So, go to your project's root and create a new file. In that file, we'll create this function:

```javascript
import { Novu } from '@novu/node'; 


export const inAppNotification = async (description, Id) => {
    const novu = new Novu(process.env.NOVU_API_KEY);
    await novu.subscribers.identify(Id, {
      firstName: "inAppSubscriber",
    });
  
    await novu.trigger("in-app", {
      to: {
        subscriberId: "Sumit",
      },
      payload: {
        description: description
      },
    });
  };
```


Notice the use of _'description'_ here (that we set up in Novu) in the previous step.

Now, the last step of the back-end is remaining, which is setting up the server and the routes.

Our app is quite simple here and we need just one route:

```javascript
import express from "express";
import { createNotif } from '../controller/notif.js'

const router = express.Router();

router.post('/', createNotif)

export default router;
```

And the server setup is also relatively straight forward:

```javascript
import express from "express";
import mongoose from "mongoose"
import cors from "cors"
import bodyParser from "body-parser";
import dotenv from "dotenv";
import notifRoute from "./routes/notif.js"

dotenv.config();

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ limit: "30mb", extended: true }));
app.use(cors());

app.use("/home", notifRoute)

app.listen(3000, function () {
    console.log('listening on 3000')
})

app.get('/', (req, res) => {
    res.send('Project running!')
})


const CONNECTION_URL = process.env.CONNECTION_URL;
const PORT = process.env.PORT || 8000
app.use("/", (req,res) => res.send('this is working'))
mongoose.connect(CONNECTION_URL, { useNewUrlParser: true, useUnifiedTopology: true })
    .then(() => app.listen(PORT, () => console.log(`server running on port: ${PORT}`)))
    .catch((error) => console.log(error));
```

With these out of the way, our backend is done and we can now move to the front end.

## Coding up the front-end:

In the front-end, we're gonna use the magical power of **_Web component._** It is a collection of three things: 
- `NovuProvider`, 
- `PopoverNotificationCenter`, and 
- `NotificationBell`

These are all combined into one simple component, that we call **_Web Component._** Web component is what enables us to embed this notification center into just about any web app.

You can [read more about it here](https://docs.novu.co/notification-center/web-component/)!


![Web component docs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13yuqudmb9krtjr62lvf.png)

Now, in the front-end, we're gonna need four files:
- 'index.html' - This will contain the markup,
- 'styles.css' - This will contain the CSS styles,
- 'app.js' - This will contain all the logic to send notifications from front-end to back-end and fetch them all in the bell icon, and
- the '.env' file - This will contain our Novu API key

The contents of each one of them are as follows, starting with 'index.html' below:


```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./styles.css">
    <script src="https://novu-web-component.netlify.app/index.js"></script>
    <title>Notification Generator</title>
</head>
<body>
    <div class="header">
        <h1>Notifications Generator</h1>
        <notification-center-component style="display: inline-flex" application-identifier="SWMw97ec1ZNA"
            subscriber-id="Sumit" class="bell"></notification-center-component>
    </div>
    <div class="content">
        <img class="img" src="./notification-bell.png" alt="notification bell image" srcset="">
        <form id="form" action="#" method="post">
            <input class="input" type="text" placeholder="Enter notification text and click the send button!" name="description">
            <button id="btn">Send</button>
        </form>
    </div>
    <footer>
        <p>Proudly powered by <a class="link" href="http://www.novu.co">Novu</a></p>
    </footer>
    <script src="./app.js"></script>
</body>
</html>
```


Then, the 'app.js' file is as follows:

```javascript
const form = document.querySelector('#form')


// extracting send button
const btn = document.querySelector('#btn');
const input = document.querySelector('.input')

// btn.onclick = () => console.log('clicked');

form.addEventListener("submit", async (e) => {
    e.preventDefault();
    console.log('button clicked');
    await fetch('https://notificationsgeneratorbackend.onrender.com/home', {
        method: 'POST',
        body: JSON.stringify({
            description: input.value,
        }),
        headers: {
            'Content-Type': 'application/json'
        }
    })
        .then(response => response.json())
        .then(data => console.log(data))
        .catch(error => console.error(error));
        input.value = ""
    
})

// extracting input value on button click

// here you can attach any callbacks, interact with the web component API
let nc = document.getElementsByTagName('notification-center-component')[0];
nc.onLoad = () => console.log('hello world!');
```

Finally, we'll have some CSS code for styling in the `styles.css` file and the Novu API key in the `.env` file.

You can find the CSS I've used [here](https://github.com/novuhq/examples/blob/main/web-component-notification-center-example/frontend/styles.css).

If you've done everything correctly, you should have an app that looks something like this:


![Home page of the app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j23o0qxzktnxjwbuv8qu.png)

In this app, we've demonstrated how to use the **_'Web component'_** to add a notification center to any web app. To keep things simple, we've just used the in-app notification feature but you can use just about any notification medium you can imagine - from chat to sms to emails and more!

## Deploying our front-end and our back-end:

The last step remaining is to deploy our front-end and our back-end. We're gonna use a service called 'Render' to deploy our back-end and the good, old 'Netlify' for our front-end:

Both are very straight forward and the process is a simple plug-and-play kinda thing: Just log in to both, point to your GitHub repo, and add the environment variables as defined in the '.env' file of both. That's it!

If you want to go over my code, it is available here:
- [Front-end](https://github.com/novuhq/examples/tree/main/web-component-notification-center-example/frontend), and
- [Back-end](https://github.com/novuhq/examples/tree/main/web-component-notification-center-example/back-end)

Lastly, if you need help with anything and wanna reach out to me, I'm always [available at the Novu discord](https://discord.gg/novu). Feel free to join in and say hi! 👋

This entire project was made possible by the awesomeness of Novu and it takes me a lot of time and effort to come up with tutorials like this one, so if you could spare a moment and give us a star on [our GitHub repo](github.com/novuhq/novu), it would mean a lot to me. 

Thanks for all your support! ⭐⭐⭐⭐⭐


![Give us a star if you liked this tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78ccuvgpih0ev212bmjl.gif)


Don't forget to comment what you liked and didn't like about this tutorial.
Have a great one, bye! 👋

~ [Sumit Saurabh](https://twitter.com/sumitsaurabh927)