n8n Socket.IO WebSocket: Real-Time Event Integration

I use WebSockets with n8n because HTTP polling wastes resources and introduces latency. Real-time event processing requires persistent connections, and n8n handles them through the right node configuration.

WebSockets keep a continuous connection between your n8n workflow and external services. Unlike HTTP requests that open and close for each operation, WebSockets stay open and push data as it becomes available. This makes them ideal for live dashboards, chat applications, and real-time notification systems.

The n8n WebSocket node establishes connections to real-time services. I configure the URL, authentication, and event handlers in the node settings. Once connected, the node listens for incoming events and routes them to the appropriate workflow logic.

WebSocket Connection Setup

n8n’s WebSocket node creates persistent connections to real-time endpoints. I configure the connection URL, set authentication headers, and define event handlers for incoming messages.

`javascript
// WebSocket connection configuration
const WebSocket = require(‘ws’);
const ws = new WebSocket(‘wss://events.example.com/stream’);

ws.on(‘open’, () => {
console.log(‘WebSocket connected’);
// Authenticate after connection
ws.send(JSON.stringify({ type: ‘auth’, token: process.env.WS_TOKEN }));
});

ws.on(‘message’, (data) => {
const parsed = JSON.parse(data);
// Route to appropriate handler based on event type
if (parsed.type === ‘order.created’) {
handleOrderCreated(parsed.payload);
} else if (parsed.type === ‘user.signup’) {
handleUserSignup(parsed.payload);
}
});
`

The WebSocket connection stays alive as long as the n8n workflow runs. For long-running workflows, I use the Code node to maintain the connection and route incoming events to sub-workflows. The connection persists across workflow re-executions.

Authentication typically happens after the connection opens. I send an auth message with a bearer token or API key. The server responds with a confirmation or rejection. Rejections trigger a reconnection with refreshed credentials from the n8n credential manager.

For production deployments, I use SSL/TLS connections (wss://). Unencrypted WebSocket connections (ws://) expose data to interception. SSL termination happens at the nginx reverse proxy level. The n8n Nginx reverse proxy guide covers SSL configuration in detail.

Socket.IO Events in n8n Workflows

Socket.IO extends WebSocket with room management, acknowledgments, and automatic reconnection. I use Socket.IO for event-driven workflows that need reliable message delivery.

`javascript
const io = require(‘socket.io-client’);
const socket = io(‘https://server.example.com’, {
transports: [‘websocket’],
auth: { token: process.env.SOCKET_TOKEN }
});

socket.on(‘connect’, () => {
console.log(‘Connected with ID:’, socket.id);
socket.emit(‘join’, ‘workflow-room’);
});

socket.on(‘data-update’, (payload) => {
// Process incoming data
return [{ json: payload }];
});

socket.on(‘disconnect’, (reason) => {
console.log(‘Disconnected:’, reason);
});
`

Rooms group related events. I join specific rooms based on the workflow’s purpose. An order processing workflow joins the orders room. A notification workflow joins the alerts room. This separation prevents event cross-contamination between different workflow instances.

Acknowledgments ensure message delivery. When I emit an event, the server sends back an ack. If no ack arrives within the timeout period, I retry the emission. This pattern guarantees at-least-once delivery for critical events.

`javascript
// Emit with acknowledgment
socket.emit(‘process-data’, eventData, (ack) => {
if (ack.success) {
console.log(‘Data processed successfully’);
} else {
console.error(‘Processing failed:’, ack.error);
// Retry or route to error handler
}
});
`

Event filtering reduces unnecessary processing. I use Socket.IO middleware to filter events before they reach the workflow. This prevents the workflow from handling events it doesn’t need.

Reconnection and Heartbeat Handling

Network interruptions break WebSocket connections. I implement automatic reconnection with exponential backoff to recover gracefully without manual intervention.

`javascript
let reconnectAttempts = 0;
const MAX_RETRIES = 5;
const BASE_DELAY = 1000;

function connectWithRetry() {
const ws = new WebSocket(url);

ws.on(‘close’, () => {
if (reconnectAttempts < MAX_RETRIES) { const delay = Math.min(BASE_DELAY * Math.pow(2, reconnectAttempts), 30000); reconnectAttempts++; console.log(Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${MAX_RETRIES}));
setTimeout(connectWithRetry, delay);
} else {
console.error(‘Max reconnection attempts reached’);
// Trigger error workflow
}
});

ws.on(‘error’, (err) => {
console.error(‘WebSocket error:’, err.message);
});
}
`

Heartbeat messages keep connections alive through firewalls and proxies. I send a ping every 30 seconds and expect a pong response. Missing pongs indicate a dead connection that needs reconnection. This heartbeat mechanism prevents silent connection failures.

`javascript
// Heartbeat implementation
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.ping();
} else {
console.warn(‘Connection not open, attempting reconnect…’);
connectWithRetry();
}
}, 30000);
`

The n8n Error Trigger node catches WebSocket disconnections and sends alerts. This gives me visibility into connection stability and helps identify network issues before they affect workflows. I monitor reconnection frequency as a health metric.

Data Transformation and Routing

Incoming WebSocket data often needs transformation before it reaches downstream systems. I use n8n’s Code node to parse, validate, and route events.

`javascript
// Parse and validate incoming event
const event = JSON.parse($json.payload);

// Validate required fields
if (!event.type || !event.timestamp || !event.data) {
throw new Error(‘Invalid event format: missing required fields’);
}

// Transform event data
const transformed = {
id: event.id || generateId(),
type: event.type,
timestamp: new Date(event.timestamp).toISOString(),
payload: event.data,
source: ‘websocket’
};

// Route based on event type
if (event.type === ‘order.created’) {
return [{ json: transformed, flow: { name: ‘Order Processing’ } }];
} else if (event.type === ‘payment.received’) {
return [{ json: transformed, flow: { name: ‘Payment Processing’ } }];
} else {
return [{ json: transformed, flow: { name: ‘General Handler’ } }];
}
`

The Merge node combines data from multiple WebSocket streams. I use it when workflows need to correlate events from different sources. For example, correlating order creation events with payment received events to calculate fulfillment times.

Batching incoming events reduces downstream API calls. Instead of calling an external API for each event, I collect events for a few seconds and send them in a single batch. This approach respects rate limits and reduces network overhead.

`javascript
// Event batching
let batch = [];
const BATCH_TIMEOUT = 5000; // 5 seconds

function addEvent(event) {
batch.push(event);
if (batch.length >= 10) {
sendBatch(batch);
batch = [];
}
}

setTimeout(() => {
if (batch.length > 0) {
sendBatch(batch);
batch = [];
}
}, BATCH_TIMEOUT);
`

Action Card: Quick Setup

`bash

Socket.IO connection in n8n Code node

const io = require(‘socket.io-client’);
const socket = io(‘wss://your-server.com’, {
auth: { token: $(‘Credentials’).item.json.token }
});

socket.on(‘event’, (data) => {
return [{ json: data }];
});

WebSocket with heartbeat

setInterval(() => socket.ping(), 30000);
`

Connecting to Your Setup

The n8n Docker Deployment guide covers container setup for WebSocket-dependent workflows. The n8n execution engine explains how n8n processes real-time events. The n8n nodes reference lists all available integration nodes for real-time connectivity.

References

  • Socket.IO Client Documentation
  • WebSocket MDN Documentation
  • n8n WebSocket Node
  • n8n HTTP Request Node
  • Leave a Reply

    Your email address will not be published. Required fields are marked *