API guide

WebSocket vs REST API: which to use for real-time data

REST asks, a WebSocket listens. For market data the choice is mostly arithmetic: count the requests polling would cost you, and the seconds of staleness it would add.

On this page
  1. What is a WebSocket?
  2. WebSocket vs REST at a glance
  3. The polling tax: requests and staleness
  4. When REST is the right answer
  5. When a WebSocket earns its complexity
  6. The hybrid pattern most production apps use
  7. Server-sent events, long polling and other options
  8. Choosing: a decision table
  9. Questions

Key takeaways

  • REST is request and response: the client asks every time. A WebSocket is one long-lived connection on which the server pushes updates as they happen.
  • Polling one symbol every 5 seconds costs 720 requests an hour and shows a price that trails the latest by 2.5 seconds on average.
  • Use REST for history, snapshots and occasional lookups; use a WebSocket for live prices on more than a handful of symbols.
  • Production market data apps use both: REST to load history and repair gaps after a reconnect, a WebSocket for the live edge.

The WebSocket vs REST API question comes down to who speaks first. With REST, your client sends an HTTP request and receives one response, every time it wants data. With a WebSocket, the client opens one long-lived connection and the server pushes each update as soon as it has one. Use REST for history, snapshots and occasional lookups; use a WebSocket for data that changes continuously, such as live prices.

For market data the decision is mostly arithmetic, so this guide does the arithmetic: requests per hour, seconds of staleness, bytes on the wire. The connection details of our own stream are in the stock WebSocket API guide, and the wider picture of endpoints, symbols and units is in market data API explained.

What is a WebSocket?

A WebSocket is a persistent, two-way connection between a client and a server, defined in RFC 6455. It starts life as an ordinary HTTP request carrying an Upgrade: websocket header. If the server agrees, it answers 101 Switching Protocols, and from then on both sides exchange frames over the same connection, in either direction, whenever they like. There is no request per message, and each frame adds only 2 to 14 bytes of header.

That is the whole difference in WebSocket vs HTTP: plain HTTP is a conversation of questions and answers, a WebSocket is an open line. This is what an open line looks like on the TickerLayer stream:

Your appTickerLayer stream
  1. GET /?apiKey=… with Upgrade: websocketYour app to TickerLayer stream
  2. 101 Switching ProtocolsTickerLayer stream to Your app
  3. {"type":"system","event":"ready"}TickerLayer stream to Your app
  4. subscribe forex.quotes EURUSDYour app to TickerLayer stream
  5. subscribedTickerLayer stream to Your app
  6. quote EURUSDpushed as the price changesTickerLayer stream to Your app
  7. quote EURUSDTickerLayer stream to Your app
  8. pingTickerLayer stream to Your app
  9. pongsent by the client libraryYour app to TickerLayer stream
One upgrade, one subscribe message, then a stream of frames. Protocol pings keep the connection alive, and standard clients answer them automatically.

Every modern browser ships the WebSocket API, and every mainstream server language has a client. The URL scheme is ws://, or wss:// over TLS, which is the only one to use for anything that carries a key. From the server's side the trade-off flips: a REST server forgets you between requests, while a WebSocket server holds state for every open connection and fans each update out to every subscriber. That is why streaming plans are capped by connections and symbols rather than by requests.

WebSocket vs REST at a glance

FeatureRESTWebSocket
Who startsThe client, every timeThe client once, then the server pushes
ConnectionShort requests, reusable with keep-aliveOne long-lived connection
FreshnessAs old as your polling intervalUpdates arrive as they happen
What you pay inRequests per second and per monthConnections and distinct symbols
Overhead per updateA full HTTP request and responseA 2 to 14 byte frame header
Sees trades between polls
HTTP caching and CDNs
Runs from cron or serverless
Client complexityLow: retry on errorHigher: reconnect, heartbeat, resubscribe
Best forHistory, snapshots, lookups, page loadsLive prices, trade tapes, alerts, dashboards
Neither is better in general. Each is cheaper for a different shape of work.

The polling tax: requests and staleness

Polling is REST in a loop: ask, sleep, ask again. It works, and it has two costs that grow together. Every poll is a request against your rate limit and monthly quota, and between polls the price on screen gets older while the market keeps moving.

requests per hour = symbols × 3,600 ÷ intervalaverage staleness ≈ interval ÷ 2 + round tripworst staleness ≈ interval + round trip

interval
Seconds between two polls of the same symbol.
round trip
Network and server time for one request.
staleness
How far the value you show trails the latest value the API holds.
One symbol every 5 s: 720 requests an hour, and a price that trails the latest by 2.5 s on average.
Polling intervalRequests per hourRequests per month, around the clockAverage added staleness
1 s3,6002,592,0000.5 s
5 s720518,4002.5 s
15 s240172,8007.5 s
60 s6043,20030 s
WebSocket1 subscribe message0 REST requestsNone from polling
One symbol, from the formula above, with a 30-day month. Multiply by the number of symbols you watch.

How old is the price on screen?

  • Polling every 5 s
  • Streaming

seconds behind the latest price

Illustrative, x axis in seconds. A 5-second poll adds up to five seconds of delay on top of network time; a stream adds only delivery time.

Run your own numbers. The calculator turns symbols, a polling interval and hours per day into requests per day and per month:

Polling budget calculator

sec
Requests per second
2.00
Requests per day
57,600
Requests per month
1,267,200
Smallest plan that fits
Business
  • Free422×
  • Individual507%
  • Business5%

One request per symbol per poll. A WebSocket subscription replaces all of these requests with one connection. Quotas are listed on pricing; per-second limits are in the X-RateLimit-Limit header.

Set symbols, polling interval and hours per day. Everything runs in your browser.

Then hold the result against real quotas. The TickerLayer free tier includes 3,000 REST requests a month: about 100 a day, or one symbol checked every 15 minutes around the clock. Individual plans include 250,000 REST calls a month and Business plans 25 million. Ten US stocks polled through the regular session land in very different places depending on the interval:

Requests per month to poll 10 US stocks through the regular session

  • Every 1 s4.9M
  • Every 5 s983K
  • Every 15 s328K
  • Every 60 s82K
  • WebSocket0
A 6.5-hour session and 21 trading days. For scale, an Individual plan includes 250,000 REST calls a month.

Bytes tell the same story. In one measurement on 28 September 2026, polling GET /forex/quote/EURUSD sent a request of about 160 bytes and received 103 bytes of JSON behind roughly 850 bytes of response headers: about 1.1 KB per update. The same quote as a stream frame is 160 bytes of JSON plus a 4-byte frame header. Header sizes vary by client and route, but the ratio holds: when data changes often, the envelope costs more than the letter.

Do keep-alive and HTTP/2 close the gap?

Partly. Keep-alive reuses one connection across polls, so you skip a TLS handshake per request, and HTTP/2 compresses repeated headers, which shrinks that 850-byte envelope a great deal. Neither touches the two costs that matter most. Each poll is still a request against your limits, and the price still waits up to a full interval before you see it. Long polling narrows the staleness but holds a request open per client while it waits, which is why it survives mostly as a fallback for clients that cannot open a WebSocket.

Polling fast also brings you closer to the per-second limit, and a 429 in a tight loop turns into a retry storm unless the client backs off properly. The fixes are in 429 Too Many Requests.

When REST is the right answer

Polling gets its bad name from live dashboards, but most market data calls are not live. REST is the better tool when:

  • You need history. Bars come in pages of up to 5,000 from GET /{asset}/agg/{symbol}/{multiplier}/{timespan}/{from}/{to}; no stream replays last year.
  • You need one value now. A page load, a report, a price check before a form: one snapshot beats opening a socket.
  • The job runs on a schedule. Cron jobs, serverless functions and spreadsheets cannot hold a connection open between runs.
  • The value changes slowly. Market status, symbol lists, daily bars and bond yields, which are daily observations, rarely justify a stream.
  • You want HTTP tooling. Caches, retries, proxies, curl and every monitoring tool speak REST.

When a WebSocket earns its complexity

A stream wins when data changes faster than you could reasonably poll, or when you care about what happened between two polls:

  • Many live symbols. One connection carries all of them, and the cost does not grow with every extra poll.
  • Trades, not just prices. Polling the last trade shows only the latest one; trades between polls vanish. A trade channel pushes trades as they print.
  • Alerts and triggers. A threshold crossed for two seconds between two polls is a threshold your alert never saw.
  • Events without a schedule. US trading halts on stocks.status arrive when they happen; there is no sensible interval to poll for them.

The price is client complexity. A socket drops, and your code has to notice, reconnect with backoff, resubscribe and backfill any bars it missed over REST. It also has to keep up: a handler that does heavy work inline falls behind a busy stream, so hand slow work to a queue. The WebSocket reconnect guide covers heartbeats, close codes and backoff, and the Python WebSocket client tutorial builds a complete client.

The hybrid pattern most production apps use

  1. Load historyREST bars
  2. Open the streamwait for ready
  3. Subscribesnapshot fills the screen
  4. Live framesupdate in place
  5. On a dropreconnect, resubscribe, backfill over REST
REST bootstraps and repairs; the WebSocket carries the live edge.

Here are both approaches side by side for one currency pair. The polling version is shorter. The streaming version sends one subscribe message and then only listens; note that the stream sends forex prices as strings, so the code converts them.

poll.pyPython
import os
import time

import requests

session = requests.Session()
session.headers["x-api-key"] = os.environ["TICKERLAYER_API_KEY"]

while True:  # one symbol every 5 s = 720 requests an hour
    resp = session.get("https://api.tickerlayer.com/forex/quote/EURUSD", timeout=10)
    resp.raise_for_status()
    q = resp.json()
    print("poll", q["bid"], q["ask"], q["timestamp"])
    time.sleep(5)
stream.pyPython
import asyncio
import json
import os
from urllib.parse import quote

import websockets  # pip install websockets

URL = "wss://stream.tickerlayer.com/?apiKey=" + quote(os.environ["TICKERLAYER_API_KEY"])
SUBSCRIBE = {"action": "subscribe", "channels": ["forex.quotes"], "symbols": ["EURUSD"]}


async def main():
    async with websockets.connect(URL, compression=None) as ws:
        ready = json.loads(await ws.recv())
        if ready.get("event") != "ready":
            raise RuntimeError(f"expected ready, got {ready}")
        await ws.send(json.dumps(SUBSCRIBE))  # one message, then the server pushes
        async for raw in ws:
            msg = json.loads(raw)
            if msg.get("type") == "quote":
                print("push", float(msg["bid"]), float(msg["ask"]), msg["ts"])
            else:
                print(msg)


asyncio.run(main())
Output (28 September 2026, trimmed)
$ python poll.py
poll 1.137281 1.137291 1790593057001
poll 1.137252 1.137293 1790593063037

$ python stream.py
{'type': 'system', 'event': 'subscribed', 'channels': ['forex.quotes'], 'symbols': ['EURUSD']}
push 1.137258 1.137268 1790593065001
...

Server-sent events, long polling and other options

WebSocket and REST polling are not the only ways to get updates from a server. Two more come up in every design review, and the server-sent events vs WebSocket comparison is the one worth knowing:

REST pollingLong pollingServer-sent eventsWebSocket
DirectionClient asksClient asks, server holds the answerServer to client onlyBoth ways
TransportHTTPHTTPHTTP, text/event-streamUpgraded connection
Binary dataYesYesNo, UTF-8 text onlyYes
Browser reconnectNot neededManualBuilt in (EventSource)Manual
Good forOccasional readsRare events, older clientsOne-way feeds to browsersHigh-rate, two-way or many-symbol streams
Server-sent events are a fine one-way option for browsers. Market data streams usually pick WebSocket because clients also send subscribe and unsubscribe messages mid-session.

TickerLayer serves REST and a raw WebSocket stream: standard WebSocket frames carrying JSON, not a library-specific protocol, so any client that speaks RFC 6455 works, from a browser to a Python script.

Choosing: a decision table

Your situationUseWhy
A backtest on two years of daily barsRESTHistory only exists as request and response
A price on a product pageREST snapshotOne value per page view, and cacheable
A nightly report or spreadsheet refreshRESTRuns on a schedule, with no connection to hold
A live watchlist of 30 symbolsWebSocketOne connection instead of thousands of requests an hour
Price alerts on thresholdsWebSocketSees moves that happen between polls
Trading halt notificationsWebSocket (stocks.status)Events arrive when they happen
A live chart with historyBothREST loads the bars; the stream moves the last candle
Rules of thumb. The request-budget calculator above settles the borderline cases.

Plans shape the choice too. The TickerLayer free tier is REST; WebSocket streaming comes with paid plans, and free accounts can request a WebSocket trial from the dashboard. An Individual plan allows one connection and 10 streamed symbols, and Business allows 10 connections with unlimited symbols. The current allowances are in the limits reference, and the WebSocket docs list every channel and frame.

Questions

Is WebSocket faster than REST?

For continuous updates, yes: the server pushes each change as it happens instead of waiting for your next poll, and each frame carries a few bytes of header instead of a full HTTP exchange. For a single lookup the difference is negligible, and REST is simpler.

Can I use a WebSocket with a REST API?

Yes, and most market data apps do. Use REST for history, snapshots and backfill after a reconnect, and a WebSocket for the live updates in between.

What is the difference between WebSocket and HTTP?

HTTP is request and response: one answer per question. A WebSocket starts as an HTTP request, upgrades with status 101, and then keeps a two-way connection open for as many messages as either side sends.

When should I not use a WebSocket?

When you need data only occasionally, run on a schedule or in serverless functions, or depend on HTTP caching. Holding a connection open costs reconnect logic that only pays off for frequent updates.

Server-sent events vs WebSocket: which should I use?

Server-sent events are simpler for one-way text updates to a browser and reconnect on their own. WebSockets are two-way and carry binary, which suits subscribe and unsubscribe traffic on market data streams.

Keep reading

Ready to integrate?

Start with the free tier, explore the docs, and connect via REST or WebSocket in minutes.