How to build dev.to In-App Notification System in 20 minutes
Tags: webdev, javascript, notifications, devto
Published: 2024-04-23 11:14:26

[dev.to](https://bit.ly/3WaNvoU) is a very popular community for developers. It’s a platform for thousands of developers to collaborate, learn, publish and explore new ways of making programming languages and technology work for them.

I’m an avid reader of [dev.to](https://bit.ly/3WaNvoU) and publish a lot of articles on the platform. My favorite thing to do is to check my [notifications](https://bit.ly/3Jxs1LA) to see who posted a new article, commented or liked any of my posts.

<figure class="wp-block-image size-large">![Guide](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-16.15.21@2x-1024x687.png)</figure>I'll guide you on how to swiftly build an In-App Notification system for your next app using [Novu](https://novu.co) and the [dev.to](https://bit.ly/3Jxs1LA) API. While it might not exactly resemble the image mentioned above, it'll have many similarities.

If you want to explore the code right away, you can **[view the completed code](https://bit.ly/3Jwq69X)** [](https://github.com/novuhq/react-translation-app) on GitHub.

Grab your dev.to API Key
-----------------------------------------

You can get your dev.to API key from your [settings page](https://bit.ly/3UexkEy).

<figure class="wp-block-image size-large">![Set Up](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-16.25.47@2x-1024x539.png)</figure>Set Up a Next.js App
--------------------

To create a Next.js app, open your terminal, `cd` into the directory you’d like to create the app in, and run the following command:


```bash
npx create-next-app@latest devto
```

Go through the prompts, select your preference, install and run the app in your browser with:

<figure class="wp-block-image size-large">![Prompts](https://manage.novu.co/wp-content/uploads/2024/04/preference-1024x658.png)</figure>

```bash
npm run dev
```

Set Up &amp; Integrate Novu
---------------------------

Run the following command to install the Novu node SDK:


```bash
npm install @novu/node
```
Run the following command to install the Novu Notification Center package:


```bash
npm install @novu/notification-center
```
The Novu Notification Center package provides a React component library that adds a notification center to your React app. The [package is also available for non-React apps](https://docs.novu.co/notification-center/introduction#ui-libraries).

Before we can start sending and receiving notifications, we need to set up a few things:

2. Create a workflow for sending notifications,
5. Create a subscriber - recipient of notifications.

**[](https://docs.novu.co/quickstarts/react#create-a-workflow)Create a Novu Workflow**
--------------------------------------------------------------------------------------

A workflow is a blueprint for notifications. It includes the following:

- Workflow name and Identifier
- Channels: - Email, SMS, Chat, In-App and Push

Create a workflow by following the steps below:

2. Click **Workflow** on the left sidebar of your Novu dashboard.
5. Click the **Add a Workflow** button on the top left. You can select a Blank workflow or use one of the existing templates.
8. The name of the new workflow is currently **“Untitled”**. Rename it to `Devto Notifications`.
11. Select **In-App** as the channel you want to add.

<figure class="wp-block-image size-large">![In-App Channel](https://manage.novu.co/wp-content/uploads/2024/04/image-8-1024x548.png)</figure>5\. Click on the recently added **“In-App”** channel and add the following text to it. Once you’re done, click **“Update”** to save your configuration.

<figure class="wp-block-image size-large">![Add text](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-19.19.47@2x-1024x588.png)</figure>

The code below is what is in the image above. You can copy & paste it into the Novu editor.

```javascript
<p><strong>{{ name }}</strong> made a new post.</p>
<br />
<article style="padding:10px;border-radius:5px;border-color: white;border-block: solid;">
  <a href="{{ article_url }}" style="font-weight:bold;">
    <h3>{{ article_title }}</h3>
  </a>
</article>
```
Enable the “Add an Avatar” button to allow the notifications coming in show a default avatar.

**[](https://docs.novu.co/quickstarts/react#create-a-subscriber)Create a Subscriber to receive Notifications**
--------------------------------------------------------------------------------------------------------------

A subscriber is the recipient of a notification. Essentially, your app users are subscribers. As a logged-in user on [dev.to](http://dev.to), you are a subscriber.

To send notifications to a user on your app, you’ll need to register that user as a subscriber on Novu. If you click **“Subscriber”** on the left sidebar of the **[Novu dashboard](https://web.novu.co/subscribers)**, you’ll see the subscriber list. As a first time Novu user, it will be an empty list.

<figure class="wp-block-image size-large">![Create a Subscriber](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-03-14-at-07.19.45@2x-2-1024x564.png)</figure>Open your terminal and run the following script to create a subscriber:


```bash
curl --location '<https://api.novu.co/v1/subscribers>' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'Authorization: ApiKey <NOVU_API_KEY>' \
  --data-raw '{
    "firstName": "John",
    "lastName": "Doe",
    "email": "johndoe@domain.com",
    "phone": "+1234567890"
    }'
```
**Note:** Grab your **NOVU API Key** from the [settings section](https://web.novu.co/settings) of your Novu dashboard.

Refresh the Subscribers page on your Novu dashboard. You should see the recently added subscriber now! You can also add a subscriber to Novu by running this [API endpoint](https://docs.novu.co/api-reference/subscribers/create-subscriber).

**Note:** The best option to add a subscriber is via code in your backend. With Node.js code, you can run the following code to create a subscriber:


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

// Insert your Novu API Key here
const novu = new Novu("<NOVU_API_KEY>");

// Create a subscriber on Novu
await novu.subscribers.identify("132", {
  email: "john.doe@domain.com",
  firstName: "John",
  lastName: "Doe",
  phone: "+13603963366",
});
```
For the sake of this article, we’ll make do with adding a subscriber via the terminal to speed the process up.

**Set up Novu Notification Center in the App**
----------------------------------------------

Head over to `scr/pages/index.js`. We’ll modify this page to include the Novu Notification Center.

Import the Notification Center components from the Novu notification center package like so:


```javascript
...
import {
  NovuProvider,
  PopoverNotificationCenter,
  NotificationBell,
} from "@novu/notification-center";
```
Display the Notification Center by adding the imported components like so:


```javascript
...
return (
    <main
      className={`flex min-h-screen flex-col items-center justify-between p-24 ${inter.className}`}
    >
      <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
        <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
           Dev.to In-App Notifications
        </p>
        <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
          <NovuProvider
            subscriberId={process.env.NEXT_PUBLIC_SUBSCRIBER_ID}
            applicationIdentifier={process.env.NEXT_PUBLIC_NOVU_APP_ID}
          >
            <PopoverNotificationCenter>
              {({ unseenCount }) => (
                <NotificationBell unseenCount={unseenCount} />
              )}
            </PopoverNotificationCenter>
          </NovuProvider>
        </div>
      </div>

      ...
      <div className="grid grid-cols-2">
```
Check your app, you should immediately see a notification bell.

<figure class="wp-block-image size-large">![Notification bell](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-17.00.36@2x-1024x749.png)</figure>Click the notification bell. The Notification Center will immediately pop up like so:

<figure class="wp-block-image size-large">![Env variables](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-16.59.44@2x-1024x665.png)</figure>Add the following to your `.env` values:


```javascript
NEXT_PUBLIC_SUBSCRIBER_ID=
NEXT_PUBLIC_NOVU_APP_ID=
NEXT_PUBLIC_NOVU_API_KEY=
```

Grab your **Novu API Key** and **APP ID** from the [Settings](https://web.novu.co/settings) section of your Novu dashboard.

<figure class="wp-block-image size-large">![Get the Subscriber ID](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-03-14-at-07.52.14@2x-1-1024x542.png)</figure>Get the Identifier of the subscriber we created earlier and add it to the `.env` values.

In a real world app, the ID of the logged-in user should be passed to the **subscriberID** property of the **NovuProvider** component.

**Note**: We’re using it as an env variable because we’re not incorporating an authentication system in this tutorial. Ideally, once the user registers, the user ID should immediately be created as a subscriber and the ID be passed to the component.

Reload your app and the notification center should be squeaky clean like so:

<figure class="wp-block-image size-large">![Build the API](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-17.16.14@2x-1024x641.png)</figure>Build the API to Publish [dev.to](http://dev.to) Articles &amp; Trigger In-App Notifications
--------------------------------------------------------------------------------------------

Create a `publish-devto-article.js` file in the `src/pages/api` directory.

Add the code below to it to import the Novu SDK and specify the workflow trigger ID:


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

const novu = new Novu(process.env.NEXT_PUBLIC_NOVU_API_KEY);

export const workflowTriggerID = "devto-notifications";
```
**Note:** The `@novu/node` Novu SDK can be used only in server-side.

The `workflowTriggerID` value is obtained from the workflow dashboard. Earlier, when we set up a workflow titled `Devto Notifications`, Novu created a slug from this title to serve as the trigger ID.

You can see it here:

<figure class="wp-block-image size-large">![Add the code below](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-19.11.33@2x-1024x593.png)</figure>Now add the following functions to the code in the `publish-devto-article.js` file:


```javascript
...
export default async function handler(req, res) {
  const { article } = req.body;

  const response = await fetch("<https://dev.to/api/articles>", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "API-Key": process.env.NEXT_PUBLIC_DEVTO_API_KEY,
    },
    body: JSON.stringify({ article: article }),
  });

  /**
   * Get response of the published article from Dev.to
   */
  const dataFromDevto = await response.json();

  /**
   * Extra the essential details needed from the Dev.to response
   */
  const { title, url, published_timestamp, user } = dataFromDevto;

  /**
   * Send notification that a new article has been published
   */
  sendInAppNotification(user, title, url);

  return res.json({ message: dataFromDevto  });
}

/**
 * SEND IN-APP NOTIFICATION VIA NOVU
 * @param {*} userDetails
 * @param {*} articleTitle
 * @param {*} articleURL
 * @returns json
 */
async function sendInAppNotification(userDetails, articleTitle, articleURL) {
  await novu.trigger(workflowTriggerID, {
    to: {
      subscriberId: process.env.NEXT_PUBLIC_SUBSCRIBER_ID,
    },
    payload: {
      name: userDetails.name,
      article_url: articleURL,
      article_title: articleTitle,
      profile_image: userDetails.profile_image_90,
    },
  });

  return res.json({ finish: true });
}
```
The `sendInAppNotification` function block of code above triggers the notification via the Novu SDK:

- Accepts the workflow trigger ID to determine which workflow to trigger.
- Accepts the subscriber ID value to identify the notification recipient.
- Accepts a payload object that represents the parameters to inject into the workflow variables.

The `handler` function block above makes a POST request to [Dev.to](http://Dev.to) to publish an article and then calls the `sendInAppNotification` to fire an In-App notification indicating that someone just published an article.

**Note:** The request body is passed from POSTMAN or Insomnia. Next, we will test our API with any of these API software tools.

Test the API with POSTMAN or Insomnia - Publish to [Dev.to](http://Dev.to)
--------------------------------------------------------------------------

Fire up either **POSTMAN** or **Insomnia** and make a request to the API we created and post a JSON request to publish an article on [Dev.to](http://Dev.to).

**Our API url:** [http://localhost:3000/api/publish-devto-article](http://localhost:3000/api/publish-devto-article*)

I personally use &amp; prefer Insomnia because it has a snappy and lovely UI. As you can see below, we passed some parameters (pulled from [dev.to](https://bit.ly/3Qf8CTA) [API docs](https://developers.forem.com/api/v1#tag/articles/operation/createArticle)) to enable us publish an article.

<figure class="wp-block-image size-large">![Instant Notification](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-19.27.12@2x-1024x745.png)</figure>Next, check your app. You should see an instant notification about the new published article on [Dev.to](http://Dev.to).

<figure class="wp-block-image size-large">![link to article](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-19.29.15@2x-1024x690.png)</figure>Click on the new post title. It should take you directly to the article on [Dev.to](http://Dev.to)!

<figure class="wp-block-image size-large">![Publish away](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-19.30.55@2x-1024x671.png)</figure>You can try publishing as many as possible.

<figure class="wp-block-image size-large">![Notification Center](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-19.33.21@2x-1024x647.png)</figure>The Notification Center provides a lot of functions built-in. A user can mark all notifications as read, mark one notification as read, and delete a notification.

The Notification Center ships with a lot of [props and options to customize the whole experience](https://docs.novu.co/notification-center/client/react/customization). [Header, footer, colors](https://docs.novu.co/notification-center/client/react/api-reference) can be customized to conform with your app.

Center the Notification Center, Just like [Dev.to](http://Dev.to)’s
-------------------------------------------------------------------

You might be wondering, [Dev.to](http://dev.to/)’s Notification Center isn't a popover; it's centered on the page. How do I achieve that?

Simply replace the `PopoverNotificationCenter` component with the `NotificationCenter` component from the Novu package.

It should look something like this:


```javascript
<NovuProvider
    subscriberId={process.env.NEXT_PUBLIC_SUBSCRIBER_ID}
    applicationIdentifier={process.env.NEXT_PUBLIC_NOVU_APP_ID}
>
  <NotificationCenter />
</NovuProvider>
```
However, Next.js uses Server side rendering so you might come across this issue on your page because the `<NotificationCenter />` component makes use of the window object.

<figure class="wp-block-image size-large">![SSR issues](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-23-at-10.12.20@2x-1024x479.png)</figure>Let’s fix this issue by wrapping the component in a way that disables ssr and lazy loads it.

Create a `components/notifications` folder in the `src/` directory. Go ahead and add these two files with the code below to them respectively:

`index.js`


```javascript
export { default } from "./notifications"; 
```
`notifications.js`


```javascript
import { NotificationCenter } from "@novu/notification-center";
import dynamic from "next/dynamic";
import React, { useCallback } from "react";

const Notifications = () => {
  const onNotificationClick = useCallback((notification) => {
    if (notification?.cta?.data?.url) {
      window.location.href = notification.cta.data.url;
    }
  }, []);

  return (
    <div>
      <NotificationCenter
        colorScheme="dark"
        onNotificationClick={onNotificationClick}
      />
    </div>
  );
};

export default dynamic(() => Promise.resolve(Notifications), {
  ssr: false,
});
```
The code above does the following:

- It imports the original `<NotificationCenter />` component from Novu.
- It uses Next’s dynamic functionality that allows us to dynamically load a component on the client side, and to use the `ssr` option to disable server-rendering.
- It defines a notificationClick handler for the onNotificationClick prop of the NotificationCenter component (The function that is called when the notification item is clicked).
- The `colorScheme` is one of the props you can pass to the NotificationCenter component. It takes in either “light” or “dark” values to enable you set the UI mode.

Finally, head back to the `pages/index.js` file, import our newly created component and use it in the `NovuProvider` parent component like so:


```javascript
...
import Notification from "../components/notifications";

...
...
...
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
    <NovuProvider
      subscriberId={process.env.NEXT_PUBLIC_SUBSCRIBER_ID}
      applicationIdentifier={process.env.NEXT_PUBLIC_NOVU_APP_ID}
    >
      <Notification />
    </NovuProvider>
</div>
...
...
...
```
Lastly, let's adjust the components' position to place the Notification Center in the middle of the page.

*pages/index.js*


```javascript
import Image from "next/image";
import { Inter } from "next/font/google";
import {
  NovuProvider,
  PopoverNotificationCenter,
  NotificationBell,
} from "@novu/notification-center";

import Notification from "../components/notifications";

const inter = Inter({ subsets: ["latin"] });

export default function Home() {
  return (
    <main
      className={`flex min-h-screen flex-col items-center justify-between p-24 ${inter.className}`}
    >
      <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
        <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
          Dev.to In-App Notifications
        </p>
      </div>

      <div className="relative flex place-items-center before:absolute before:h-[300px] before:w-full sm:before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full sm:after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700/10 after:dark:from-sky-900 after:dark:via-[#0141ff]/40 before:lg:h-[360px]">
        <NovuProvider
          subscriberId={process.env.NEXT_PUBLIC_SUBSCRIBER_ID}
          applicationIdentifier={process.env.NEXT_PUBLIC_NOVU_APP_ID}
        >
          <Notification />
        </NovuProvider>
      </div>

      <div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
        <a
          href="<https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app>"
          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
          target="_blank"
          rel="noopener noreferrer"
        >
          <h2 className={`mb-3 text-2xl font-semibold`}>
            Docs{" "}
            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
              -&gt;
            </span>
          </h2>
          <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
            Find in-depth information about Next.js features and API.
          </p>
        </a>

        <a
          href="<https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app>"
          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
          target="_blank"
          rel="noopener noreferrer"
        >
          <h2 className={`mb-3 text-2xl font-semibold`}>
            Learn{" "}
            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
              -&gt;
            </span>
          </h2>
          <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
            Learn about Next.js in an interactive course with&nbsp;quizzes!
          </p>
        </a>

        <a
          href="<https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app>"
          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
          target="_blank"
          rel="noopener noreferrer"
        >
          <h2 className={`mb-3 text-2xl font-semibold`}>
            Templates{" "}
            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
              -&gt;
            </span>
          </h2>
          <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
            Discover and deploy boilerplate example Next.js&nbsp;projects.
          </p>
        </a>

        <a
          href="<https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app>"
          className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
          target="_blank"
          rel="noopener noreferrer"
        >
          <h2 className={`mb-3 text-2xl font-semibold`}>
            Deploy{" "}
            <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
              -&gt;
            </span>
          </h2>
          <p className={`m-0 max-w-[30ch] text-sm opacity-50 text-balance`}>
            Instantly deploy your Next.js site to a shareable URL with Vercel.
          </p>
        </a>
      </div>
    </main>
  );
}
```
**Note:** Ensure this is the full code of the `pages/index.js` file to avoid missing anything.

Now, reload your app. It should resemble [Dev.to](http://dev.to/)'s centered Notification page. Yaayyyy!!

<figure class="wp-block-image size-large">![Centered Notifications](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-23-at-10.30.02@2x-1024x666.png)</figure>Publish a new article on [Dev.to](http://dev.to/) and observe how the notifications arrive via the centralized Notifications component, even without a notification bell. The Notification unseen counter shows right there.

<figure class="wp-block-image size-large">![Change to light mode](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-23-at-10.33.18@2x-1024x693.png)</figure>Go one step further, make the background light mode &amp; change the Notification Center to light mode.

<figure class="wp-block-image size-large">![Email Community Digest](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-23-at-10.37.22@2x-1024x685.png)</figure>Up Next: Build [Dev.to](http://Dev.top) Email Community Digest
--------------------------------------------------------------

You've learned how to develop an In-App Notification System in under 30 minutes. Over time, I've learned that the best developers use battle-tested tools to build their apps and systems.

Fortunately, there's more. I have additional tips to share with you. 😉

Next, I'll demonstrate how to use Novu to build an Email Community Digest, similar to the excellent digest from [Dev.to](http://dev.to/), which keeps us updated on the top published articles.

<figure class="wp-block-image size-large">![Stay tuned.](https://manage.novu.co/wp-content/uploads/2024/04/CleanShot-2024-04-22-at-15.14.13@2x-1024x648.png)</figure>Stay tuned for the next part of this article!

A reminder to check out the [completed code for this article](https://github.com/novuhq/novu-devto) on GitHub. Let me know if you run into any issues at all.


Don't hesitate to ask any questions or request support. You can find me on [Discord](https://bit.ly/3QfOQHp) and [Twitter](https://bit.ly/3JCpHCR). Please feel free to reach out.