Connect to ChainStream
ChainStream delivers real-time Solana blockchain data by aggregating streams from multiple validators using a "fastest wins" strategy. This multi-validator approach ensures you never miss events while minimizing notification latency, making it ideal for applications requiring complete blockchain visibility and high reliability.
- Scale Mode or higher account (upgrade your plan)
- ChainStream enabled in your dashboard (see below)
- An API key (use your default key or create a new one)
- Basic understanding of WebSocket connections and JSON-RPC 2.0
Enable ChainStream
Before connecting, enable ChainStream from your dashboard's ChainStream API page:

Once enabled, select how many concurrent streams you need. Scale Mode includes one stream, with additional streams available at $0.14/hour (up to 10 total).

ChainStream Endpoint
ChainStream uses a dedicated endpoint with your API key embedded in the URL path:
Mainnet:
wss://solana-mainnet.chainstream.syndica.io/api-key/YOUR_API_KEY
Devnet:
wss://solana-devnet.chainstream.syndica.io/api-key/YOUR_API_KEY
Subscribe to Transaction Events
Monitor transactions in real-time with flexible filtering options. This example subscribes to confirmed transactions involving specific accounts:
- JavaScript
- Python
- cURL
const ws = new WebSocket('wss://solana-mainnet.chainstream.syndica.io/api-key/YOUR_API_KEY')
ws.onopen = () => {
console.log('Connected to ChainStream')
// Subscribe to filtered transaction events
ws.send(
JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'transactionsSubscribe',
params: {
network: 'solana-mainnet',
verified: false,
filter: {
commitment: 'confirmed',
excludeVotes: true,
accountKeys: {
// All these keys must be present
all: ['675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'],
// At least one of these must be present
oneOf: [
'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
],
},
},
},
})
)
}
ws.onmessage = (event) => {
const data = JSON.parse(event.data)
if (data.result) {
console.log('Subscription ID:', data.result)
} else if (data.method === 'transactionNotification') {
const tx = data.params.result
console.log('Transaction:', tx.context.signature)
console.log('Slot:', tx.value.slot)
}
}
ws.onerror = (error) => {
console.error('ChainStream error:', error)
}
ws.onclose = () => {
console.log('ChainStream connection closed')
}
import asyncio
import websockets
import json
async def subscribe_to_transactions():
uri = 'wss://solana-mainnet.chainstream.syndica.io/api-key/YOUR_API_KEY'
async with websockets.connect(uri) as websocket:
# Subscribe to filtered transaction events
await websocket.send(json.dumps({
'jsonrpc': '2.0',
'id': 1,
'method': 'transactionsSubscribe',
'params': {
'network': 'solana-mainnet',
'verified': False,
'filter': {
'commitment': 'confirmed',
'excludeVotes': True,
'accountKeys': {
'all': ['675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'],
'oneOf': [
'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
]
}
}
}
}))
# Listen for events
async for message in websocket:
data = json.loads(message)
if 'result' in data:
print(f"Subscription ID: {data['result']}")
elif data.get('method') == 'transactionNotification':
tx = data['params']['result']
print(f"Transaction: {tx['context']['signature']}")
print(f"Slot: {tx['value']['slot']}")
# Run the subscription
asyncio.run(subscribe_to_transactions())
# ChainStream requires WebSocket connection, not HTTP
# Use wscat for command-line testing:
wscat -c wss://solana-mainnet.chainstream.syndica.io/api-key/YOUR_API_KEY
# Then send:
{
"jsonrpc": "2.0",
"id": 1,
"method": "transactionsSubscribe",
"params": {
"network": "solana-mainnet",
"verified": false,
"filter": {
"commitment": "confirmed",
"excludeVotes": true,
"accountKeys": {
"all": ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"],
"oneOf": [
"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
]
}
}
}
}
Understanding the Request
ChainStream subscription requests include these key parameters:
network- The Solana network (solana-mainnetorsolana-devnet). Required for all subscriptions.verified- Whentrue, waits for multiple validators to confirm transactions at theprocessedcommitment level (adds ~400ms maximum delay). Only supported withcommitment: "processed".filter.commitment- Commitment level:processed(fastest),confirmed(balanced), orfinalized(safest).filter.excludeVotes- Whentrue, filters out validator vote transactions to reduce noise.filter.accountKeys- Filter transactions by accounts:all: Transaction must include all specified keysoneOf: Transaction must include at least one specified keyexclude: Transaction must not include any specified keys
Expected Response
Subscription Confirmation:
{
"jsonrpc": "2.0",
"result": 446257156701906,
"id": 1
}
Disconnecting the WebSocket automatically unsubscribes all active subscriptions.
Transaction Notification:
{
"jsonrpc": "2.0",
"method": "transactionNotification",
"params": {
"subscription": 446257156701906,
"result": {
"context": {
"slotStatus": "confirmed",
"nodeTime": "2025-10-01T22:20:38.121983224Z",
"signature": "5k5MgvCWxrZ2haxKKDjigAp2oPoaCEYUf2Ct4qDfhUTT...",
"index": 62,
"isVote": false
},
"value": {
"slot": 370568409,
"meta": {
"err": null,
"fee": 5000,
"logMessages": [
"Program invoke...",
"Program success"
],
"computeUnitsConsumed": 28215,
"innerInstructions": [],
"loadedAddresses": {
"writable": [],
"readonly": []
},
"postBalances": [
49809089923,
...
],
"postTokenBalances": [],
"preBalances": [
49809098321,
...
],
"preTokenBalances": [],
"rewards": [],
"returnData": null,
"costUnits": 1939
},
"transaction": {
"message": {
"accountKeys": [
"4dxRtLucVXZ4o9drN5jtCs5X9TJdv79KwPDp4fsVqtqh",
...
],
"version": 0,
"addressTableLookups": [],
"header": {
"numReadonlySignedAccounts": 0,
"numReadonlyUnsignedAccounts": 3,
"numRequiredSignatures": 1
},
"instructions": [
{
"programIdIndex": 4,
"accounts": [
0,
...
],
"data": "9CJyjpsEQ4fyzLcwYUZS2uzaMe2PJUdJ18744eCk63M8g2HF3B8PFdu14Sq4rJnrKdLQdrruQyFkAcybovQ5RXwHQ"
},
...
],
"recentBlockhash": "4JsY3dvQaRTTwrYvAqdRpcmJTvkmryvF5SsEXu7GYLVj"
},
"messageHash": "6ChShqpS1zxurZ2gNpvrGWUtK2NXPS6RxicHJkhZmsHj",
"signatures": [
"5k5MgvCWxrZ2haxKKDjigAp2oPoaCEYUf2Ct4qDfhUTT..."
]
}
}
}
}
}
Available Stream Types
Beyond transaction streams, ChainStream supports:
slotSubscribe- Slot progression events showing blockchain advancementblockSubscribe- Complete block data including all transactionsencodedBlockSubscribe- Encoded block data for efficient processing
For detailed documentation on each stream type including payload examples and filtering options, see the ChainStream API reference.
Unsubscribe from Events
Stop receiving notifications using the subscription ID:
- JavaScript
ws.send(
JSON.stringify({
jsonrpc: '2.0',
id: 3,
method: 'transactionsUnsubscribe',
params: [446257156701906], // Your subscription ID
})
)
Monitor Your Streams

After connecting, monitor your ChainStream activity on the analytics dashboard:
- Active subscription count and connection status
- Message and data throughput in real-time
- Historical usage patterns and trends
- Connection health and error rates
Access your ChainStream analytics from the ChainStream API page in your dashboard.
FAQ and Troubleshooting
What's the difference between WebSocket subscriptions and ChainStream?
Standard WebSocket subscriptions connect
directly to whichever validator your connection reaches and expose the base Solana RPC methods
(slotSubscribe, logsSubscribe, accountSubscribe, etc.). That keeps them lightweight and
available on every plan, but you own the operational work when the validator you hit lags or
restarts.
ChainStream is a separate endpoint
(wss://solana-mainnet.chainstream.syndica.io/api-key/...) that streams data from the
validator's geyser interface. It
aggregates streams from multiple validators using a "fastest-wins" strategy to provide redundancy
and high availability. ChainStream also unlocks capabilities standard WebSockets do not provide:
transactionsSubscribe,blockSubscribe, andencodedBlockSubscribefor full transaction/block payload streaming- Rich account filtering via
all,oneOf, andexcludematchers plus theverifiedflag for multi-validator confirmation - Built-in delivery guarantees so you no longer maintain resend buffers or custom analytics
ChainStream requires Scale Mode or higher (see plans and pricing); standard WebSockets work on all plans.
When should I use ChainStream verified transactions?
Set verified: true when you need confirmation that multiple validators have processed a
transaction before acting on it. This adds up to ~400ms delay but provides additional data
correctness guarantees.
Only use verified: true with commitment: "processed". For confirmed or finalized commitment,
the network itself provides multi-validator consensus, making the verified flag unnecessary.
How many concurrent ChainStream streams can I have?
Scale Mode includes one ChainStream subscription. You can add up to 9 additional subscriptions ($0.14/hour each) for a maximum of 10 concurrent streams. Each subscription represents one WebSocket connection with one or more active event subscriptions. You can also configure custom rate limits for ChainStream subscriptions on your API keys. Refer to plans and pricing for current limits.
What commitment level should I use with ChainStream?
Choose based on your use case:
- Processed: Fastest notifications as transactions are processed by the validator, ideal for price feeds and real-time applications.
- Confirmed: Balanced option with network consensus, good for most applications.
- Finalized: Guaranteed by network finality, ~13 second delay, required for financial settlement.
Review the commitment levels documentation for deeper detail.
Can I filter ChainStream traffic by multiple account keys?
Yes, the accountKeys filter supports three operators:
all: Transaction must include all specified keysoneOf: Transaction must include at least one specified keyexclude: Transaction must not include any specified keys
You can combine operators—filters apply in order: exclude first, then all, then oneOf. See the
ChainStream API documentation for examples.
How do I reduce ChainStream bandwidth usage?
Syndica automatically offers
Per-Message Deflate compression (RFC 7692)
on every ChainStream endpoint, typically reducing bandwidth by 70-90%. Most client libraries
negotiate this extension automatically, but some require you to enable compression explicitly or
install an additional dependency—check your client's docs to confirm it advertises
permessage-deflate during the handshake.
For transaction-heavy streams you can further trim payloads by:
- Setting
metadataOnly: trueto receive signatures, slots, and metadata without full transaction data. - Using
excludeVotes: trueto drop validator vote transactions. - Applying
accountKeysfilters to limit events to the accounts you care about.
Why is my ChainStream connection failing?
Common issues:
- Scale Mode not enabled: ChainStream requires Scale Mode or higher. Upgrade your plan or review plans and pricing.
- ChainStream not enabled: Enable ChainStream from your dashboard's ChainStream API page.
- No available streams / Error 7429 (
subscription method exceeded limit): More concurrent ChainStream streams are active than your plan allows (Scale includes one stream). Close unused streams or enable additional streams—see plans and pricing for current costs. - Invalid API key: Verify your API key has ChainStream access enabled.
Check your subscription status and limits on the ChainStream API page in your dashboard.
What happens if a validator goes offline when using ChainStream?
ChainStream automatically routes around validator outages. Since data is aggregated from multiple validators, you continue receiving events from healthy validators without interruption. This multi-validator redundancy is a key advantage over single-node WebSocket connections.
How do I use ChainStream with devnet?
Use the devnet endpoint and set the network parameter to solana-devnet:
const ws = new WebSocket('wss://solana-devnet.chainstream.syndica.io/api-key/YOUR_API_KEY')
ws.send(
JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'transactionsSubscribe',
params: {
network: 'solana-devnet', // Use devnet
verified: false,
filter: { commitment: 'confirmed' },
},
})
)
What latency should I expect from ChainStream?
Once a validator feeding ChainStream timestamps an event at the geyser interface, it takes ≤10 ms to
reach clients co-located in the same AWS region (RTT under 10 ms). Over typical public-internet
links you can expect 50–100 ms end-to-end latency, depending on your ISP and geography. To measure
your real-world performance, compare the nodeTime field (UTC timestamp) in each ChainStream
message with your local clock and log the delta over time.
What You Can Do Next
Now that you're streaming with ChainStream:
- Explore Stream Types - Transaction, block, slot, and encoded block subscriptions
- ChainStream Overview - Multi-validator architecture and features
- Connection Guide - Best practices for reconnection and error handling
- WebSocket Compression - Optimize bandwidth usage
- Monitor Your Usage - Track ChainStream performance and costs
- Understand Commitment Levels - Choose the right balance of speed vs. safety