← Back to Blog

Building Real-Time Apps with WebSockets: Chat, Notifications, and Live Collaboration

 

Written by SnapIT SaaS | October 23, 2025 | 7 min read

 


 

WebSockets enable instant, bidirectional communication between browsers and servers. Learn how to build real-time chat, live notifications, and collaborative editing with WebSocket APIs and AWS infrastructure.

 

Why WebSockets Over HTTP Polling?

Traditional HTTP polling wastes bandwidth and adds latency:

Performance Comparison

Scenario: 1,000 concurrent users, 1 update per minute

HTTP Polling (1s interval):
  Requests: 60,000/minute (1,000 users x 60 polls)
  Data transferred: ~12 MB/min (overhead)
  Server load: High (constant request processing)
  Latency: 0-1000ms (depends on poll timing)

WebSockets:
  Requests: 1,000 connections (persistent)
  Data transferred: ~50 KB/min (only actual updates)
  Server load: Low (idle connections)
  Latency: under 50ms (instant push)

Result: ~98% reduction in server requests

WebSocket Architecture on AWS

1. AWS API Gateway WebSocket API

# Create WebSocket API
aws apigatewayv2 create-api \
  --name "SnapIT-Chat-WebSocket" \
  --protocol-type WEBSOCKET \
  --route-selection-expression '$request.body.action'

# Routes:
# $connect    -> onConnect Lambda (authenticate user)
# $disconnect -> onDisconnect Lambda (cleanup)
# sendMessage -> sendMessage Lambda (broadcast to users)
# $default    -> default Lambda (error handling)

2. Connection Management with DynamoDB

// DynamoDB Table: WebSocketConnections
{
  connectionId: "abc123def456",    // Primary Key
  userId: "user_789",
  roomId: "room_general",
  connectedAt: 1697654400000,
  ttl: 1697740800  // Auto-delete after 24 hours
}

// onConnect Lambda
exports.handler = async (event) => {
  const connectionId = event.requestContext.connectionId
  const userId = event.queryStringParameters.userId
  await dynamodb.put({
    TableName: 'WebSocketConnections',
    Item: { connectionId, userId, connectedAt: Date.now(),
            ttl: Math.floor(Date.now() / 1000) + 86400 }
  }).promise()
  return { statusCode: 200, body: 'Connected' }
}

Building a Real-Time Chat App

Frontend: React WebSocket Client

import { useEffect, useState } from 'react'

const ChatApp = ({ userId, roomId }) => {
  const [ws, setWs] = useState(null)
  const [messages, setMessages] = useState([])
  const [input, setInput] = useState('')

  useEffect(() => {
    const wsUrl = 'wss://your-api-id.execute-api.us-east-1.amazonaws.com/prod'
      + '?userId=' + userId + '&roomId=' + roomId
    const socket = new WebSocket(wsUrl)
    socket.onmessage = (event) => {
      const message = JSON.parse(event.data)
      setMessages(prev => [...prev, message])
    }
    setWs(socket)
    return () => socket.close()
  }, [userId, roomId])

  const sendMessage = () => {
    ws.send(JSON.stringify({
      action: 'sendMessage', roomId, userId,
      message: input, timestamp: Date.now()
    }))
    setInput('')
  }
  // ... render messages and input
}

Backend: Message Broadcasting Lambda

const apiGateway = new AWS.ApiGatewayManagementApi({
  endpoint: process.env.WEBSOCKET_ENDPOINT
})

exports.handler = async (event) => {
  const { roomId, userId, message } = JSON.parse(event.body)

  // Get all connections in room
  const connections = await dynamodb.query({
    TableName: 'WebSocketConnections',
    IndexName: 'roomId-index',
    KeyConditionExpression: 'roomId = :roomId',
    ExpressionAttributeValues: { ':roomId': roomId }
  }).promise()

  // Broadcast message to all room members
  await Promise.all(
    connections.Items.map(conn =>
      apiGateway.postToConnection({
        ConnectionId: conn.connectionId,
        Data: JSON.stringify({ userId, message, timestamp: Date.now() })
      }).promise().catch(err => {
        if (err.statusCode === 410) {
          // Stale connection, remove from DB
          dynamodb.delete({ TableName: 'WebSocketConnections',
            Key: { connectionId: conn.connectionId } }).promise()
        }
      })
    )
  )
  return { statusCode: 200, body: 'Message sent' }
}

Advanced Use Cases

1. Live Notifications

Push alerts to users instantly:

2. Collaborative Editing

Real-time document collaboration like Google Docs using Operational Transformation (OT) for conflict resolution and cursor position broadcasting.

3. Live Dashboards

Real-time metrics for analytics platforms:

Security & Best Practices

1. Authentication

// Validate JWT token in $connect route
const jwt = require('jsonwebtoken')
exports.handler = async (event) => {
  const token = event.queryStringParameters.token
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET)
    await storeConnection(event.requestContext.connectionId, decoded.userId)
    return { statusCode: 200 }
  } catch (error) {
    return { statusCode: 401, body: 'Unauthorized' }
  }
}

2. Rate Limiting

3. Error Handling

Cost Analysis

Scenario: Chat app with 10,000 concurrent users, 1 million messages per day

SnapIT Real-Time Infrastructure

SnapIT products like ChatFly and ForumFly use WebSocket architectures like the one described above. See the full SnapIT product suite for real-time tools built on AWS serverless infrastructure.

Explore SnapIT SaaS Products →

Conclusion

WebSockets transform user experience with instant updates and real-time collaboration. AWS API Gateway + Lambda + DynamoDB provides a scalable, cost-effective infrastructure for chat apps, live notifications, and collaborative tools. With low latency and far fewer server requests than HTTP polling, WebSockets are worth the added complexity for any app that needs real-time features.