High Granular Tick Data API: US Stocks Learn more

Real-Time Data API via Websockets

EODHD offers one of the best ways for investors, developers, and data analysts to incorporate real-time finance data for the stocks, 1100+ Forex pairs, 1000+ Digital Currencies into their decision-making projects with a delay of less than 50ms via WebSockets. For stocks our real-time data API supports pre-market and post-market hours (from 4 am to 8 pm EST).

The subscription provides real-time access to prices for 50 tickers simultaneously via WebSockets. Additionally, the 50-symbol limit can be increased through the user dashboard.

For global markets and all exchanges around the world we also offer Live (Delayed) data with 15min delay.

What is WebSocket protocol

WebSockets is a communication protocol that provides full-duplex communication channels over a single TCP connection. It enables real-time communication between a client and a server, allowing them to exchange messages continuously without the overhead of repeatedly establishing new connections. In the case of financial data providers, Websockets API provides real-time stock market information with minimal delay.

Because real-time WebSocket streaming is resource-intensive, it is offered on paid plans rather than a free tier.

What you get (Data availability)

Stocks (full list of tickers available)
• Trade stream (last price, size, conditions, etc.)
• Quote stream (bid/ask, sizes)
• Extended hours supported (pre‑ and post‑market)

FOREX (full list of available currency pairs)
• Bid/ask + day change/difference
• Tickers like EURUSD, AUDUSD, etc.

Digital Currencies (Full list of available crypto pairs)
• Last price, quantity, day change/difference
• Tickers like ETH-USD, BTC-USD

Lists of available tickers and pairs for Real-Time feeds can be retrieved in JSON format via this API endpoint, providing the full list of exchange or asset class components (use “US” for US stocks, “CC” for cryptocurrencies, “FOREX” for currency pairs).

Demo access is available with API key “demo” for: AAPL, MSFT, TSLA, EURUSD, ETH-USD, BTC-USD.

Data source and what the data represents

Real-time US and European equities are delivered directly from Cboe Global Cloud, our official exchange data source. Because this is a direct-from-exchange feed rather than an aggregated one, it is worth being precise about what it contains.

US equities

US trades and quotes come from Cboe EDGX, one of Cboe’s four US equity exchanges. Trades are executions that occurred on EDGX — this is not a consolidated (SIP) tape, so it does not include executions from other exchanges, or off-exchange and FINRA TRF prints. Quotes are the EDGX top of book with sizes, not a national best bid and offer aggregated across venues. Pre-market and post-market trades are delivered and flagged through the market status field.

European equities

European trades and quotes come from Cboe Europe, across its BXE, CXE and DXE order books, covering UK-listed names and continental large-caps over a single endpoint. Trading hours follow each instrument’s home venue, so the last trade for a symbol may lag once that venue enters its closing auction while quotes continue elsewhere.

European quotes differ from the US ones in one important way: they are a consolidated best bid and offer across all three books. The best price wins, and where two books show the same price their sizes are added, so the size you see is the depth available at that price across the venues we carry.

Updates & Latency

  • Streaming updates pushed in real time over a persistent WebSocket connection.
  • Typical transport latency < 50 ms from our gateway to your client (excluding network distance).
  • Market status flag indicates openclosed, or extended hours for stocks.

Endpoints

Open connection – use wss:// in production. ws:// is available for local testing.

Equities (Trades and Quotes):

wss://ws.eodhistoricaldata.com/ws/us?api_token=YOUR_API_KEY
wss://ws.eodhistoricaldata.com/ws/us-quote?api_token=YOUR_API_KEY

European Equities (Trades and Quotes):

wss://ws.eodhistoricaldata.com/ws/eu?api_token=YOUR_API_KEY
wss://ws.eodhistoricaldata.com/ws/eu-quote?api_token=YOUR_API_KEY

Minute Bars (US and Europe):

wss://ws.eodhistoricaldata.com/ws/us-candles?api_token=YOUR_API_KEY
wss://ws.eodhistoricaldata.com/ws/eu-candles?api_token=YOUR_API_KEY


Forex

wss://ws.eodhistoricaldata.com/ws/forex?api_token=YOUR_API_KEY

Crypto

wss://ws.eodhistoricaldata.com/ws/crypto?api_token=YOUR_API_KEY

Subscribe / Unsubscribe

After the socket is open, send JSON commands.

Connection and status messages: on a successful connection the server first sends an authorization message. If you subscribe to a symbol your plan does not allow, for example a non-demo ticker on the demo key, the server replies with a status message instead of data.

{"status_code": 200, "message": "Authorized"}
{"status_code": 422, "message": "Only limited symbols allowed for demo"}

Subscribe:

{"action": "subscribe", "symbols": "ETH-USD"}

Multiple symbols (comma‑separated):

{"action": "subscribe", "symbols": "AAPL,TSLA"}

Unsubscribe:

{"action": "unsubscribe", "symbols": "ETH-USD,BTC-USD"}

Response Schemas

Trades (endpoint: /ws/us):

{
"s": "AAPL",             // ticker
"p": 309.19,             // last trade price
"c": [],                 // trade conditions (array) - empty on this feed, see note
"v": 2,                  // trade size (shares)
"dp": false,             // dark pool flag - always false on this feed, see note
"ms": "extended-hours",  // market status: open | closed | extended-hours
"t": 1787671313868       // epoch ms, UTC
}

Two fields need a word of explanation. The conditions field c is an array, and on this feed it is always empty: the exchange top-of-book source does not carry per-trade sale conditions. The field is kept so the message shape stays identical across all our equity streams. The dark-pool flag dp is always false, because this is a single lit-exchange feed with no off-exchange or FINRA TRF prints in it.

Quotes (endpoint: /ws/us-quote):

{
"s": "AAPL",         // ticker
"ap": 317.297,       // ask price
"as": 160,           // ask size
"bp": 316.988,       // bid price
"bs": 40,            // bid size
"t": 1784115291977   // epoch ms
}

European Equities (endpoints: /ws/eu and /ws/eu-quote):

European equities use exactly the same schemas as US equities — the trade stream matches /ws/us and the quote stream matches /ws/us-quote. Only the symbol format differs. Example trade message:

{
"s": "GSK.LSE",          // ticker (TICKER.EXCHANGE)
"p": 1911,               // last trade price, in the venue's quoting units
"c": [],                 // trade conditions (array) - empty on this feed
"v": 155,                // trade size (shares)
"dp": false,             // dark pool flag - always false on this feed
"ms": "open",            // market status: open | closed
"t": 1787671304945       // epoch ms, UTC
}

Prices are JSON numbers and may arrive with no decimal part when the venue quotes in whole units, as above. Do not assume a fractional component.

Minute Bars (endpoints: /ws/us-candles and /ws/eu-candles):

A rolling one-minute OHLCV bar per subscribed symbol, built from the trade stream.

{
"s": "AAPL",             // ticker
"i": "1m",               // bar interval
"t": 1787671260000,      // bar OPEN time, epoch ms UTC
"o": 309.25,             // open
"h": 309.26,             // high
"l": 309.19,             // low
"c": 309.19,             // close
"v": 1101                // volume in shares, accumulated within the bar
}

The field c means two different things depending on the stream: on the trade streams it is the conditions array, and on the minute-bar streams it is the bar close price. The current bar is also re-sent every time it changes, so the same bar-open timestamp arrives repeatedly with a growing volume until the minute rolls over. Treat the newest message for a given timestamp as authoritative rather than adding them together.

FOREX (endpoint: /ws/forex):

{
"s": "EURUSD",       // symbol
"a": 1.1419,         // ask
"b": 1.1416,         // bid
"dc": "0.3005",      // daily change, % (string)
"dd": "0.0034",      // daily difference, price units (string)
"ppms": true,        // pre/post market status flag
"t": 1784115288241   // epoch ms
}

Crypto (endpoint: /ws/crypto):

{
"s": "ETH-USD",       // symbol
"p": "1881.0931",     // last price (string)
"q": "1.9e-7",        // trade quantity (string, may use exponent notation)
"dc": "5.6041",       // daily change, % (string)
"dd": "105.4177",     // daily difference, price units (string)
"t": 1784115286805    // epoch ms
}

Symbol Limits & Usage Notes

Concurrent subscriptions: up to 50 symbols per connection by default (upgradeable in user dashboard for extra fee).

Tickers:

  • US Stocks: use plain tickers like AAPL, MSFT — no exchange suffix
  • European Stocks: use TICKER.EXCHANGE, e.g., GSK.LSE, SAP.XETRA, ASML.AS — the native Cboe symbol is accepted too
  • Forex: no separator, e.g., EURUSD
  • Crypto: dash‑separated, e.g., BTC-USD

Resubscribe on reconnect: if the socket reconnects, re‑send your current subscriptions.
Compression/Throughput: consider batching symbol lists in a single subscribe call for efficiency.

Symbols that never arrive

A symbol that is unknown, or correct-looking but in the wrong format for the market, is accepted silently — no error is returned and the symbol simply never streams. If one symbol arrives and others stay quiet, check the format of the quiet ones first. The most common cause is an exchange suffix on a US ticker, or a missing one on a European ticker.

One input mistake does produce an error: sending the symbols value as a JSON array instead of a comma-separated string is rejected with a 422.

European tickers containing a hyphen

Known limitation. European tickers that contain a hyphen — mostly Nordic dual-class shares such as ERIC-B.ST or NOVO-B.CO — do not currently resolve under that name, and because unknown symbols are ignored silently you will see no error. Subscribe with the hyphen removed instead, for example ERICB.ST or NOVOB.CO. This affects the subscription name only, not the data. We are correcting the mapping so the hyphenated ticker works, and the un-hyphenated form will keep working afterwards, so code written against it today will not break. Note also that some hyphenated tickers are not part of the venue coverage behind this feed and return nothing in either form.

Connection limits

You may hold up to 64 concurrent connections per API token. That budget is shared across every market — trades, quotes, minute bars, forex and crypto sockets all count toward the same total. Opening one beyond it is refused with a 429 before the WebSocket opens.

Opening a separate connection per stream is expected and supported. The cap exists so one runaway client cannot degrade the feed for everyone, so if you legitimately need more, contact support rather than retrying in a loop.

Sign up & Get Data

Errors and status codes

Error frames come in two shapes, and the difference matters if you write one parser for both. An authentication failure uses the key status. Every other frame uses status_code.

Authentication, before the connection opens

{"status":422,"message":"Server error"}   // api_token missing
{"status":403,"message":"Server error"}   // token not recognised, or no real-time entitlement

These are returned as the HTTP response to the handshake, so the WebSocket never opens and nothing arrives on the socket. Browsers deliberately hide the details of a failed WebSocket handshake, so a browser client sees only a generic connection error — to tell a missing token from an unentitled one, read the HTTP status from a server-side client.

After the connection is open

CodeMessageCause
404No market ‘…’ foundThe endpoint path is not one of the markets listed above.
422Invalid requestThe command was not valid JSON.
422action and symbols should be passed in a commandOne of the two required keys is missing.
422Action and symbols should be stringWrong types — most often symbols sent as a JSON array instead of a comma-separated string.
422Unknown action. Possible actions: subscribe, unsubscribeThe action value is not recognised.
422Symbols limit reachedThe subscription would exceed your plan’s symbol limit.
422Only limited symbols allowed for demoA demo token asked for a symbol outside the demo list.
429Too many connections (token)The 64-connection budget for this token is full.
500Internal error. Try again laterServer-side failure.

Examples (copy‑paste ready)

Open connection for trades:

wss://ws.eodhistoricaldata.com/ws/us?api_token=demo

Then send:

{"action": "subscribe", "symbols": "AMZN,TSLA"}


Open connection for Forex pairs:

wss://ws.eodhistoricaldata.com/ws/forex?api_token=demo

Then send:

{"action": "subscribe", "symbols": "EURUSD,AUDUSD"}


Open connection for Crypto:

wss://ws.eodhistoricaldata.com/ws/crypto?api_token=demo

Then send:

{"action": "subscribe", "symbols": "ETH-USD,BTC-USD"}

Tools for Testing

ChromeSimple WebSocket Client extension (open a socket, paste open URL, send JSON quote).

EODHD Chrome extension: free mini ticker window for live Stocks/FX/Crypto. Perfect to see our real-time data feed. No commands needed. Install from here.

Postman (or Insomnia) – point-and-click:

  1. New → WebSocket Request
  2. URL: wss://ws.eodhistoricaldata.com/ws/crypto?api_token=demo
  3. Connect → send: {“action”:”subscribe”,”symbols”:”BTC-USD”}


Python (minimal script):

import asyncio, websockets, json

URL = "wss://ws.eodhistoricaldata.com/ws/crypto?api_token=demo"
async def main():
    async with websockets.connect(URL) as ws:
        await ws.send(json.dumps({"action":"subscribe","symbols":"BTC-USD"}))
        while True:
            print(await ws.recv())

asyncio.run(main())


Mac Os Terminal – websocat (via Homebrew):

Install websocat:

brew install websocat

One-liner command:

printf '{"action":"subscribe","symbols":"BTC-USD"}\n' | \
websocat "wss://ws.eodhistoricaldata.com/ws/crypto?api_token=demo"

Quick Comparison with Live (Delayed) API and Intraday API

AspectReal-Time (WebSockets)Live (Delayed)Intraday Historical
TransportWebSocket (push)HTTPS REST (pull)HTTPS REST (pull)
Latency / Freshness~live (<50 ms transport)Stocks: 15–20 min delay; Currencies: ~1 minFinalized ~2–3 h after US after-hours close
Data typesTrades & quotes; FX ticks; crypto ticksLatest OHLCV snapshot (1-min updates)OHLCV bars at 1m / 5m / 1h
Time rangesn/a (streaming)n/a (snapshot feed)1m: 120 d · 5m: 600 d · 1h: 7200 d
Markets & assets*US stocks (pre/post supported), Forex & Digital CurrenciesUS & Global StocksForex & Digital CurrenciesUS & Global StocksForex & Digital Currencies
Best forDashboards, signals, market-making toolsQuote tickers, watchlists, lightweight UIsBacktests, analytics, charting

* Get the full list of covered tickers.

Compare plans and find your fit
Free and paid plans for individual and commercial use
Go to Pricing
Chat