Skip to main content
Once a backfill has caught up, keep running the same query on new blocks. Three things to get right: when to poll, what to do when there’s nothing new, and how to handle blocks that a reorg replaces.

The loop

bl is the Python client. The same structure works in any language and with the API directly. How it works:
  • No toBlock: each request reads up to the current head.
  • fromBlock stays at the first block that isn’t final yet. Every poll re-reads everything that could still change, so a reorg is handled by replacing your tentative rows with the new ones. You never diff or roll back.
  • Final rows are handed over once. The next start is the block after the finalized one, but never past the end of the page just read: when many new rows arrive, the loop pages through them before it waits.
  • Tentative rows are reported from every page that reaches the head, even when there are none, so they always describe the whole unfinalized tail, and a reorg that removes rows clears them too.
We tested this loop against a simulated chain with a moving head, a lagging finalized block, 4-block pages and a reorg of the tail: every final block was delivered exactly once, in its final version. On Robinhood Chain the unfinalized tail is 64 blocks (about 7 seconds); on Ethereum it’s about 13 minutes of blocks. Re-reading it every poll costs little: usually a few hundred rows.

When there’s nothing new

A request starting past the head returns no rows and next_block equal to your fromBlock. That’s the normal “nothing yet” answer, not an error. Wait and repeat.

Poll about once per block, not faster

Polling faster than blocks arrive returns mostly empty responses. Each one still counts toward your rate limit and is billed the 10 KB minimum. On pay-as-you-go (1 request per second), polling every second uses your whole rate limit and costs about 26 GB a month (≈ $13) in minimums alone. Polling Ethereum every 12 seconds costs about 2 GB a month (≈ $1). See Estimating costs.
On pay-as-you-go, the 1 request-per-second limit is shared by all your requests on all chains. A head-follower polling two chains every second leaves nothing for anything else. Poll less often, or use a subscription (10 requests per second).

Only final data

If your consumers can’t handle replaced rows, only hand over final rows: call on_final and ignore on_tentative. Your data then lags the head by the finality delay (about 7 seconds on Robinhood Chain, about 13 minutes on Ethereum) and never changes after you store it.

Detecting a reorg explicitly

If you want to log or count reorgs: keep the last response’s to_block and to_block_hash (present when to_block is above finalized_block). On the next poll, read that block’s hash again (select fields.block.hash for it). If it differs, a reorg replaced it. A reorg can replace a block without changing the height, so never use the height alone.