Skip to main content

Rate Limits

The public OXN RPC endpoint applies rate limits to prevent abuse and ensure availability for all users. This page documents what those limits are and how to handle them.

Limits

Rate limits apply per source IP address. Concrete numbers may change; contact the team via Support for the current guidance.

Rough current limits (subject to change):

  • Standard JSON-RPC requests: several requests per second per IP.
  • Batch requests: limited batch size (25 requests per batch as a rule of thumb).
  • WebSocket subscriptions: limited number of concurrent connections per IP; limited subscriptions per connection.
  • Heavy calls (eth_getLogs with wide ranges): consume multiple quota units.
  • debug_* methods: may be disabled entirely under load.

Behavior on limit exceeded

When you exceed the rate limit, the server returns:

HTTP/1.1 429 Too Many Requests
Retry-After: N

Where N is the number of seconds to wait before retrying. Well-behaved clients should:

  1. Respect the Retry-After header.
  2. Implement exponential backoff for repeated failures.
  3. Not immediately retry — that just wastes both sides' resources.

Example handling in ethers.js:

import { ethers } from "ethers";

async function withRetry(fn, maxAttempts = 5) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fn();
} catch (err) {
if (err.code !== 429) throw err;
const wait = Math.min(1000 * 2 ** attempt, 30_000);
console.log(`Rate limited. Waiting ${wait}ms`);
await new Promise((r) => setTimeout(r, wait));
}
}
throw new Error("Rate limited too many times");
}

// Usage
const balance = await withRetry(() => provider.getBalance(addr));

Requesting increased limits

If your integration genuinely needs more headroom than the default allows, contact the team through the Support channels. Include:

  • What you're building.
  • Your expected request rate (per second, per hour).
  • Which methods you use most heavily.
  • Whether you can run your own node instead.

Elevated limits are granted on a case-by-case basis for legitimate applications.

Alternatives to hitting the public endpoint hard

Before pushing the limits, consider:

  1. Cache read results locally. Chain state does not change more than once per block. If you're calling eth_getBalance repeatedly for the same address within a block, cache the result.

  2. Batch multiple queries into one request. See JSON-RPC Overview for batch format.

  3. Subscribe to events instead of polling. Use WebSocket newHeads and logs subscriptions instead of polling eth_blockNumber in a tight loop.

  4. Run your own node. For sustained high traffic, hosting your own RPC node is more reliable and predictable than the public endpoint. See Running a Read-Only RPC Node.

Monitoring your usage

The public endpoint does not currently expose per-user usage counters. You can measure your own request rate client-side:

let requestCount = 0;
provider._perform_orig = provider._perform;
provider._perform = function(...args) {
requestCount++;
return this._perform_orig(...args);
};

setInterval(() => {
console.log("Requests in last minute:", requestCount);
requestCount = 0;
}, 60_000);

Next steps