Skip to main content
The official clients are the easiest way to use Bloklake. You write queries with typed filters and field names; the response travels as Apache Arrow (about 2–2.5× smaller than JSON, so cheaper) and the client decodes it into plain JSON rows with exactly the values /query/json would return. They also do the things every production client needs:
  • Pagination: follow next_block over any range, reusing the prepared query and re-sending it if it expired.
  • Retries: rate limits (429), busy servers (503), server errors and dropped connections, honoring Retry-After.
  • Integrity: a response that ends early or carries fewer rows than announced is an error and is retried, never returned as a short result.
  • Types: field names are checked. In TypeScript, each row is typed with exactly the fields you selected.

Install

Node.js 18+ (or Bun, Deno), Python 3.9+, Rust 2024 edition. Set your API key in the BLOKLAKE_API_KEY environment variable, or pass it to the constructor.

Your first query

Pick the chain with chain ("eth", "rh"), or pass a full baseUrl / base_url. One client talks to one chain; create one per chain.

Reading a whole range

paginate follows next_block until toBlock (or the chain head if you leave toBlock out), one page at a time, so memory stays flat however long the range is. collect returns all pages merged into one, for ranges that fit in memory.
After the first page, only the prepared-query id and the range are sent.

What you get back

A page has logs, transactions and blocks (empty when not requested) and meta: fromBlock, toBlock, nextBlock, objects, archiveHeight, finalizedBlock, toBlockHash, queryId and unavailableFields (snake_case in Python and Rust). See Response metadata. Each client names fields in its own language’s style: In Python, every query key may be written in snake_case ("from_block", "address_set", "block_number") or in the API’s camelCase; the client sends camelCase either way. Give each key one way only. Values follow the JSON encoding: In Rust, query returns typed structs (Log, Transaction, Block, every field an Option); query_raw returns the rows as serde_json objects exactly as /query/json would.
Amounts are decimal strings because they exceed 64 bits. Use BigInt(x) in JavaScript, int(x) in Python, or parse to u128 in Rust.

Sets

In Rust: client.create_set("address", tokens, None), then LogFilter::new().address_set(&set.set_id). See Sets.

Errors

Errors that retrying can’t fix are raised at once, with the API’s status and code (see Errors) and the response’s request id:
Client-side failures have status 0 and code network, timeout or truncated (after the retries ran out).

More calls

Options

When to use the API directly

The clients return JSON-like rows. If you want Arrow tables (to write Parquet, or to load into pandas, Polars or DuckDB without conversion), or you use another language, read the Arrow response yourself: Reading Arrow has complete readers, and Export to Parquet shows the pattern.