RPC Rate Limits Decoded: req/s, CUs, API Credits

June 10, 2026 · 5 min read · #rpc #rate-limits #compute-units #explainer

Every RPC provider limits you. The problem is they don't agree on what a "limit" even is. One caps you at a number of requests per second. Another meters "compute units." A third deducts "API credits" from a monthly pool. The exact same workload can sit comfortably within budget on one provider and get throttled instantly on another — and you can't compare two plans side by side, because the units don't line up.

This is an explainer, not a sales pitch. By the end you'll know the three models, why a logs-heavy indexer can cost ten times what its raw request count suggests, and how to estimate the number you actually need.

The three things "rate limit" can mean

1. Requests per second (req/s). The simplest model: a ceiling on how many JSON-RPC calls you may make per second. Every call counts as exactly one, whether it's a trivial eth_blockNumber or a brutal debug_traceTransaction. You're billed on a flat plan; there's no per-method weighting and no monthly call meter to drain. This is the model SwiftNodes uses.

2. Compute units (CUs). Each method is assigned a weight in "compute units." You get a CU-per-second throughput budget and a monthly CU cap. A cheap call might be 10 CUs; an expensive one, several hundred. Alchemy popularized this model — and it's the one that makes budgeting hard, because your bill depends on your method mix, not your request count. (We went deep on this in Alchemy's compute units.)

3. API credits. Each method deducts a fixed number of credits from a monthly pool. Same idea as CUs but framed as a prepaid balance you burn down. QuickNode uses this model; we broke down predicting that bill in QuickNode's API credits explained.

These aren't always mutually exclusive — a metered provider often imposes both a per-second throughput limit and a monthly quota, so you can be under your monthly CU cap and still get 429'd for a burst.

Why the same workload costs wildly differently

Under a req/s model, every call is worth one. Under a metered model, the heavy methods cost a multiple of the light ones. That single difference is why you can't eyeball a comparison.

Method Cost under req/s Typical metered weight
eth_blockNumber 1 very low
eth_getBalance 1 low
eth_call 1 low–medium
eth_getLogs (wide range) 1 high
eth_getBlockByNumber (full tx) 1 medium
debug_traceTransaction 1 very high

(Exact metered weights vary by provider and change over time — treat the right column as relative, and check your provider's current table.)

The consequence: an indexer that leans on eth_getLogs and debug_traceTransaction burns a metered budget far faster than its request-per-second rate implies. The same indexer on a flat req/s plan is priced purely on how fast it calls, not on which methods it picks.

The traps that blow a metered budget

  • Heavy methods. Wide eth_getLogs ranges, traces, and archive lookups dominate metered bills. A single debug_traceTransaction can cost as much as dozens of eth_calls. (Why eth_getLogs range caps bite covers the logs side.)
  • Batching doesn't save metered cost. A JSON-RPC batch of 50 is one HTTP request but fifty method calls. It cuts latency and round trips — but under CU/credit models you're charged the sum of all fifty. Great for batching throughput, neutral for metered spend.
  • Tight polling loops. Polling eth_blockNumber every 100ms is 600 calls/minute of pure overhead. Cheap under req/s, still wasteful; under metered models it's a slow leak. Use WebSocket subscriptions instead.

Estimate your own number

Don't guess — measure. Drop a counter in front of your provider and tally calls by method over a representative window:

const counts: Record<string, number> = {};

async function rpc(method: string, params: unknown[] = []) {
  counts[method] = (counts[method] ?? 0) + 1;
  const res = await fetch("https://rpc.swiftnodes.io/rpc/eth?key=YOUR_API_KEY", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
  });
  return (await res.json()).result;
}

// Later: console.table(counts) -> calls by method over your run.

Now you can map that profile onto each model:

  • req/s: take your peak calls-per-second and pick a plan above it. If you burst to 60 calls/s, you need ~60+ req/s of headroom — done.
  • metered (CU/credit): multiply each method's count by the provider's weight and sum it for the month. This is where a logs- or trace-heavy profile suddenly looks expensive.

Worked example — an indexer averaging 3,000 eth_call/min and 600 eth_getLogs/min: that's ~60 calls/s peak (a mid req/s plan), but on a metered plan the 600 heavy eth_getLogs calls each minute drive the bill, not the cheap eth_calls.

Staying under the limit

Whatever model you're on, two things keep you out of 429 territory: don't send calls you don't need, and back off when you're told to.

async function withRetry<T>(fn: () => Promise<T>, max = 5): Promise<T> {
  for (let attempt = 0; ; attempt++) {
    try {
      return await fn();
    } catch (err: any) {
      const is429 = err?.status === 429 || /rate limit|429/i.test(String(err?.message));
      if (!is429 || attempt >= max) throw err;
      const wait = Math.min(1000 * 2 ** attempt, 15000) + Math.random() * 250; // jittered backoff
      await new Promise((r) => setTimeout(r, wait));
    }
  }
}

Then trim the load itself:

  • Cache immutable reads. Old blocks, eth_chainId, eth_getCode, finalized receipts — none of these change. Cache them and stop re-asking.
  • Narrow eth_getLogs ranges and paginate instead of one giant query.
  • Use subscriptions, not polling, for new blocks and events.
  • Bound concurrency so a burst can't spike you past the per-second ceiling.

Which model should you pick?

It comes down to your traffic shape:

  • Flat req/s is predictable. Your bill is one number and it doesn't move when you add a heavy method or a new chain. It wins for steady load, trace-heavy work, and anyone who just wants to budget without a spreadsheet of per-method weights.
  • Metered (CU/credit) can be cheaper at genuinely low, light-method volume — but a single heavy-method spike can blow the monthly budget, and forecasting it is real work.

Roughly: below ~100–150M calls/month with light methods, a metered free or entry tier may come out cheaper; above that, or for any trace-heavy workload, flat-rate wins. SwiftNodes runs the flat req/s model — every plan from the free tier (no monthly call cap, just the rate limit) up to 500 req/s on Pro, archive included, no compute units to track.

Profile your method mix, pick the model that matches your traffic, and add jittered backoff so a burst degrades gracefully instead of failing. Grab a free SwiftNodes API key and you can size your real req/s against the Ethereum RPC endpoint — and every other chain — on the same key.

Related posts

Try SwiftNodes free — multi-chain RPC across 75+ networks, flat-rate pricing, crypto-payable, no KYC. Get an API key in 30 seconds →