Stream SEC Filings in Real-Time Using Node.js
This guide illustrates how to use Node.js and WebSocket for streaming SEC filings in real-time, immediately after their publication on EDGAR. You'll learn to connect to the Stream API and display filing metadata - such as filing ID, CIK of the filer, form type, the acceptance date/time by the EDGAR system, and the filing URL - as soon as a filing is released.
First, install the WebSocket ws package for Node.js by running the following command in your terminal:
npm install wsNext, copy the example code provided below into a new file on your machine, naming it websocket-client.js. Ensure to replace YOUR_API_KEY with the actual API key from your account.
1
const WebSocket = require('ws');
2
3
const API_KEY = 'YOUR_API'; // Replace this with your actual API key
4
const STREAM_API_URL = 'wss://stream.sec-api.io?apiKey=' + API_KEY;
5
6
const ws = new WebSocket(STREAM_API_URL);
7
8
ws.on('open', () => console.log('✅ Connected to:', STREAM_API_URL));
9
ws.on('close', () => console.log('Connection closed'));
10
ws.on('error', (err) => console.log('Error:', err.message));
11
12
ws.on('message', (message) => {
13
const filings = JSON.parse(message.toString());
14
filings.forEach((filing) => {
15
console.log(
16
filing.id,
17
filing.cik,
18
filing.formType,
19
filing.filedAt,
20
filing.linkToFilingDetails,
21
);
22
});
23
});
To initiate the connection and start receiving new filings, enter the following command in your terminal:
node websocket-client.jsBy following these steps, you'll set up a real-time stream of SEC filings, directly accessible from your terminal.
Advanced Example: Auto-Reconnect, Heartbeats, and Keep-Alives
This advanced Node.js code sample introduces a robust reconnection mechanism. It enables the client to monitor the connection status actively and perform an automatic reconnection if the connection drops. The strategy involves dispatching a heartbeat ping to the server at 30-second intervals, awaiting a pong response. Should the server fail to reply within a 5-second window, the client terminates the current connection and initiates a new connection process, thereby maintaining continuous connectivity.
1
const WebSocket = require('ws');
2
3
const API_KEY = 'YOUR_API_KEY'; // Replace this with your actual API key
4
const STREAM_API_URL = 'wss://stream.sec-api.io?apiKey=' + API_KEY;
5
6
let connectionAttempts = 0;
7
const maxConnectionAttempts = 4;
8
9
function connect() {
10
const ws = new WebSocket(STREAM_API_URL);
11
12
let pingTimeout = null;
13
let heartbeatInterval = null;
14
15
const heartbeat = () => {
16
clearTimeout(pingTimeout);
17
18
// Terminate connection if pong is not received within 5 seconds
19
pingTimeout = setTimeout(() => {
20
console.log('Pong not received, terminating connection...');
21
ws.terminate();
22
}, 5000);
23
24
// Send a ping every 30 seconds
25
ws.ping();
26
};
27
28
ws.on('open', () => {
29
console.log('✅ Connected to:', STREAM_API_URL);
30
connectionAttempts = 0; // Reset connection attempts on successful connection
31
heartbeat(); // Initiate the heartbeat process
32
// Ensure heartbeat continues, so setup interval right after connection
33
heartbeatInterval = setInterval(heartbeat, 30000);
34
});
35
36
ws.on('pong', () => {
37
console.log('Pong received');
38
clearTimeout(pingTimeout); // Clear the pong wait timeout
39
});
40
41
ws.on('close', () => {
42
console.log('Connection closed');
43
clearTimeout(pingTimeout);
44
clearInterval(heartbeatInterval);
45
attemptReconnect();
46
});
47
48
ws.on('error', (err) => {
49
console.log('Error:', err.message);
50
clearTimeout(pingTimeout);
51
clearInterval(heartbeatInterval);
52
});
53
54
ws.on('message', (message) => {
55
const filings = JSON.parse(message.toString());
56
filings.forEach((filing) => {
57
console.log(
58
filing.id,
59
filing.cik,
60
filing.formType,
61
filing.filedAt,
62
filing.linkToFilingDetails,
63
);
64
});
65
});
66
}
67
68
function attemptReconnect() {
69
if (connectionAttempts < maxConnectionAttempts) {
70
connectionAttempts++;
71
console.log(`Attempt ${connectionAttempts} to reconnect...`);
72
setTimeout(connect, 1000 * connectionAttempts); // Exponential back-off
73
} else {
74
console.log('Max reconnection attempts reached. Giving up.');
75
}
76
}
77
78
connect();
79