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 ws
Next, 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.js
By 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
14
const heartbeat = () => {
15
clearTimeout(pingTimeout);
16
17
// Terminate connection if pong is not received within 5 seconds
18
pingTimeout = setTimeout(() => {
19
console.log('Pong not received, terminating connection...');
20
ws.terminate();
21
attemptReconnect();
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
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
attemptReconnect();
45
});
46
47
ws.on('error', (err) => {
48
console.log('Error:', err.message);
49
clearTimeout(pingTimeout);
50
attemptReconnect();
51
});
52
53
ws.on('message', (message) => {
54
const filings = JSON.parse(message.toString());
55
filings.forEach((filing) => {
56
console.log(
57
filing.id,
58
filing.cik,
59
filing.formType,
60
filing.filedAt,
61
filing.linkToFilingDetails,
62
);
63
});
64
});
65
}
66
67
function attemptReconnect() {
68
if (connectionAttempts < maxConnectionAttempts) {
69
connectionAttempts++;
70
console.log(`Attempt ${connectionAttempts} to reconnect...`);
71
setTimeout(connect, 1000 * connectionAttempts); // Exponential back-off
72
} else {
73
console.log('Max reconnection attempts reached. Giving up.');
74
}
75
}
76
77
connect();
78