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.

Node.js
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.

Node.js
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