# Real-Time Subscriptions Monitor blockchain activity in real-time using GraphQL subscriptions. Track blocks, transactions, and events as they occur without polling. ## WebSocket Endpoint ``` wss://graph.kadindexer.io/graphql ``` **Protocol:** `graphql-ws` **Subscription Limits by Tier:** - Free: 5 concurrent subscriptions - Developer: 25 concurrent subscriptions - Team: Custom limits ## newBlocks Subscribe to new blocks as they are mined on specified chains. ```graphql subscription NewBlocks($chainIds: [String!]) { newBlocks(chainIds: $chainIds, quantity: 20) { hash height chainId creationTime minerAccount { accountName } transactions(first: 5) { totalCount edges { node { hash } } } totalGasUsedInKda } } ``` **Variables:** ```json { "chainIds": ["0", "1", "2"] } ``` **Parameters:** - `chainIds` - Filter specific chains (omit for all 20 chains) - `quantity` - Initial payload size (default: 20) **Use Cases:** - Block explorer real-time feeds - Network health dashboards - Mining pool monitoring - Transaction volume tracking **Notes:** - Streams continuous updates for each new block - Returns latest blocks immediately on connection - Use `chainIds` to reduce message volume ## newBlocksFromDepth Subscribe to blocks after they reach specified confirmation depth. ```graphql subscription ConfirmedBlocks($minimumDepth: Int!) { newBlocksFromDepth( chainIds: ["0", "1"] minimumDepth: $minimumDepth quantity: 10 ) { hash height chainId canonical creationTime transactions { totalCount } } } ``` **Variables:** ```json { "minimumDepth": 5 } ``` **Parameters:** - `minimumDepth` - Required confirmations before emission - `chainIds` - Filter specific chains - `quantity` - Initial payload size **Recommended Depths:** - 5-10: Standard finality - 20+: Exchange deposits, high-value transactions **Use Cases:** - Exchange deposit confirmations - Settlement systems - Finality-dependent processing - Reorg-resistant notifications **Notes:** - Only emits blocks after reaching `minimumDepth` - Higher depth = greater finality, more latency - `canonical` flag indicates main chain inclusion ## transaction Track a specific transaction by request key until it's confirmed. ```graphql subscription TrackTransaction($requestKey: String!, $chainId: String) { transaction(requestKey: $requestKey, chainId: $chainId) { hash cmd { meta { chainId sender } } result { ... on TransactionResult { gas goodResult badResult block { height creationTime } } } } } ``` **Variables:** ```json { "requestKey": "abc123keyXYZ", "chainId": "0" } ``` **Parameters:** - `requestKey` - Transaction hash from submission (required) - `chainId` - Specific chain (omit to search all chains) **Use Cases:** - Wallet transaction confirmations - Payment processing - User notifications - Transaction status tracking **Notes:** - Emits once when transaction is mined and indexed - Omit `chainId` to monitor across all chains - Use `requestKey` from transaction submission response ## transactions Subscribe to all confirmed transactions in real-time. ```graphql subscription RecentTransactions { transactions(quantity: 20) { hash cmd { meta { sender chainId creationTime } } result { ... on TransactionResult { gas } } } } ``` **Parameters:** - `quantity` - Initial payload size (default: 20) **Use Cases:** - Network activity monitoring - Transaction feed displays - Real-time analytics - Activity dashboards **Notes:** - Streams all confirmed transactions across chains - High message volume - use carefully - Consider filtering by chain client-side ## events Monitor specific blockchain events with filtering. ```graphql subscription CoinTransfers($chainId: String) { events( qualifiedEventName: "coin.TRANSFER" chainId: $chainId minimumDepth: 5 quantity: 20 ) { name parameterText block { height creationTime } transaction { hash } } } ``` **Variables:** ```json { "chainId": "1" } ``` **Parameters:** - `qualifiedEventName` - Event name (format: `module.EVENT`) (required) - `chainId` - Filter specific chain - `minimumDepth` - Wait for confirmations - `parametersFilter` - JSON filter for event parameters - `quantity` - Initial payload size **Common Event Names:** - `coin.TRANSFER` - KDA transfers - `coin.ALLOCATION` - Gas allocations - Custom events: `free.my-contract.EVENT_NAME` **Use Cases:** - Token transfer notifications - DeFi protocol monitoring - Smart contract event tracking - Cross-chain activity alerts **Notes:** - Event names are case-sensitive - Use `minimumDepth` for finality confidence - `parametersFilter` uses Prisma JSON filter syntax ## Event Parameter Filtering Filter events by parameter values using JSON filters. ```graphql subscription TransfersFromAccount($accountName: String!) { events( qualifiedEventName: "coin.TRANSFER" parametersFilter: "{\"array_starts_with\":\"k:5a2afbc...\"}" minimumDepth: 5 ) { parameterText block { height } } } ``` **Filter Syntax:** ```json { "parametersFilter": "{\"array_starts_with\":\"k:account123\"}" } ``` **Common Patterns:** - `{"array_starts_with":"value"}` - First element matches (sender) - `{"array_contains":"value"}` - Contains element anywhere - `{"string_contains":"substring"}` - String match **Use Cases:** - Account-specific notifications - Value threshold alerts - Address filtering - Custom parameter matching **Notes:** - Must be JSON-stringified Prisma filter - Use `array_starts_with` for sender in transfers - Combine with other filters for precision ## Multi-Subscription Pattern Combine multiple subscriptions for comprehensive monitoring. ```graphql subscription DashboardData { # New blocks on primary chains blocks: newBlocks(chainIds: ["0", "1", "8"]) { height chainId } # Confirmed transfers transfers: events( qualifiedEventName: "coin.TRANSFER" minimumDepth: 5 ) { parameterText } # Specific transaction myTx: transaction(requestKey: "abc123") { hash result { ... on TransactionResult { goodResult } } } } ``` **Use Cases:** - Comprehensive dashboards - Multi-chain monitoring - Parallel event tracking - Real-time analytics **Notes:** - Each subscription counts toward tier limit - Use aliases to distinguish results - Close unused subscriptions promptly ## Practical Examples ### Example 1: Wallet Transaction Confirmation ```graphql subscription WalletConfirmation($requestKey: String!) { transaction(requestKey: $requestKey) { hash result { ... on TransactionResult { gas goodResult badResult block { height } } } } } ``` ```javascript // Usage const unsubscribe = client.subscribe(query, { requestKey: userTransactionHash }, { next: (data) => { if (data.transaction.result.goodResult) { showSuccess('Transaction confirmed!'); } else { showError('Transaction failed'); } unsubscribe(); } }); ``` ### Example 2: DEX Activity Monitor ```graphql subscription DexActivity { swaps: events( qualifiedEventName: "free.my-dex.SWAP" chainId: "8" ) { parameterText block { creationTime } } liquidityAdds: events( qualifiedEventName: "free.my-dex.ADD_LIQUIDITY" chainId: "8" ) { parameterText } } ``` ### Example 3: Mining Pool Dashboard ```graphql subscription MiningDashboard($minerAccount: String!) { newBlocks(chainIds: ["0", "1", "2", "3"]) { height chainId minerAccount { accountName balance } totalGasUsedInKda } } ``` Filter client-side for specific miner: ```javascript client.subscribe(query, {}, { next: (data) => { const block = data.newBlocks[0]; if (block.minerAccount.accountName === targetMiner) { updateMiningStats(block); } } }); ``` ### Example 4: Exchange Deposit Monitor ```graphql subscription ExchangeDeposits($exchangeAddress: String!) { events( qualifiedEventName: "coin.TRANSFER" parametersFilter: "{\"array_contains\":\"k:exchange-address\"}" minimumDepth: 20 ) { parameterText block { height } } } ``` ## Best Practices ### Request Only Needed Fields ```graphql # ❌ Over-fetching subscription { newBlocks(chainIds: ["0"]) { hash height chainId creationTime difficulty nonce weight powHash target # ... all fields } } # ✅ Minimal subscription { newBlocks(chainIds: ["0"]) { hash height } } ``` ### Use Appropriate Filters ```graphql # ❌ Broad (high message volume) subscription { events(qualifiedEventName: "coin.TRANSFER") { parameterText } } # ✅ Filtered (targeted) subscription { events( qualifiedEventName: "coin.TRANSFER" chainId: "0" minimumDepth: 5 ) { parameterText } } ``` ### Close Unused Subscriptions ```javascript const subscriptions = new Set(); function subscribe(query, variables, handlers) { const unsubscribe = client.subscribe(query, variables, handlers); subscriptions.add(unsubscribe); return () => { unsubscribe(); subscriptions.delete(unsubscribe); }; } // Clean up on exit window.addEventListener('beforeunload', () => { subscriptions.forEach(unsub => unsub()); }); ``` ### Handle High-Frequency Updates ```javascript const buffer = []; let processing = false; client.subscribe(query, {}, { next: (data) => { buffer.push(data); if (!processing) processBuffer(); } }); async function processBuffer() { processing = true; while (buffer.length > 0) { const batch = buffer.splice(0, 10); await processBatch(batch); } processing = false; } ``` ## Troubleshooting ### Not Receiving Events **Check:** - Event name spelling (case-sensitive) - Chain ID matches event location - `minimumDepth` not too high - Connection still active - Subscription within tier limits ### High Latency **Solutions:** - Reduce requested fields - Apply more restrictive filters - Check network latency - Verify keepAlive configuration ### Missing Initial Data **Solution:** Use `quantity` parameter to get recent data on connection: ```graphql subscription { newBlocks(chainIds: ["0"], quantity: 20) { hash height } } ``` ## Next Steps - **Manage connections:** [Connection Management →](/guides/realtime/connection-management) - **Query historical data:** [Query Optimization →](/guides/advanced/query-optimization) - **Full schema:** [GraphQL API Reference →](https://docs.kadindexer.io/apis) **Need help?** [toni@hackachain.io](mailto:toni@hackachain.io)