DEV Community

Cover image for Sending real-time notifications with Socket.io in Node.js
Nevo David for novu

Posted on • Originally published at novu.co

Sending real-time notifications with Socket.io in Node.js

How do websites work?

  • A user provides a URL to the web browser.
  • The browser sends a request to the web server, asking for resources related to the URL.
  • The server receives the request and sends an HTTP response containing the related files to the web browser.
  • The browser displays the response as web pages to the user.

This type of communication is an HTTP connection, suitable for applications where data doesn't change frequently.

Have you ever used a forex trading app or visited a sports betting website? You will notice that the data changes almost every minute; these changes are possible with the help of WebSockets.

WebSockets create a connection between a client and a server, allowing them to send data both ways; client-server and server-client. Compared to HTTP, WebSockets provide a lasting bi-directional client-server connection, making it possible for data to change in real-time without refreshing the page.

Novu

If you are looking to implement in-app notifications (kind of like Facebook / Instagram / Upwork etc..), Check out Novu, we bring you the whole solution without dealing with websockets / scaling / databases / servers. Come and star us ⭐️🤩
https://github.com/novuhq/novu

Image description

And we are back!

Node.js has a built-in WebSocket module, but this module doesn't provide the functionalities required to build complex real-time applications; this is why Socket.io exists.

Socket.io is a popular JavaScript library that allows us to create real-time, bi-directional communication between clients and a Node.js server. It is a highly performant and reliable library optimized to process a large volume of data messages with minimal delay. It follows the WebSocket protocol and provides better functionalities, such as fallback to HTTP long-polling or automatic reconnection, which enables us to build efficient chat and real-time web applications.

In this article, you'll learn how to send notifications between web clients and a Node.js server using Socket.io. Before we start coding this project, let's see how Socket.io works.

This tutorial assumes that you have a basic knowledge of building web applications with Express.js and Node.js.

How does the Socket.io library work?

Real-time Node.js applications such as forex trading, sports betting websites, chat applications, and many others use Socket.io. In this section, you'll learn how Socket.io transfer messages between the client and the server in a web application.

The Socket.io library has two parts - the client and the server API. The client API enables users to connect to the server via WebSocket, and the server API initiates a Socket.io connection on the backend server.

To connect Socket.io to the web client, you'll need to download the client JavaScript bundle via CDN or NPM.

For HTML clients, add this code within the head tag.

<script src="https://cdn.socket.io/4.5.0/socket.io.min.js" integrity="sha384-7EyYLQZgWBi67fBtVxw60/OWl1kjsfrPFcaU0pp0nAh+i8FD068QogUvg85Ewy1k" crossorigin="anonymous"></script>
Enter fullscreen mode Exit fullscreen mode

The code snippet above downloads Socket.io via CDN and exposes a client bundle at /socket.io/socket.io.js to the client. We can then access Socket.io by adding the code below to the bottom of our HTML body tag.

<script src="/socket.io/socket.io.js"></script>
<script>
    const socket = io();
</script>
Enter fullscreen mode Exit fullscreen mode

For React.js, Next.js, and other JavaScript libraries or frameworks, you can download the Socket.io client API via NPM.

npm install socket. io-client
Enter fullscreen mode Exit fullscreen mode

For the backend server installation, you need to have at least Node.js v10 installed on your computer before you can install the Server API via NPM.

npm install socket.io
Enter fullscreen mode Exit fullscreen mode

With this library, you can create a Socket.io connection, connect web clients to the backend server, and start sending messages between the client and the server.
However, this is just a simple explanation of how Socket.io works. In this article, I will walk you through adding the Socket.io library to the client and the server by building a notification system.

Setting up Express.js on a Node.js server

Here, I will guide you through setting up Express.js on a Node.js server. Express.js is a fast, minimalist framework that provides several features for building Node.js web applications. It enables us to create the web client for Node.js applications.

Create a folder that will contain our app. Then, create a package.json file by running the code below.

mkdir <folder-name>
cd <folder-name>
npm init -y
Enter fullscreen mode Exit fullscreen mode

Create an index.js file - the entry point to the web application.

touch index.js
Enter fullscreen mode Exit fullscreen mode

Install Express.js, Nodemon, and Socket.io. Nodemon is a Node.js tool that automatically restarts the server after detecting file changes.

npm install express nodemon socket.io
Enter fullscreen mode Exit fullscreen mode

Configure Nodemon by adding the start command to the list of the scripts in the package.json file. The code snippet below starts the server using Nodemon.

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon index.js" //npm start - starts the server with Nodemon
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.1",
    "nodemon": "^2.0.19",
    "socket.io": "^4.5.1"
  }
}
Enter fullscreen mode Exit fullscreen mode

Update the index.js file to render an HTML page. Copy the code below into the index.js file.

const express = require('express');
const app = express();
const path = require('path');
const PORT = process.env.PORT || 8080;

//enables us to host static CSS & JS files.
//The public folder contains the CSS & JS files.
app.use(express.static('public'));

//Route to the homepage of the application
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '/index.html'));
});

//Listens for changes in the web application
app.listen(PORT, () => {
  console.log(`App listening at ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Create an index.html file that displays a message bar and button.

<!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" />
    <title>Socket IO Chat App</title>

    <!-- Link to CSS file-->
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div id="message-bar">
      <p id="notification"></p>
    </div>
    <form class="container">
      <h2>Send Messages with Socket.io</h2>
      <textarea
        rows="5"
        width="100%"
        name="message"
        id="message"
        placeholder="Enter your message..."
      ></textarea>
      <button>SEND MESSAGE</button>
    </form>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Create a folder named public. This folder will contain the CSS file for the HTML page.

mkdir public
cd public
touch index.css
Enter fullscreen mode Exit fullscreen mode

Copy the code below into the index.css file

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-family: 'Poppins', sans-serif;
}
#message-bar {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#notification {
  color: #fff;
}
.container {
  height: 80vh;
  width: 100%;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
h2 {
  text-align: center;
  margin-bottom: 30px;
}
textarea {
  font-size: 16px;
  margin-bottom: 30px;
  padding: 15px;
  outline: none;
}
button {
  width: 200px;
  padding: 15px;
  cursor: pointer;
  background-color: #2c3639;
  outline: none;
  border: none;
  color: #dcd7c9;
  font-size: 16px;
}
button:hover {
  background-color: #3f4e4f;
}
Enter fullscreen mode Exit fullscreen mode

Run the Node.js server. You can view the index.html file at https://localhost:8080 in your web browser.

npm start
Enter fullscreen mode Exit fullscreen mode

Configuring Socket.io on the client

In this section, I will walk you through connecting the web client to Socket.io.

Update the index.html file to connect Socket.io JavaScript bundles via CDN. Add the first snippet within the head tag and the other at the bottom of the body tag.

<head>
    <!-- This links to Socket.io client JavaScript bundle via CDN. -->
    <script
      src="https://cdn.socket.io/4.5.0/socket.io.min.js"
      integrity="sha384-7EyYLQZgWBi67fBtVxw60/OWl1kjsfrPFcaU0pp0nAh+i8FD068QogUvg85Ewy1k"
      crossorigin="anonymous"
    ></script>
  </head>
Enter fullscreen mode Exit fullscreen mode
<body>
......
The page content
.....
    <!-- Link to the JavaScript file-->
    <script src="./script.js" type="module"></script>

    <!-- This access the client JavaScript bundle provided via its CDN -->
    <script src="/socket.io/socket.io.js"></script>
  </body>
Enter fullscreen mode Exit fullscreen mode

Create a JavaScript file - script.js that enables us to access the user's inputs and the HTML elements on the webpage via JavaScript DOM.

cd public
touch script.js
Enter fullscreen mode Exit fullscreen mode

Access the HTML elements via the Document Object Model provided by JavaScript.

//In script.js

const notify = document.querySelector('#notification');
const message = document.querySelector('#message');
const button = document.querySelector('button');
const messageBar = document.querySelector('#message-bar');
Enter fullscreen mode Exit fullscreen mode

Create an event listener that logs the message provided by the user to the console whenever the form is submitted.

function printMessage(e) {
  e.preventDefault();
  console.log(message.value);
}
button.addEventListener('click', printMessage);
Enter fullscreen mode Exit fullscreen mode

Next, add Socket.io to the client JavaScript file - script.js.

const socket = io();

socket.on('response', (data) => {
  notify.textContent = data;
  messageBar.style.backgroundColor = '#3F4E4F';
  messageBar.style.height = '20vh';
});
Enter fullscreen mode Exit fullscreen mode

The code snippet above listens for messages labeled response from the server. If there is a message, it displays the message on the webpage.

Edit the printMessage function to send messages from the client to the Node.js server. The code snippet below sends messages to the server when a user clicks the submit button.

function printMessage(e) {
  e.preventDefault();
  socket.emit('message', message.value);
}
Enter fullscreen mode Exit fullscreen mode

Adding Socket.io to the Node.js server

In this section, you will learn how to configure Socket.io on a Node.js server, and you can receive and send messages from the client via Socket.io.

Update the index.js by importing Socket.io and the HTTP module from Node.js. The HTTP module creates an HTTP server that allows Node.js to transfer data via the network.

const express = require('express');
const app = express();
const path = require('path');
const PORT = process.env.PORT || 8080;

//New imports
const http = require('http').Server(app);
//Pass the Express app into the HTTP module.
const socketIO = require('socket.io')(http);

app.use(express.static('public'));

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '/index.html'));
});

//Listen for changes on the HTTP server not the Express server
http.listen(PORT, () => {
  console.log(`App listening at ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

From the code snippet above, the HTTP server accepts the Express app as a parameter, and we listen for changes on the HTTP server instead of Express.

Before the app.get() block, create a connection to the web client with Socket.io.

socketIO.on('connection', (socket) => {
  console.log(`⚡: ${socket.id} user just connected`);
  socket.on('disconnect', () => {
    console.log('A user disconnected');
  });
});
Enter fullscreen mode Exit fullscreen mode

The socket.io("connection") function above creates a connection with the web client. Socket.io creates a unique ID for each client and logs the ID to the console whenever a user visits the web page. When you refresh or close the web page, the socket fires the disconnect event showing that a user has disconnected from the socket.

Next, update the function to send and receive data from the client.

socketIO.on('connection', (socket) => {
  console.log(`⚡: ${socket.id} user just connected`);
  socket.on('disconnect', () => {
    console.log('A user disconnected');
  });

  socket.on('message', (data) => {
        //sends the data to everyone except you.
    socket.broadcast.emit('response', data); 

        //sends the data to everyone connected to the server
    // socket.emit("response", data)
  });
});
Enter fullscreen mode Exit fullscreen mode

*socket.broadcast.emit() - sends the data to everyone except you, and the socket.emit() - sends the data to everyone connected to the server, including you*

Congratulations!🎊 You've just completed the project for this tutorial.

Conclusion

In this tutorial, you've learned

  • What WebSockets are
  • Why and when do we need Socket.io?
  • How to connect Socket.io to a web client and a Node.js server, and
  • how to send messages between an HTML client and a Node.js server.

Socket.io supports private messaging and group chats, identifying users by nicknames, showing whether a user is online, and knowing if a user is typing.

With these features provided by Socket.io, you can build complex real-time applications useful in various industries such as aviation, gaming, media, and finance.

Socket.io is an excellent choice for real-time communication between a client and a Node.js server. Some other libraries like Twilio, Firebase, Supabase, and many others support real-time communication. Feel free to check them out.

Thank you for reading,
You can find the full source-code here:
https://github.com/novuhq/blog/tree/main/sending%20emails%20via%20SocketIO

Top comments (11)

Collapse
 
nevodavid profile image
Nevo David

Happy to hear about a project you made involving websockets

Collapse
 
maurerkrisztian profile image
Krisztián Maurer

I made a Youtube downloader with real time download progress view: my blog post

Collapse
 
nevodavid profile image
Nevo David

Looks good! Maybe you can also do a managed version with public api :)

Collapse
 
nevodavid profile image
Nevo David

Awesome! Just had a look at your project.
You have put the websockets area in the www, happy to hear the motivation behind that, why not just a js file?
Funny to look at a 7 years old code and see that not a lot changed today 😇

Collapse
 
andrewbaisden profile image
Andrew Baisden

Love using Socket.io.

Collapse
 
nevodavid profile image
Nevo David

Me too!
Have you built something with socket.io lately?

Collapse
 
nevodavid profile image
Nevo David

I would expect pong 🤣
But that's better!

Collapse
 
nevodavid profile image
Nevo David

Ping?

Collapse
 
nevodavid profile image
Nevo David

How do you use websockets? Do you use Socket.io?

Collapse
 
nevodavid profile image
Nevo David

New Post: Core Team vs. Contributors 🚀
dev.to/novu/core-team-vs-contribut...

Collapse
 
nevodavid profile image
Nevo David

New Post: Create a notifications system using in-app (bell icon) and emails
dev.to/novu/create-a-notifications...