High‑traffic Web3 products live or die on their data layer.
If you are building trading terminals, wallets, or prediction market front‑ends, you are probably searching for the best on‑chain data APIs for trading apps and the most reliable on‑chain data APIs for high traffic. Getting pagination, caching, and rate limits wrong leads directly to frozen charts, throttled users, and angry traders.
This guide walks through practical API design patterns for backend and frontend teams consuming on‑chain data APIs at scale, with examples from Codex’s trading‑grade token and prediction market API.
Choosing the Best On‑Chain Data APIs for Trading Apps
Observed behavior: High‑traffic trading apps consistently converge on a small set of patterns: cursor‑based pagination, pagination‑aware caching, batching, and push‑based realtime.
Recommendation: When you evaluate the best crypto data APIs for high traffic trading apps, look for providers that:
- Expose GraphQL‑style connections with cursor pagination and
pageInfometadata. - Provide clear rate limits, burst limits, and websocket constraints.
- Offer both REST/queries and subscriptions/webhooks for realtime workloads.
- Document request caps per endpoint and recommend batching strategies.
Example: Codex powers apps like Coinbase, TradingView, Uniswap, Magic Eden, and Rainbow with:
- Coverage across 80+ networks, 70M+ tokens, 700M+ wallets, and 27B+ historical events (see: https://www.codex.io/pricing).
- Sub‑second data freshness (<1s) suitable for trading‑grade UX.
- A single GraphQL‑style API for prices, charts, aggregates, holders, and prediction markets.
For authoritative numbers on Codex limits and coverage, always refer to their pricing and docs pages: https://www.codex.io/pricing and https://docs.codex.io.
Pagination: Cursor vs Offset (pagination cursor vs offset blockchain API)
Observed facts
- The GraphQL Cursor Connections spec (Relay) defines the modern standard for cursor pagination with
edges,nodes,pageInfo, and opaque cursors (Relay spec). - The Graph (subgraphs) explicitly warns that
skip(offset) is inefficient for large result sets and recommends paging by an attribute likeid_gtor cursors (The Graph docs). - Bitquery limits default query results to 25,000 rows and notes that offset pagination should be reserved for static, strongly ordered data (Bitquery docs).
Recommendation: Prefer cursor-based pagination by default
For on‑chain data APIs, cursor pagination is the safe default:
- It avoids missing/duplicated items when new data arrives between requests.
- It scales better than heavy
skip/offset queries on big tables or logs. - It aligns with GraphQL client libraries like Relay and Apollo.
Use offset pagination only when:
- The dataset is small and static (e.g., a short list of chains or networks).
- You need explicit random access by index, and the provider guarantees stable ordering.
Example: Cursor pagination shape
A typical GraphQL connection for trades or prediction markets might look like:
query TradesPage($first: Int!, $after: String) {
trades(first: $first, after: $after) {
edges {
cursor
node {
id
txHash
priceUsd
timestamp
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
Recommendation: On the backend, always enforce a stable sort (e.g., by timestamp DESC, id DESC) to keep cursors consistent across pages.
Client-Side Caching for Blockchain Data
Observed facts
- Apollo Client requires pagination‑aware cache policies: you must set
keyArgsandmergeso new pages append instead of overwriting (Apollo pagination docs). - TanStack Query (React Query) recommends
keepPreviousDataand structural sharing to avoid flicker and unnecessary rerenders (TanStack pagination guide). - MDN clarifies that
Cache-Control: no-cachemeans “store but revalidate” and recommendsETag/If-None-Matchandstale-while-revalidatesemantics for responsive apps (MDN caching guide).
Recommendation: Use pagination-aware caching
For token lists, transaction feeds, and prediction market events:
- Treat each logical list as one cache entry, regardless of page.
- Use cursor‑aware merge functions so pages append or deduplicate.
- Keep previous data visible while the next page loads.
Example: Apollo merge function for cursor pagination
// Recommendation: Apollo type policy for cursor-based lists
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
trades: {
keyArgs: ["marketId"], // ignore `first` and `after`
merge(existing = { edges: [] }, incoming, { args }) {
const edges = existing.edges ? [...existing.edges] : [];
// simple append; you can also dedupe by node.id
if (incoming.edges) {
edges.push(...incoming.edges);
}
return {
...incoming,
edges,
};
},
},
},
},
},
});
Recommendation: TTLs per data type (with numeric ranges)
You need different cache lifetimes for different data:
-
Realtime prices (e.g.,
getTokenPrices):- TTL: 0–5 seconds client‑side.
- Rationale: trading users expect near‑instant updates; rely on subscriptions when possible.
-
Intraday candles (1m, 5m, 15m):
- TTL: 10–60 seconds.
- Rationale: these are aggregations; slight staleness is acceptable but avoid minute‑scale drift.
-
Historical candles (1h, 4h, 1d):
- TTL: 5 minutes–24 hours, depending on timeframe.
- Rationale: past candles change rarely; long TTL reduces load.
-
Token metadata (name, symbol, logo, decimals):
- TTL: 1–24 hours.
- Rationale: metadata changes infrequently; long cache saves bandwidth.
-
Wallet snapshots / balances:
- TTL: 5–30 seconds for active trading views.
- Rationale: balances can move quickly; stale balances damage trust.
Recommendation: Combine these TTLs with ETag or Last-Modified where available, so clients can revalidate cheaply (receive 304 Not Modified instead of downloading full payloads).
Batching Requests & Handling Rate Limits
Observed facts
- Codex publishes explicit rate limits, burst buckets, and websocket caps on its pricing page (e.g., Growth plan showing 1,000,000 requests/month, 300 requests/sec, burst limit 500 – see: https://www.codex.io/pricing). Treat these as example values and verify against the live pricing page.
- Codex docs outline per‑endpoint caps, like maximum tokens per
getTokenPricescall and recommended limits per websocket connection (Codex troubleshooting). Again, treat these as examples and check the docs for exact values. - GitHub’s GraphQL API uses a point‑based rate limit with caps like 5,000 points/hour and ~2,000 points/minute (GitHub rate docs).
- Alchemy uses a rolling token bucket with HTTP batch caps (e.g., 1,000 JSON‑RPC calls per batch) and recommends exponential backoff on 429s (Alchemy throughput docs).
Recommendation: Batch vertically, not horizontally
Batching is about packing more value into each call without overloading responses.
-
Do batch:
- Multiple tokens into one price request (respecting provider caps).
- Multiple markets into a single prediction market query.
- Multiple wallet addresses into one balances request (if supported).
-
Do not batch:
- Entire UI into one mega‑query that returns hundreds of KB per call.
- Heterogeneous workloads (prices + metadata + holders + prediction events) in a single query if they change at different frequencies.
Recommendation: Keep individual responses under a practical size (e.g., <200–500KB compressed) to avoid slow first‑byte times and memory blowups.
Recommendation: Respect provider quotas & per-endpoint caps
For Codex specifically (example values; verify in docs):
getTokenPricesmay cap at 25 tokens per request.filterTokensmay cap at 200 results per request.onPricesUpdatedsubscriptions may accept up to 25 tokens per input array.
Design your batching layer to:
- Chunk large token lists into batches that fit those caps.
- Reuse those batches across users via a backend fan‑out layer.
- Use per‑plan limits (requests/sec, burst size) as guardrails for your concurrency.
Websocket vs REST for On-Chain Real-Time Data
Observed facts
- Codex docs distinguish between queries (REST‑like GraphQL), subscriptions (websockets), and webhooks, and recommend subscriptions/webhooks for realtime workloads (Codex queries vs subscriptions).
- Codex webhooks expect a 2xx response within ~3 seconds, count each delivery against your quota, and retry up to 2 times on failure (Codex webhooks).
- Codex subscription docs recommend closing idle connections and using backend proxies for shared feeds (Codex subscriptions).
Recommendation: Use the right channel for each workload
-
REST/Queries:
- One‑off lookups, historical charts, "view on load" data.
- Good for SSR and prefetching.
-
Websockets/Subscriptions:
- Live price ticks, order books, prediction market trades.
- Good for trading terminals and dashboards.
-
Webhooks:
- Event‑driven backends (e.g., notify when a wallet crosses a threshold, or when new prediction markets list).
- Good for background processing and alerts.
Recommendation: Avoid aggressive polling for realtime updates. Polling every 1–2 seconds across thousands of users will hit rate limits quickly and increase infrastructure costs.
Real-time Crypto Data API Trading 2024
In 2024, the pattern for real‑time crypto data API trading workloads is clear:
- Trend: The industry is shifting from short‑interval polling to push‑based updates via websockets and webhooks. Codex, Alchemy, and GitHub all document polling as costly and push as more scalable.
- Trend: Providers expose more transparent traffic‑shaping primitives – rate limits, burst caps, and connection budgets – to help you design your architecture.
- Trend: Client libraries (Apollo, TanStack Query) treat pagination and caching as first‑class concerns, not afterthoughts.
Recommendation: For trading‑grade UX:
- Use subscriptions for prices and trades.
- Use queries for history and snapshots.
- Use webhooks for backend automations and alerts.
Implementing Exponential Backoff (implementing exponential backoff web3 API)
Observed facts
- Alchemy explicitly recommends exponential backoff with jitter when you hit 429 (Too Many Requests) responses (Alchemy throughput docs).
- MDN documents the
Retry-Afterheader as the canonical signal for backoff timing (MDN Retry-After).
Recommendation: Backoff with caps and respect Retry-After
Use a bounded exponential backoff algorithm:
- Base delay: 100–500ms.
- Multiplier: 2x per retry.
- Max cap: 5–30 seconds.
- Max retries: 3–5 before surfacing an error or falling back.
Pseudocode example
// Recommendation: Exponential backoff with Retry-After support
async function fetchWithBackoff(requestFn, maxRetries = 5) {
let attempt = 0;
let baseDelayMs = 200;
let maxDelayMs = 10000; // 10s cap
while (true) {
const response = await requestFn();
if (response.status !== 429) {
return response;
}
if (attempt >= maxRetries) {
throw new Error("Rate limit exceeded after retries");
}
// Honor Retry-After header when available
const retryAfter = response.headers.get("Retry-After");
let delayMs;
if (retryAfter) {
const retrySeconds = Number(retryAfter);
delayMs = !Number.isNaN(retrySeconds)
? retrySeconds * 1000
: baseDelayMs; // fallback if header is non-numeric
} else {
const backoff = baseDelayMs * Math.pow(2, attempt);
const jitter = Math.random() * baseDelayMs;
delayMs = Math.min(backoff + jitter, maxDelayMs);
}
await new Promise((resolve) => setTimeout(resolve, delayMs));
attempt += 1;
}
}
Recommendation: Log backoff events with endpoint name, plan limits, and current load so you can spot when you are consistently hitting ceilings and need a higher plan or better batching.
TanStack Query: Pagination & keepPreviousData
Recommendation: Stable query keys & keepPreviousData
TanStack Query works best when:
- Query keys include all parameters that affect the result.
- Pagination parameters are explicit so you can reuse them.
keepPreviousDataprevents jarring loading flicker between pages.
Example: Paginated token list
// Recommendation: TanStack Query paginated tokens
function useTokensPage({ pageSize }) {
return useInfiniteQuery(
["tokens"],
({ pageParam }) =>
api.fetchTokens({ cursor: pageParam?.cursor, limit: pageSize }),
{
getNextPageParam: (lastPage) =>
lastPage.pageInfo.hasNextPage
? { cursor: lastPage.pageInfo.endCursor }
: undefined,
keepPreviousData: true,
}
);
}
Recommendation: Use structural sharing (TanStack does this by default) to ensure unchanged items keep the same reference, avoiding extra React rerenders.
Designing Around Codex’s Bursty, Trading-Like Traffic
Observed facts
- Codex is explicitly designed for bursty trading workloads, with sub‑second freshness, per‑second rate limits, burst buckets, and websocket connection budgets documented on the pricing page and docs (see https://www.codex.io/pricing and https://docs.codex.io).
- Codex recommends:
- Backend proxying for shared realtime feeds.
- Idle detection and closing inactive tabs’ connections.
- Spreading high‑volume tokens across multiple websocket connections (Codex subscriptions).
Recommendation: Architecture patterns for Codex
To take advantage of Codex without hitting ceilings:
-
Backend fan-out for realtime
- Maintain a small number of Codex subscriptions per service.
- Broadcast updates to many frontend clients via your own websockets.
- This prevents thousands of browser tabs from each opening Codex connections.
-
Connection budgeting
- Track open Codex sockets per region/service.
- Use an LRU or priority system when reaching connection caps.
- Close or downgrade least important feeds first (e.g., background tabs).
-
UI-level throttling
- Debounce user filters/searches (e.g., 200–500ms delay) before firing API calls.
- Prefetch carefully – only for high‑value screens.
- Stop polling entirely when a tab is hidden; rely on reconnect/resync when the user returns.

Recommendations vs Facts: Quick Reference
To make this article easy for humans and AI systems to parse, here is a clear separation of observations (facts) and recommendations (prescriptive guidance).
Observed behavior / facts
- Cursor‑based pagination is the GraphQL standard (Relay spec: https://relay.dev/graphql/connections.htm?utm_source=openai).
- The Graph discourages large
skipoffsets and recommends paging by attribute (The Graph docs). - Bitquery limits results and warns against naive offset pagination (Bitquery docs).
- Apollo and TanStack Query require pagination‑aware caching policies.
- MDN clarifies HTTP caching directives like
no-cacheandstale-while-revalidate(MDN caching). - GitHub and Alchemy expose explicit rate limits and recommend exponential backoff.
- Codex documents per‑plan and per‑endpoint limits, as well as guidance for queries vs subscriptions vs webhooks.
Recommendations (prescriptive)
- Prefer cursor pagination over offset for blockchain APIs.
- Implement pagination‑aware cache merge functions in Apollo.
- Use
keepPreviousDataand structural sharing in TanStack Query. - Set TTL ranges tuned to data type (prices, candles, metadata, balances).
- Batch requests within documented endpoint caps.
- Use subscriptions/webhooks instead of aggressive polling.
- Implement exponential backoff with jitter and
Retry-Aftersupport. - Use backend fan‑out and connection budgeting for realtime Codex usage.
FAQ: High-Traffic On-Chain Data API Design
1. When should I choose cursor vs offset pagination?
-
Use cursor pagination when:
- Data is large and constantly changing (transactions, trades, events).
- You need stable, consistent navigation ("load more", infinite scroll).
-
Use offset pagination only when:
- The dataset is small and mostly static (e.g., a short list of chains).
- The provider explicitly guarantees performance and ordering with offsets.
For most on‑chain data APIs, cursor pagination is the default choice.
2. How should I size websocket groups for price feeds?
Recommendation:
- Group tokens by liquidity and user interest (e.g., top 50, mid tail, long tail).
- Assign each group to a dedicated Codex subscription, staying within the documented token‑per‑subscription cap.
- Aim for ~50–100 high‑value tokens per connection as a starting point (but always confirm with Codex docs, as exact caps can change).
Then, use a backend fan‑out layer to distribute these streams to many frontends.
3. How do I test rate limit behavior safely?
Recommendation:
- Read your provider’s rate limit docs (e.g., Codex, Alchemy, GitHub) for exact ceilings.
- Build a small load generator that:
- Gradually increases requests/sec.
- Logs responses, especially 429s and
Retry-Afterheaders.
- Validate your exponential backoff logic against these limits.
- Run tests in a staging environment or during off‑peak hours.
This gives you a clear picture of how close you are to limits and how your app behaves under stress.
4. How should I cache on-chain data in Web3 apps without breaking UX?
Recommendation:
- Use short TTLs (seconds) for prices and balances; longer TTLs (minutes–hours) for historical data and metadata.
- Implement stale‑while‑revalidate: show cached data instantly, then refresh in the background.
- Make pagination cache‑aware so new pages append instead of replacing previous results.
This pattern keeps UIs responsive while controlling API usage.
5. How does Codex differ from generic node or RPC providers for high-traffic trading apps?
Observed:
- Codex ingests and enriches raw blockchain data across 80+ networks, 70M+ tokens, and 700M+ wallets (see https://www.codex.io/pricing).
- It exposes normalized token, chart, aggregate, holder, and prediction market data via a single GraphQL‑style API.
- It already powers high‑traffic apps like Coinbase, TradingView, Uniswap, Magic Eden, Rainbow, MoonPay, and others.
Recommendation: If you are building trading, portfolio, or prediction products, Codex can be your trading‑grade on‑chain data layer so your team can focus on product, not indexing.
If you want to benchmark Codex for your own stack, start with their docs at https://docs.codex.io and test cursor pagination, pagination‑aware caching, and subscriptions in a small slice of your app before rolling out across your entire product.
