Immutable zkEVM RPC: A Developer's Guide (Chain ID 13371)

By John Sullivan · October 16, 2026 · 6 min read · #immutable #immutable zkevm #immutable zkevm rpc #imx #gaming #developer guide

Immutable zkEVM is the EVM chain behind Immutable's games: in-game items, marketplaces and player wallets. If you are building a game backend, an inventory indexer or a marketplace bot against it, most of your code carries over from Ethereum unchanged. Two things do not: the chain rejects any transaction with a priority fee under 10 gwei, and it has no safe or finalized block, so libraries that wait for finality get an error instead of a block.

Everything below was measured against the live chain on October 16, 2026, through the same endpoint SwiftNodes customers use and through Immutable's own public RPC.

The endpoint

https://rpc.swiftnodes.io/rpc/immutable-zkevm?key=YOUR_API_KEY
import { createPublicClient, http, defineChain } from "viem";

const immutable = defineChain({
  id: 13371,
  name: "Immutable zkEVM",
  nativeCurrency: { name: "IMX", symbol: "IMX", decimals: 18 },
  rpcUrls: { default: { http: ["https://rpc.swiftnodes.io/rpc/immutable-zkevm?key=YOUR_API_KEY"] } },
});

const client = createPublicClient({ chain: immutable, transport: http() });

viem also ships this chain as immutableZkEvm in viem/chains; pass our URL to http() to use it. Native balances are IMX, not ETH.

What we measured

Property Value
Chain ID 13371 (0x343b)
Client (Immutable public RPC) Geth/v1.0.0-beta.17-952166b1/linux-amd64/go1.21.13
Block 1 December 11, 2023
Block interval exactly 2 s (120 of 120 intervals)
Transactions per block 0.93 on average; 49 of 121 blocks empty
Block gas limit 30,000,000
Gas used 0.4% of the limit on average
Base fee 49 wei
eth_maxPriorityFeePerGas 11 gwei
eth_gasPrice 11 gwei (11,000,000,049 wei)
Minimum tip accepted 10 gwei
Plain IMX transfer 21,000 gas, 0.000231 IMX
safe / finalized tags not supported
eth_getLogs range 5,000 blocks maximum
Historical state full, back to early blocks

Despite the name, the chain answers like a go-ethereum node. Blocks are sealed Clique-style: the miner field is the zero address, difficulty is 2, and the signer's signature sits in extraData. The genesis block authorizes a single signer. None of the zk-specific RPC namespaces exist: zkevm_batchNumber and zks_L1BatchNumber both return "method does not exist". Treat it as a fast, low-traffic geth chain with two rules of its own.

Rule one: the tip must be at least 10 gwei

On Ethereum a 1 or 2 gwei priority fee is normal, and plenty of code hardcodes it. Immutable zkEVM rejects that at the door. We signed three transactions from an empty wallet with different tips and sent them to the public RPC:

Tip Response
1 gwei transaction underpriced: gas tip cap 1000000000, minimum needed 10000000000
9 gwei transaction underpriced: gas tip cap 9000000000, minimum needed 10000000000
10 gwei insufficient funds for intrinsic transaction cost

The third error is the one you want: the node checked the tip, accepted it, and only then noticed the wallet had no IMX. Anything under 10 gwei never reaches the balance check.

The base fee, meanwhile, has drifted from 1 gwei at genesis down to 49 wei, because blocks run at well under half full and EIP-1559 lowers the base fee after every such block. So the price you pay is almost entirely tip. In the 287 transactions we sampled from the last 300 blocks, the tips were:

Tip Transactions
10 gwei 35
11 gwei 234
12 gwei 12
15 to 100 gwei 6

256 were EIP-1559 (type 2) and 31 legacy (type 0). For legacy transactions the same floor applies to gasPrice, since the tip is gasPrice minus the base fee.

The safe pattern is to ask the node:

const tip = await client.estimateMaxPriorityFeePerGas(); // 11 gwei today
const { maxFeePerGas } = await client.estimateFeesPerGas();

viem's estimateMaxPriorityFeePerGas calls eth_maxPriorityFeePerGas, which returns 11 gwei here. If you build transactions yourself, clamp the tip: max(eth_maxPriorityFeePerGas, 10 gwei). Bumping a stuck transaction works as usual, with the replacement needing a higher tip than the original.

Costs stay small. A plain IMX transfer used exactly 21,000 gas at an effective price of 11 gwei, which is 0.000231 IMX. Estimate contract calls with eth_estimateGas as usual; see estimating gas with EIP-1559 for padding advice.

Rule two: no safe or finalized block

eth_getBlockByNumber("safe")      -> safe block not found
eth_getBlockByNumber("finalized") -> finalized block not found

Immutable zkEVM is one of the chains in our survey of the finalized block tag across 62 chains that return an error rather than a block. That matters in three places:

  • client.getBlock({ blockTag: "finalized" }) throws instead of returning a block.
  • Indexers that read up to finalized and stop never make progress.
  • Wallet and bridge code that waits for safe before showing "confirmed" waits forever, or crashes.

Use a confirmation count on latest instead. At 2 seconds per block, 30 confirmations is one minute and 150 is five. Keep reorg handling in your indexer anyway, as described in handling chain reorgs in an indexer: store block hashes and check each new block's parent hash, so a replaced block is caught whatever depth you choose.

Logs: 5,000 blocks per request

eth_getLogs is limited by block range, not by result count:

Range Result
100 blocks 380 logs
1,000 blocks 3,769 logs
5,000 blocks 24,112 logs
5,001 blocks exceeded maximum block range: 5000

At 2 seconds per block, 5,000 blocks is under three hours of chain. Backfilling a contract deployed a year ago means about 3,200 requests, so filter by address and topics and run several ranges in parallel. Unfiltered, the chain emits about 4.8 logs per block, so a full 5,000-block page is a few megabytes of JSON. More on range caps in eth_getLogs range caps.

For live data, poll eth_getLogs or eth_getBlockByNumber every 2 seconds over HTTP, which matches the block interval. WebSocket subscriptions are not available for Immutable zkEVM on SwiftNodes today.

History, receipts and tracing

Historical state reads worked at every depth we tried, including block 16,777,216 from early in the chain's life, so balance-at-block and eth_call at old blocks work for analytics and airdrop snapshots. eth_getBlockReceipts works and returns [] for the many empty blocks.

Tracing does not: debug_traceBlockByNumber and trace_block both return "method does not exist", and so do txpool_status and the clique_* methods. If you need internal transactions, decode them from logs or replay calls with eth_call at the parent block.

Method Result
eth_getLogs works, 5,000-block cap
eth_getBlockReceipts works
eth_getBalance / eth_call at old blocks work
eth_maxPriorityFeePerGas, eth_feeHistory work
safe / finalized tags not available
debug_*, trace_* not available
txpool_*, clique_* not available

Summary

  • Geth-based gaming chain, chain ID 13371, gas in IMX, 2-second blocks.
  • The minimum tip is 10 gwei; lower tips fail with transaction underpriced. Read eth_maxPriorityFeePerGas (11 gwei) and never hardcode an Ethereum tip.
  • The base fee is 49 wei, so the tip is the price: a transfer costs 0.000231 IMX.
  • No safe or finalized block: count confirmations on latest.
  • eth_getLogs is capped at 5,000 blocks; no tracing.

Immutable zkEVM endpoints and method support are on our Immutable zkEVM RPC page, with 127 other chains on the same key. SwiftNodes has a free tier to try it.

J
John Sullivan
Infrastructure Writer, SwiftNodes

John Sullivan covers RPC infrastructure, node operations, and multi-chain development at SwiftNodes — what it actually takes to keep endpoints fast, fresh, and reliable across EVM and non-EVM networks.

Related posts

Try SwiftNodes free — multi-chain RPC across 83 networks, flat-rate pricing, pay by card or crypto, no KYC. Get an API key in 30 seconds →