Base RPC Guide: How to Connect and Build on Base (2026)
Base is Coinbase’s OP Stack Layer 2. Its RPC layer has unique characteristics every developer should understand before going to production. This guide covers HTTP vs WSS selection, Base-specific RPC methods, multi-library connection examples, OP Stack architecture considerations, common production issues, provider selection.
For MetaMask setup and endpoint details, see our Base RPC endpoint page.
What is a Base RPC Endpoint
A Base RPC endpoint is an HTTP or WebSocket URL that lets your application send JSON-RPC 2.0 requests to Base Mainnet. Every read (balance checks, contract calls, event logs) and every write (transaction broadcasts) goes through this endpoint.
HTTP vs WebSocket: when to use each
HTTP (https://) is the right choice for the majority of application calls: fetching balances, reading contract state, estimating gas, broadcasting transactions. Each request is independent, stateless, maps cleanly to standard backend request patterns. HTTP works with all libraries, reverse proxies, serverless environments without configuration.
WebSocket (wss://) is the right choice when your application needs to react to on-chain events in real time. WebSocket connections are persistent and let you subscribe to Base blockchain events using eth_subscribe. The three subscription types you will use most on Base:
newHeads: fires on every new block (~2 s cadence on Base)logs: fires when a contract emits an event matching your filternewPendingTransactions: fires for each transaction entering the mempool
If your backend polls eth_blockNumber every few seconds to detect new state, migrate to a WebSocket newHeads subscription. It reduces RPC call volume significantly.
Example Base RPC Methods
Base is EVM-equivalent and runs on the OP Stack. It supports all standard Ethereum JSON-RPC methods plus a set of op_ namespace methods specific to OP Stack chains.
Standard eth_ methods used most on Base:
| Method | What it does |
|---|---|
eth_call | Read contract state without a transaction |
eth_getLogs | Fetch historical event logs by address or topic |
eth_getBalance | Get ETH balance for any address |
eth_getTransactionReceipt | Check transaction status and gas used |
eth_blockNumber | Get the latest confirmed block number |
eth_sendRawTransaction | Broadcast a signed transaction |
eth_subscribe | Open a WebSocket event subscription |
eth_estimateGas | Estimate gas for a transaction before sending |
OP Stack-specific op_ methods:
Base exposes several op_ namespace methods that reflect its rollup architecture. These are not available on Ethereum mainnet.
| Method | What it does |
|---|---|
optimism_outputAtBlock | Returns the output root at a given block (used by bridge contracts) |
optimism_syncStatus | Returns sync status including L1 head, L2 head, safe/finalized heads |
optimism_rollupConfig | Returns the rollup configuration including genesis block, L1 contract addresses |
optimism_version | Returns the OP Stack version string for the node |
optimism_syncStatus is particularly useful in production: it tells you the safe head (L2 blocks confirmed on L1) and finalized head (L2 blocks past the 7-day challenge window), which lets your application make correct finality decisions.
Public Base RPC Endpoints (For Testing Only)
These public endpoints are suitable for development and testing. Do not use them in production applications.
| Provider | HTTP Endpoint | Notes |
|---|---|---|
| Base (official) | https://mainnet.base.org | Rate-limited, shared |
| Coinbase | https://api.developer.coinbase.com/rpc/v1/base/ | Requires Coinbase Developer API key |
| Chainlist | https://base.llamarpc.com | Community aggregator |
| 1RPC | https://1rpc.io/base | Privacy-focused proxy |
Public endpoints are congested during high-traffic events on Base (token launches, NFT mints, viral moments). For production workloads, use a dedicated provider.
Connecting Step by Step
ethers.js (v6)
import { ethers } from "ethers";
// HTTP provider
const provider = new ethers.JsonRpcProvider(
"https://eu.endpoints.matrixed.link/rpc/base?auth=YOUR_KEY"
);
// WebSocket provider for subscriptions
const wsProvider = new ethers.WebSocketProvider(
"wss://eu.endpoints.matrixed.link/ws/base?auth=YOUR_KEY"
);
// Subscribe to new blocks
wsProvider.on("block", (blockNumber) => {
console.log("New Base block:", blockNumber);
});
// Listen to contract events
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, wsProvider);
contract.on("Transfer", (from, to, amount) => {
console.log(`Transfer: ${from} to ${to}, amount: ${amount}`);
});
Web3.py
from web3 import Web3
# HTTP connection
w3 = Web3(Web3.HTTPProvider(
"https://eu.endpoints.matrixed.link/rpc/base?auth=YOUR_KEY"
))
print("Connected:", w3.is_connected())
print("Chain ID:", w3.eth.chain_id) # 8453
print("Latest block:", w3.eth.block_number)
# Read contract state
balance = w3.eth.get_balance("0xYourAddress")
print("Balance (wei):", balance)
# WebSocket connection for subscriptions
from web3 import AsyncWeb3
from web3.providers import WebsocketProviderV2
async def listen_blocks():
async with AsyncWeb3(WebsocketProviderV2(
"wss://eu.endpoints.matrixed.link/ws/base?auth=YOUR_KEY"
)) as w3:
subscription_id = await w3.eth.subscribe("newHeads")
async for response in w3.socket.process_subscriptions():
print("New block:", response["result"]["number"])
curl
# Get latest block number
curl https://eu.endpoints.matrixed.link/rpc/base?auth=YOUR_KEY \
-X POST \
-H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
# Call a contract (read-only)
curl https://eu.endpoints.matrixed.link/rpc/base?auth=YOUR_KEY \
-X POST \
-H "Content-Type: application/json" \
--data '{
"jsonrpc":"2.0",
"method":"eth_call",
"params":[{"to":"0xYourContract","data":"0xYourCalldata"},"latest"],
"id":1
}'
# Get OP Stack sync status
curl https://eu.endpoints.matrixed.link/rpc/base?auth=YOUR_KEY \
-X POST \
-H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}'
Base-Specific Considerations
OP Stack sequencer and block production
Base uses a single sequencer operated by Coinbase. The sequencer batches transactions and posts them to Ethereum L1 approximately every few minutes. From an RPC perspective, you interact only with the L2 sequencer, not L1 directly. Base produces blocks roughly every 2 seconds regardless of transaction volume.
Finality model: safe vs finalized
Base has three distinct finality states that matter for production applications:
- Unsafe (latest): The sequencer has included your transaction but it has not been posted to L1 yet. Fastest to appear, but theoretically reversible if the sequencer fails.
- Safe: The transaction batch containing your transaction has been posted to Ethereum L1. Practically irreversible under normal conditions.
- Finalized: The 7-day fraud proof challenge window has passed. Cryptographically finalized on Ethereum.
For consumer apps (NFT mints, balance displays, social actions) the safe head is sufficient. For bridge operations or cross-chain settlement, wait for finalized. Use optimism_syncStatus to query which head is safe and which is finalized.
L2 to L1 interaction
Base uses the OP Stack standard bridge for moving assets between Base and Ethereum. The bridge contracts live on both chains. If your application monitors bridge withdrawals or deposits, you will need RPC access to both Base (Chain ID 8453) and Ethereum mainnet simultaneously.
Gas on Base
Base uses EIP-1559 gas pricing plus an L1 data fee component. The L1 data fee reflects the cost of posting your transaction’s calldata to Ethereum. eth_estimateGas returns the L2 execution gas estimate only. To compute the full fee, read the L1 block base fee from the GasPriceOracle contract at 0x420000000000000000000000000000000000000F.
Common Issues and Fixes
eth_getLogs returns an error or empty result on large ranges
Base nodes limit the block range for eth_getLogs requests. If your range exceeds the node’s limit (commonly 2,000 to 10,000 blocks depending on provider), the request fails. Fix: paginate your log queries. Fetch in chunks of 500-1,000 blocks, loop until you reach the target block.
async function getLogsInChunks(provider, filter, fromBlock, toBlock, chunkSize = 500) {
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;
}
WebSocket connection drops silently
WebSocket connections to Base RPC endpoints can drop without raising an exception if no keepalive mechanism is in place. In production, implement reconnect logic on the close event and resend subscriptions after reconnection. ethers.js v6 WebSocketProvider handles reconnection automatically if you use it correctly.
Stale latest block during sequencer degradation
If the Base sequencer is experiencing issues, the latest block can appear stale (not advancing). Your application should monitor eth_blockNumber against real time. If the block number does not change for more than 30 seconds, trigger an alert. Use optimism_syncStatus to check whether the sequencer is behind.
Transaction broadcast returns success but receipt is delayed
Transactions on Base are included in ~2 seconds under normal conditions. If eth_getTransactionReceipt returns null after 10-15 seconds, the transaction may have been dropped by the sequencer (e.g., due to a nonce gap or insufficient gas). Implement timeout handling: after 30 seconds with no receipt, re-query the mempool or rebroadcast.
Chain ID mismatch errors
Base Mainnet chain ID is 8453. Base Sepolia testnet is 84532. Sending a transaction signed for the wrong chain ID will be rejected. Always validate chain ID before broadcasting in multi-chain setups.
Choosing a Provider
Public Base RPC endpoints work for development and testing. Production applications need to evaluate providers on a few key factors:
Reliability during traffic spikes. Base sees irregular but intense traffic bursts during NFT launches and viral moments. Providers that share infrastructure across all customers throttle requests during these peaks. Dedicated or flat-rate providers do not.
Rate limits and caps. Compute-unit billing (used by most providers) attaches different weights to different methods. A single eth_getLogs call can cost 20-75 compute units. Under sustained read load, daily caps can be hit unexpectedly. Flat-rate pricing removes this variable entirely.
WebSocket support. Not all providers support persistent WebSocket subscriptions at every tier. Verify WebSocket availability before committing.
Method support. Some providers do not expose op_ namespace methods or do not expose the debug/trace namespace. If your application uses debug_traceTransaction or optimism_syncStatus, confirm support before choosing.
BoltRPC provides a dedicated Base endpoint with flat monthly billing, WebSocket support, no daily caps. Start your free 2-week trial at trial.boltrpc.io.
FAQ
What is the difference between Base safe and finalized blocks?
Safe blocks have been posted to Ethereum L1 by the Base sequencer and are practically irreversible. Finalized blocks have also passed the 7-day fraud proof challenge window and are cryptographically final on Ethereum. For most application logic, safe is sufficient. Use optimism_syncStatus to check both heads.
Which OP Stack methods does Base support?
Base supports optimism_outputAtBlock, optimism_syncStatus, optimism_rollupConfig, optimism_version. These expose rollup-specific state not available through standard eth_ methods. Some providers restrict these methods to paid tiers.
How do I avoid eth_getLogs timeouts on Base? Paginate your queries. Keep block ranges under 1,000 blocks per request and loop across the range you need. Many Base node providers enforce a 2,000 block limit per log query, some as low as 500.
Can I use the same API key for Base and Optimism with BoltRPC?
Yes. BoltRPC uses a consistent endpoint format across OP Stack chains. Change base to optimism in the path and your existing key works on Optimism. Both chains share the same endpoint format: https://eu.endpoints.matrixed.link/rpc/[chain]?auth=YOUR_KEY.
FAQPage Schema
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is the difference between Base safe and finalized blocks?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Safe blocks have been posted to Ethereum L1 by the Base sequencer and are practically irreversible. Finalized blocks have also passed the 7-day fraud proof challenge window and are cryptographically final on Ethereum. For most application logic, safe is sufficient. Use optimism_syncStatus to check both heads."
}
},
{
"@type": "Question",
"name": "Which OP Stack methods does Base support?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Base supports optimism_outputAtBlock, optimism_syncStatus, optimism_rollupConfig, optimism_version. These expose rollup-specific state not available through standard eth_ methods. Some providers restrict these methods to paid tiers."
}
},
{
"@type": "Question",
"name": "How do I avoid eth_getLogs timeouts on Base?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Paginate your queries. Keep block ranges under 1,000 blocks per request and loop across the range you need. Many Base node providers enforce a 2,000 block limit per log query, some as low as 500."
}
},
{
"@type": "Question",
"name": "Can I use the same API key for Base and Optimism with BoltRPC?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. BoltRPC uses a consistent endpoint format across OP Stack chains. Change base to optimism in the path and your existing key works on Optimism. Both chains share the same endpoint format: https://eu.endpoints.matrixed.link/rpc/[chain]?auth=YOUR_KEY."
}
}
]
}
</script>
Start your free 2-week trial at trial.boltrpc.io.