You connect MetaMask to a dApp. A balance appears. You swap a token, and a confirmation pops up 12 seconds later. Behind every one of those interactions - the balance check, the gas estimate, the transaction broadcast, the receipt confirmation - your application made an RPC call to a blockchain node. Every read and every write to any EVM chain goes through RPC.
RPC (Remote Procedure Call) is a protocol that lets one program execute a function on another machine over a network. In blockchain, RPC is how applications communicate with nodes. A wallet checking ETH balances makes eth_getBalance calls. A DEX displaying token prices makes eth_call to read smart contracts. A deployment script submitting a contract makes eth_sendRawTransaction. Each of these is a remote procedure call to a node that holds blockchain state.
This guide covers how blockchain RPC works from protocol to production: the JSON-RPC format, essential Ethereum methods, transport trade-offs (HTTP vs WebSocket), provider evaluation criteria, and working code examples in curl, JavaScript, and Python.
What Is a Remote Procedure Call?
Bruce Jay Nelson coined "Remote Procedure Call" in his 1981 PhD dissertation at Xerox PARC. The core idea: let a program call a function on a remote machine as if it were local. The caller does not manage socket connections, serialization, or protocol details. A client stub serializes the function name and arguments, sends them over the network, and a server stub on the remote machine deserializes and executes the call. The result travels back the same way.
RPC became foundational across distributed systems. Sun RPC, gRPC, XML-RPC, and JSON-RPC all descend from this concept. In each case, the developer writes what looks like a local function call, and the RPC framework handles the network transport.
In blockchain, the node is the remote server. Your dApp, wallet, or script is the client. JSON-RPC is the protocol that structures requests and responses. When you call eth_getBalance, you are making a remote procedure call to a node that holds blockchain state.
How Blockchain RPC Works

Every blockchain interaction follows the same five-step flow. This is the path from your code to on-chain data and back:
- Your application constructs a JSON-RPC request with a method name and parameters (e.g.,
eth_getBalancewith an address and block number). - The request is sent via HTTP or WebSocket to an RPC endpoint URL.
- The endpoint routes the request to a blockchain node running client software (Geth, Nethermind, Reth, Besu, or another implementation).
- The node executes the requested operation - reading state from its database, simulating a call against the EVM, or broadcasting a signed transaction to the peer-to-peer network.
- The node returns a JSON-RPC response containing the result (a balance, a transaction hash, a block) or an error.
This happens constantly. A block explorer displaying chain data makes thousands of RPC calls per second. Your Hardhat deployment script submitting a contract is an eth_sendRawTransaction followed by polling eth_getTransactionReceipt. The entire Web3 application layer runs on this request-response loop.
What Is an RPC Endpoint?
Two terms get used interchangeably but mean different things:
An RPC node is a server running blockchain client software (Geth, Nethermind, Reth, Erigon) that maintains a copy of the blockchain and exposes an RPC interface to accept external requests.
An RPC endpoint is the URL your application sends requests to - for example, https://api-ethereum-mainnet.n.dwellir.com/<API_KEY>. An endpoint can point to a single node, or to a load balancer distributing requests across hundreds of nodes in multiple regions.
Node Types and What They Store
Not all nodes hold the same data. The type of node behind your RPC endpoint determines what queries it can answer.

The distinction matters in practice. Querying "what was this address's balance at block 1,000,000?" requires an archive node. A full node can only answer for recent blocks. Many providers gate archive access behind premium tiers or charge 2-3x higher rates for archive queries. Some, like Dwellir, include archive access on all paid plans at no extra cost.
JSON-RPC - The Protocol Behind Every Blockchain Call
Ethereum and most EVM-compatible chains use JSON-RPC 2.0, a stateless, transport-agnostic protocol that structures requests and responses as JSON objects. Every request contains 4 fields:
jsonrpc- Always"2.0"method- The RPC method name (e.g.,eth_blockNumber)params- An array of parameters (can be empty)id- A unique identifier to match responses to requests
Here is a real, copy-pasteable request for eth_blockNumber - the simplest RPC call, which returns the latest block number on the chain:
curl -X POST https://ethereum-rpc.publicnode.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}'
The response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x13f8e6a"
}
All Ethereum RPC values are hex-encoded with a 0x prefix. 0x13f8e6a converts to 20,906,602 in decimal. Balances, block numbers, gas values, and nonces all use this encoding. Libraries like ethers.js and web3.py handle the conversion automatically, but when working with raw JSON-RPC, expect hex everywhere.
When something goes wrong, the response includes an error object with code, message, and optional data fields instead of a result. Standard error codes are defined in the JSON-RPC 2.0 specification - the troubleshooting section below covers the ones you will encounter most.
Essential Ethereum JSON-RPC Methods
These are the methods that cover 90% of Ethereum application development. Each one maps to a specific node operation.
| Method | What It Does | Example Use |
|---|---|---|
eth_blockNumber | Returns the latest block number | Syncing status, block explorers |
eth_getBalance | Returns an address's ETH balance in wei | Wallet balance display |
eth_call | Executes a read-only smart contract call without creating a transaction | Reading ERC-20 token balances, checking prices |
eth_sendRawTransaction | Submits a signed transaction to the network | Token transfers, contract interactions |
eth_getTransactionReceipt | Returns the receipt of a mined transaction (null if pending) | Confirming transaction success/failure |
eth_getLogs | Returns event logs matching a filter (address, topics, block range) | Monitoring token transfers, contract events |
eth_estimateGas | Estimates gas needed for a transaction | Setting gas limits before submission |
eth_gasPrice | Returns the current gas price in wei | Fee estimation |
eth_getBlockByNumber | Returns block data by number (with or without full transactions) | Block explorers, chain analysis |
eth_subscribe | Creates a real-time subscription over WebSocket | Live transaction monitoring, new block alerts |
Read-only calls (eth_call, eth_getBalance, eth_getLogs) do not require a signed transaction or spend gas. State-changing operations (eth_sendRawTransaction) require the transaction to be signed client-side before submission. The node never sees your private key.
For the complete Ethereum JSON-RPC method reference with parameter details, see Dwellir's Ethereum documentation.
RPC Beyond Ethereum
JSON-RPC is the dominant protocol across blockchains, but method names, data encoding, and chain-specific concepts differ by ecosystem.
Solana
Solana uses JSON-RPC 2.0 with its own method namespace: getBalance, getTransaction, sendTransaction, getSlot. The distinctive feature is commitment levels - every read request accepts a commitment parameter (processed, confirmed, finalized) controlling the finality guarantee of returned data. processed is fastest but might be rolled back. finalized is slower but irreversible. Balances are returned in lamports (1 SOL = 1,000,000,000 lamports).
Substrate and Polkadot
Substrate-based chains use namespaced JSON-RPC methods: chain_getBlock, state_getStorage, system_health, author_submitExtrinsic. Storage values use SCALE encoding (a compact binary format) rather than ABI encoding. Transactions are called "extrinsics" - a term that extends to any externally-submitted data.
Sui
Sui uses JSON-RPC 2.0 with methods like sui_getObject and sui_executeTransactionBlock. The data model is object-centric rather than account-based - you query and manipulate objects, not account state. Sui is migrating toward gRPC and GraphQL.
The concept is the same across every chain: your application sends a structured request to a node and gets a structured response. The method names and data formats differ, but the RPC pattern is universal.
HTTP vs WebSocket - Choosing Your Transport
RPC calls travel over a transport protocol. The two options - HTTP and WebSocket - serve different use cases.
| HTTP (HTTPS) | WebSocket (WSS) | |
|---|---|---|
| Connection model | New connection per request (or reuse via HTTP/2) | Persistent bidirectional connection |
| Data flow | Request-response only | Server can push data to client |
| Real-time support | Must poll repeatedly | Native subscriptions (eth_subscribe) |
| Best for | Discrete queries, low-frequency reads | Real-time monitoring, event streaming |
| Overhead | Higher per-request (connection setup) | Lower per-message once connected |
| Example methods | eth_getBalance, eth_call, eth_sendRawTransaction | eth_subscribe("newHeads"), eth_subscribe("logs") |

Use HTTP for most RPC calls - balance checks, transaction submissions, contract reads. These are discrete request-response operations that do not benefit from a persistent connection. Switch to WebSocket when you need real-time data: monitoring new blocks, watching for specific contract events, or tracking pending transactions in the mempool.
A common pattern in production: HTTP for all standard reads and writes, plus a single WebSocket connection for event subscriptions that trigger application logic (new block notifications, specific contract events, pending transaction alerts).
RPC vs REST vs GraphQL
Three API paradigms exist in the blockchain ecosystem, and you will likely use more than one.
JSON-RPC is action-oriented. You call methods directly (eth_getBalance, eth_sendRawTransaction), each mapping to a node operation. This is the native interface for talking to blockchain nodes.
REST is resource-oriented. Data is exposed as URLs: /blocks/123, /transactions/0xabc, /addresses/0xdef/balance. Block explorers like Etherscan expose REST APIs over indexed and enriched data. REST suits caching, browser access, and CRUD-style queries over processed blockchain data.
GraphQL lets clients specify exactly which fields they need in a single request, avoiding over-fetching. The Graph protocol uses GraphQL for querying indexed blockchain data across subgraphs - a strong fit for complex queries that span multiple entity types.
The rule of thumb: talking to a node directly? JSON-RPC. Querying indexed historical data? REST or GraphQL.
Running Your Own Node vs Using a Provider
You can run your own RPC infrastructure or use a managed provider. The trade-offs are significant.
Self-Hosting Reality Check
An Ethereum full node requires 8+ CPU cores, 32-64 GB RAM, a 4+ TB NVMe SSD, and 300+ Mbps bandwidth. Monthly cost for a single node: $300-600. A production setup with redundancy, load balancing, and geographic distribution runs $15,000-24,000/month once you factor in DevOps time and multi-region hosting.
Maintenance is ongoing. Ethereum averages 2 major client updates per year. Missing a hard fork means your node follows the wrong chain. Disk usage grows continuously - plan for regular pruning or storage expansion. And that covers a single chain. Every additional network requires its own infrastructure stack.
Managed Providers
Managed RPC providers handle node operations, uptime, fork upgrades, and scaling. Setup takes minutes instead of days, and a single API key covers multiple chains.
| Self-Hosted | Managed Provider | |
|---|---|---|
| Setup time | Days to weeks | Minutes |
| Monthly cost (moderate volume) | $300-600+ per chain | $49-299 |
| Maintenance | You handle forks, updates, disk growth | Provider handles it |
| Uptime | Your responsibility | 99.9-99.99% SLA |
| Multi-chain | Separate infrastructure per chain | Single API key |
| Customization | Full control | Limited to provider options |
| Data sovereignty | Complete | Data passes through provider |
Self-hosting makes sense when you need full control over node configuration, require data sovereignty for compliance, or run latency-sensitive MEV operations where every millisecond between your application and the node matters. For most teams, a managed provider is the practical choice.
For a deeper breakdown of what to evaluate, see 7 essential things you need to know about Ethereum RPC providers.
What to Look for in an RPC Provider
Not all RPC providers are equivalent. These are the criteria that matter most in production.
Pricing Transparency
Pricing is the biggest variable across providers. Some use compute units where different methods cost different amounts - an eth_call might cost 26 compute units while an eth_getLogs request costs 255. Your actual cost per request depends on your call mix, and a shift in usage patterns can spike your bill without any increase in total request volume.
Other providers charge a flat rate per request regardless of method complexity. Flat-rate pricing makes costs predictable and eliminates the need to optimize which methods your application calls. RPC providers without compute units breaks down the difference in detail.
Uptime and Reliability
Look for 99.9%+ uptime SLAs with response credits for downtime. Single-cloud providers carry concentration risk - an AWS outage can take down multiple RPC providers simultaneously because they share the same underlying infrastructure. Ask about multi-cloud and bare-metal strategies.
Latency
Sub-100ms p95 latency is the benchmark for production applications. Regional distribution matters more than raw average numbers - a provider with nodes in your users' geographic regions delivers lower latency than one with a faster global average but no presence near your users.
Rate Limits
Free tiers typically cap at 100-200 requests per minute. Production tiers range from 100 to 2,000+ requests per second depending on the plan. Burst capacity during traffic spikes (a token launch, a market crash, a viral mint) matters as much as sustained throughput.
Archive Data
If your application queries historical state (balances at past blocks, old event logs, historical contract storage), confirm that archive access is included in your plan. Some providers charge 2x or more for archive queries, or restrict archive access to enterprise tiers.
Chain Coverage
Multi-chain applications need a provider that supports all target networks. Coverage varies widely - from 30 networks at some providers to 150+ at others like Dwellir. Consolidating on a single provider simplifies key management, billing, and monitoring.
Making Your First RPC Call
Three practical examples, each querying the ETH balance of Vitalik Buterin's public address (0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045).
curl (works anywhere)
curl -X POST https://ethereum-rpc.publicnode.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest"],
"id": 1
}'
The response returns the balance in wei, hex-encoded. Divide by 10^18 to get ETH.
JavaScript (ethers.js v6)
import { JsonRpcProvider, formatEther } from 'ethers';
const provider = new JsonRpcProvider('https://ethereum-rpc.publicnode.com');
const balance = await provider.getBalance(
'0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
);
console.log(`Balance: ${formatEther(balance)} ETH`);
Python (web3.py)
from web3 import Web3
w3 = Web3(Web3.HTTPProvider('https://ethereum-rpc.publicnode.com'))
balance = w3.eth.get_balance('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')
print(f"Balance: {w3.from_wei(balance, 'ether')} ETH")
These examples use a public endpoint for demonstration. Public endpoints work for learning and testing, but production applications need a dedicated endpoint with an API key for higher rate limits, uptime guarantees, and support. Dwellir's free tier provides 5 million requests per month across 150+ networks to get started.
Common RPC Errors and How to Fix Them
These are the errors you will encounter most in development and production.
| Error Code | Message | Common Cause | Fix |
|---|---|---|---|
| -32700 | Parse error | Malformed JSON in request body | Validate JSON before sending |
| -32600 | Invalid Request | Missing jsonrpc or method field | Check required fields |
| -32601 | Method not found | Typo in method name, or method not supported by node | Verify method name and case sensitivity |
| -32602 | Invalid params | Missing 0x prefix, wrong parameter count, block range too wide | Check hex encoding, reduce eth_getLogs block range |
| -32603 | Internal error | Execution reverted, bad payload, or node issue | Test with eth_call first; check revert reason in error data |
| -32000 | Server error | Block not found, nonce too low, filter expired | Verify node is synced; check nonce; recreate filters |
| HTTP 429 | Rate limited | Too many requests per second | Implement exponential backoff; cache stable values; batch requests |
Rate limiting (HTTP 429) is the most common production issue. Three strategies help: cache values that change slowly (eth_chainId never changes, eth_blockNumber changes every ~12 seconds on Ethereum), batch independent requests into a single call, and implement exponential backoff with jitter on retries.
Advanced RPC Patterns
Batch Requests
JSON-RPC 2.0 supports sending an array of requests in a single HTTP call. Instead of 3 round trips, you make 1:
[
{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1},
{"jsonrpc": "2.0", "method": "eth_gasPrice", "params": [], "id": 2},
{"jsonrpc": "2.0", "method": "eth_getBalance", "params": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest"], "id": 3}
]
The server returns an array of responses. Match results to requests by id - response order is not guaranteed. Batching reduces round trips and works well for pages that need multiple pieces of chain data on load. One caveat: a single slow query (like a large eth_getLogs range) delays the entire batch response.
WebSocket Subscriptions
eth_subscribe over WebSocket enables real-time data streams without polling overhead. Three subscription types cover most use cases:
newHeads- Pushes block header data each time a new block is produced. Useful for updating UIs, triggering batch jobs, or tracking chain progress.logs- Pushes filtered contract events as they are included in blocks. You specify an address and topics to match. This is how DeFi dashboards track swaps, transfers, and liquidity events in real time.newPendingTransactions- Pushes transaction hashes as they enter the node's mempool. High-volume stream used for gas estimation and MEV detection. See the mempool guide for deep coverage of pending transaction monitoring.
gRPC
gRPC is an alternative transport that uses Protocol Buffers (binary serialization) instead of JSON text. The result: 3-10x smaller payloads and significantly faster serialization/deserialization compared to JSON-RPC. Solana's Yellowstone gRPC, Cosmos/Tendermint, and Sui all use gRPC for high-throughput data streaming.
For most dApp developers, JSON-RPC over HTTP and WebSocket covers all requirements. gRPC becomes relevant when you process high volumes of chain data - indexers, analytics pipelines, or infrastructure-level tooling.
Getting Started
The fastest way to start making RPC calls is with a free endpoint from any major provider. Most offer free tiers ranging from 3 to 30 million requests per month - enough to build and test applications before committing to a paid plan.
When evaluating production providers, pay attention to the pricing model. Compute-unit pricing means your cost varies by method - a debug_traceTransaction might cost 10-30x more than an eth_chainId. Flat-rate providers like Dwellir charge 1 credit per response regardless of method, which simplifies cost forecasting for applications with mixed call patterns.
To get started with Dwellir: register for a free account, create a project, and copy your endpoint URL. First RPC call in under 2 minutes.
Frequently Asked Questions
What does RPC stand for?
Remote Procedure Call - a protocol for executing functions on remote machines over a network. In blockchain, it is the standard interface between applications and nodes.
What is the difference between an RPC node and a full node?
An RPC node is a full node with its RPC interface enabled, allowing it to accept external requests over HTTP or WebSocket. Not all full nodes expose an RPC interface - some run only for peer-to-peer network participation.
Is JSON-RPC the same as REST?
No. JSON-RPC is action-oriented - you call methods (eth_getBalance). REST is resource-oriented - you access URLs (/blocks/123). Both use HTTP as a transport, but the interaction models differ. JSON-RPC sends all requests to a single endpoint with method names in the body; REST maps operations to distinct URLs and HTTP verbs.
Can I use a public RPC endpoint in production?
Not recommended. Public endpoints typically have low rate limits (often 100 requests per minute), no uptime guarantees, shared capacity with every other user, and no support. Use a dedicated endpoint with an API key for production applications.
What is the difference between HTTP and WebSocket RPC?
HTTP is request-response: you send a request, the node returns an answer. WebSocket maintains a persistent bidirectional connection where the node can push data to your application in real time - new blocks, contract events, pending transactions - without polling.
Do I need an archive node?
Only if your application queries historical blockchain state older than ~128 blocks. Current balances, recent transactions, and new contract events all work on standard full nodes. Historical balance lookups, old event log queries, and block explorer functionality require archive nodes.
How much does an RPC endpoint cost?
Free tiers exist at most providers, ranging from 3 to 30 million requests per month. Paid plans typically range from $49 to $999/month depending on volume and features. Self-hosting a single Ethereum full node costs $300-600/month in infrastructure alone, before accounting for maintenance time.
What is a compute unit in RPC pricing?
A compute unit (CU) is a billing metric some RPC providers use to weight different methods by complexity. A simple eth_blockNumber call might cost 1 CU, while eth_getLogs costs 20-255 CUs depending on the provider. The same total request count produces different bills depending on the method mix. Flat-rate providers charge the same per request regardless of method.
How do I handle RPC failover in production?
Configure at least two RPC endpoints from different providers. If your primary endpoint returns errors or exceeds latency thresholds, route requests to the backup. Most Web3 libraries support fallback providers - ethers.js has FallbackProvider, and viem supports fallback transports. This protects against single-provider outages.


