Ethereum Chain Scraper: Gas, Blocks & Balances
Pricing
from $0.56 / 1,000 result scrapeds
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
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Share

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 field | Appears on | Meaning |
|---|---|---|
method | all | The JSON-RPC method behind the row, e.g. eth_getBalance |
network, chainId, rpcEndpoint | all | Which chain, and the node that actually answered |
blockNumber | gasPrice, blockNumber, getBlock | Block height as a decimal integer |
gasPriceWei, gasPriceGwei | gasPrice | Current gas price, decoded from hex |
baseFeePerGasWei, baseFeePerGasGwei | gasPrice, getBlock | EIP-1559 base fee for the block |
nextBlockBaseFeePerGasWei/Gwei | gasPrice | The next block's base fee, what you'll actually pay if you send now |
maxPriorityFeePerGasWei/Gwei | gasPrice | Suggested priority tip |
address, blockTag | getBalance | The account queried and the point in history |
balanceWei, balanceEth, currency | getBalance | Exact balance, see the precision note below |
nonce | getBalance | Transaction count for the account |
blockHash, parentHash | getBlock | Block identity |
timestamp, timestampUnix | getBlock | ISO-8601 and raw Unix seconds |
transactionCount | getBlock | Number of transactions in the block |
miner | getBlock | Fee recipient / proposer address |
gasUsed, gasLimit, blockSizeBytes | getBlock | Block utilisation |
scrapedAt | all | Run 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
| Field | Type | Default | Notes |
|---|---|---|---|
queries | array | ["gasPrice","blockNumber"] | Required. Any of gasPrice, blockNumber, getBalance, getBlock. |
addresses | array | [] | 0x + 40 hex characters. Required when getBalance is selected, the run fails fast with a clear message otherwise. |
blockNumbers | array | ["latest"] | Decimal height, hex height, or one of latest, finalized, safe, earliest, pending. |
network | string | mainnet | mainnet, sepolia, base, arbitrum. |
rpcEndpoint | string | - | 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 exceedsNumber.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 aBigIntinternally and leaves as a decimal string, sobalanceWeiandgasPriceWeiare exact.balanceEthand the*Gweifields 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, notparseFloat. - 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
idbecause 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
getBalanceat an old block may be rejected even thoughgetBlockat the same height works fine. The failure is recorded per query inRUN_SUMMARY.failuresand the rest of the run continues. Use an archive node viarpcEndpointif you need deep history. - A chain-ID mismatch is a warning, not a stop. If a custom
rpcEndpointreports a different chain than thenetworkyou 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.