programSubscribe
Subscribe to a program to receive notifications when the lamports or data for an account owned by the given program changes
Common use cases
| Token balance monitoring | Subscribe to all token accounts for a specific mint or owner to track balance changes in real-time. Common for wallet UIs displaying live balance updates or DEX interfaces monitoring liquidity pool token holdings without polling. |
| DeFi protocol state tracking | Monitor all accounts owned by lending protocols, AMMs, or derivatives programs to track position changes, liquidation events, or pool rebalancing. More efficient than individual accountSubscribe calls when monitoring many related accounts (10-100+). |
| NFT marketplace activity | Track all NFT metadata accounts for a collection to detect listings, sales, or metadata updates. Enables real-time marketplace feeds and collection analytics dashboards without indexing infrastructure. |
| Whale wallet tracking | Use memcmp filters to monitor large token holders (whales) by subscribing to token accounts with high balances. Offset 64 + memcmp on balance field to detect when whale positions change, enabling copy-trading or market sentiment analysis. |
| Custom indexing and caching | Build lightweight real-time indexes for specific programs by subscribing with filters to capture account changes. Store filtered account data locally for fast queries, using programSubscribe as cheaper alternative to full indexer infrastructure for single-program focus. |
Parameters
subscriptionId (string, required)
Pubkey of the program_id, as base-58 encoded string
config (object, optional)
Configuration object containing the following fields:
Fields:
commitment(string): The commitment describes how finalized a block is at that point in time. See Configuring State Commitment.filters(array): Filter results using various filter objects. See Filtering. The resultant account must meet ALL filter criteria to be included in the returned resultsencoding(string): Encoding format for Account database58is slow.jsonParsedencoding attempts to use program-specific state parsers to return more human-readable and explicit account state data.- If
jsonParsedis requested but a parser cannot be found, the field falls back tobase64encoding, detectable when thedatafield is typestring.
Request
- wscat
- JavaScript
- Python
wscat -c wss://solana-mainnet.api.syndica.io -x '{
"jsonrpc": "2.0",
"id": 1,
"method": "programSubscribe",
"params": [
"11111111111111111111111111111111",
{
"encoding": "base64",
"filters": [{ "dataSize": 80 }]
}
]
}'
const ws = new WebSocket('wss://solana-mainnet.api.syndica.io');
ws.on('open', function open() {
ws.send(JSON.stringify({
"jsonrpc": "2.0",
"id": 1,
"method": "programSubscribe",
"params": [
"11111111111111111111111111111111",
{
"encoding": "base64",
"filters": [{ "dataSize": 80 }]
}
]
}));
});
ws.on('message', function incoming(data) {
console.log(data);
});
import websocket
import json
ws = websocket.create_connection('wss://solana-mainnet.api.syndica.io')
ws.send(json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "programSubscribe",
"params": [
"11111111111111111111111111111111",
{
"encoding": "base64",
"filters": [{ "dataSize": 80 }]
}
]
}))
result = ws.recv()
print(result)
ws.close()
Replace mainnet with devnet in the URL to query devnet instead.
Response
{
"jsonrpc": "2.0",
"result": 24040,
"id": 1
}
Response Fields
Return value: integer
Subscription id (needed to unsubscribe)
FAQ and Troubleshooting
How do I filter for multiple specific accounts when filters use AND logic?
You can't use OR filters—must create separate programSubscribe calls for each account or filter combination. For monitoring 2-5 disparate accounts, use individual accountSubscribe instead. For 10+ accounts with common patterns, use broader programSubscribe filter and filter client-side.
What's the difference between base58, base64, and jsonParsed encoding?
base58 is compact for public keys, base64 is standard for binary data, jsonParsed auto-decodes known program accounts (SPL Token, etc.) into JSON. Use jsonParsed for token accounts to avoid manual decoding; use base64+zstd for large accounts to reduce bandwidth; use base58 when you only need account keys.
Why do my subscriptions disconnect or miss updates at scale?
Most RPC providers limit concurrent subscriptions (100-1000 per connection) and notification throughput. For high-frequency programs, use confirmed commitment (faster) instead of finalized, apply tighter memcmp filters to reduce notification volume, or distribute subscriptions across multiple connections. Consider HTTP getProgramAccounts for initial snapshot.
How do memcmp filters work and what's the offset for token owner?
memcmp compares bytes at specified offset. For SPL Token accounts: offset 0 = mint (32 bytes), offset 32 = owner (32 bytes), offset 64 = amount (8 bytes). Use offset 32 + base58 owner pubkey to filter by token owner. Filters combine with AND logic—multiple memcmp filters must all match.
Should I use programSubscribe or getProgramAccounts for initial data load?
Use getProgramAccounts for initial snapshot (1000-10000+ accounts), then programSubscribe for real-time updates. getProgramAccounts is single HTTP call returning all matches; programSubscribe is WebSocket streaming only changes. Common pattern: snapshot on load, subscribe for live updates, unsubscribe on unmount.
Related Methods
programUnsubscribe
Cancel a programSubscribe subscription by subscription ID. Essential for cleanup to prevent memory leaks and excessive RPC node load. Always call in component unmount or before closing WebSocket.
accountSubscribe
Subscribe to a single specific account instead of all accounts in a program. Use when monitoring one known account rather than filtering program-wide. More efficient for 1-5 specific accounts; programSubscribe better for 10+ accounts or dynamic discovery.
getProgramAccounts
HTTP method to get a snapshot of all program accounts at a specific time. Use for initial state, then programSubscribe for real-time updates. Common pattern: getProgramAccounts (snapshot) → programSubscribe (live changes) → programUnsubscribe (cleanup).
logsSubscribe
Subscribe to transaction logs mentioning a program instead of account state changes. Use logsSubscribe for transaction monitoring (swaps, transfers, errors); use programSubscribe for account state tracking (balances, positions). Often used together for comprehensive program monitoring.
slotSubscribe
Get slot progression notifications to track when program account updates occur relative to chain state. Combine with programSubscribe to correlate account changes with specific slots for timing analysis or MEV detection.
External Resources
- Solana Official Documentation
- Anza agave: RPC PubSub Implementation - Official validator source code showing how WebSocket subscriptions are implemented, including programSubscribe filter processing, AND logic, commitment handling, and notification generation. Essential for understanding server-side filter behavior and limitations.
- Solana RPC: getProgramAccounts Filter Examples - Official RPC documentation showing memcmp filter syntax with examples. Demonstrates dataSize and memcmp offset/bytes structure. Same filter format used by programSubscribe—use for filtering by account data patterns (e.g., token owner at offset 32).