Ethereum Chain Scraper: Gas, Blocks & Balances avatar

Ethereum Chain Scraper: Gas, Blocks & Balances

Pricing

from $0.56 / 1,000 result scrapeds

Go to Apify Store
Ethereum Chain Scraper: Gas, Blocks & Balances

Ethereum Chain Scraper: Gas, Blocks & Balances

Query Ethereum through public JSON-RPC endpoints: gas price, block data, account balances and chain height. No API key, no third-party indexer.

Pricing

from $0.56 / 1,000 result scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

3 days ago

Last modified

Share

Ethereum Chain Scraper: Gas price, chain head, block headers and account balances, decoded from public JSON-RPC nodes with BigInt precision

Ethereum Chain Scraper reads Ethereum straight from public JSON-RPC nodes: current gas price and base fee, chain head, full block headers, and account balances with nonces. Works on mainnet, Sepolia, Base and Arbitrum One.

No credentials to manage. No third-party index sitting between you and the chain, this talks to the same JSON-RPC interface your wallet does, and every number it emits is decoded from the node's own hex.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/ethereum-rpc-scraper.md

What you get

One dataset row per query. Fields are emitted per method, so a gasPrice row carries fee fields and a getBalance row carries balance fields.

Output fieldAppears onMeaning
methodallThe JSON-RPC method behind the row, e.g. eth_getBalance
network, chainId, rpcEndpointallWhich chain, and the node that actually answered
blockNumbergasPrice, blockNumber, getBlockBlock height as a decimal integer
gasPriceWei, gasPriceGweigasPriceCurrent gas price, decoded from hex
baseFeePerGasWei, baseFeePerGasGweigasPrice, getBlockEIP-1559 base fee for the block
nextBlockBaseFeePerGasWei/GweigasPriceThe next block's base fee, what you'll actually pay if you send now
maxPriorityFeePerGasWei/GweigasPriceSuggested priority tip
address, blockTaggetBalanceThe account queried and the point in history
balanceWei, balanceEth, currencygetBalanceExact balance, see the precision note below
noncegetBalanceTransaction count for the account
blockHash, parentHashgetBlockBlock identity
timestamp, timestampUnixgetBlockISO-8601 and raw Unix seconds
transactionCountgetBlockNumber of transactions in the block
minergetBlockFee recipient / proposer address
gasUsed, gasLimit, blockSizeBytesgetBlockBlock utilisation
scrapedAtallRun timestamp

A RUN_SUMMARY record in the key-value store holds per-run counts, the queries used, per-query failures, which endpoints were used and which ones were rejected on the way there.

Common use cases

1. Monitor gas to time transactions. Schedule this every few minutes; nextBlockBaseFeePerGasGwei is the number to alert on.

{
"queries": ["gasPrice"],
"network": "mainnet"
}

2. Track treasury wallet balances. Reading at finalized rather than latest gives you a figure that cannot be reorged away.

{
"queries": ["getBalance"],
"addresses": [
"0x00000000219ab540356cBB839Cbe05303d7705Fa",
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
],
"blockNumbers": ["finalized"],
"network": "mainnet"
}

3. Build on-chain alerts without an indexer. Chain head plus block headers is enough to detect stalls, unusual block sizes or a change in proposer.

{
"queries": ["blockNumber", "getBlock"],
"blockNumbers": ["latest", "finalized"],
"network": "base"
}

Quick start

Simplest possible run:

{
"queries": ["gasPrice", "blockNumber"]
}

Everything at once on mainnet:

{
"queries": ["gasPrice", "blockNumber", "getBalance", "getBlock"],
"addresses": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
"blockNumbers": ["latest", "18000000"],
"network": "mainnet"
}

Through your own node:

{
"queries": ["gasPrice"],
"network": "mainnet",
"rpcEndpoint": "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
}

Input

FieldTypeDefaultNotes
queriesarray["gasPrice","blockNumber"]Required. Any of gasPrice, blockNumber, getBalance, getBlock.
addressesarray[]0x + 40 hex characters. Required when getBalance is selected, the run fails fast with a clear message otherwise.
blockNumbersarray["latest"]Decimal height, hex height, or one of latest, finalized, safe, earliest, pending.
networkstringmainnetmainnet, sepolia, base, arbitrum.
rpcEndpointstring-Optional. Full https URL of your own node; tried first, public nodes remain as fallbacks.

Which combinations make sense. blockNumbers does double duty: it lists the blocks getBlock fetches, and it sets the point in history at which getBalance reads. So getBalance with blockNumbers: ["latest","finalized"] and two addresses gives four rows, a small matrix, so keep an eye on it. gasPrice and blockNumber ignore both addresses and blockNumbers and always return exactly one row each, at the chain head.

Output example

gasPrice on mainnet:

{
"method": "eth_gasPrice",
"network": "mainnet",
"chainId": 1,
"rpcEndpoint": "https://ethereum-rpc.publicnode.com",
"blockNumber": 25695686,
"gasPriceWei": "192636783",
"gasPriceGwei": "0.192636783",
"baseFeePerGasWei": "192536783",
"baseFeePerGasGwei": "0.192536783",
"nextBlockBaseFeePerGasWei": "194809698",
"nextBlockBaseFeePerGasGwei": "0.194809698",
"maxPriorityFeePerGasWei": "100000",
"maxPriorityFeePerGasGwei": "0.0001",
"scrapedAt": "2026-08-06T11:43:53.191Z"
}

getBalance for the beacon deposit contract, note the 26-digit wei value survives intact:

{
"method": "eth_getBalance",
"network": "mainnet",
"chainId": 1,
"rpcEndpoint": "https://ethereum-rpc.publicnode.com",
"address": "0x00000000219ab540356cbb839cbe05303d7705fa",
"blockTag": "latest",
"balanceWei": "89299316879836548086007430",
"balanceEth": "89299316.87983654808600743",
"currency": "ETH",
"nonce": 1,
"scrapedAt": "2026-08-06T11:43:53.289Z"
}

getBlock:

{
"method": "eth_getBlockByNumber",
"network": "mainnet",
"chainId": 1,
"rpcEndpoint": "https://ethereum-rpc.publicnode.com",
"blockTag": "latest",
"blockNumber": 25695686,
"blockHash": "0x5072bea4d9c5cb8907c67b9a465d0b3e06767e73d5727e3a562c7f6669412fb6",
"parentHash": "0x80460ad541a0f9e93a7658e02534b4d2798672406ee818abc0bdf94345ebfa95",
"timestamp": "2026-08-06T11:43:47.000Z",
"timestampUnix": 1786016627,
"transactionCount": 509,
"miner": "0x396343362be2a4da1ce0c1c210945346fb82aa49",
"gasUsed": "32833224",
"gasLimit": "60000000",
"baseFeePerGasWei": "192536783",
"baseFeePerGasGwei": "0.192536783",
"blockSizeBytes": 247593,
"scrapedAt": "2026-08-06T11:43:53.346Z"
}

RUN_SUMMARY:

{
"network": "mainnet",
"chainId": 1,
"rpcEndpoint": "https://ethereum-rpc.publicnode.com",
"endpointsUsed": ["https://ethereum-rpc.publicnode.com"],
"endpointFailures": [
{ "endpoint": "https://cloudflare-eth.com", "error": "RPC error -32046: Cannot fulfill request" }
],
"queriesRequested": ["gasPrice"],
"queriesFailed": 0,
"failures": [],
"recordsSaved": 1,
"filters": {
"queries": ["gasPrice"],
"addresses": [],
"blockNumbers": ["latest"],
"network": "mainnet",
"rpcEndpoint": null
},
"finishedAt": "2026-08-06T11:44:59.062Z"
}

Limits and behaviour

  • Hex is decoded with BigInt, never with Number. A mainnet balance in wei routinely exceeds Number.MAX_SAFE_INTEGER, the beacon deposit contract's is a 26-digit integer, and parsing that as a float silently corrupts the low-order digits. Every wei value is a BigInt internally and leaves as a decimal string, so balanceWei and gasPriceWei are exact. balanceEth and the *Gwei fields are also strings, formatted by integer division rather than floating-point maths. Only small counters, block number, nonce, transaction count, timestamp, become JSON numbers, and even those are range-checked first. Parse them with a decimal library, not parseFloat.
  • Calls are batched, at a size the node will actually take. Requests go out as JSON-RPC batch arrays, up to 25 per POST, and responses are re-aligned by request id because nodes are free to answer out of order. Four queries against two addresses and two blocks is a handful of HTTP requests, not a dozen. Some free public nodes cap batch arrays well below 25 and reject an oversized array wholesale rather than trimming it, so the ceiling is measured once per endpoint right after the health check and the run splits to fit it.
  • Endpoints fail over automatically, in two ways. Before anything is read, candidates are probed for chain ID and head height, and the first healthy one wins. Then, if the chosen node later refuses an entire batch, the Actor moves to the next endpoint once and retries. Everything rejected on the way is listed in RUN_SUMMARY.endpointFailures, so you can see exactly which public node was down.
  • Public nodes rate-limit. They are shared infrastructure. For heavy or high-frequency use, put your own Alchemy/Infura/QuickNode URL in rpcEndpoint. It is tried first and the public nodes stay as a safety net.
  • Historical state is often pruned. Most public nodes keep only recent state, so getBalance at an old block may be rejected even though getBlock at the same height works fine. The failure is recorded per query in RUN_SUMMARY.failures and the rest of the run continues. Use an archive node via rpcEndpoint if you need deep history.
  • A chain-ID mismatch is a warning, not a stop. If a custom rpcEndpoint reports a different chain than the network you picked, the run continues but logs a loud warning, a self-hosted node on a fork is a legitimate thing to want.
  • One failed query never aborts the run. Per-query failures land in RUN_SUMMARY.failures; the Actor only errors out if no query produced a single row.
  • Read-only. No transactions are signed or sent, no private keys exist anywhere in this Actor, and every method it calls is a read.

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~ethereum-rpc-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"queries": ["gasPrice", "getBalance"],
"addresses": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
"network": "mainnet"
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/ethereum-rpc-scraper').call({
queries: ['gasPrice', 'getBalance'],
addresses: ['0x00000000219ab540356cBB839Cbe05303d7705Fa'],
blockNumbers: ['finalized'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const row of items) {
if (row.method === 'eth_gasPrice') console.log(`gas: ${row.gasPriceGwei} gwei`);
// BigInt, not Number, the wei value is far past float precision.
if (row.method === 'eth_getBalance') console.log(`${row.address}: ${BigInt(row.balanceWei)} wei`);
}

FAQ

Do I need a proxy? No. Proxy configuration is not required to run this Actor.

Do I need an Alchemy or Infura account? No, the built-in public endpoints work without one. Supply your own URL in rpcEndpoint if you want higher limits or archive-node history.

What happens if a node is unavailable? It is skipped during the health probe, or failed over mid-run, and recorded in RUN_SUMMARY.endpointFailures. The run continues on the next endpoint. Only if every endpoint for the network is down does the run fail.

Can I schedule it? Yes, that is the main use. Gas monitoring and balance tracking are both designed for recurring runs.

Why are balances strings instead of numbers? Because they are exact. Wei values exceed JavaScript's safe integer range, and JSON numbers would round them. Convert with BigInt(row.balanceWei).

Why is balanceEth also a string? Same reason. It is produced by integer division and formatted digit by digit, so it never loses precision. Feed it to a decimal library rather than parseFloat if the low digits matter.

Can it read ERC-20 token balances or call contracts? Not in this version. It covers native balances, gas, chain height and block headers. Token balances need eth_call with ABI encoding.

Can it fetch transactions or receipts? Not yet, getBlock returns the header plus a transaction count, not the transaction bodies.

Which network does balanceEth apply to? All four supported networks use ETH as their native currency, and the currency field states it explicitly on every balance row.

Can I integrate it with something else? Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.