eth_getBalance: Read an Address's ETH Balance
eth_getBalance•Read method•Ethereum JSON-RPCeth_getBalance returns the native ETH balance of an address, in wei, at a block you choose. It is one of the simplest methods in the API and the source of two of its most common bugs: reading the number as ether instead of wei, and expecting it to know anything about tokens.
Try eth_getBalance
curl -s https://ethereum-rpc.publicnode.com \
-X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_getBalance",
"params": [
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"latest"
]
}'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_getBalance does
Balances are part of Ethereum's state, not its history. The node looks up the account in the state trie of the block you named and reports the balance stored there. That applies to externally owned accounts and contracts alike; a contract holding ETH is just an account with a balance, and an address that has never been used returns 0x0 rather than an error.
The block parameter is what makes the method interesting. latest reads the head, finalized reads settled state, a hex block number reads history, and pending reads the node's own projection including transactions sitting in its mempool. Historical reads only work while the node still holds that block's state, which is the practical limit on how far back you can go.
The result is wei: 18 decimal places, routinely a number in the 10^18 range and beyond. It is returned as a hex quantity precisely because it does not fit in a double-precision float, so the value has to be parsed into a big integer and formatted for display rather than read as a number.
Parameters
| # | Name | Type | Description |
|---|---|---|---|
| 1 | address | string | 20-byte address to read. Case is irrelevant to the node; EIP-55 checksumming is a client-side convention. |
| 2 | blockParameter | string | Hex block number or one of latest, pending, safe, finalized, earliest. Also accepts an EIP-1898 object with blockHash or blockNumber. |
What it returns
A hex quantity: the balance in wei. 0x0 means the account holds no ETH, whether or not it has ever been used; there is no separate "account does not exist" answer.
Only native ETH is reported. Token balances are contract storage, not account balance, so an address holding a million USDC and no ETH returns 0x0 here.
Example response
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x5c0a880814b3b96c"
}0x5c0a880814b3b96c is 6,632,262,969,544,915,308 wei, about 6.63 ETH, as of the block this page was written against. The live call returns whatever the address holds now.
eth_getBalance with ethers.js
import { JsonRpcProvider, formatEther } from "ethers";
const provider = new JsonRpcProvider("https://ethereum-rpc.publicnode.com");
const address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
const wei = await provider.getBalance(address); // bigint, never a number
console.log(formatEther(wei), "ETH");
// same call pinned to a block the node still has state for
const head = await provider.getBlockNumber();
const earlier = await provider.getBalance(address, head - 100);
console.log("delta over 100 blocks:", formatEther(wei - earlier));Gotchas and common errors
The number does not fit in a JavaScript number
One ether is 10^18 wei, which is far above the 2^53 limit where JavaScript numbers stop being exact. Number(result) on a balance silently rounds; parseInt is worse. Parse into a BigInt and format only at the edge, which is what ethers' formatEther and web3's fromWei do for you.
It knows nothing about tokens
USDC, WETH and every other ERC-20 keep balances in their own contract storage. Reading one means an eth_call to balanceOf(address) on the token contract, and remembering that each token sets its own decimals: 6 for USDC, 18 for most others. A wallet screen showing a dozen assets is a dozen eth_call requests plus this one.
Historical balances need historical state
Full nodes keep recent state and prune the rest, so a balance query for an old block fails with errors like "missing trie node" or "required historical state unavailable" rather than returning a stale number. Reconstructing a balance timeline over months is an archive workload; on BLAZED.sh, standard plans run tip-of-chain nodes and archive access is an Enterprise feature.
Balances change without transactions
You cannot reconstruct an account's balance history from its transaction list. Validator withdrawals credit ETH through the consensus layer with no transaction at all, a block's fee recipient is credited directly, and a self-destructing contract can push ETH into an address that never asked for it. If the numbers do not add up, this is usually why.
pending is a local opinion
Reading at pending includes the effect of transactions in this node's mempool, which is a different set on every node and changes between calls. It is useful for deciding whether your own just-broadcast transaction has been accounted for locally, and misleading for anything that has to agree with another machine.
What eth_getBalance costs on BLAZED.sh
eth_getBalance costs 1 credit per call on BLAZED.sh and returns a few dozen bytes, so the over-100KB surcharge never applies. Cost only becomes a topic when the pattern is fan-out: a portfolio tracker checking thousands of addresses every block is issuing thousands of requests, each trivially small. That workload is where a local socket changes the economics, since every one of those calls is a sub-10ms round-trip on the node host instead of a queued request against a shared gateway.
See the full credit price listeth_getBalance: frequently asked questions
Is eth_getBalance returning ether or wei?
Wei, as a hex quantity. Divide by 10^18 for ether, and do it with big-integer arithmetic; a plain JavaScript number cannot represent wei balances exactly.
How do I get an ERC-20 token balance?
Call the token contract with eth_call and the balanceOf(address) selector; the token's own storage holds the balance. eth_getBalance only ever reports native ETH.
Can I read a balance at an old block?
Yes, pass a hex block number, but only while the node still has that block's state. Beyond the pruning window you need archive state, which on BLAZED.sh is an Enterprise feature.
Why does a contract address have a balance?
Because contracts are accounts. Any address can hold ETH, and contracts routinely do; the balance you read is the ETH the contract itself controls, not anything it tracks internally for its users.
Why does the balance not match the sum of the transactions?
Validator withdrawals, block fee payments and forced transfers from a self-destructing contract all move ETH without producing a transaction on the account. Balance is state, not the replay of a transaction list.
Call eth_getBalance 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.