When is a socket the right tool, and when is asking again?
Everything so far has been request and response: you ask, the server answers, the connection closes. For live prices there is a second model — you open a connection once and the server pushes updates until you disconnect. Knowing which to use is mostly a question about how fast your data changes relative to how often you ask.
The WebSocket feed
Streaming is not part of the REST specification. It lives at its own endpoint:
wss://ws.eodhistoricaldata.com/ws/{market}
where {market} selects the feed. The ones observable in practice are us (US trades), us-quote (US quotes), forex and crypto. Different markets, different sockets — you do not mix asset classes on one connection the way you can in a batched REST call.
The sequence is: connect, authenticate, subscribe to symbols, then read. The first message back after connecting is a status message, not market data:
{"status_code": 200, "message": "Authorized"}
Then the ticks arrive. A live capture on the crypto feed, one symbol:
{"s":"BTC-USD","p":"63779.2177","q":"1","dc":"-2.5468","dd":"-1624.3026","t":1785264496932}
s is the symbol, p the price, q the quantity, dc and dd the day's change in percent and in currency, t the timestamp in milliseconds.
Two things in that message deserve attention. p is a string, not a number — "63779.2177" with quotes. Parse it, do not assume your JSON library handed you a float. And five of those messages arrived inside 424 milliseconds for a single symbol. That is roughly twelve updates a second, from one instrument. Multiply by a fifty-symbol subscription and you have a firehose that your consumer, not the server, has to keep up with.
The honest comparison
Polling a REST quote endpoint every second gets you one price per second and burns a request each time. A socket gets you every update and burns one connection. That sounds like the socket always wins, and it does not.
Polling is the right tool when your consumer cannot use sub-second resolution anyway — a dashboard a human reads, a report, an alert with a minute's tolerance. It is stateless, it is trivially retried, it works through any proxy, and a failed request costs you one refresh.
Streaming is the right tool when you genuinely need every print, or when your poll interval would be shorter than a second. But you have taken on real work: reconnection with backoff, re-subscription after every reconnect, heartbeats, buffering when your consumer falls behind, and gap detection — because a socket that drops loses data silently, whereas a failed HTTP request tells you it failed.
There is also a coverage boundary. Subscriptions are capped per connection (on the order of tens of symbols), so a large universe means several sockets and the bookkeeping that comes with them.
When a socket says nothing
A useful failure to recognise. In a live test during an open US session, the us trades feed connected and returned {"status_code": 200, "message": "Authorized"} — and then delivered zero trade messages in six seconds, while the crypto feed on the same token streamed continuously.
Authorization succeeded; entitlement did not. A silent but connected socket during trading hours is almost always a data-entitlement result, not a network fault. Before debugging your client, check what the account is licensed for. This is exactly the delayed-versus-real-time boundary from two lessons ago, showing up as silence instead of as a timestamp.
Try it now
- A socket is not something a page can replay, so here is a capture: the
cryptofeed, subscribed toBTC-USDat 15:54 UTC on 28 September 2026, its first ten messages after the status message, trimmed topandt. Compute the interval between consecutivetvalues, and note the two places where a message arrived with an earliertthan the one before it.
| # | p |
t |
|---|---|---|
| 1 | "83303.5" | 1790610855560 |
| 2 | "83303.5" | 1790610855741 |
| 3 | "83271.97" | 1790610855815 |
| 4 | "83271.98" | 1790610855817 |
| 5 | "83271.97" | 1790610856048 |
| 6 | "83296.01" | 1790610855978 |
| 7 | "83296.01" | 1790610856108 |
| 8 | "83271.97" | 1790610856195 |
| 9 | "83303.5" | 1790610856122 |
| 10 | "83296.01" | 1790610856141 |
- Over the same ten seconds,
/real-time/BTC-USD.CCwas polled once a second, ten times. All ten answers carried the sameclose, 83222.4765625, and the sametimestamp, 1790610840; the socket delivered 784 messages carrying 248 distinct prices. Compare the two, and say what the poll'stimestamptells you about how its price is sampled. The quote as it stood at the last refresh is below.
- Kill your network mid-stream and watch what your client does. If the answer is "nothing, quietly", you have found the piece of streaming code that always has to be written.