When a dApp (decentralized application) talks to an Ethereum-like blockchain, it does so using a JSON-RPC interface. In essence, an RPC URL is the web address of a node’s JSON-RPC endpoint. It’s a server URL (usually an HTTPS endpoint) that your dApp calls to retrieve on-chain data or push transactions.
For example, Infura and GetBlock are commonly used node services that give you URLs like https://mainnet.infura.io/v3/YOUR-API-KEY
or <https://go.getblock.io/<ACCESS-TOKEN>/>
. In the background these URLs point to a complete Ethereum node which indeed accesses the blockchain. That is, your dApp’s web3 library (Ethers.js, Web3.js, etc.) makes JSON-RPC “remote procedure calls” through that URL to the blockchain. The RPC URL is literally the network address to invoke the RPC endpoint in the Web3 environment.
As it’s a network request, you can (and should) pick a decent RPC provider. Public endpoints like GetBlock or the Cloudflare Ethereum Gateway allow you to invoke Ethereum or EVM chains without needing your own node. For example, Infura’s quickstart shows a curl to https://mainnet.infura.io/v3/<YOUR-API-KEY>
for the Ethereum Mainnet. Using public RPCs (or having your own node) guarantees that your dApp will always be able to read the latest blocks and send transactions.
Chain IDs: Finding Each Network
A chain ID is a unique number that identifies an EVM-compatible chain. Every network (Ethereum Mainnet, Polygon, Arbitrum, etc.) has a specific chain ID so wallets and transactions know which chain they are using. In practice, the chain ID is baked into signatures of transactions (following Ethereum’s EIP-155). This stops a transaction from one chain from being replayed on another, despite addresses looking the same format on different chains. That is, by adding a chain ID in the signed transaction, replay attacks across chains are prevented.
In network configuration in MetaMask, you supply the chain ID and RPC URL manually. For instance, MetaMask’s “Add a Network” window has Network URL (the RPC endpoint) and Chain ID (the numeric ID to use when signing transactions on the said network) fields. These two fields tell MetaMask where to send your calls and which chain to signal in the signatures. If they don’t match the actual network, you’ll get errors or even sign transactions on the wrong chain.
Chain IDs for major networks include:
- Ethereum Mainnet – Chain ID 1
- Polygon (PoS) – Chain ID 137
- Arbitrum One – Chain ID 42161
- Optimism Mainnet – Chain ID 10
- BNB Smart Chain – Chain ID 56
- Avalanche C-Chain – Chain ID 43114
All of these numeric IDs are the ones used internally by nodes and wallets. For example, Alchemy’s Chain Connect page shows “Chain Id 1” for Ethereum and “Chain Id 10” for Optimism, with their RPC URLs. When you switch or set up networks, this ID is how everyone knows what blockchain you’re talking about.
Why These Matter: Correct Networks, Security, and Multi-Chain Support
It’s essential that the RPC URL and chain ID are properly set in any dApp. Having the wrong RPC or network ID can get your app reading the wrong data or even attempting to send transactions on the wrong blockchain. As an illustration, pointing to a Polygon RPC but with Ethereum’s chain ID (or vice versa) will cause MetaMask to display “Wrong chain ID” warning. Practically speaking, the RPC URL and chain ID ensure that your dApp is talking to the correct network.
Further, chain ID on transactions (as per EIP-155) prevents a signed transaction on one chain from being accepted on another. That’s replay protection the way Ethereum does it. Without chain ID, an Ethereum token transfer would be replayable between, say, Ethereum Classic or a sidechain with the same network address formats. With chain ID, every signature is tied to a single network. It’s “important to keep track of the user’s network chain ID because all RPC requests are submitted to the currently connected network”. In practice, dApps should always fetch chainId
(for example, via ethereum.request({ method: 'eth_chainId' })
) so they can determine which network they are on.
For dApps on multiple chains, this data is even more important. An application like Uniswap running on both Ethereum and Polygon will have to modify RPC URLs and sign with the correct chain ID whenever the user changes networks. MetaMask emits a chainChanged
event when the user changes networks, and dApps typically listen for that in order to reload or re-create connections. In a word, having control over RPC endpoints and chain IDs is the foundation of safely plugging your front end into whatever EVM blockchain.
How MetaMask Uses RPC URLs and Chain IDs
MetaMask (and similar) muxes the RPC URL and chain ID together internally to set a network. When a dApp calls window.ethereum.request(…)
, MetaMask initiates the JSON-RPC request to the set RPC URL. It employs the chain ID during message and transaction signing. The MetaMask UI actually shows these fields when you add a network:
As this screenshot shows, MetaMask will display the Network URL and Chain ID fields. Network URL is the URL that MetaMask will use to access the network, and Chain ID is the chain ID that MetaMask will use to sign transactions for the network. In other words, once you approve this dialog, MetaMask knows exactly which node to talk to (via the RPC URL) and which chain to signal in transaction signatures (via the chain ID).
Programmatically, dApps can query the chain ID and handle network changes. MetaMask’s developer guides recommend using the eth_chainId
RPC method and listening for the chainChanged
event to detect when the user switches networks. For example, one might do:
const chainId = await ethereum.request({ method: 'eth_chainId' });
ethereum.on('chainChanged', (newChainId) => { window.location.reload(); });
This ensures your code always knows the current chain ID and reconnects if it changes. All of this logic relies on having the right RPC endpoint and chain ID configured in MetaMask.
Common RPC Endpoints and Chain IDs
Here are some typical networks, their chain IDs, and example public RPC URLs:
- Ethereum Mainnet – Chain ID 1. Public RPCs: Infura at
https://mainnet.infura.io/v3/YOUR-PROJECT-ID
or GetBlock athttps://go.getblock.io/<your_access_token>
. (You must replaceYOUR-PROJECT-ID
/YOUR-ACESS-TOKEN
with your credentials.) - Polygon PoS – Chain ID 137. RPC examples: e.g.
https://polygon-mainnet.infura.io/v3/YOUR-PROJECT-ID
or GetBlockhttps://go.getblock.io/<your_access_token>
- Arbitrum One – Chain ID 42161. Example RPC: Alchemy’s
https://arb-mainnet.g.alchemy.com/v2/YOUR-API-KEY
(or public Arbitrum endpoints). - Optimism Mainnet – Chain ID 10. RPC example: GetBlock
https://go.getblock.io/<your_access_token>
, or Optimism’s officialhttps://mainnet.optimism.io
. - BNB Smart Chain – Chain ID 56. (RPC
https://bsc-dataseed.binance.org/
). - Avalanche C-Chain – Chain ID 43114 (RPC
https://api.avax.network/ext/bc/C/rpc
).
Each of these networks can be added to wallets like MetaMask by supplying the RPC URL and chain ID. Websites like Chainlist collect verified lists of these details for many networks – exactly the kind of info MetaMask suggests you check if something “isn’t matching”.
Tips for Custom Networks and Local Development
Here is what I recommend:
- Verify network data. Reverify the RPC URL and chain ID against official documentation or community lists (e.g. Chainlist). MetaMask has actually promoted checking the chain ID searched on Chainlist (chainid.network) to verify that it is correct.
- Decimal v Hex. Chain IDs can be specified in decimal (137) or hex (0x89) form. MetaMask prefers to accept both but use both consistently. For example, Hardhat’s default chain ID is 1337 decimal (0x539 hex). If you modify one without modifying the other, MetaMask will complain about a mismatch.
- Get local nodes set up correctly. For local dev chains (Ganache, Hardhat, etc.), make sure your node chain ID is identical to what you’ve got MetaMask configured to use. As an example, if you’re using the default Hardhat node, you’d have MetaMask set to http://127.0.0.1:8545 with chain ID 1337. Ganache users typically see chain IDs 1337 or 5777; you can run Ganache with a custom
--chainId
flag to match Hardhat if needed. Other chain IDs lead to Hardhat failures.
- Switching networks manually in code. Use
provider.getNetwork()
orethereum.request({method: 'eth_chainId'})
to grab the current chain ID at runtime. Listen for MetaMask’schainChanged
event and reload or reconfigure your app when it fires. This makes your dApp always aware which network it’s communicating with after the user has changed chains.
- Be careful of replay attacks when testing. When testing on several chains (like a local mainnet fork and testnet), always sign transactions with the right chain ID. The chain ID in EIP-155 is what makes a transaction only valid on its destination chain, so a choice of the wrong one would nullify your signature.
By carefully setting the RPC URL and chain ID, you’re connecting your dApp to the right blockchain. This avoids fine-grained bugs (like sending tokens to the wrong network or leaving yourself open to replay attacks) and enables seamless multi-chain compatibility. In short, think of the RPC URL as “which node” and the chain ID as “which world” — both are critical pieces of connection information for any Ethereum-compatible dApp.