Skip to main content
Base has no public mempool — pending transactions are held privately by the sequencer, so eth_newPendingTransactionFilter and eth_subscribe("newPendingTransactions") return empty. To watch transactions in real time on Base, subscribe to Flashblocks: the sequencer streams pre-confirmed sub-blocks roughly every 200 ms over WebSocket. This guide streams individual transactions, filtered event logs, and the in-progress block, with tested Python and JavaScript.
Flashblocks is enabled by default on Chainstack Base endpoints. For how it works, see Flashblocks on Base.

Prerequisites

  • A Base mainnet WebSocket endpoint. On Chainstack, copy the WSS endpoint from your Base node’s Access and credentials tab — it looks like wss://base-mainnet.core.chainstack.com/<key>. The examples below use YOUR_CHAINSTACK_WSS_ENDPOINT as a placeholder.
  • Python 3.8+ with the websockets library (pip install websockets), or Node.js 22+ (the WebSocket client is built in, so there are no dependencies to install).

Why pending-transaction filters return empty on Base

Base is an OP Stack chain with a single sequencer. Transactions go to the sequencer’s private mempool and are never gossiped to RPC nodes, so a node has no public pending transactions to report. eth_newPendingTransactionFilter and eth_subscribe("newPendingTransactions") are accepted but always return empty — this is by design, not a node error, and it is the same on every Base RPC provider. See Mempool configurations for the per-protocol breakdown. Flashblocks fills this gap from the other side: instead of unconfirmed mempool transactions, it streams transactions the sequencer has already pre-confirmed into a 200 ms sub-block.

Stream individual transactions

eth_subscribe("newFlashblockTransactions") pushes each transaction as the sequencer pre-confirms it — one WebSocket message per transaction, roughly every 200 ms in batches. By default each message is a transaction hash. Pass true as a second parameter to receive the full transaction object instead.
You get a continuous stream of transaction hashes:

Full transaction objects

Pass true to receive the full transaction with its receipt fields (logs, status, gasUsed) embedded — useful when you want to act on the transaction without a follow-up eth_getTransactionReceipt call:
blockHash is null because the transaction is pre-confirmed, not yet sealed into a final block. blockNumber is the block the sequencer is currently building.

Stream filtered event logs

eth_subscribe("pendingLogs") streams event logs from pre-confirmed transactions, filtered by address and topics the same way as eth_getLogs. This example follows USDC transfers on Base:
Each log carries the standard fields, with blockHash set to zero until the block seals:

Stream the in-progress block

eth_subscribe("newFlashblocks") pushes the block the sequencer is currently building as a standard block object, refreshed roughly every 200 ms. Across updates the block number stays the same while transactions grows, and hash and stateRoot are zero until the block seals — it is the pending block, streamed:
The block number repeats while transactions accumulate, then advances to the next block — each 2-second block is built from about 10 Flashblocks.

Read pre-confirmed state over HTTP

If you need request-response access rather than a stream, the pending block tag reflects the latest Flashblock on Chainstack Base endpoints. eth_getBlockByNumber("pending"), eth_getTransactionReceipt, and eth_call with the pending tag all return pre-confirmed state:
The pending block is one block ahead of latest, with a zero hash and fewer transactions, because the sequencer is still building it.

Production considerations

  • Pre-confirmations are not final. Flashblock state can change until the 2-second block seals, so for settlement confirm the transaction against latest or a finalized block.
  • Empty hashes are expected. blockHash is null on streamed transactions and zero on logs and Flashblocks until the block seals — read the final hash from the sealed block.
  • The stream is best-effort. Flashblocks can arrive in bursts or pause briefly; if the stream stops, fall back to the finalized block from the node.
  • Re-subscribe on reconnect. A subscription ends when the WebSocket drops, so re-send the eth_subscribe request after reconnecting.
  • Throughput tracks network activity. In tests against Base mainnet, newFlashblockTransactions delivered roughly 130–330 transactions per second.
Last modified on June 26, 2026