WebSockets & Real-Time Apps

Socket.io Client Setup

16 min Lesson 7 of 35

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