Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions benchmarks/base-rpc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ methodology:
- "Call-result classification: `ok` (HTTP 200 + non-empty result), `http_err`, `jsonrpc_err` (HTTP 200 carrying an error body), `stale` (more than 20 blocks behind the cross-provider tip), `timeout`. Latency without reliability is a misleading ranking signal."
- "Archive depth: every 5 minutes we issue `eth_getBalance` at (head − depth) for depths from Geth's default pruned cap up to 5M blocks, exposing which free endpoints actually serve historical state."
- "This page is part of the per-chain RPC cluster derived from the cross-chain [rpc-capabilities](https://openchainbench.com/benchmarks/rpc-capabilities) benchmark; the identical harness, methodology and exclusion rules apply on every chain."
- "Chain scope: every query on this page is pinned to chain=\"base\". Provider coverage: 5 no-key endpoints (PublicNode, dRPC, Tenderly, Nodies, Base). Merkle was delisted 2026-07: its gateway does not serve `eth_getBlockByNumber`, the anti-cache probe this cluster standardized on, so it cannot be measured on equal terms. Exclusions follow the cluster-wide rules documented on the parent benchmark."
- "Chain scope: every query on this page is pinned to chain=\"base\". Provider coverage: 5 no-key endpoints (PublicNode, dRPC, Tenderly, Nodies, Base). Merkle (rebranded Blink Labs) was delisted 2026-07: its gateway does not serve `eth_getBlockByNumber`, the anti-cache probe this cluster standardized on, so it cannot be measured on equal terms. Exclusions follow the cluster-wide rules documented on the parent benchmark."

findings:
- "{{best_name}} currently leads free Base RPC at {{best_p50}} (`eth_getBlockByNumber` p50, 24h) across 6 measured providers."
Expand All @@ -36,7 +36,7 @@ faq:
- q: "What is the fastest free Base RPC right now?"
a: "{{best_name}} currently leads at {{best_p50}} (`eth_getBlockByNumber` p50 over the last 24h), measured against 6 no-key providers probed every 60 seconds from us-east, eu-west and Singapore. The leaderboard re-sorts continuously against fresh Prometheus samples, so the answer on this page is the answer right now, not a quarterly snapshot. Use the region tabs to see the leader from the origin closest to your deployment."
- q: "Which Base RPCs work without an API key?"
a: "The 5 providers on this page: PublicNode, dRPC, Tenderly, Nodies, Base. Merkle was delisted in July 2026 because its gateway does not serve `eth_getBlockByNumber` (JSON-RPC -32601), the anti-cache probe used across the cluster, so its latency cannot be compared on equal terms. Every (provider, chain) pair was live-verified no-key before inclusion, and anything that key-gates, region-blocks or rate-limits below our 15-second cadence is excluded rather than listed with an asterisk."
a: "The 5 providers on this page: PublicNode, dRPC, Tenderly, Nodies, Base. Merkle (rebranded Blink Labs) was delisted in July 2026 because its gateway does not serve `eth_getBlockByNumber` (JSON-RPC -32601), the anti-cache probe used across the cluster, so its latency cannot be compared on equal terms. Every (provider, chain) pair was live-verified no-key before inclusion, and anything that key-gates, region-blocks or rate-limits below our 15-second cadence is excluded rather than listed with an asterisk."
- q: "Does the fastest Base RPC change by region?"
a: "Frequently. The headline number averages three probe origins (us-east, eu-west, Singapore), but per-region leaders regularly diverge, a gateway that wins from Virginia can lose from Singapore by multiples. The region tabs at the top of the page re-scope every number on the page to a single origin; pick the one closest to where your requests actually originate."
- q: "How is Base RPC latency measured here?"
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/bnb-rpc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ methodology:
- "Call-result classification: `ok` (HTTP 200 + non-empty result), `http_err`, `jsonrpc_err` (HTTP 200 carrying an error body), `stale` (more than 20 blocks behind the cross-provider tip), `timeout`. Latency without reliability is a misleading ranking signal."
- "Archive depth: every 5 minutes we issue `eth_getBalance` at (head − depth) for depths from Geth's default pruned cap up to 5M blocks, exposing which free endpoints actually serve historical state."
- "This page is part of the per-chain RPC cluster derived from the cross-chain [rpc-capabilities](https://openchainbench.com/benchmarks/rpc-capabilities) benchmark; the identical harness, methodology and exclusion rules apply on every chain."
- "Chain scope: every query on this page is pinned to chain=\"bnb\". Provider coverage: 4 no-key endpoints (PublicNode, dRPC, Nodies, Binance). Merkle was delisted 2026-07: its gateway does not serve `eth_getBlockByNumber`, the anti-cache probe this cluster standardized on, so it cannot be measured on equal terms. Exclusions follow the cluster-wide rules documented on the parent benchmark."
- "Chain scope: every query on this page is pinned to chain=\"bnb\". Provider coverage: 4 no-key endpoints (PublicNode, dRPC, Nodies, Binance). Merkle (rebranded Blink Labs) was delisted 2026-07: its gateway does not serve `eth_getBlockByNumber`, the anti-cache probe this cluster standardized on, so it cannot be measured on equal terms. Exclusions follow the cluster-wide rules documented on the parent benchmark."

findings:
- "{{best_name}} currently leads free BNB Chain RPC at {{best_p50}} (`eth_getBlockByNumber` p50, 24h) across 5 measured providers."
Expand All @@ -36,7 +36,7 @@ faq:
- q: "What is the fastest free BNB Chain RPC right now?"
a: "{{best_name}} currently leads at {{best_p50}} (`eth_getBlockByNumber` p50 over the last 24h), measured against 5 no-key providers probed every 60 seconds from us-east, eu-west and Singapore. The leaderboard re-sorts continuously against fresh Prometheus samples, so the answer on this page is the answer right now, not a quarterly snapshot. Use the region tabs to see the leader from the origin closest to your deployment."
- q: "Which BNB Chain RPCs work without an API key?"
a: "The 4 providers on this page: PublicNode, dRPC, Nodies, Binance. Merkle was delisted in July 2026 because its gateway does not serve `eth_getBlockByNumber` (JSON-RPC -32601), the anti-cache probe used across the cluster, so its latency cannot be compared on equal terms. Every (provider, chain) pair was live-verified no-key before inclusion, and anything that key-gates, region-blocks or rate-limits below our 15-second cadence is excluded rather than listed with an asterisk."
a: "The 4 providers on this page: PublicNode, dRPC, Nodies, Binance. Merkle (rebranded Blink Labs) was delisted in July 2026 because its gateway does not serve `eth_getBlockByNumber` (JSON-RPC -32601), the anti-cache probe used across the cluster, so its latency cannot be compared on equal terms. Every (provider, chain) pair was live-verified no-key before inclusion, and anything that key-gates, region-blocks or rate-limits below our 15-second cadence is excluded rather than listed with an asterisk."
- q: "Does the fastest BNB Chain RPC change by region?"
a: "Frequently. The headline number averages three probe origins (us-east, eu-west, Singapore), but per-region leaders regularly diverge, a gateway that wins from Virginia can lose from Singapore by multiples. The region tabs at the top of the page re-scope every number on the page to a single origin; pick the one closest to where your requests actually originate."
- q: "How is BNB Chain RPC latency measured here?"
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/rpc-capabilities.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ methodology:
- "Success gating: because failed probes record no latency, a mostly failing endpoint can post a fast p50 from its rare successes. The ledger pairs every latency figure with a Success column computed as ok calls over total calls in the same 24h window; read rows below 50 percent success as degraded. Providers with under 5 percent success lose their latency series to Prometheus staleness and are pinned below the table as unresponsive instead of being ranked."
- "Archive depth: every 5 minutes we issue `eth_getBalance` at (head, depth) for `depth` in {300, 7200, 216_000, 1_296_000, 5_000_000}. Gauge `rpc_archive_depth_supported{depth}` is 1 when the response is non-pruned, 0 otherwise. The 300/7200 thresholds cover Geth's default pruned-cap range; 216k ≈ 1 month; 1.3M ≈ 6 months; 5M ≈ genesis-era full archive."
- "Chain coverage: 10 EVM chains. Ethereum (9 providers), Arbitrum (8), Base (6), Optimism (6), Avalanche (6), BNB (5), Polygon (5), Linea (4), Scroll (4), Mantle (4). Provider matrix per chain is documented in `miniapps/rpc-capabilities/cmd/script/config.go`."
- "Excluded: 1RPC (delisted 2026-07-09, under 13% success even at two chains and one probe per minute), Ankr (key-gated), gateway.fm (29 req/IP budget too tight for 15s polling), LlamaRPC + BlockPI + OmniaTech (Cloudflare 521 region-blocked), Alchemy demo (rate-limited dead), NodeReal + GetBlock + Chainstack (key-gated). Merkle (no eth_getBlockByNumber, the cluster anti-cache probe) + Lava and MeowRPC outside ETH/Arb excluded. Every (provider, chain) was live-verified no-key before inclusion."
- "Excluded: 1RPC (delisted 2026-07-09, under 13% success even at two chains and one probe per minute), Ankr (key-gated), gateway.fm (29 req/IP budget too tight for 15s polling), LlamaRPC + BlockPI + OmniaTech (Cloudflare 521 region-blocked), Alchemy demo (rate-limited dead), NodeReal + GetBlock + Chainstack (key-gated). Merkle, now Blink Labs (no public eth_getBlockByNumber) + Lava and MeowRPC outside ETH/Arb excluded. Every (provider, chain) was live-verified no-key before inclusion."

findings:
- "Per-chain leaders, not a cross-chain crown. On Ethereum the current leader is {{best_name:chain:ethereum}} at {{best_p50:chain:ethereum}} (p50, 24 h) across 9 measured providers, the largest cohort in this bench. Ethereum is also the chain where Cloudflare-eth's `jsonrpc_err` traps the lazy reader."
Expand Down
7 changes: 7 additions & 0 deletions src/app/products/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ export async function generateMetadata({
// <head> injection — return the canonical + redirect-safe metadata so
// crawlers that peek at the response before the 308 fires still see the
// right canonical target.
// Merkle rebranded to Blink Labs and went keyed-only; the provider was
// fully delisted 2026-07-10 so this page has no data left. 301 to the
// capabilities bench (whose exclusion note explains both names) instead
// of 404ing away the page's accumulated link equity.
if (slug === "merkle") {
permanentRedirect("/benchmarks/rpc-capabilities");
}
if (await isHlBuilderWithHistory(slug)) {
const canonicalUrl = `${SITE.url}/hyperliquid/${slug}`;
return {
Expand Down
146 changes: 109 additions & 37 deletions src/components/chain-rpc-section.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import Link from "next/link";
import { ArrowUpRight } from "lucide-react";
import { ProviderLogo } from "@/components/provider-logo";
import {
fetchRpcHub,
getRpcChainRow,
RPC_REGION_KEYS,
type RpcRegionKey,
type RpcRegionBest,
} from "@/lib/rpc-hub-stats";

/**
* Compact RPC summary panel for /chains/<slug>: the chain centric cut of
* the rpc-hub cohort snapshot (the provider centric cut lives in
* RpcProviderChainsSection on product pages). Shows the 24h p50 leader,
* the best provider per probe region, and links out to the full
* <chain>-rpc bench page for the complete leaderboard.
* RPC summary panel for /chains/<slug>: the chain centric cut of the
* rpc-hub cohort snapshot (the provider centric cut lives in
* RpcProviderChainsSection on product pages). A leader card plus one
* card per probe region, in the same card language as the Live KPIs
* strip above it, then a link out to the full <chain>-rpc bench.
*
* Server component, snapshot only (fetchRpcHub reads the worker written
* cohort blob via unstable_cache; zero Prometheus traffic). Returns null
* when the chain has no rpc-hub row, so the page can render it
* unconditionally, though the chain page gates the pill upfront via
* when the chain has no rpc-hub row; the page gates the pill upfront via
* getRpcChainRow (same cached read, no extra roundtrip).
*/

Expand Down Expand Up @@ -49,10 +50,27 @@ export async function ChainRpcSection({ chainSlug }: { chainSlug: string }) {

return (
<section className="mt-6">
<h2 className="text-[11px] font-medium uppercase tracking-[0.18em] text-ink-muted">
<p
className="label-mono text-[10px] text-ink-faint mb-3"
style={{ fontFamily: "var(--font-mono, monospace)" }}
>
Fastest public RPC on {row.name}
</h2>
<p className="mt-2 text-sm text-ink-soft leading-snug max-w-2xl">
</p>

<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
<LeaderCard best={row.best} providerCount={row.providerCount} />
{RPC_REGION_KEYS.map((region) => (
<RegionCard
key={region}
label={REGION_LABELS[region]}
best={row.regions[region] ?? null}
/>
))}
</div>

{/* Quotable one liner kept as plain server rendered text: this is
the sentence answer engines lift, cards alone do not quote. */}
<p className="mt-3 text-[12.5px] text-ink-soft leading-snug max-w-2xl">
The fastest public RPC endpoint on {row.name} right now is{" "}
<span className="font-medium text-ink">{row.best.providerName}</span>{" "}
at{" "}
Expand All @@ -63,32 +81,7 @@ export async function ChainRpcSection({ chainSlug }: { chainSlug: string }) {
{row.providerCount} live provider
{row.providerCount === 1 ? "" : "s"} measured from 3 probe regions.
</p>
<dl className="mt-4 grid grid-cols-1 sm:grid-cols-3 border-y border-rule divide-y sm:divide-y-0 sm:divide-x divide-rule">
{RPC_REGION_KEYS.map((region) => {
const best = row.regions[region];
return (
<div key={region} className="py-3 sm:px-4 sm:first:pl-0">
<dt className="text-[10px] font-medium uppercase tracking-[0.16em] text-ink-muted">
{REGION_LABELS[region]}
</dt>
<dd className="mt-1 text-[12.5px]">
{best ? (
<>
<span className="font-medium text-ink">
{best.providerName}
</span>{" "}
<span className="text-ink-soft tabular-nums">
{fmtMs(best.p50Ms)}
</span>
</>
) : (
<span className="text-ink-faint">no data</span>
)}
</dd>
</div>
);
})}
</dl>

<div className="mt-3 flex flex-wrap items-baseline gap-x-4 gap-y-1">
<Link
href={`/benchmarks/${row.slug}`}
Expand All @@ -98,9 +91,88 @@ export async function ChainRpcSection({ chainSlug }: { chainSlug: string }) {
<ArrowUpRight size={14} strokeWidth={2} />
</Link>
{asOf && (
<span className="text-[10.5px] text-ink-faint">Data as of {asOf}</span>
<span className="text-[10.5px] text-ink-faint">
Data as of {asOf}
</span>
)}
</div>
</section>
);
}

function LeaderCard({
best,
providerCount,
}: {
best: RpcRegionBest;
providerCount: number;
}) {
return (
<div
className="card-soft rounded-lg p-3 sm:p-4 border border-ink/15 flex flex-col"
title="Lowest p50 latency across all probe regions over the last 24 hours, successful calls only."
style={{ minHeight: 118 }}
>
<p
className="label-mono text-[10px] text-ink-faint uppercase tracking-wide leading-snug"
style={{ fontFamily: "var(--font-mono, monospace)" }}
>
Fastest · 24h p50
</p>
<div className="mt-2 flex items-center gap-2 min-w-0">
<ProviderLogo slug={best.provider} name={best.providerName} size={20} />
<span className="font-medium text-ink text-sm truncate">
{best.providerName}
</span>
</div>
<p className="mt-1 text-2xl font-semibold text-ink tabular-nums leading-none">
{fmtMs(best.p50Ms)}
</p>
<p className="mt-auto pt-2 text-[10.5px] text-ink-faint">
{providerCount} live provider{providerCount === 1 ? "" : "s"} measured
</p>
</div>
);
}

function RegionCard({
label,
best,
}: {
label: string;
best: RpcRegionBest | null;
}) {
return (
<div
className="card-soft rounded-lg p-3 sm:p-4 border border-ink/15 flex flex-col"
title={`Fastest provider probed from ${label}, p50 over the last 24 hours.`}
style={{ minHeight: 118 }}
>
<p
className="label-mono text-[10px] text-ink-faint uppercase tracking-wide leading-snug"
style={{ fontFamily: "var(--font-mono, monospace)" }}
>
{label}
</p>
{best ? (
<>
<div className="mt-2 flex items-center gap-2 min-w-0">
<ProviderLogo
slug={best.provider}
name={best.providerName}
size={20}
/>
<span className="font-medium text-ink text-sm truncate">
{best.providerName}
</span>
</div>
<p className="mt-1 text-xl font-semibold text-ink-soft tabular-nums leading-none">
{fmtMs(best.p50Ms)}
</p>
</>
) : (
<p className="mt-2 text-sm text-ink-faint italic">no data</p>
)}
</div>
);
}
Loading