Web3.js: Implementing Reliable Event Subscriptions for Ethereum Smart Contracts
Event-driven applications using Web3.js often fail silently when websocket connections drop. This leaves critical contract events unprocessed, breaking application state and user experience.
23 Jun 2026, 02:30 UTC

The Problem: Missed Events Break Production Applications
Event-driven applications using Web3.js often fail silently when websocket connections drop or rate limits interrupt polling. This leaves critical contract events—like token transfers or governance votes—unprocessed, breaking application state and user experience.
Prerequisites
- Node.js environment with web3.js v4.x installed:
npm install web3@latest - Access to an Ethereum JSON-RPC endpoint (Infura, Alchemy, or local node)
- Contract ABI and address for the event-emitting smart contract
- Network permissions: CORS configured for local nodes, API keys for hosted providers
Focused Procedure: Robust Event Subscription Pattern
Use Web3.js event subscription with automatic reconnection and error handling:
const Web3 = require('web3');
const web3 = new Web3('wss://eth-mainnet.alchemyapi.io/v2/YOUR_API_KEY');
const contract = new web3.eth.Contract(abi, contractAddress);
// Track subscription state
let subscription = null;
let reconnectAttempts = 0;
const MAX_RECONNECTS = 5;
function startEventSubscription() {
subscription = contract.events.Transfer({
fromBlock: 'latest'
}, {
// Enable websocket transport for real-time delivery
transport: 'websocket'
})
.on('data', (event) => {
console.log('Event received:', event);
// Process event - critical: handle asynchronously
handleEvent(event).catch(console.error);
})
.on('error', (error) => {
console.error('Subscription error:', error.message);
if (reconnectAttempts < MAX_RECONNECTS) {
reconnectAttempts++;
setTimeout(startEventSubscription, 2000 * reconnectAttempts);
}
})
.on('connected', (subscribeId) => {
console.log('Subscribed with ID:', subscribeId);
reconnectAttempts = 0;
});
}
async function handleEvent(event) {
// Your event processing logic here
// Example: update database, notify users
}
startEventSubscription();
Expected Checks
- Connection verification: Run
node -e "const Web3 = require('web3'); console.log(new Web3('wss://eth-mainnet.alchemyapi.io/v2/demo').version.api)"to confirm websocket support - Event delivery test: Deploy a test contract that emits events, then verify your handler receives them within seconds
- Reconnection test: Simulate network interruption (disconnect internet briefly), confirm subscription recovers within 10 seconds
- Error handling validation: Force invalid event filter, confirm error callback triggers without crashing the process
Relevant Recovery Options
If events are missed during downtime, implement event replay:
// After reconnection, query recent blocks for missed events
async function replayMissedEvents(lastProcessedBlock) {
const currentBlock = await web3.eth.getBlockNumber();
for (let block = lastProcessedBlock; block <= currentBlock; block++) {
const events = await contract.getPastEvents('Transfer', {
fromBlock: block,
toBlock: block
});
for (const event of events) {
await handleEvent(event);
}
}
}
Limitations
- Websocket subscriptions are not supported by all providers; Infura requires wss:// endpoints
- Public endpoints may rate-limit subscription requests; use authenticated providers for production
- Event ordering is not guaranteed across reconnections; include block number and transaction hash in your processing logic
- Memory usage grows if events queue during processing delays; implement backpressure handling
Verification Method
Create a Hardhat test that emits events and confirms your subscription handler processes them correctly. Use npx hardhat test to run against a local node where you can control timing and verify no events are lost during simulated disconnects.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.