Creating Real-Time Chat and Video Calling Applications with WebSockets, WebRTC, and Angular

Real-time communication is an essential feature for modern web applications, enabling instant messaging, notifications, and collaborative tools. In this guide, we’ll explore how to build a real-time chat and video calling application using WebSockets, WebRTC, Spring Boot as a signaling server, and Angular for the front-end.
Understanding WebSockets
WebSockets provide a full-duplex communication channel over a single TCP connection, making them ideal for real-time interactions. Unlike traditional HTTP, which requires a request-response cycle, WebSockets allow the server and client to exchange data freely without repeated requests. This is particularly useful for applications like messaging and notifications, where real-time performance is critical.
Why Angular and WebSockets?
Angular is a popular front-end framework that provides powerful tools for building dynamic, single-page applications. With features like two-way data binding and RxJS, Angular makes it easy to integrate real-time communication via WebSockets, ensuring a smooth and scalable user experience.
WebSockets allow the application to push messages from the server to the client instantly, ensuring that the chat and video calling experience feels immediate and engaging.
Setting Up Angular with WebSockets
Let’s first set up the chat functionality with WebSockets before moving to the video calling part.
1. Create a New Angular Project
Start by creating a new Angular project using the Angular CLI:
ng new real-time-chat-video cd real-time-chat-video
2. Install WebSocket Dependencies
We’ll use the native JavaScript WebSocket
API to integrate WebSockets into our Angular application.
3. Implement WebSocket Service for Chat
Create a service that will handle communication between the client and the server. For simplicity, let’s call it websocket.service.ts
:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class WebSocketService { private socket: WebSocket; constructor() { // Connect to WebSocket server this.socket = new WebSocket('ws://localhost:8080/chat'); } sendMessage(message: string) { if (this.socket.readyState === WebSocket.OPEN) { this.socket.send(message); } } receiveMessages() { return new Observable<string>((observer) => { this.socket.onmessage = (event) => { observer.next(event.data); }; this.socket.onerror = (error) => { observer.error(error); }; }); } closeConnection() { if (this.socket) { this.socket.close(); } } }
4. Creating the Chat Component
Create the chat.component.ts
component for chat functionality:
import { Component, OnInit, OnDestroy } from '@angular/core'; import { WebSocketService } from './websocket.service'; @Component({ selector: 'app-chat', templateUrl: './chat.component.html', styleUrls: ['./chat.component.css'] }) export class ChatComponent implements OnInit, OnDestroy { message: string = ''; messages: string[] = []; private socketSubscription: any; constructor(private webSocketService: WebSocketService) {} ngOnInit(): void { this.socketSubscription = this.webSocketService.receiveMessages().subscribe((message: string) => { this.messages.push(message); }); } ngOnDestroy(): void { if (this.socketSubscription) { this.socketSubscription.unsubscribe(); } this.webSocketService.closeConnection(); } sendMessage(): void { if (this.message.trim()) { this.webSocketService.sendMessage(this.message); this.messages.push(this.message); this.message = ''; } } }
5. Setting Up the HTML Template for Chat
In chat.component.html
, set up the basic structure of the chat interface:
<div class="chat-container"> <h1>Real-Time Chat</h1> <div class="messages"> <div *ngFor="let msg of messages">{{ msg }}</div> </div> <input [(ngModel)]="message" placeholder="Type a message" /> <button (click)="sendMessage()">Send</button> </div>
6. Run the Angular Application
To start the Angular development server:
ng serve
Your real-time chat application should now be running on http://localhost:4200/
.
Implementing WebRTC for Video Calling
WebRTC (Web Real-Time Communication) enables peer-to-peer video, voice, and data sharing between browser clients. It's a powerful API that works natively in modern browsers without needing additional plugins. To integrate WebRTC into our chat application, we'll set up video calling functionality and use Spring Boot as the signaling server.
1. WebRTC Video Calling – Front-End (Angular)
Setting Up Video Elements
In your chat.component.html
, add video elements for local and remote video streams:
<div class="video-container"> <video #localVideo autoplay muted></video> <video #remoteVideo autoplay></video> </div>
WebRTC Setup in Component
In chat.component.ts
, initialize the WebRTC API:
import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; import { WebSocketService } from './websocket.service'; @Component({ selector: 'app-chat', templateUrl: './chat.component.html', styleUrls: ['./chat.component.css'] }) export class ChatComponent implements OnInit, OnDestroy { @ViewChild('localVideo') localVideo!: ElementRef; @ViewChild('remoteVideo') remoteVideo!: ElementRef; private peerConnection: RTCPeerConnection | undefined; private localStream: MediaStream | undefined; constructor(private webSocketService: WebSocketService) {} ngOnInit(): void { this.initializeWebRTC(); this.webSocketService.receiveMessages().subscribe(message => { // Handle signaling messages (offer/answer/ICE candidates) this.handleSignalingMessage(JSON.parse(message)); }); } ngOnDestroy(): void { if (this.peerConnection) { this.peerConnection.close(); } } initializeWebRTC() { navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => { this.localStream = stream; this.localVideo.nativeElement.srcObject = stream; }); } // Handle signaling messages handleSignalingMessage(message: any) { switch (message.type) { case 'offer': this.handleOffer(message); break; case 'answer': this.handleAnswer(message); break; case 'candidate': this.handleCandidate(message); break; } } // Sending signaling data to server sendSignalingMessage(message: any) { this.webSocketService.sendMessage(JSON.stringify(message)); } // Create and send an offer createOffer() { this.peerConnection = new RTCPeerConnection(); this.localStream?.getTracks().forEach(track => this.peerConnection!.addTrack(track, this.localStream!)); this.peerConnection.onicecandidate = (event) => { if (event.candidate) { this.sendSignalingMessage({ type: 'candidate', candidate: event.candidate }); } }; this.peerConnection.ontrack = (event) => { this.remoteVideo.nativeElement.srcObject = event.streams[0]; }; this.peerConnection.createOffer().then(offer => { return this.peerConnection!.setLocalDescription(offer); }).then(() => { this.sendSignalingMessage({ type: 'offer', offer: this.peerConnection!.localDescription }); }); } // Handle an offer message handleOffer(message: any) { this.peerConnection = new RTCPeerConnection(); this.localStream?.getTracks().forEach(track => this.peerConnection!.addTrack(track, this.localStream!)); this.peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer)); this.peerConnection.createAnswer().then(answer => { return this.peerConnection!.setLocalDescription(answer); }).then(() => { this.sendSignalingMessage({ type: 'answer', answer: this.peerConnection!.localDescription }); }); this.peerConnection.onicecandidate = (event) => { if (event.candidate) { this.sendSignalingMessage({ type: 'candidate', candidate: event.candidate }); } }; this.peerConnection.ontrack = (event) => { this.remoteVideo.nativeElement.srcObject = event.streams[0]; }; } // Handle an answer message handleAnswer(message: any) { this.peerConnection!.setRemoteDescription(new RTCSessionDescription(message.answer)); } // Handle ICE candidates handleCandidate(message: any) { const candidate = new RTCIceCandidate(message.candidate); this.peerConnection!.addIceCandidate(candidate); } }
2. Spring Boot as a Signaling Server
We’ll use Spring Boot as the signaling server for WebRTC. The signaling server is responsible for exchanging messages like offer, answer, and ICE candidates between peers.
Setting Up Spring Boot Project
Use Spring Initializr or your preferred method to create a Spring Boot project with the necessary dependencies: WebSocket
and Spring Web
.
spring init --dependencies=websocket,web data-springboot-signaling-server
Implementing Signaling Server
In your Spring Boot application, create a WebSocket controller to handle signaling messages:
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.stereotype.Controller; @Controller public class WebRTCController { @MessageMapping("/chat") public void handleSignalingMessage(String message) { // Broadcast message to all connected clients messagingTemplate.convertAndSend("/topic/messages", message); } }
Running the Server
Run the Spring Boot application:
mvn spring-boot:run
This will start the WebSocket server that will handle the signaling for WebRTC connections.
Conclusion
By combining WebSockets, WebRTC, Spring Boot, and Angular, you can create powerful real-time communication applications. From text messaging with WebSockets to video calling with WebRTC, this guide provides a hands-on approach to building a robust, interactive platform for your users.
With the included chat and video calling functionality, your application will offer a seamless experience with both audio/video support and messaging—all powered by real-time communication technologies.
Happy coding!
Tags
Related Posts
About the Author

Sagar Subedi
A passionate writer and technologist exploring the intersections of code and creativity.