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.

ChainChain IDWSS endpoint
Ethereum1wss://ethereum-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000
Base8453wss://base-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000
Arbitrum One42161wss://arbitrum-one-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000
BNB Smart Chain56wss://bsc-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000
Robinhood4663wss://robinhood-mainnet-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000
Arc5042wss://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 60

Node.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.

CodeWhenWhat to do
-32601The 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.
-32000The 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_subscribe counts 1 Request, like any request.
  • Each whole-block notification delivered to you counts 2 Requests: the newHeads notification 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. Use number and parentHash to 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 number with the previous one and fetch the missing blocks with eth_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

newHeadsblockreq_newBlocks
Standard Ethereum subscriptionYesNo, a BlockReq extension
NotificationBlock headerWhole block with full transaction objects
Getting the transactionsA second call to eth_getBlockByHash per headIn the notification
Requests per notification12
ChainsEvery chain with WSSThe six listed above
AccessPublic endpoint or keyed endpointKeyed endpoint only
Message sizeA headerThe 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.