Whole-Block Subscription (blockreq_newBlocks)
blockreq_newBlocks is a BlockReq subscription type for eth_subscribe. Each time the chain produces a block, you receive one standard eth_subscription notification whose params.result is the whole block with full transaction objects. It is the same object eth_getBlockByHash(hash, true) returns, with every field passed through as the node produced it.
It replaces the usual two-step loop: subscribe to newHeads, then call eth_getBlockByHash for every head you receive.
This is a BlockReq extension, not an Ethereum standard subscription. The built-in block listeners of ethers and viem do not use it, so send a raw eth_subscribe as in the examples below.
Supported chains
Available on the mainnets served by BlockReq's own nodes. Every other chain, and every testnet, refuses the subscription.
| Chain | Chain ID | WSS endpoint |
|---|---|---|
| Ethereum | 1 | wss://ethereum-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Base | 8453 | wss://base-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Arbitrum One | 42161 | wss://arbitrum-one-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| BNB Smart Chain | 56 | wss://bsc-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Robinhood | 4663 | wss://robinhood-mainnet-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Arc | 5042 | wss://arc-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
The subscription needs an endpoint with an API key. The public endpoint (/v1/rpc/public) refuses it.
Subscribe
Send exactly one parameter, "blockreq_newBlocks", written exactly like that. Any other shape is an invalid params error.
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_subscribe",
"params": ["blockreq_newBlocks"]
}The response carries the subscription ID, as for every other subscription:
{ "jsonrpc": "2.0", "id": 1, "result": "0x9a1c3f0e5b7d2a48c6e1f3b5d7a9c2e4" }Each new block then arrives as a notification. The example is shortened: values are illustrative, logsBloom is cut, and the transaction list holds one of the block's transactions.
{
"jsonrpc": "2.0",
"method": "eth_subscription",
"params": {
"subscription": "0x9a1c3f0e5b7d2a48c6e1f3b5d7a9c2e4",
"result": {
"number": "0x1312d00",
"hash": "0x5e1c0b7c2c4f0a9d6b3e8f21a7d4c9b05e6f1a2b3c4d5e6f708192a3b4c5d6e7",
"parentHash": "0x3b9f4a1d8c7e6052f1a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f809",
"timestamp": "0x6745a9c3",
"miner": "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97",
"gasLimit": "0x1c9c380",
"gasUsed": "0xb71b00",
"baseFeePerGas": "0x3b9aca00",
"logsBloom": "0x00a1…0004",
"transactionsRoot": "0x7a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
"stateRoot": "0x1f2e3d4c5b6a79880716253443526170899a8b7c6d5e4f30211203f4e5d6c7b8",
"receiptsRoot": "0x9c8b7a69584736251403f2e1d0c9b8a7968574635241302f1e0d1c2b3a495867",
"transactions": [
{
"hash": "0xa1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90",
"blockHash": "0x5e1c0b7c2c4f0a9d6b3e8f21a7d4c9b05e6f1a2b3c4d5e6f708192a3b4c5d6e7",
"blockNumber": "0x1312d00",
"transactionIndex": "0x0",
"from": "0x00000000219ab540356cbb839cbe05303d7705fa",
"to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"type": "0x2",
"nonce": "0x2a",
"gas": "0x186a0",
"maxFeePerGas": "0x77359400",
"maxPriorityFeePerGas": "0x59682f00",
"value": "0x0",
"input": "0xa9059cbb…",
"chainId": "0x1",
"accessList": []
}
],
"uncles": []
}
}
}Which fields appear depends on the chain and its latest hard fork: the notification carries what the node returns for eth_getBlockByHash(hash, true), including any chain-specific extension fields.
Cancel with eth_unsubscribe, passing the subscription ID:
{ "jsonrpc": "2.0", "id": 2, "method": "eth_unsubscribe", "params": ["0x9a1c3f0e5b7d2a48c6e1f3b5d7a9c2e4"] }Examples
Replace BRQ1P0000000000000000000000000000000000000000000000000000000 with your endpoint key, here read from the BLOCKREQ_API_KEY environment variable.
wscat
npx wscat -c "wss://ethereum-rpc.blockreq.com/v1/rpc/$BLOCKREQ_API_KEY" \
-x '{"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["blockreq_newBlocks"]}' -w 60Node.js
Node.js 22 or later, no packages needed:
const ws = new WebSocket(`wss://ethereum-rpc.blockreq.com/v1/rpc/${process.env.BLOCKREQ_API_KEY}`);
ws.addEventListener("open", () => {
ws.send(JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_subscribe", params: ["blockreq_newBlocks"] }));
});
let lastNumber = null;
ws.addEventListener("message", (event) => {
const message = JSON.parse(event.data);
if (message.error) {
console.error(message.error.code, message.error.message);
ws.close();
return;
}
if (message.method !== "eth_subscription") {
console.log("subscription id:", message.result);
return;
}
const block = message.params.result;
const number = Number(block.number);
if (lastNumber !== null && number > lastNumber + 1) {
console.warn(`blocks ${lastNumber + 1}..${number - 1} were not pushed; fetch them with eth_getBlockByNumber`);
}
lastNumber = number;
console.log(number, block.hash, `${block.transactions.length} transactions`);
});Python
Python 3.9 or later with pip install websockets:
import asyncio
import json
import os
import websockets
URL = f"wss://ethereum-rpc.blockreq.com/v1/rpc/{os.environ['BLOCKREQ_API_KEY']}"
async def main() -> None:
async with websockets.connect(URL, max_size=None) as ws:
await ws.send(json.dumps({"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["blockreq_newBlocks"]}))
last_number = None
async for raw in ws:
message = json.loads(raw)
if "error" in message:
print(message["error"]["code"], message["error"]["message"])
return
if message.get("method") != "eth_subscription":
print("subscription id:", message["result"])
continue
block = message["params"]["result"]
number = int(block["number"], 16)
if last_number is not None and number > last_number + 1:
print(f"blocks {last_number + 1}..{number - 1} were not pushed; fetch them with eth_getBlockByNumber")
last_number = number
print(number, block["hash"], f"{len(block['transactions'])} transactions")
asyncio.run(main())max_size=None lifts the default 1 MiB message limit of the websockets library, which an Ethereum block can exceed.
Errors
A refused subscription is not counted as a Request.
| Code | When | What to do |
|---|---|---|
-32601 | The chain does not offer the subscription, or the connection has no API key (public endpoint). The message is subscription blockreq_newBlocks is not available on this network or endpoint. | Use one of the supported chains with a keyed endpoint. |
-32000 | The subscription capacity of this network is full for the moment. The message starts blockreq_newBlocks subscriptions are temporarily unavailable on this network and suggests trying again later. | Subscribe again a little later. |
Request Counting
eth_subscribecounts 1 Request, like any request.- Each whole-block notification delivered to you counts 2 Requests: the
newHeadsnotification it replaces, plus the block fetch you would otherwise send. A block you are not sent costs nothing. - Refused subscriptions count nothing.
See Request Counting for the general rule.
Reorgs and gaps
The subscription follows newHeads:
- After a reorg, the replacing blocks are pushed as they arrive, so you can receive two blocks with the same
number. UsenumberandparentHashto decide which blocks are on your chain. - If the node cannot give a block's contents in time, that block is not pushed and you see the block number jump. A skipped block is not sent later, and nothing is replayed after you connect again. If you need every block, compare each
numberwith the previous one and fetch the missing blocks witheth_getBlockByNumber.
Message size
A whole block is far larger than a head. An Ethereum block is roughly 0.5-0.7 MB of JSON, a BNB Smart Chain block about 0.1 MB, and a block on the other chains a few KB to a few tens of KB. Messages are not compressed. A client that reads too slowly is disconnected, as for every other subscription, so read messages as they arrive and do heavy work off the socket loop.
Compared with newHeads
newHeads | blockreq_newBlocks | |
|---|---|---|
| Standard Ethereum subscription | Yes | No, a BlockReq extension |
| Notification | Block header | Whole block with full transaction objects |
| Getting the transactions | A second call to eth_getBlockByHash per head | In the notification |
| Requests per notification | 1 | 2 |
| Chains | Every chain with WSS | The six listed above |
| Access | Public endpoint or keyed endpoint | Keyed endpoint only |
| Message size | A header | The whole block, up to about 0.7 MB |
Use newHeads when you only need to know that a block exists. Use blockreq_newBlocks when you read the block's transactions for each new block.