eth_blockNumber: Get the Current Block Height

eth_blockNumberRead methodEthereum JSON-RPC

eth_blockNumber takes no parameters and returns the number of the most recent block the node has imported. It is the health check everyone writes first, the cursor every indexer keeps, and, because it is so cheap to call, the method most often abused in a polling loop.

1 credit
per call on BLAZED.sh
Read
call type
0
parameters
All clients
client support

Try eth_blockNumber

Request as curl
curl -s https://ethereum-rpc.publicnode.com \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_blockNumber",
  "params": []
}'

Runs the example straight from your browser against the endpoint above. The prefilled URL is a third-party public endpoint, not run by BLAZED.sh.

What eth_blockNumber does

The answer is this node's opinion of the head. A node that is still syncing returns the height it has reached, not the height of the network, so a small number is a symptom of a syncing or stalled node rather than of a short chain. eth_syncing is the companion call that tells the two apart.

Post-Merge, blocks arrive on a 12-second slot schedule, and slots can be missed, so the number normally advances by one every 12 seconds and occasionally pauses for a slot. It can also move backwards: during a reorg the node drops one head and adopts another, so a number you read once is not a promise about what that height contains later.

The value is a hex quantity like any other in this API. Block heights are comfortably inside the range a JavaScript number represents exactly, so parsing with Number or parseInt on base 16 is safe here, unlike balances or wei-denominated fields.

Parameters

eth_blockNumber takes no parameters; send an empty params array. Some clients tolerate omitting the key entirely, but the empty array is what the spec asks for.

What it returns

A hex quantity holding the head block number, for example 0x18789a6 for block 25,659,814. There is no null case; a node always has a head, even if it is genesis.

What the number does not tell you is how settled that block is. For that, read the safe and finalized tags with eth_getBlockByNumber, which come from the consensus layer rather than from local import progress.

Example response

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x18789a6"
}

0x18789a6 is block 25,659,814. Run the example and you will get a larger number; mainnet adds one roughly every 12 seconds.

eth_blockNumber with ethers.js

import { JsonRpcProvider, WebSocketProvider } from "ethers";

const provider = new JsonRpcProvider("https://ethereum-rpc.publicnode.com");
console.log("head:", await provider.getBlockNumber());

// Do not poll this in a loop. Subscribe instead:
// inside a BLAZED.sh container the node is one local socket away
const ws = new WebSocketProvider("ws://eth:8545");
ws.on("block", (blockNumber) => {
  console.log("new head", blockNumber);
});

Gotchas and common errors

Polling it is the wrong pattern

Blocks arrive every 12 seconds, so a loop calling eth_blockNumber every 100ms wastes 119 of every 120 requests and still learns about the block later than a subscriber does. Open a WebSocket and subscribe to newHeads: the node pushes the header the moment it imports the block, and the same connection carries whatever follow-up calls the new block triggers.

A low number means the node is behind

During initial sync, and after any outage, the head this method reports is the node's own progress. Monitoring code that compares it against a hardcoded expectation, or against another provider, is really implementing a liveness check; eth_syncing does that properly by reporting the current and highest known block while a sync is in progress and false when it is done.

The number can go backwards

Reorgs replace the head, so an indexer that stores "processed up to N" must be prepared for N to belong to a block that no longer exists. Keep the block hash alongside the number and verify the parent chain as you advance, or stay behind the finalized tag where reorgs cannot reach.

Two endpoints disagree by design

Different nodes import a new block at slightly different moments, so comparing eth_blockNumber across providers will regularly show a one-block gap. That is propagation, not an error. It matters when you split reads across endpoints: a follow-up call routed to a node one block behind can miss data the first call implied exists.

What eth_blockNumber costs on BLAZED.sh

eth_blockNumber costs 1 credit per call on BLAZED.sh, the same as any other standard method, which is precisely why the polling habit is worth breaking: a one-second loop is 86,400 credits a day for information that changes 7,200 times. A newHeads subscription over WebSocket delivers the same signal as it happens, and on a co-located node that push arrives over a local socket rather than crossing the public internet.

See the full credit price list

eth_blockNumber: frequently asked questions

How often does eth_blockNumber change?

Roughly every 12 seconds, the length of a slot, with occasional pauses when a slot is missed. Polling faster than that only multiplies requests.

Is eth_blockNumber the same as the latest tag?

They refer to the same block. eth_blockNumber gives you the height as a value; latest is the tag other methods accept to mean that same head.

Why is my node's block number lower than the explorer's?

The node is syncing, stalled, or has lost peers. Call eth_syncing: while a sync is running it returns the current and highest known blocks, and it returns false once the node is caught up.

How do I watch for new blocks without polling?

Use eth_subscribe with newHeads over WebSocket, or eth_newBlockFilter with polling if you are stuck on HTTP. The subscription pushes each new header as the node imports it.

Call eth_blockNumber from the node itself

Deploy your container or script next to a synced Ethereum node. No rate limits, no compute units, sub-10ms local RPC.