Episode 4 of 5

Emitting Messages

Learn how to emit custom events with data between the server and client — the core of real-time Socket.io communication.

Emitting Messages

Now that the server and client are connected, it is time to send data between them. In Socket.io, communication happens through custom events. You "emit" an event with a name and data, and the other side "listens" for that event. This is the core of Socket.io communication.

The emit/on Pattern

// Sending side
socket.emit('event-name', data);

// Receiving side
socket.on('event-name', (data) => {
    // Handle the received data
});

It works the same way in both directions — the server can emit to the client, and the client can emit to the server. The event name is a string you choose, and the data can be any JSON-serializable value (strings, numbers, objects, arrays).

Client → Server: Sending a Chat Message

Update the client script in public/index.html:

<script src="/socket.io/socket.io.js"></script>
<script>
    const socket = io();
    const messageInput = document.getElementById('message-input');
    const sendBtn = document.getElementById('send-btn');
    const chatMessages = document.getElementById('chat-messages');

    // Send message when button is clicked
    sendBtn.addEventListener('click', () => {
        const message = messageInput.value.trim();
        if (message) {
            socket.emit('chat message', message);
            addMessage('You: ' + message);
            messageInput.value = '';
        }
    });

    // Send message on Enter key
    messageInput.addEventListener('keypress', (e) => {
        if (e.key === 'Enter') {
            sendBtn.click();
        }
    });

    function addMessage(text) {
        const div = document.createElement('div');
        div.textContent = text;
        div.style.padding = '8px 0';
        div.style.borderBottom = '1px solid rgba(255,255,255,0.05)';
        chatMessages.appendChild(div);
        chatMessages.scrollTop = chatMessages.scrollHeight;
    }
</script>

When the user clicks Send or presses Enter, the client emits a 'chat message' event with the input text as data. The message is also displayed locally using the addMessage function.

Receiving on the Server

Update the server code in index.js:

io.on('connection', (socket) => {
    console.log('A user connected:', socket.id);

    // Listen for 'chat message' events from this client
    socket.on('chat message', (msg) => {
        console.log(`Message from ${socket.id}: ${msg}`);
    });

    socket.on('disconnect', () => {
        console.log('User disconnected:', socket.id);
    });
});

Inside the connection handler, we listen for the 'chat message' event on the individual socket. When a client sends a message, the server logs it. The event name 'chat message' must match exactly between emit and on.

Server → Client: Sending Data Back

// Server sends a welcome message when client connects
io.on('connection', (socket) => {
    console.log('A user connected:', socket.id);

    // Send a welcome message to the connected client
    socket.emit('welcome', {
        message: 'Welcome to the chat!',
        id: socket.id
    });

    socket.on('chat message', (msg) => {
        console.log(`Message from ${socket.id}: ${msg}`);
    });

    socket.on('disconnect', () => {
        console.log('User disconnected:', socket.id);
    });
});

Here the server emits a 'welcome' event to the client immediately after connection. Notice we use socket.emit() — this sends the event only to that specific client, not to everyone.

Receiving on the Client

// Listen for the welcome event from the server
socket.on('welcome', (data) => {
    addMessage(data.message + ' (ID: ' + data.id + ')');
});

The client listens for the 'welcome' event and displays the server's message. The data parameter contains the object the server sent — in this case with message and id properties.

Sending Different Data Types

// String
socket.emit('message', 'Hello!');

// Number
socket.emit('score', 42);

// Object
socket.emit('user-data', { 
    name: 'Alice', 
    age: 25, 
    online: true 
});

// Array
socket.emit('scores', [100, 200, 300]);

// Multiple arguments
socket.emit('move', 'player1', { x: 10, y: 20 });

Socket.io automatically serializes and deserializes JSON data. You can send strings, numbers, booleans, objects, arrays, or even multiple arguments in a single emit call.

Event Naming Best Practices

✅ Good❌ AvoidWhy
'chat message''msg'Descriptive names are easier to debug
'user-joined''connect'Don't use reserved Socket.io events
'typing-start''a'Single letters are impossible to understand
'score-update''update'Be specific about what is being updated

Reserved Event Names

Socket.io has several built-in events that you must not use as custom event names:

EventPurpose
connectClient successfully connected
disconnectClient disconnected
connect_errorConnection failed
errorAn error occurred

The Emit Flow

CLIENT                          SERVER
  │                                │
  │──── emit('chat message') ────→ │  socket.on('chat message')
  │                                │
  │←── emit('welcome') ───────────│  socket.emit('welcome')
  │                                │
  │  socket.on('welcome')         │

Key Takeaways

  • socket.emit(eventName, data) sends a custom event with data to the other side
  • socket.on(eventName, callback) listens for incoming events
  • Event names must match exactly between emit and on — they are case-sensitive strings
  • Data can be any JSON-serializable type: strings, numbers, objects, arrays
  • socket.emit() on the server sends only to that specific client, not to all clients
  • Avoid using reserved event names like connect, disconnect, and error
  • Use descriptive event names for easier debugging and maintenance