Infura API integration
The problem most projects face at startup: you need a node right now, running your own Geth/Besu means days of waiting for synchronization and DevOps work that doesn't bring business value at MVP stage. Infura is a managed RPC provider supporting Ethereum, Polygon, Arbitrum, Optimism, Base and a dozen other networks. Integration takes an hour, but there are several non-obvious points.
What the service is and how it differs from others
Infura is one of the oldest providers (ConsenSys, 2016). Competitors: Alchemy, QuickNode, Chainstack, Ankr. Key differences of Infura:
- WebSocket support through separate WSS endpoint — important for event subscriptions
- Ethereum Gas API — separate service with historical gas data
- IPFS gateway — the same key works for IPFS API, convenient for NFT metadata
-
Archive data — access to historical states through
eth_getStorageAton any block (limited on Core plan, unlimited on Growth/Custom)
For most projects Infura and Alchemy are interchangeable — both implement standard Ethereum JSON-RPC. Migration between them is just replacing the URL in config.
Setup and first request
Registration → create project → get Project ID. Endpoint is formed like this:
https://mainnet.infura.io/v3/{PROJECT_ID}
WSS: wss://mainnet.infura.io/ws/v3/{PROJECT_ID}
Networks: mainnet, sepolia, polygon-mainnet, arbitrum-mainnet, optimism-mainnet, base-mainnet and others.
Basic request through viem:
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
const client = createPublicClient({
chain: mainnet,
transport: http(`https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`),
});
const blockNumber = await client.getBlockNumber();
const balance = await client.getBalance({ address: '0x...' });
Through ethers.js:
import { JsonRpcProvider } from 'ethers';
const provider = new JsonRpcProvider(
`https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`
);
Rate limits and handling them
Free plan: 100,000 requests/day. Core: 3M requests/day. RPS limits depend on plan.
Practical tips:
Request batching. JSON-RPC supports batch — multiple methods in one HTTP request:
// One HTTP request instead of three
const [block, balance, nonce] = await client.multicall({
contracts: [...],
});
// Or via raw batch
const batch = [
{ jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1 },
{ jsonrpc: '2.0', method: 'eth_getBalance', params: ['0x...', 'latest'], id: 2 },
];
const response = await fetch(rpcUrl, {
method: 'POST',
body: JSON.stringify(batch),
});
Caching static data. Results of eth_getCode, eth_getTransactionByHash for confirmed transactions — never change. Cache to Redis with infinite TTL or until restart.
Fallback to backup provider. Infura sometimes degrades. Pattern — fallback transport:
import { fallback, http } from 'viem';
const transport = fallback([
http(`https://mainnet.infura.io/v3/${INFURA_KEY}`),
http(`https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}`),
]);
WebSocket subscriptions
For real-time events — WebSocket endpoint:
import { createPublicClient, webSocket } from 'viem';
const wsClient = createPublicClient({
chain: mainnet,
transport: webSocket(`wss://mainnet.infura.io/ws/v3/${INFURA_KEY}`),
});
// Subscribe to new blocks
const unwatch = wsClient.watchBlockNumber({
onBlockNumber: (blockNumber) => console.log(blockNumber),
});
// Subscribe to contract events
const unwatch = wsClient.watchContractEvent({
address: '0x...',
abi: erc20Abi,
eventName: 'Transfer',
onLogs: (logs) => processTransfers(logs),
});
Important: WebSocket connection needs to be restored on disconnections. viem does this automatically, in ethers.js you need WebSocketProvider with manual reconnect logic.
API key security
Infura API key is not a secret in the full sense. Abuse will exhaust rate limits, not compromise funds. Nevertheless:
- Don't commit to git —
.env+.gitignore - Configure Allowlist by origin in Infura dashboard for frontend use
- Configure Allowlist by contract address if working with specific contracts only
- Separate keys for dev/staging/production environments
For frontend: key is visible in browser anyway. Solution — either accept this risk with allowlist restrictions, or proxy requests through your own backend.
What's included in the work
Setup takes 2-8 hours depending on environment: creating account and project, configuring endpoint for needed networks, integration into existing code (replacing hardcoded RPC or adding first provider), setting up fallback and caching, configuring allowlist in dashboard. For projects with WebSocket — setting up subscriptions and reconnect logic.







