chain_subscribeNewHeads - JSON-RPC Method
Description​
Creates a subscription to receive notifications about new block headers as they are produced. This JSON-RPC method is only available via WebSocket connections and provides real-time updates about the blockchain state.
Parameters​
This method does not require any parameters.
Returns​
Field | Type | Description |
---|---|---|
subscription | string | Subscription ID for managing the subscription |
Subscription Updates​
Each notification contains a block header with:
Field | Type | Description |
---|---|---|
parentHash | string | Hash of the parent block |
number | string | Block number (hex-encoded) |
stateRoot | string | Root of the state trie |
extrinsicsRoot | string | Root of the extrinsics trie |
digest | object | Digest items including consensus messages |
Request Example​
{
"jsonrpc": "2.0",
"method": "chain_subscribeNewHeads",
"params": [],
"id": 1
}
Response Example​
{
"jsonrpc": "2.0",
"result": "0x1234567890abcdef",
"id": 1
}
Subscription Update Example​
{
"jsonrpc": "2.0",
"method": "chain_newHead",
"params": {
"subscription": "0x1234567890abcdef",
"result": {
"parentHash": "0x4a84d1c5fc5c725b26a3c8e126d8f65e1c2d2dc5b3fcbc91e67e7637fa136789",
"number": "0x123456",
"stateRoot": "0x8f7a82e2e0f3e73f5e232e68de18144f6e7a52a6db39bb5e5e3d9ca6e1f72845",
"extrinsicsRoot": "0x2e6f9a7d2c4b3e1a8f5c6d9e4b1a7c3f8e5d2a9b6c4e1f8a5d3c2b9e7f6a4d38",
"digest": {
"logs": [
"0x0642414245b501013c0000009d2ef70f00000000"
]
}
}
}
}
Code Examples​
JavaScript (WebSocket)​
const WebSocket = require('ws');
const subscribeToNewHeads = () => {
const ws = new WebSocket('wss://api-polkadot.n.dwellir.com');
ws.on('open', () => {
// Subscribe to new heads
ws.send(JSON.stringify({
jsonrpc: '2.0',
method: 'chain_subscribeNewHeads',
params: [],
id: 1
}));
});
ws.on('message', (data) => {
const response = JSON.parse(data);
// Handle subscription confirmation
if (response.id === 1) {
console.log('Subscribed with ID:', response.result);
}
// Handle new block headers
if (response.method === 'chain_newHead') {
const header = response.params.result;
const blockNumber = parseInt(header.number, 16);
console.log(`New block #${blockNumber}:`, header.parentHash);
// Process block header
processNewBlock(header);
}
});
// Clean up subscription on disconnect
ws.on('close', () => {
console.log('WebSocket connection closed');
});
return ws;
};
const processNewBlock = (header) => {
// Implement your block processing logic
const blockNumber = parseInt(header.number, 16);
console.log(`Processing block ${blockNumber}`);
// Example: Check for specific events in digest
if (header.digest && header.digest.logs) {
header.digest.logs.forEach(log => {
// Process consensus messages
console.log('Digest log:', log);
});
}
};
Python (websockets)​
import asyncio
import json
import websockets
async def subscribe_new_heads():
uri = "wss://api-polkadot.n.dwellir.com"
async with websockets.connect(uri) as websocket:
# Subscribe to new heads
subscribe_msg = json.dumps({
"jsonrpc": "2.0",
"method": "chain_subscribeNewHeads",
"params": [],
"id": 1
})
await websocket.send(subscribe_msg)
subscription_id = None
async for message in websocket:
data = json.loads(message)
# Handle subscription confirmation
if data.get("id") == 1:
subscription_id = data["result"]
print(f"Subscribed with ID: {subscription_id}")
# Handle new block headers
elif data.get("method") == "chain_newHead":
header = data["params"]["result"]
block_number = int(header["number"], 16)
print(f"New block #{block_number}")
await process_block(header)
async def process_block(header):
"""Process new block header"""
block_number = int(header["number"], 16)
# Example: Track block production rate
print(f"Block {block_number} parent: {header['parentHash']}")
print(f"State root: {header['stateRoot']}")
# Monitor for reorganizations
# Store parent hash and detect if chain reorgs
# Run the subscription
asyncio.run(subscribe_new_heads())
TypeScript (@polkadot/api)​
import { ApiPromise, WsProvider } from '@polkadot/api';
async function subscribeToHeads() {
const provider = new WsProvider('wss://api-polkadot.n.dwellir.com');
const api = await ApiPromise.create({ provider });
// Subscribe to new headers
const unsubscribe = await api.rpc.chain.subscribeNewHeads((header) => {
console.log(`New block #${header.number.toNumber()}`);
console.log(` Parent: ${header.parentHash.toHex()}`);
console.log(` State Root: ${header.stateRoot.toHex()}`);
console.log(` Extrinsics Root: ${header.extrinsicsRoot.toHex()}`);
// Process digest items
header.digest.logs.forEach((log, index) => {
console.log(` Digest[${index}]: ${log.toHex()}`);
});
// Example: Monitor block production time
const blockTime = new Date();
console.log(` Received at: ${blockTime.toISOString()}`);
});
// Unsubscribe after some time
setTimeout(async () => {
unsubscribe();
await api.disconnect();
}, 60000); // 1 minute
}
subscribeToHeads().catch(console.error);
Block Production Monitoring​
class BlockMonitor {
constructor(wsUrl) {
this.wsUrl = wsUrl;
this.lastBlock = null;
this.blockTimes = [];
}
async start() {
const ws = new WebSocket(this.wsUrl);
ws.on('open', () => {
ws.send(JSON.stringify({
jsonrpc: '2.0',
method: 'chain_subscribeNewHeads',
params: [],
id: 1
}));
});
ws.on('message', (data) => {
const response = JSON.parse(data);
if (response.method === 'chain_newHead') {
const header = response.params.result;
const blockNumber = parseInt(header.number, 16);
const now = Date.now();
if (this.lastBlock) {
const timeDiff = now - this.lastBlock.timestamp;
this.blockTimes.push(timeDiff);
// Calculate average block time
const avgTime = this.blockTimes.reduce((a, b) => a + b, 0) / this.blockTimes.length;
console.log(`Block ${blockNumber} - Time since last: ${timeDiff}ms, Avg: ${avgTime.toFixed(0)}ms`);
}
this.lastBlock = {
number: blockNumber,
timestamp: now,
hash: header.parentHash
};
}
});
}
}
Use Cases​
- Block Explorer: Display real-time blockchain updates
- Transaction Monitoring: Watch for transaction inclusion
- Network Health: Monitor block production rate
- Reorganization Detection: Detect and handle chain reorgs
- Event Listening: Watch for specific on-chain events
Notes​
- WebSocket connection required (not available over HTTP)
- Headers are sent for all blocks, not just finalized ones
- Use
chain_subscribeFinalizedHeads
for finalized blocks only - Remember to handle reconnection logic for production systems
- Unsubscribe when no longer needed to free resources
Related Methods​
chain_subscribeFinalizedHeads
- Subscribe to finalized headerschain_getHeader
- Get specific block headerchain_getBlock
- Get full block with extrinsics