Solana

Solana Beta is live. Try BoltRPC Solana endpoints free - start your trial now.

Ethereum RPC Guide: How to Connect and Build on Ethereum (2026)

A complete 2026 developer guide to Ethereum RPC endpoints. Learn how to connect with ethers.js, Web3.py, and curl, use key JSON-RPC methods, handle EIP-1559 fees, finality tags, fix common production issues.

BoltRPC
BoltRPC Team
10 min read
Ethereum RPC Guide: How to Connect and Build on Ethereum (2026)

Ethereum RPC Guide: How to Connect and Build on Ethereum (2026)

Ethereum is the reference Layer 1 for smart contract development. Every wallet, dApp, and on-chain protocol relies on an RPC endpoint to communicate with the network. This guide walks through everything you need to connect to Ethereum, use its JSON-RPC methods in production, understand its finality model, and avoid the issues that catch developers off-guard.

What is an Ethereum RPC Endpoint

An Ethereum RPC endpoint is a URL that lets your application interact with the Ethereum blockchain without running a node. You send JSON-RPC 2.0 requests over HTTP or WebSocket, and the node responds with block data, balances, transaction receipts, contract state, or confirmation that your transaction was accepted.

Two connection types are available:

HTTP (HTTPS): Stateless request-response. Use this for reading data (balances, logs, receipts) and broadcasting signed transactions. Simpler to use, sufficient for most use cases.

WebSocket (WSS): Persistent connection. Use this when you need real-time event subscriptions via eth_subscribe: new block headers, contract event logs, pending transactions. The node pushes data to your app as it arrives.

Default rule: use HTTPS, switch to WebSocket when you need real-time subscriptions.

Public Ethereum RPC Endpoints

The following public endpoints are suitable for testing only. Do not use them in production.

NetworkRPC URLChain ID
Ethereum Mainnethttps://eth.llamarpc.com1
Ethereum Mainnethttps://cloudflare-eth.com1
Ethereum Mainnethttps://ethereum.publicnode.com1
Ethereum Hoodi Testnethttps://rpc.hoodi.ethpandaops.io560048

Public endpoints are rate-limited to a few requests per second, run on shared infrastructure, and provide no support or SLA. For any app with real users or real transaction volume, use a dedicated authenticated endpoint.

BoltRPC provides dedicated Ethereum RPC at https://eu.endpoints.matrixed.link/rpc/ethereum?auth=YOUR_KEY. Start with a free 2-week trial at trial.boltrpc.io.

Ethereum RPC Methods

Ethereum’s full JSON-RPC 2.0 spec is implemented by all major execution clients. Here are the five methods you will use most in production:

eth_getBalance

Returns the ETH balance of an address at a given block tag.

curl -X POST \
  "https://eu.endpoints.matrixed.link/rpc/ethereum?auth=YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": ["0xYourAddress", "latest"],
    "id": 1
  }'

Result is in wei (hex). Divide by 10^18 to get ETH. Use block tags "latest", "safe", "finalized" as needed (see the finality section below).

eth_call

Executes a read-only call against a contract without creating a transaction. Use this for view and pure functions.

import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider(
  "https://eu.endpoints.matrixed.link/rpc/ethereum?auth=YOUR_KEY"
);

const abi = ["function totalSupply() view returns (uint256)"];
const contract = new ethers.Contract("0xTokenAddress", abi, provider);
const supply = await contract.totalSupply();
console.log("Total supply:", supply.toString());

eth_sendRawTransaction

Broadcasts a signed transaction to the network. Your library signs the transaction locally and passes the raw hex to this method.

const wallet = new ethers.Wallet("0xYourPrivateKey", provider);
const tx = await wallet.sendTransaction({
  to: "0xRecipientAddress",
  value: ethers.parseEther("0.01"),
  maxFeePerGas: ethers.parseUnits("20", "gwei"),
  maxPriorityFeePerGas: ethers.parseUnits("1.5", "gwei")
});
const receipt = await tx.wait();
console.log("Confirmed in block:", receipt.blockNumber);

eth_getLogs

Fetches event logs matching a filter. This is the foundation of event-driven Ethereum apps: indexing transfers, tracking oracle updates, monitoring DEX swaps.

const logs = await provider.getLogs({
  address: "0xContractAddress",
  topics: [ethers.id("Transfer(address,address,uint256)")],
  fromBlock: 21000000,
  toBlock: 21001000
});
console.log(`Found ${logs.length} Transfer events`);

Keep block ranges under 2,000 blocks per request unless your provider explicitly supports larger ranges. See the common issues section for pagination.

eth_subscribe

WebSocket-only. Pushes events to your app in real time. Supports newHeads, logs, newPendingTransactions.

const wsProvider = new ethers.WebSocketProvider(
  "wss://eu.endpoints.matrixed.link/ws/ethereum?auth=YOUR_KEY"
);

wsProvider.on("block", (blockNumber) => {
  console.log("New block:", blockNumber);
});

const filter = {
  address: "0xContractAddress",
  topics: [ethers.id("Transfer(address,address,uint256)")]
};
wsProvider.on(filter, (log) => {
  console.log("Transfer:", log.transactionHash);
});

Connecting Step by Step

ethers.js

import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider(
  "https://eu.endpoints.matrixed.link/rpc/ethereum?auth=YOUR_KEY"
);

const blockNumber = await provider.getBlockNumber();
console.log("Connected. Block:", blockNumber);

Web3.py

from web3 import Web3

w3 = Web3(Web3.HTTPProvider(
    "https://eu.endpoints.matrixed.link/rpc/ethereum?auth=YOUR_KEY"
))

if w3.is_connected():
    print(f"Connected. Block: {w3.eth.block_number}")

balance_wei = w3.eth.get_balance("0xYourAddress")
balance_eth = w3.from_wei(balance_wei, "ether")
print(f"Balance: {balance_eth} ETH")

For WebSocket in Web3.py:

from web3 import Web3
from web3.middleware import ExtraDataToPOAMiddleware

w3 = Web3(Web3.WebsocketProvider(
    "wss://eu.endpoints.matrixed.link/ws/ethereum?auth=YOUR_KEY"
))

curl

curl -X POST \
  "https://eu.endpoints.matrixed.link/rpc/ethereum?auth=YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x13d99f0"
}

Convert the hex result with parseInt("0x13d99f0", 16).

For MetaMask setup and manual network configuration, see the Ethereum RPC endpoint page.

Ethereum-Specific Considerations

EIP-1559 Fee Model

Ethereum uses a two-part fee structure since the London upgrade. Every transaction specifies:

  • maxFeePerGas: the maximum total you will pay per gas unit (base fee + priority fee)
  • maxPriorityFeePerGas: the tip paid directly to the validator

The base fee is set by the protocol and burned. It adjusts up or down based on block utilization. You can read the current base fee from eth_feeHistory or use your library’s getFeeData() method:

const feeData = await provider.getFeeData();
console.log("Base fee:", ethers.formatUnits(feeData.gasPrice, "gwei"), "gwei");
console.log("Max fee suggestion:", ethers.formatUnits(feeData.maxFeePerGas, "gwei"), "gwei");

Never hardcode gas prices. Always fetch live fee data before submitting a transaction to avoid overpaying during spikes or getting stuck during surges.

PoS Finality and Block Tags

Ethereum uses Proof of Stake. Blocks progress through three states:

TagMeaningWhen to Use
latestMost recent block (may reorg)Balance reads, general queries
safeUnlikely to reorg (a few epochs behind head)Transaction status where near-finality is sufficient
finalizedCryptographically final (two epochs, ~12 min)Bridges, cross-chain transfers, custody systems

Most applications use latest. If you are building infrastructure that depends on irreversibility (a bridge releasing funds, a custody system crediting deposits), use finalized. Using latest for bridge finality has historically led to losses from reorg-based exploits.

const finalizedBlock = await provider.getBlock("finalized");
console.log("Finalized block:", finalizedBlock.number);

Archive vs Full Node

A full node stores recent state (typically the last 128 blocks plus full block history). An archive node stores all historical state from genesis.

You need an archive node when:

  • Querying balances or contract state at old block numbers
  • Backfilling historical eth_getLogs over large ranges
  • Running historical simulations or analytics

For most dApps and trading bots that only interact with current state, a full node is sufficient. BoltRPC provides archive access on request.

Common Issues and Fixes

eth_getLogs block range exceeded

Most providers cap eth_getLogs ranges to avoid overloading the node. If you receive an error like block range too large, paginate your requests:

async function getLogsInRange(provider, filter, fromBlock, toBlock, chunkSize = 2000) {
  const logs = [];
  for (let start = fromBlock; start <= toBlock; start += chunkSize) {
    const end = Math.min(start + chunkSize - 1, toBlock);
    const chunk = await provider.getLogs({ ...filter, fromBlock: start, toBlock: end });
    logs.push(...chunk);
  }
  return logs;
}

Nonce errors on eth_sendRawTransaction

If you get nonce too low or replacement transaction underpriced, your local nonce is out of sync with the network. Fetch the current nonce before every transaction in non-sequential flows:

const nonce = await provider.getTransactionCount("0xYourAddress", "pending");

Use "pending" if you have unconfirmed transactions in flight.

WebSocket connection drops

WebSocket connections close for many reasons: provider restarts, network hiccups, idle timeouts. Always implement reconnection:

function createWsProvider() {
  const ws = new ethers.WebSocketProvider(
    "wss://eu.endpoints.matrixed.link/ws/ethereum?auth=YOUR_KEY"
  );
  ws.websocket.on("close", () => {
    console.log("WebSocket closed. Reconnecting...");
    setTimeout(() => createWsProvider(), 3000);
  });
  return ws;
}

Stale results after block reorg

Ethereum PoS has very rare but possible short reorgs (1-2 blocks). If you cache block data by number, invalidate on reorg:

wsProvider.on("block", async (blockNumber) => {
  const block = await provider.getBlock(blockNumber);
  if (lastHash && block.parentHash !== lastHash) {
    console.warn("Reorg detected at", blockNumber);
  }
  lastHash = block.hash;
});

Choosing a Provider

For Ethereum specifically, consider these factors:

Finality support. Confirm the provider exposes safe and finalized block tags. Some older or public endpoints only support latest.

Archive access. If your app queries historical state, verify whether archive is included or costs extra.

Pricing model. Some providers use compute unit (CU) pricing, where heavy methods like eth_getLogs or debug_traceTransaction multiply your costs unpredictably. Flat-rate pricing removes this variable.

Infrastructure certification. For enterprise teams with procurement or compliance requirements, ISO 27001:2022 certification is meaningful. BoltRPC runs on Matrixed.Link’s ISO/IEC 27001:2022 certified infrastructure.

BoltRPC offers dedicated Ethereum RPC with flat-rate pricing from $49/mo, WebSocket support, EU infrastructure, and professional support on all plans. Trusted by Chainlink, Tiingo, Gains Network, Enjin.

Start your free 2-week trial at trial.boltrpc.io.

For endpoint details, MetaMask setup, and full network specs, see the Ethereum RPC endpoint page.

FAQ

What is the Ethereum RPC endpoint URL?

BoltRPC’s Ethereum Mainnet endpoint is https://eu.endpoints.matrixed.link/rpc/ethereum?auth=YOUR_KEY. Replace YOUR_KEY with your key from trial.boltrpc.io. The WebSocket endpoint is wss://eu.endpoints.matrixed.link/ws/ethereum?auth=YOUR_KEY. Chain ID is 1.

What is the difference between latest, safe, and finalized block tags on Ethereum?

latest is the most recent block and may be reorganized. safe is a recent block unlikely to reorg. finalized is cryptographically final after two epochs (approximately 12 minutes). Use latest for general reads, safe for transaction status checks, finalized for bridge and custody systems where irreversibility is required.

Do I need an archive node for Ethereum?

Only if you query historical state (balances at old blocks, large eth_getLogs ranges, historical simulations). Standard full nodes keep only recent state. For most dApps and bots working with current state, a full node is sufficient and cheaper.

What is EIP-1559 and how does it affect gas fees?

EIP-1559 replaced the legacy single-price gas auction with a base fee (burned, set by the protocol) plus a priority fee (tip to the validator). Your transaction sets maxFeePerGas as a ceiling and maxPriorityFeePerGas as the tip. Always fetch live fee data with provider.getFeeData() rather than hardcoding gas prices, since the base fee adjusts every block.


Frequently asked questions

Ready to build with high-performance RPC?

Start your free trial today. No credit card required. Access 20+ networks instantly.

Disclaimer: The content in this article is for informational purposes only and does not constitute financial, legal, or technical advice. Code examples and configurations are provided as-is. Always verify information with official documentation and test thoroughly in your own environment before deploying to production.

Continue reading