Skip to main content
This tutorial teaches you how to monitor on-chain events and transactions on Monad. You’ll use WebSocket subscriptions (eth_subscribe) for real-time streaming, with HTTP polling via eth_getLogs as an alternative pattern for environments where WebSocket isn’t an option.
Get your own node endpoint todayStart for free and get your app to production levels immediately. No credit card required.You can sign up with your GitHub, X, Google, or Microsoft account.
TLDR:
  • Stream real-time events with eth_subscribe("logs", {...}) over WebSocket
  • Stream new blocks with eth_subscribe("newHeads")
  • Alternative: query logs over HTTP with eth_getLogs
  • Monitor ERC-20 Transfer events on WMON (Wrapped MON)
  • Handle Monad’s high-throughput blocks efficiently
  • Both JavaScript and Python implementations

Prerequisites

  • Chainstack account with a Monad node endpoint
  • Node.js v16+ or Python 3.8+
  • Basic understanding of Ethereum events and logs

Overview

Event monitoring on Monad differs from Ethereum in a few ways:
  • WebSocket subscriptionseth_subscribe("newHeads") and eth_subscribe("logs", {...}) are supported for real-time streaming. eth_subscribe("newPendingTransactions") and eth_subscribe("syncing") are not supported and return -32602 Invalid params.
  • 1-second blocks — events appear roughly every second
  • High transaction volume — blocks contain many transactions, so when using eth_getLogs, query small block ranges
  • Immediate finality — no need to wait for confirmations or handle reorgs
This tutorial shows you how to build efficient monitoring tools that work with Monad’s architecture.
Use your Chainstack node’s WSS endpoint (wss://…) for subscription examples. See Node access and credentials.

Understanding Monad’s event system

Events (logs) on Monad work the same as Ethereum:
  1. Smart contracts emit events during execution
  2. Events are stored in transaction receipts
  3. You stream events in real time with eth_subscribe("logs", {...}) over WebSocket, or query historical events with eth_getLogs over HTTP
Pick the pattern that fits your use case:
  • Real-time streaming — use eth_subscribe over WebSocket. Lower latency, no polling loop, no missed blocks
  • Historical queries or HTTP-only environments — use eth_getLogs. Use small block ranges (1–10 blocks) per query, and process logs immediately since they’re final

Stream events in real time with eth_subscribe

eth_subscribe("logs", {...}) streams matching events to you over a WebSocket connection as soon as a block containing them lands. No polling, no missed blocks, no extra request budget burned on idle intervals.

JavaScript — subscribe to WMON Transfers

subscribe-wmon.js
Run:
Under the hood, provider.on(filter, handler) sends a raw eth_subscribe request:

Python — subscribe to WMON Transfers

subscribe_wmon.py
Run:

Subscribe to new block headers

Use eth_subscribe("newHeads") to react to every new block as it’s produced:
subscribe-newheads.js

Alternative: poll with eth_getLogs

If you can’t use WebSocket — for example, in a serverless function, a browser environment without persistent sockets, or a constrained runtime — poll eth_getLogs over HTTP instead.

JavaScript polling implementation

monitor-wmon.js
Run:

Python polling implementation

monitor_wmon.py
Run:

Build a block monitor with polling

Monitor all transactions in new blocks over HTTP. For a WebSocket equivalent, see the eth_subscribe("newHeads") example above.

JavaScript block monitor

monitor-blocks.js

Python block monitor

monitor_blocks.py

Monitor custom contract events

Track events from any contract by defining the event signature:
monitor-custom.js

Filter events by address

Monitor transfers to or from a specific address:
monitor-address.js

Best practices for Monad

Optimize your monitoring for Monad’s characteristics:
  1. Prefer eth_subscribe over polling — WebSocket subscriptions are lower latency and don’t burn request budget on idle intervals. Reach for eth_getLogs polling only when WebSocket isn’t an option.
  2. Use small block ranges when polling — query 1–10 blocks at a time. Monad blocks can contain thousands of transactions.
  3. Match polling cadence to block time — Monad produces blocks every ~1 second. Polling faster wastes requests; slower misses events.
  4. Handle high volume — be prepared for blocks with many events. Process asynchronously if needed.
  5. No reorg handling needed — Monad has instant finality. Once you see an event, it’s permanent.
  6. Batch your queries — if monitoring multiple contracts, combine filters where possible.
eth_getLogs limitations:
  • Most nodes limit the block range per query (typically 1,000–10,000 blocks)
  • For historical data, paginate through block ranges
  • For real-time monitoring, stick to recent blocks only — or use eth_subscribe("logs", {...}) instead

Monad-specific notes

Key differences from Ethereum monitoring:
  • eth_subscribe subsetnewHeads and logs are supported. eth_subscribe("newPendingTransactions") and eth_subscribe("syncing") are not supported on Monad and return -32602 Invalid params.
  • 1-second blocks — events appear faster than on Ethereum. Your monitor needs to keep up.
  • No pending transactions — you can’t monitor the mempool. Only confirmed transactions are visible.
  • Immediate finality — no need to wait for confirmations. Events are final when you see them.
  • High throughput — expect more events per block than on Ethereum. Design accordingly.

Complete monitoring script

A production-ready monitor combining all techniques:
monitor-complete.js

Next steps

Now that you can monitor events on Monad, you can:
  • Build real-time dashboards for DEX activity
  • Create alerting systems for large transfers
  • Track NFT mints and sales
  • Monitor your own smart contract events
  • Build analytics pipelines for on-chain data
Last modified on June 22, 2026