WebSockets & Real-Time Apps
Socket.io Client Setup
Socket.io Client Setup
The Socket.io client library allows web browsers and Node.js applications to connect to Socket.io servers. It handles connection management, reconnection logic, and provides an intuitive API for real-time communication.
Installing the Client Library
There are multiple ways to include the Socket.io client in your project:
<!-- Option 1: CDN (easiest for testing) -->
<script src="https://cdn.socket.io/4.6.0/socket.io.min.js"></script>
<!-- Option 2: NPM (recommended for production) -->
npm install socket.io-client
<!-- Option 3: Served by Socket.io server -->
<script src="/socket.io/socket.io.js"></script>
Note: When using a bundler (Vite, Webpack, etc.), always install via npm. The CDN approach is only suitable for quick prototypes and learning.
Basic Client Connection
Here's how to establish a connection from the browser:
<!-- HTML -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket.io Client</title>
</head>
<body>
<h1>Socket.io Client</h1>
<div id="status">Disconnected</div>
<div id="messages"></div>
<script src="https://cdn.socket.io/4.6.0/socket.io.min.js"></script>
<script>
// Connect to server
const socket = io('http://localhost:3000');
// Connection successful
socket.on('connect', () => {
console.log('Connected with ID:', socket.id);
document.getElementById('status').textContent = 'Connected';
});
// Connection failed
socket.on('connect_error', (error) => {
console.error('Connection error:', error);
document.getElementById('status').textContent = 'Error';
});
// Disconnected
socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason);
document.getElementById('status').textContent = 'Disconnected';
});
</script>
</body>
</html>
Using Socket.io Client with Modern JavaScript
In a Vite or React project with npm installation:
// main.js or app.js
import { io } from 'socket.io-client';
// Connect to server
const socket = io('http://localhost:3000', {
autoConnect: true, // Connect automatically (default)
reconnection: true, // Enable reconnection (default)
reconnectionDelay: 1000, // Wait 1s before reconnecting
reconnectionAttempts: 5 // Try 5 times
});
// Connection events
socket.on('connect', () => {
console.log('Connected! Socket ID:', socket.id);
});
socket.on('disconnect', (reason) => {
console.log('Disconnected because:', reason);
if (reason === 'io server disconnect') {
// Server forcefully disconnected, manually reconnect
socket.connect();
}
});
socket.on('connect_error', (error) => {
console.error('Failed to connect:', error.message);
});
Connection Options
The client accepts many options to customize behavior:
const socket = io('http://localhost:3000', {
// Connection options
autoConnect: true, // Connect immediately
reconnection: true, // Enable auto-reconnection
reconnectionDelay: 1000, // Initial delay (ms)
reconnectionDelayMax: 5000, // Maximum delay (ms)
reconnectionAttempts: Infinity, // Number of attempts
// Transport options
transports: ['websocket', 'polling'], // Preferred transports
upgrade: true, // Upgrade from polling to WebSocket
// Authentication
auth: {
token: 'your-auth-token',
userId: '12345'
},
// Query parameters (sent in URL)
query: {
room: 'general',
username: 'John'
},
// Timeout settings
timeout: 20000, // Connection timeout (ms)
// Path (if server uses custom path)
path: '/socket.io/'
});
Tip: Use
auth for sensitive data like tokens (sent in handshake), and query for non-sensitive data like room names (visible in URL).
Emitting Events from Client
Send custom events to the server using emit():
// Simple event with string
socket.emit('greeting', 'Hello Server!');
// Event with object
socket.emit('chatMessage', {
room: 'general',
message: 'Hello everyone!',
timestamp: Date.now()
});
// Event with multiple arguments
socket.emit('userAction', 'click', 'button-1', { x: 100, y: 200 });
// Event with callback (acknowledgement)
socket.emit('saveData', { name: 'John' }, (response) => {
if (response.success) {
console.log('Data saved!');
} else {
console.error('Error:', response.error);
}
});
Listening for Events from Server
Receive events from the server using on():
// Listen for welcome message
socket.on('welcome', (message) => {
console.log('Server says:', message);
alert(message);
});
// Listen for chat messages
socket.on('chatMessage', (data) => {
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML += `
<div class="message">
<strong>${data.id}:</strong> ${data.message}
<span class="time">${new Date(data.timestamp).toLocaleTimeString()}</span>
</div>
`;
});
// Listen for user count updates
socket.on('userCount', (count) => {
document.getElementById('user-count').textContent = count;
});
// Listen for typing indicator
socket.on('userTyping', (data) => {
console.log(`User ${data.userId} is ${data.isTyping ? 'typing' : 'stopped typing'}`);
});
Handling Disconnection
Properly handle disconnection scenarios:
socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason);
switch(reason) {
case 'io server disconnect':
// Server forcefully disconnected this socket
// Need to manually reconnect
console.log('Server kicked us out. Reconnecting...');
socket.connect();
break;
case 'io client disconnect':
// We manually disconnected
console.log('We disconnected ourselves');
break;
case 'ping timeout':
// Server didn't respond to ping in time
console.log('Connection timeout. Will auto-reconnect');
break;
case 'transport close':
// Connection lost (network issue)
console.log('Connection lost. Will auto-reconnect');
break;
case 'transport error':
// Transport error (e.g., CORS)
console.log('Transport error. Will auto-reconnect');
break;
}
});
// Track reconnection attempts
socket.io.on('reconnect_attempt', (attemptNumber) => {
console.log(`Reconnection attempt ${attemptNumber}`);
});
socket.io.on('reconnect', (attemptNumber) => {
console.log(`Reconnected after ${attemptNumber} attempts`);
});
socket.io.on('reconnect_failed', () => {
console.log('Failed to reconnect after all attempts');
alert('Unable to connect to server. Please refresh the page.');
});
Connection Query Parameters
Pass data during connection handshake:
// Client sends query parameters
const socket = io('http://localhost:3000', {
query: {
username: 'John',
room: 'general',
token: 'abc123'
}
});
// Server receives query parameters
io.on('connection', (socket) => {
console.log('Query:', socket.handshake.query);
// { username: 'John', room: 'general', token: 'abc123' }
const username = socket.handshake.query.username;
const room = socket.handshake.query.room;
// Auto-join room based on query
socket.join(room);
// Send personalized welcome
socket.emit('welcome', `Welcome ${username} to ${room}!`);
});
Warning: Query parameters are visible in the URL and network logs. Don't use them for sensitive authentication tokens. Use the
auth option instead.
Manual Connection Control
Connect and disconnect programmatically:
// Create socket without auto-connecting
const socket = io('http://localhost:3000', {
autoConnect: false
});
// Manually connect when needed
document.getElementById('connect-btn').addEventListener('click', () => {
socket.connect();
});
// Manually disconnect
document.getElementById('disconnect-btn').addEventListener('click', () => {
socket.disconnect();
});
// Check connection status
if (socket.connected) {
console.log('Already connected');
} else {
console.log('Not connected');
}
Complete Client Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Chat Client</title>
<style>
#status { padding: 10px; margin: 10px 0; border-radius: 5px; }
.connected { background: #d4edda; color: #155724; }
.disconnected { background: #f8d7da; color: #721c24; }
#messages { height: 300px; overflow-y: auto; border: 1px solid #ccc; padding: 10px; }
.message { margin: 5px 0; padding: 5px; background: #f0f0f0; border-radius: 3px; }
</style>
</head>
<body>
<h1>Chat Application</h1>
<div id="status" class="disconnected">Connecting...</div>
<div>Users online: <span id="user-count">0</span></div>
<div id="messages"></div>
<input type="text" id="message-input" placeholder="Type a message...">
<button id="send-btn">Send</button>
<script src="https://cdn.socket.io/4.6.0/socket.io.min.js"></script>
<script>
const socket = io('http://localhost:3000');
const statusDiv = document.getElementById('status');
const messagesDiv = document.getElementById('messages');
const messageInput = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');
// Connection status
socket.on('connect', () => {
statusDiv.textContent = `Connected (${socket.id})`;
statusDiv.className = 'connected';
});
socket.on('disconnect', () => {
statusDiv.textContent = 'Disconnected';
statusDiv.className = 'disconnected';
});
// User count updates
socket.on('userCount', (count) => {
document.getElementById('user-count').textContent = count;
});
// Receive messages
socket.on('message', (data) => {
messagesDiv.innerHTML += `
<div class="message">
<strong>${data.id}:</strong> ${data.message}
</div>
`;
messagesDiv.scrollTop = messagesDiv.scrollHeight;
});
// Send message
sendBtn.addEventListener('click', () => {
const message = messageInput.value.trim();
if (message) {
socket.emit('message', message);
messageInput.value = '';
}
});
// Send on Enter key
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendBtn.click();
}
});
</script>
</body>
</html>
Exercise: Create a Socket.io client that:
- Connects to your server with a custom username passed via query parameters
- Displays connection status with visual indicators (green/red)
- Shows the number of connected users in real-time
- Sends chat messages to the server
- Receives and displays messages from other users
- Handles reconnection gracefully with user feedback
- Includes a manual disconnect button