/v2/websocket-key
endpoint.Once you have your WebSocket API key, establish a connection to one of the following endpoints:
wss://realtime.insightsentry.com/live
wss://realtime.insightsentry.com/newsfeed
Both endpoints require authentication using your WebSocket API key, but the format differs slightly:
Authentication is combined with your subscription request (detailed in the next section).
Send only the API key in a simplified format:
{
"api_key": "<your_websocket_api_key>"
// No subscriptions needed for news feed
}
Upon connecting or reconnecting to the /newsfeed
endpoint, the server will automatically send you the most recent 10 news items. This ensures you have immediate access to recent news without making additional requests.
Upon establishing a WebSocket connection to the market data endpoint, you must send a JSON-encoded message to authenticate and subscribe to data feeds for specific symbols.
Message Format:
{
"api_key": "<your_websocket_api_key>",
"subscriptions": [
// Array of subscription objects
]
}
Subscription Object Parameters:
code
(string, required): The symbol identifier (e.g., "NASDAQ:AAPL"
, "BINANCE:BTCUSDT"
).type
(string, optional, default: "series"
): The type of data feed. Valid options are "series"
or "quote"
."series"
is the default, you can omit "type": "series"
if subscribing to series data.bar_type
(string, required for type: "series"
): The time interval for bars (e.g., "minute"
, "hour"
, "day"
or "tick"
for Tick Data). Matches parameters in the /series
REST endpoint.bar_interval
(integer, required for type: "series"
): The number of bar_type
units per bar (e.g., 1
, 5
, 15
). Matches parameters in the /series
REST endpoint.extended
(boolean, optional for type: "series"
, default: true
): See Extended Hours.dadj
(boolean, optional for type: "series"
, default: false
): See Dividend Adjustment.Example Subscription Message:
{
"api_key": "<your_websocket_api_key>",
"subscriptions": [
{"code": "NASDAQ:AAPL", "type": "series", "bar_type": "minute", "bar_interval": 1},
{"code": "NASDAQ:TSLA", "type": "quote"}
]
}
You can add, remove, or change subscriptions without disconnecting by sending a new subscription message containing the complete desired list of subscriptions. The server will replace your previous subscriptions with the ones in the latest message.
Example - Changing Subscriptions:
To change the previous example to track minute bars and quotes for AAPL, send:
{
"api_key": "<your_websocket_api_key>",
"subscriptions": [
{"code": "NASDAQ:AAPL", "type": "series", "bar_type": "minute", "bar_interval": 1},
{"code": "NASDAQ:AAPL", "type": "quote"}
// NASDAQ:TSLA quote subscription is removed as it's not in the new list
]
}
api_key
.subscriptions
array. To stop receiving all data, disconnect the WebSocket client. Reconnect when you need data again.subscriptions
array.The server pushes data updates as JSON-encoded messages. The format depends on the subscription type
. For detailed field descriptions, refer to the corresponding REST API endpoints (/symbols/:symbol/series
or /symbols/quotes
).
type: "series"
)Provides OHLCV (Open, High, Low, Close, Volume) bar data Tick Data.
bar_type
and bar_interval
you choose (e.g., hour
, minute
, or second
), you will receive updates in real-time whenever the close price or volume changes within the current bar period. For example, with bar_type: "hour"
, you're not limited to receiving updates once per hour—you'll receive the hourly aggregated data updated in real-time as trades occur.Data push behavior varies based on your bar_type
subscription:
bar_type: "tick"
): Whenever trade is made, data will be pushed. Each data represent a trade (regardless of volumes).bar_type: "second"
): Data is pushed only when there is a change in close price or volume.bar_type: "minute"
or above): Data is pushed both when close price or volume changes and when a new bar period starts.{
"code": "NASDAQ:AAPL",
"bar_end": 1733432399.0,
"last_update": 1733432399820,
"bar_type": "1m",
"series": [
{
"time": 1733432340.0,
"open": 242.89,
"high": 243.09,
"low": 242.82,
"close": 243.08,
"volume": 533779.0
}
]
}
type: "quote"
)Provides real-time quote information, including price, volume, and bid/ask details.
{
"code": "NASDAQ:AAPL",
"lp_time": 1733432340.0,
"volume": 533779.0,
"last_price": 243.08,
"change_percent": 0.41,
"change": 979.96,
"ask": 243.09,
"bid": 243.08,
"ask_size": 520.0,
"bid_size": 430.0
}
The WebSocket API supports several additional parameters for fine-tuning your data feeds and customizing the response format.
extended
)The extended
parameter applies to many US and Global stock markets.
extended: true
(default) - Includes pre-market and after-hours trading data where available. For US equities, this covers 4:00 AM - 9:30 AM ET (pre-market) and 4:00 PM - 8:00 PM ET (after-hours).extended: false
- Only includes regular trading hours data.extended: true
for markets without extended hours will return only regular session data.Example:
{
"api_key": "<your_websocket_api_key>",
"subscriptions": [
{"code": "NASDAQ:AAPL", "bar_type": "minute", "bar_interval": 1, "extended": false}
]
}
dadj
)For equities data, you can request dividend-adjusted price series.
dadj: true
- Applies dividend adjustments to all price values.dadj: false
(default) - Shows unadjusted prices.Example:
{
"api_key": "<your_websocket_api_key>",
"subscriptions": [
{"code": "NASDAQ:AAPL", "bar_type": "day", "bar_interval": 1, "dadj": true}
]
}
recent_bars
)Request historical bars when first subscribing to a symbol.
recent_bars: true
- Includes up to 15 most recent complete bars with the initial response.recent_bars: false
(default) - Only receives new updates as they occur.Example:
{
"api_key": "<your_websocket_api_key>",
"subscriptions": [
{"code": "NASDAQ:AAPL", "bar_type": "minute", "bar_interval": 5, "recent_bars": true}
]
}
When recent_bars
is enabled, the first message you receive will contain an array of recent bars in the series
property, followed by subsequent updates with single bars.
onOpen
(or equivalent) event handler. This ensures you re-subscribe immediately upon successful reconnection.The server periodically sends a timestamp message (approximately every 10 seconds) to help keep the connection alive and allow clients to verify connectivity.
Format:
{"server_time": 1741397070281}
Some WebSocket libraries can drop connections during periods of inactivity. To maintain a stable connection:
'ping'
text message every 20-30 seconds to keep the connection active.'pong'
message, confirming the connection is still alive.const ws = new WebSocket('wss://realtime.insightsentry.com/live');
const pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send('ping');
}
}, 20000);
ws.onclose = () => {
clearInterval(pingInterval);
console.log('WebSocket connection closed');
};
ws.onmessage = (event) => {
const data = event.data;
if (data === 'pong') {
console.log('Received pong from server');
return;
}
};
Configure your WebSocket library with an appropriate timeout value. We recommend a minimum timeout of 12 seconds. This helps handle periods of low market activity (e.g., weekends, holidays) where price updates might be infrequent, preventing premature disconnection by the client.
If you send an invalid request (e.g., incorrect format, invalid symbol) or if a server-side error occurs related to your request, the server will send a JSON-encoded error message:
{
"message": "Invalid Symbol Code"
}
The WebSocket API key can be rotated for security purposes. Important notes about WebSocket API keys:
/v2/websocket-key
endpoint.{
"api_key": "your-websocket-api-key",
"expiration": 1747580931
}
const baseUrl = 'https://insightsentry.p.rapidapi.com';
interface WebSocketKey {
key: string;
expiresAt: number;
}
async function getValidWebSocketKey(): Promise<string> {
const storedKey = await database.getWebSocketKey();
const now = Math.floor(Date.now() / 1000);
const bufferTime = 24 * 60 * 60;
if (storedKey && storedKey.expiresAt > (now + bufferTime)) {
return storedKey.key;
}
const response = await fetch(`${baseUrl}/v2/websocket-key`, {
method: 'GET',
headers: {
'x-rapidapi-key': 'YOUR_RAPID_API_KEY'
}
});
const data = await response.json();
await database.saveWebSocketKey({
key: data.api_key,
expiresAt: data.expiration
});
return data.api_key;
}
Below are basic examples demonstrating how to connect and subscribe using popular WebSocket libraries.
<your apikey>
or <your_key>
with your actual WebSocket API key.
# pip install requests
# pip install websockets
# pip install asyncio
import requests
import websockets
import json
import asyncio
# If you've subscribed via RapidAPI
url = "https://insightsentry.p.rapidapi.com/v2/websocket-key"
# Replace with your actual API key
apiKey = "YOUR_API_KEY_HERE"
headers = {
"x-rapidapi-key": apiKey,
"x-rapidapi-host": "insightsentry.p.rapidapi.com"
}
response = requests.get(url, headers=headers)
json_response = response.json()
print(json_response)
### Important ###
# Save the api_key somewhere in your database or file and then reuse it later
# Since the api_key's expiration is after one week, please refresh it accordingly
# You can retrieve only up to 10 Websocket API keys per day
# This is just an example to show how to get the api_key
api_key = json_response.get("api_key")
async def handle_messages(websocket):
async for message in websocket:
if message == "pong": # skip pong
continue
# can safely assume that the message is a JSON string
try:
data = json.loads(message)
# Check if json contains 'code'
if 'code' in data:
# Do something with the Quote or Series data
if 'series' in data:
# Handle Series data
print(data)
else:
# Handle Quote data
print(data)
else:
# "server_time" is for checking latency and connection status. If it's not received within 30 seconds, there may be a connection issue
# "message" is for initial connection and error messages
print(data)
except json.JSONDecodeError as e:
print(f"Failed to decode JSON: {e}")
print(f"Raw message: {message}")
async def send_ping(websocket):
"""Send ping messages every 15 seconds to keep connection alive"""
while True:
try:
await asyncio.sleep(15)
await websocket.send('ping')
except Exception as e:
print(f"Ping failed: {e}")
break
async def connect_and_subscribe():
uri = "wss://realtime.insightsentry.com/live"
try:
async with websockets.connect(uri) as websocket:
print("Connected to websocket")
# Send subscription message
subMsg = json.dumps({
"api_key": api_key,
"subscriptions": [
# Subscribe to either "series" or "quote" types
# With 1 Symbol Subscription you can subscribe to 1 "series" or 10 "quote"
{
"code": "NASDAQ:AAPL",
"type": "quote"
},
{
"code": "CME_MINI:ES1!",
"type": "quote"
}
#,
# {
# "code": "NASDAQ:GOOGL",
# "type": "series",
# "bar_type": "second",
# "extended": "false", # to receive only regular trading hours data
# "bar_interval": 1,
# "recent_bars": 'true' # to receive recent bars whenever connected/reconnected
# },
# {
# "code": "NASDAQ:AAPL",
# "type": "series",
# "bar_type": "tick",
# "bar_interval": 1,
# "recent_bars": 'false'
# }
]
})
await websocket.send(subMsg)
# Periodically sending 'ping' can help to keep connection sticky
ping_task = asyncio.create_task(send_ping(websocket))
try:
# Handle incoming messages
await handle_messages(websocket)
finally:
# Cancel ping task when done
ping_task.cancel()
try:
await ping_task
except asyncio.CancelledError:
pass
except websockets.exceptions.ConnectionClosed as e:
print(f"Connection closed: {e}")
raise
except Exception as e:
print(f"Connection error: {e}")
raise
async def run_with_retry():
attempt = 0
while True:
try:
attempt += 1
await connect_and_subscribe()
break
except Exception as e:
wait_time = min(0.1 + (attempt - 1) * 0.5, 5) # Start at 100ms, increase by 500ms, cap at 5 seconds
print(f"Reconnecting in {wait_time} seconds...")
await asyncio.sleep(wait_time)
if __name__ == "__main__":
asyncio.run(run_with_retry())
There could be several causes. First, check if your main thread is blocked due to heavy data processing. If the main thread is blocked, the WebSocket library's internal ping mechanism may fail to respond, which can lead to disconnection. This is one of the most common causes. You can easily identify this by comparing your machine’s current time with the server_time
field in the messages sent from our servers. If Time.inMilliseconds - server_time
results in a negative value, it indicates that your main thread is being blocked.
For the 1-second time frame, a bar message is sent only when there is a change in the close price or volume. This means you may not receive a message every second. To handle missing bars, you can normalize your data by filling in with the previous bar's values when no update is received.