getLogs best practices
eth_getLogs can be an expensive read. Narrow filters and bounded ranges keep it reliable; an empty result only means no matching logs were returned for that filter and range.
Chunk your block ranges
jsjs
// paginate a large range in fixed-size chunksconst CHUNK = 2000nfor (let from = start; from <= end; from += CHUNK) {const to = from + CHUNK - 1n > end ? end : from + CHUNK - 1nconst logs = await client.request({method: 'eth_getLogs',params: [{fromBlock: '0x' + from.toString(16),toBlock: '0x' + to.toString(16),address: contractAddress,topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'],}],})// process logs…}
- Set
contractAddressto a contract deployed on the selected network and configureclient,startandendbefore using the example. - Filter by known addresses and topics. For non-anonymous events, topic 0 is the event signature hash; anonymous events omit that signature topic.
- The 2,000-block chunk is only a starting point. On range, payload or timeout errors, shrink it and retry; upstream limits vary.
- Where supported, use
finalizedas a conservative boundary under that chain's finality assumptions. A block number is a height, not a promise that its hash can never change. - Save progress only after a chunk is processed successfully. Track block hashes, handle reorgs and make repeated processing idempotent.
- For continuous tailing, poll bounded ranges on HTTP-only networks. A WebSocket-enabled network can use
logssubscriptions with HTTP backfill.