Summary
Polygon rate limits cap how many JSON-RPC requests an endpoint will accept in a given window, and when you exceed them you get HTTP 429 responses, dropped WebSocket subscriptions, or silent timeouts. Public endpoints share those caps across every caller, so a single heavy loop can stall your whole app.
This article explains how Polygon rate limiting actually behaves, how to read the 429 and retry signals, and how to choose between public endpoints, a managed RPC API, and a dedicated Polygon node based on your request volume and method mix.
What a Polygon rate limit actually controls
A Polygon rate limit is a ceiling on how many JSON-RPC requests an endpoint will serve from you inside a fixed time window. It is not a single number. Providers usually enforce several limits at once: requests per second, requests per minute, concurrent connections, and sometimes a separate cap on expensive methods such as eth_getLogs, debug_traceTransaction, or eth_call against archive state.
When you cross a limit, the endpoint does not queue you politely. It returns an HTTP 429 Too Many Requests, closes a WebSocket, or lets the request time out. Your client sees a failed call, and if you retry immediately you make the problem worse.
Polygon mainnet (chain ID 137) runs on Bor for block production and Heimdall for checkpointing, and both public and managed endpoints sit in front of that stack. The rate limit is a property of the endpoint you call, not of the Polygon network itself. That distinction matters: two endpoints can serve the same chain and behave completely differently under load.
Quick recommendation: which endpoint fits your traffic
Before tuning retries, decide whether the endpoint you have can carry the workload you are sending. Use this as a first pass.
| Your situation | Likely bottleneck | Sensible next step |
|---|---|---|
| Prototyping, a few calls per minute | Nothing yet | A public endpoint is fine to start |
| Wallet or dApp with steady user traffic | Shared per-IP or per-key caps | Move to a managed RPC API with your own key |
| Indexer backfilling logs over long ranges | eth_getLogs caps and timeouts | Split ranges, then consider a dedicated node |
| Trading bot or liquidator | Latency plus per-second caps | Dedicated node close to your app |
| Archive queries over old blocks | Archive availability, not just rate | Confirm archive support before you commit |
If you are unsure which of these you are, the honest answer is usually the second row. Most teams outgrow a shared public endpoint before they outgrow the chain.
Reading the signals: 429, timeouts, and silent drops
Rate limiting rarely announces itself cleanly. These are the patterns worth recognizing.
- HTTP 429 with a
Retry-Afterheader. The clearest signal. Respect the header rather than retrying at a fixed interval. - HTTP 429 without headers. Common on shared public endpoints. Back off exponentially and add jitter.
- Timeouts on
eth_getLogs. Often a range or result-size limit rather than a per-second cap. - WebSocket disconnects. Subscriptions can be dropped when connection limits are hit; you need reconnect logic regardless of provider.
- Intermittent failures under load only. Classic shared-cap symptom: fine at 10 requests per second, flaky at 50.
A quick way to confirm the cause is to log the status code and the response body for every failed call. Many providers return a JSON-RPC error object with a message that distinguishes throttling from a bad request.
# Probe a Polygon endpoint and inspect the status code and body
curl -s -o /tmp/resp.json -w "%{http_code}\n" \
-X POST https://polygon.api.onfinality.io/public \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
cat /tmp/resp.json
Run that in a short loop and watch the status codes. A steady stream of 200 means you are inside the limit; a 429 tells you where the ceiling is.
Why public Polygon endpoints throttle so aggressively
Public RPC endpoints exist so anyone can read the chain without signing up. That openness is exactly why their limits are tight. Every caller shares the same pool, so the provider has to protect the node from one noisy client starving everyone else.
In practice this means public endpoints are good for:
- Reading a block number or gas price occasionally
- Manual testing in a wallet or a block explorer
- A fallback path when your primary endpoint is down
They are a poor fit for:
- Loops that poll every block
- Batch requests with hundreds of calls
- Log queries over wide block ranges
- Anything with a user-facing latency budget
The moment your application has real users, the shared cap becomes a product risk, not just an engineering detail. That is the point where teams move to a managed endpoint with a dedicated key, and later to a dedicated node when they need predictable throughput or archive access. You can compare those options on the RPC pricing page and see which chains are available under supported RPC networks.
Methods that hit limits first
Not all JSON-RPC methods cost the same. If you are debugging a rate limit, check whether the failures cluster around a few heavy calls.
| Method | Why it is expensive | Mitigation |
|---|---|---|
eth_getLogs | Scans many blocks and returns large payloads | Narrow the block range, paginate, cache results |
eth_call on old state | Needs archive data | Pin to recent blocks unless you truly need history |
debug_traceTransaction | Re-executes a transaction | Use sparingly, off the hot path |
eth_getBlockByNumber with full txs | Large response per call | Request transaction hashes only when possible |
eth_newFilter polling | Many small calls over time | Prefer WebSocket subscriptions where supported |
Polygon endpoints from OnFinality support both HTTP and WebSocket transports, so subscription-based patterns are available when you want to replace polling with push. See the Polygon network page for the current endpoint and transport details.
Client-side patterns that survive throttling
You cannot always avoid a rate limit, but you can make your client behave well when it hits one.
Back off with jitter. Retrying immediately turns a brief throttle into a sustained one. Exponential backoff with random jitter spreads retries out.
async function rpcWithRetry(url, body, maxRetries = 5) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (res.status !== 429) return res.json();
const retryAfter = Number(res.headers.get("retry-after")) || 0;
const base = retryAfter * 1000 || 2 ** attempt * 250;
const wait = base + Math.random() * 250;
await new Promise((r) => setTimeout(r, wait));
}
throw new Error("RPC rate limit: retries exhausted");
}
Batch carefully. JSON-RPC batch requests reduce round trips, but a batch of 200 calls still counts as 200 calls against most limits. Batching helps latency, not quota.
Cache what does not change. Block numbers, chain IDs, and finalized data can be cached. Do not re-fetch a block you already have.
Separate read paths from write paths. A user-facing read should not compete with a background indexer for the same quota. Give them different keys or different endpoints.
Add a fallback endpoint. If your primary returns 429, fail over to a secondary. Keep the failover logic simple and log when it triggers, so you know how often you are actually throttled.
When to move from a shared endpoint to a dedicated node
A managed RPC API with your own key raises your ceiling and gives you visibility into your usage. A dedicated node changes the equation again: you get infrastructure reserved for your workload rather than a shared pool.
Consider a dedicated Polygon node when:
- Your request rate is predictable and high enough that shared caps are the limiting factor
- You need archive data or trace methods that shared endpoints restrict
- You want consistent latency for a latency-sensitive workload
- You need to isolate one application's traffic from another's
Stay on a managed shared endpoint when your traffic is bursty, your method mix is light, and you would rather not operate infrastructure. Most teams land here first and only move to dedicated when a specific method or volume forces it. OnFinality offers both paths, and the dedicated node page covers what reserved infrastructure involves.
A short debugging checklist for 429s
When a Polygon rate limit error appears in production, work through this in order:
- Confirm the status code and response body, not just the client-side error.
- Identify which method is failing and whether it is one of the heavy calls above.
- Check whether failures correlate with a deploy, a cron job, or a traffic spike.
- Count your actual requests per second during the failure window.
- Verify you are not retrying without backoff, which multiplies load.
- Check whether a batch job and user traffic share the same key.
- If the ceiling is genuinely too low for your workload, evaluate a managed key or a dedicated node.
Steps 1 through 4 usually reveal the cause. Steps 5 and 6 are the most common self-inflicted problems.
Key Takeaways
- A Polygon rate limit is enforced by the endpoint, not the chain, and usually combines per-second, per-minute, and concurrency caps.
- HTTP 429 is the clearest signal, but timeouts on
eth_getLogsand WebSocket drops are also throttling symptoms. - Public endpoints share their caps across all callers, which makes them unsuitable for user-facing traffic.
- Backoff with jitter, caching, and separating read paths from batch jobs reduce how often you hit limits.
- Heavy methods like
eth_getLogsanddebug_traceTransactionhit limits before simple calls do. - Move to a managed key when shared caps become a product risk, and to a dedicated node when you need reserved throughput or archive access.
Frequently Asked Questions
What is the Polygon rate limit on public endpoints? It varies by provider and is usually not published as a single number. Public endpoints typically enforce low per-second and per-IP caps because capacity is shared across all callers. Test your actual endpoint rather than assuming a figure.
Why do I get 429 errors only sometimes? Intermittent 429s usually mean you are near a shared cap that other callers also consume. Your traffic is fine most of the time and over the line during spikes or when a batch job runs alongside user traffic.
Does batching JSON-RPC requests avoid rate limits? No. Most providers count each call inside a batch against your quota. Batching reduces network round trips and latency, not request count.
How do I handle 429s in a WebSocket connection? Reconnect with backoff and re-subscribe to your topics. Log disconnects so you can tell throttling apart from network issues. Subscription limits are separate from HTTP request limits.
When should I use a dedicated Polygon node instead of a shared endpoint? When shared caps are the limiting factor for your workload, when you need archive or trace methods, or when you need consistent latency. If your traffic is light and bursty, a managed shared endpoint is usually the better fit.
Can I raise my limits without running a node? Yes. A managed RPC API with your own key gives you a higher, isolated ceiling without operating infrastructure. Review RPC pricing to compare options, and check supported RPC networks for availability.