Websocket Dashboard
title: "WebSocket Real-Time Dashboard" description: "Build a real-time analytics dashboard with WebSocket for live data visualization, streaming metrics, and interactive charts." weight: 27 date: 2026-06-28 lastmod: 2026-06-28 tags: ["apis", "websocket"]
Real-time dashboards push live data to users without page refreshes. WebSocket enables streaming metrics, live charts, and instant updates for monitoring systems, analytics platforms, and operational dashboards.
## What You'll Learn
- Streaming metrics over WebSocket
- Real-time chart updates
- Server-side metric aggregation
- Dashboard data filtering
- Performance optimization for frequent updates
## Why It Matters
Monitoring and analytics require up-to-the-second data. WebSocket dashboards provide instant visibility into system health, business metrics, and operational status.
## Real-World Use
A DevOps monitoring platform streams server metrics (CPU, memory, disk, network) via WebSocket to a real-time dashboard. Operations engineers see infrastructure changes within milliseconds, enabling rapid incident response.
## Flow Chart
```mermaid
flowchart LR
A[Metrics Sources] --> B[Metric Aggregator]
B --> C[WebSocket Server]
C --> D[Dashboard Client]
D --> E[CPU Chart]
D --> F[Memory Gauge]
D --> G[Network Graph]
D --> H[Alert Panel]
Code Examples
Example 1: Server-Side Metric Streaming
const WebSocket = require('ws');
const os = require('os');
const server = new WebSocket.Server({ port: 8080 });
const clients = new Set();
server.on('connection', (ws) => {
clients.add(ws);
console.log('Dashboard client connected. Total:', clients.size);
ws.on('close', () => {
clients.delete(ws);
console.log('Dashboard client disconnected. Total:', clients.size);
});
});
// Collect and stream metrics every second
setInterval(() => {
const metrics = {
type: 'metrics',
timestamp: Date.now(),
cpu: {
loadAverage: os.loadavg(),
cpus: os.cpus().length,
},
memory: {
total: os.totalmem(),
free: os.freemem(),
used: os.totalmem() - os.freemem(),
usagePercent: ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(1),
},
uptime: os.uptime(),
network: getNetworkStats(),
processes: process.memoryUsage(),
};
const data = JSON.stringify(metrics);
clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
}, 1000);
function getNetworkStats() {
const interfaces = os.networkInterfaces();
const stats = {};
for (const [name, addrs] of Object.entries(interfaces)) {
if (addrs) {
stats[name] = addrs.filter(a => a.family === 'IPv4').map(a => a.address);
}
}
return stats;
}
Expected output: Server streams system metrics every second to all connected dashboard clients.
Example 2: Client-Side Chart Updates
class MetricsDashboard {
constructor(wsUrl) {
this.charts = {};
this.historySize = 60; // 60 data points (1 minute at 1/sec)
this.metricHistory = {
cpu: [],
memory: [],
timestamps: [],
};
this.connect(wsUrl);
this.initCharts();
}
connect(url) {
this.ws = new WebSocket(url);
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'metrics') {
this.updateDashboard(data);
}
};
this.ws.onclose = () => {
setTimeout(() => this.connect(url), 2000);
};
}
initCharts() {
const ctx = document.getElementById('cpu-chart').getContext('2d');
this.charts.cpu = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'CPU Load Average (1m)',
data: [],
borderColor: 'rgb(75, 192, 192)',
tension: 0.1,
}],
},
options: {
animation: false,
scales: {
x: { display: true, max: this.historySize },
y: { min: 0, max: 100 },
},
},
});
// Memory gauge chart
const memCtx = document.getElementById('memory-chart').getContext('2d');
this.charts.memory = new Chart(memCtx, {
type: 'doughnut',
data: {
labels: ['Used', 'Free'],
datasets: [{
data: [0, 100],
backgroundColor: ['rgb(255, 99, 132)', 'rgb(75, 192, 192)'],
}],
},
options: {
animation: false,
plugins: {
tooltip: {
callbacks: {
label: (context) => {
return `${context.label}: ${context.parsed.toFixed(1)}%`;
},
},
},
},
},
});
}
updateDashboard(metrics) {
// Update CPU chart
const cpuLoad = (metrics.cpu.loadAverage[0] / metrics.cpu.cpus) * 100;
this.metricHistory.cpu.push(cpuLoad);
this.metricHistory.timestamps.push(
new Date(metrics.timestamp).toLocaleTimeString()
);
if (this.metricHistory.cpu.length > this.historySize) {
this.metricHistory.cpu.shift();
this.metricHistory.timestamps.shift();
}
this.charts.cpu.data.labels = this.metricHistory.timestamps;
this.charts.cpu.data.datasets[0].data = this.metricHistory.cpu;
this.charts.cpu.update('none');
// Update memory gauge
this.charts.memory.data.datasets[0].data = [
metrics.memory.usagePercent,
100 - metrics.memory.usagePercent,
];
this.charts.memory.update('none');
// Update metric displays
document.getElementById('cpu-value').textContent =
`${cpuLoad.toFixed(1)}%`;
document.getElementById('memory-value').textContent =
`${metrics.memory.usagePercent}%`;
document.getElementById('uptime').textContent =
formatUptime(metrics.uptime);
document.getElementById('clients').textContent =
metrics.clients || 'N/A';
}
}
function formatUptime(seconds) {
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const mins = Math.floor((seconds % 3600) / 60);
return `${days}d ${hours}h ${mins}m`;
}
// Initialize dashboard
const dashboard = new MetricsDashboard('wss://metrics.example.com/ws');
Expected output: Real-time dashboard updates CPU line chart, memory doughnut gauge, and metric displays every second.
Example 3: Filtered Metric Subscriptions
// Server with subscription filters
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });
server.on('connection', (ws) => {
ws.filters = {
metrics: ['cpu', 'memory', 'disk'],
interval: 1000,
aggregation: 'raw',
};
ws.on('message', (data) => {
const message = JSON.parse(data);
switch (message.type) {
case 'subscribe':
ws.filters.metrics = message.metrics || ws.filters.metrics;
ws.filters.interval = message.interval || ws.filters.interval;
ws.filters.aggregation = message.aggregation || ws.filters.aggregation;
ws.send(JSON.stringify({
type: 'subscribed',
metrics: ws.filters.metrics,
interval: ws.filters.interval,
}));
break;
}
});
});
// Per-client metric streaming
setInterval(() => {
const allMetrics = collectAllMetrics();
server.clients.forEach((client) => {
if (client.readyState !== WebSocket.OPEN) return;
const filteredMetrics = {};
client.filters.metrics.forEach((metric) => {
if (allMetrics[metric]) {
filteredMetrics[metric] = allMetrics[metric];
}
});
client.send(JSON.stringify({
type: 'metrics',
timestamp: Date.now(),
...filteredMetrics,
}));
});
}, 100);
Expected output: Dashboard allows users to subscribe to specific metrics, and the server sends only the requested data.
Common Mistakes
| Mistake | Explanation |
|---|---|
| Sending too much data too frequently | High-frequency updates overwhelm clients; use throttling and aggregation |
| Not using animation: false in charts | Animations cause performance issues with rapid updates; disable for streaming data |
| Forgetting to clean up old data points | Memory grows indefinitely if old data is not discarded from chart datasets |
| Sending full metric snapshots every time | Use delta updates for large datasets to reduce bandwidth |
| Not handling client backpressure | Slow clients can cause server memory growth; implement client-side throttling |
Practice Questions
- How do you optimize real-time charts for frequent updates?
- How do you implement metric subscription filtering?
- What is the difference between push and pull metric collection?
- How do you handle backpressure from slow dashboard clients?
- How do you aggregate metrics for different time windows?
Challenge
Build a real-time application performance monitoring (APM) dashboard that streams request latency, error rates, and throughput from a WebSocket server. Include charts for p50/p95/p99 latency, a heat map of error rates, and live request log.
FAQ
Mini Project
Build a full-stack real-time monitoring dashboard for a web application. Include server metrics (CPU, memory), application metrics (request rate, response time, error rate), business metrics (active users, signups), and alerting when metrics exceed thresholds. Use WebSocket for all live updates.
What's Next
Learn WebSocket with Spring Boot
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro