Monitor blockchain activity in real-time using GraphQL subscriptions. Track blocks, transactions, and events as they occur without polling.
wss://graph.kadindexer.io/graphql
Protocol: graphql-ws
Subscription Limits by Tier:
- Free: 5 concurrent subscriptions
- Developer: 25 concurrent subscriptions
- Team: Custom limits
Subscribe to new blocks as they are mined on specified chains.
subscription NewBlocks($chainIds: [String!]) {
newBlocks(chainIds: $chainIds, quantity: 20) {
hash
height
chainId
creationTime
minerAccount {
accountName
}
transactions(first: 5) {
totalCount
edges {
node {
hash
}
}
}
totalGasUsedInKda
}
}
Variables:
{
"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
Subscribe to blocks after they reach specified confirmation depth.
subscription ConfirmedBlocks($minimumDepth: Int!) {
newBlocksFromDepth(
chainIds: ["0", "1"]
minimumDepth: $minimumDepth
quantity: 10
) {
hash
height
chainId
canonical
creationTime
transactions {
totalCount
}
}
}
Variables:
{
"minimumDepth": 5
}
Parameters:
minimumDepth
- Required confirmations before emissionchainIds
- Filter specific chainsquantity
- 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
Track a specific transaction by request key until it's confirmed.
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:
{
"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
Subscribe to all confirmed transactions in real-time.
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
Monitor specific blockchain events with filtering.
subscription CoinTransfers($chainId: String) {
events(
qualifiedEventName: "coin.TRANSFER"
chainId: $chainId
minimumDepth: 5
quantity: 20
) {
name
parameterText
block {
height
creationTime
}
transaction {
hash
}
}
}
Variables:
{
"chainId": "1"
}
Parameters:
qualifiedEventName
- Event name (format:module.EVENT
) (required)chainId
- Filter specific chainminimumDepth
- Wait for confirmationsparametersFilter
- JSON filter for event parametersquantity
- Initial payload size
Common Event Names:
coin.TRANSFER
- KDA transferscoin.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
Filter events by parameter values using JSON filters.
subscription TransfersFromAccount($accountName: String!) {
events(
qualifiedEventName: "coin.TRANSFER"
parametersFilter: "{\"array_starts_with\":\"k:5a2afbc...\"}"
minimumDepth: 5
) {
parameterText
block {
height
}
}
}
Filter Syntax:
{
"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
Combine multiple subscriptions for comprehensive monitoring.
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
subscription WalletConfirmation($requestKey: String!) {
transaction(requestKey: $requestKey) {
hash
result {
... on TransactionResult {
gas
goodResult
badResult
block {
height
}
}
}
}
}
// Usage
const unsubscribe = client.subscribe(query, {
requestKey: userTransactionHash
}, {
next: (data) => {
if (data.transaction.result.goodResult) {
showSuccess('Transaction confirmed!');
} else {
showError('Transaction failed');
}
unsubscribe();
}
});
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
}
}
subscription MiningDashboard($minerAccount: String!) {
newBlocks(chainIds: ["0", "1", "2", "3"]) {
height
chainId
minerAccount {
accountName
balance
}
totalGasUsedInKda
}
}
Filter client-side for specific miner:
client.subscribe(query, {}, {
next: (data) => {
const block = data.newBlocks[0];
if (block.minerAccount.accountName === targetMiner) {
updateMiningStats(block);
}
}
});
subscription ExchangeDeposits($exchangeAddress: String!) {
events(
qualifiedEventName: "coin.TRANSFER"
parametersFilter: "{\"array_contains\":\"k:exchange-address\"}"
minimumDepth: 20
) {
parameterText
block {
height
}
}
}
# ❌ Over-fetching
subscription {
newBlocks(chainIds: ["0"]) {
hash
height
chainId
creationTime
difficulty
nonce
weight
powHash
target
# ... all fields
}
}
# ✅ Minimal
subscription {
newBlocks(chainIds: ["0"]) {
hash
height
}
}
# ❌ Broad (high message volume)
subscription {
events(qualifiedEventName: "coin.TRANSFER") {
parameterText
}
}
# ✅ Filtered (targeted)
subscription {
events(
qualifiedEventName: "coin.TRANSFER"
chainId: "0"
minimumDepth: 5
) {
parameterText
}
}
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());
});
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;
}
Check:
- Event name spelling (case-sensitive)
- Chain ID matches event location
minimumDepth
not too high- Connection still active
- Subscription within tier limits
Solutions:
- Reduce requested fields
- Apply more restrictive filters
- Check network latency
- Verify keepAlive configuration
Solution: Use quantity
parameter to get recent data on connection:
subscription {
newBlocks(chainIds: ["0"], quantity: 20) {
hash
height
}
}
- Manage connections: Connection Management →
- Query historical data: Query Optimization →
- Full schema: GraphQL API Reference →
Need help? toni@hackachain.io