Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
ab53f32
rss: ship /rss.xml feed for benchmark releases + fix duplicate import
Flotapponnier Jun 18, 2026
9de2e34
Merge pull request #540 from ChainBench/feat/rss-feed
Flotapponnier Jun 18, 2026
056a4ea
chore: cherry-pick /partners + footer link to prod (#543)
Flotapponnier Jun 18, 2026
9633e99
fix(hl): biggest day marker always from displayed series, not stale g…
Flotapponnier Jun 19, 2026
0783c8b
fix(bench): resolve {{p50:slug}} placeholders on overlayEditorial fas…
Flotapponnier Jun 19, 2026
898c104
fix(bench): aggregate per-route vector before exposing success rate (…
Flotapponnier Jun 19, 2026
aabac4c
feat(bridge): add Near Intents provider to quote-latency and bridge-f…
Flotapponnier Jun 19, 2026
5b09f3e
feat(bridge-benches): add per-destination chain dimension (#595) (#596)
Flotapponnier Jun 20, 2026
3fcbdb8
refactor(bridge-benches): label chain tabs with full corridor name (#…
Flotapponnier Jun 20, 2026
34be11f
refactor(bridge-benches): hypercore logo alias + drop misleading All …
Flotapponnier Jun 20, 2026
253c88c
fix(seo): serve /llms-full.txt as direct 200, not 307 redirect (#602)…
Flotapponnier Jun 21, 2026
aaa314e
hotfix: sitemap lastmod fix + hold solana-tx-landing-latency off main…
Flotapponnier Jun 21, 2026
6f11ea3
fix(citable): stop poisoning aggregator cache with all-draft set (#610)
Flotapponnier Jun 21, 2026
2812f10
seo: move site-wide Organization + WebSite JSON-LD to <head> (#609)
Flotapponnier Jun 21, 2026
f6e306b
fix(compare): restore SSR content and canonical, 301 reverse-pair to …
Flotapponnier Jun 21, 2026
f814d29
content(alternatives): differentiate intros across same benchmark clu…
Flotapponnier Jun 21, 2026
18072c9
feat(rate-limit): bypass per-IP throttle for known AI crawler UAs (#6…
Flotapponnier Jun 21, 2026
cac87a8
fix(sitemap): drop /products/<slug> URLs that 404 (align with generat…
Flotapponnier Jun 21, 2026
2065ea7
hotfix(compare): drop loading.tsx + hasSharedBenches gate (cherry-pic…
Flotapponnier Jun 21, 2026
0718299
seo: per_chain_explainer on perp-fees + wallet-labels-coverage (#619)…
Flotapponnier Jun 21, 2026
b81ce60
fix(api): /api/stat returns insufficient status to match /api/citable…
Flotapponnier Jun 22, 2026
1c6222f
fix(citation): drop b.sampleSize===0 from isInsufficient predicate (#…
Flotapponnier Jun 22, 2026
6390d5e
fix(citable): quorum guard against mostly-draft aggregator cache (#631)
Flotapponnier Jun 22, 2026
cd137a1
feat(hf): cherry-pick HF dataset publisher from dev (#632) (#633)
Flotapponnier Jun 22, 2026
a4dac6c
Merge pull request #606 from ChainBench/feat/pm-bench-aggregator-prov…
Flotapponnier Jun 21, 2026
4e7a486
Merge pull request #634 from ChainBench/fix/next-include-benchmarks-i…
Flotapponnier Jun 22, 2026
94298a1
Merge pull request #635 from ChainBench/chore/cherry-pick-pm-aggregat…
Flotapponnier Jun 22, 2026
b49c320
feat(hf): card metadata + schema completeness v2 (audit follow-up) (#…
Flotapponnier Jun 22, 2026
50c67e1
Merge pull request #638 from ChainBench/feat/pm-venue-dim-collapse-ag…
Flotapponnier Jun 22, 2026
fba1375
Merge pull request #639 from ChainBench/chore/cherry-pick-pm-venue-di…
Flotapponnier Jun 22, 2026
ef307a4
fix(hf): swallow timeout + socket errors in fetch_json so /api/series…
Flotapponnier Jun 22, 2026
9d322d3
seo(jsonld): add schema.org/Dataset markup linking HF parquet mirror …
Flotapponnier Jun 22, 2026
f4c589e
fix(hf): populate chain_leaders from /api/stat bestPerChain (#642)
Flotapponnier Jun 22, 2026
713c468
Merge pull request #644 from ChainBench/fix/predexon-logo-manifest
Flotapponnier Jun 22, 2026
d3bfc6e
Merge pull request #645 from ChainBench/chore/cherry-pick-predexon-lo…
Flotapponnier Jun 22, 2026
2a758a9
fix(l2-block-time): switch from gauge quantile_over_time to histogram…
Flotapponnier Jun 22, 2026
58a3f9a
Merge pull request #646 from ChainBench/hotfix/l2-block-time-histogram
Flotapponnier Jun 22, 2026
cf216ca
Merge pull request #647 from ChainBench/fix/pm-api-latency-direct-only
Flotapponnier Jun 22, 2026
68e1416
Merge pull request #648 from ChainBench/chore/cherry-pick-pm-api-late…
Flotapponnier Jun 22, 2026
97bcd81
feat(hf-publisher): mirror daily snapshot to kaggle (#649)
Flotapponnier Jun 22, 2026
e54bb70
feat(hf-space): leaderboard app for the OCB dataset (#651)
Flotapponnier Jun 22, 2026
f3dfe5d
fix(pm): codex/predexon logo via manifest + filter dead composite slugs
Flotapponnier Jun 22, 2026
b65321f
Merge pull request #653 from ChainBench/chore/cherry-pick-pm-logo-com…
ChainBench Jun 22, 2026
b542a03
hotfix(build): loadBenchmark falls back to safe aggregator + shorter …
Flotapponnier Jun 22, 2026
2d695e4
feat(zenodo): wire DOI 10.5281/zenodo.20800311 into HF card + site JS…
Flotapponnier Jun 22, 2026
984ecfa
Merge pull request #655 from ChainBench/feat/zenodo-doi-integration
ChainBench Jun 22, 2026
5df2903
hotfix(hf-space): pin starlette + fastapi for gradio 4.44.1 compat (#…
Flotapponnier Jun 22, 2026
c158e5c
fix(kaggle): shorten subtitle to fit 20-80 char limit + add guard (#658)
Flotapponnier Jun 22, 2026
c190b0c
feat(pm): cherry-pick prediction-market cluster to prod
Flotapponnier Jun 22, 2026
ffc08ee
Merge pull request #659 from ChainBench/chore/cherry-pick-pm-cluster-…
ChainBench Jun 22, 2026
62fd90a
fix(pm): hide PM section when nothing is measured (no 'not live yet' …
Flotapponnier Jun 22, 2026
e4ce207
Merge pull request #661 from ChainBench/chore/cherry-pick-pm-hide-emp…
ChainBench Jun 22, 2026
ac34986
chore: remove em/en dashes from user-facing strings
Flotapponnier Jun 23, 2026
33a240c
Merge pull request #663 from ChainBench/chore/remove-em-dashes
Flotapponnier Jun 23, 2026
17ae38a
perf: cut Vercel→Railway Prom egress via aggressive edge cache
Flotapponnier Jun 23, 2026
f51746d
Merge pull request #664 from ChainBench/perf/vercel-cache-egress-redu…
Flotapponnier Jun 23, 2026
69fde54
chore(hf-space): keepalive cron every 4h (#668)
Flotapponnier Jun 24, 2026
119a828
fix(mcp): point HF card + prod-deploy warmup at /api/mcp/mcp (#672)
Flotapponnier Jun 24, 2026
373cb9e
feat(perps): cherry-pick perp cluster sprint 1+2 to prod
Flotapponnier Jun 24, 2026
19be4da
Merge pull request #676 from ChainBench/chore/cherry-pick-perp-cluste…
Flotapponnier Jun 24, 2026
93e3d7c
fix(perp-benches): correct gmx slug + funding-stability cohort
Flotapponnier Jun 24, 2026
2a0f4be
Merge pull request #679 from ChainBench/chore/cherry-pick-perp-bench-…
Flotapponnier Jun 24, 2026
3f34721
fix(perps): seed cohort venues in provider index + funding-stability …
Flotapponnier Jun 24, 2026
1314288
Merge pull request #683 from ChainBench/chore/cherry-pick-perp-sprint…
Flotapponnier Jun 24, 2026
34554ea
fix(perps): bump providers cache key + loosen vol/oi bands
Flotapponnier Jun 24, 2026
021e726
Merge pull request #686 from ChainBench/chore/cherry-pick-perp-cache-…
Flotapponnier Jun 24, 2026
ca5d54b
feat: snapshot + carry-forward for /perps and /hyperliquid cohorts
Flotapponnier Jun 24, 2026
5934e2d
Merge pull request #690 from ChainBench/chore/cherry-pick-cohort-mate…
Flotapponnier Jun 24, 2026
b300123
chore(gas-estimation): drop Blocknative provider after API sunset (De…
Flotapponnier Jun 24, 2026
9281a81
Merge pull request #694 from ChainBench/chore/cherry-pick-drop-blockn…
Flotapponnier Jun 24, 2026
b719b0f
hotfix(cron): point snapshot-hl-cohort import at @/lib/hl-builder-sta…
Flotapponnier Jun 24, 2026
e7d87ce
fix(perp-funding-stability): success query uses funding sample presen…
Flotapponnier Jun 25, 2026
9da5a06
Merge pull request #700 from ChainBench/chore/cherry-pick-funding-sta…
Flotapponnier Jun 25, 2026
30eeb11
header search bar (Cmd+K) + dialog redesign — cherry-pick to main (#698)
Flotapponnier Jun 25, 2026
84227a4
rename TON → Gram across the site (token rebrand June 2026) (#696) (#…
Flotapponnier Jun 25, 2026
535c767
feat(analytics): wire Ahrefs Web Analytics via NEXT_PUBLIC_AHREFS_KEY
Flotapponnier Jun 25, 2026
0ffc453
Merge pull request #703 from ChainBench/chore/cherry-pick-ahrefs-prod
Flotapponnier Jun 25, 2026
fd9b934
rename chain slug ton → gram + redirects + Prom straddle
Flotapponnier Jun 25, 2026
8258ff4
Merge pull request #705 from ChainBench/chore/ton-to-gram-slug-rename
Flotapponnier Jun 25, 2026
a8c9266
chore: trigger rebuild to pick NEXT_PUBLIC_AHREFS_KEY env
Flotapponnier Jun 25, 2026
1f9c848
chore: cherry-pick SEO fixes (drop solana-tx-landing-latency + slim /…
Flotapponnier Jun 25, 2026
e3c234d
search dialog: cron-warmed KV blob for Live Leaders + Trending (#707)
Flotapponnier Jun 25, 2026
524bc3c
finish ton→gram migration: slug aliasing + overlay reconciliation (#708)
Flotapponnier Jun 25, 2026
bc765eb
fix(perp-funding-stability): pivot to perp_funding_hold_24h_bps (benc…
Flotapponnier Jun 25, 2026
eb30095
fix(build): break circular import causing TDZ on /alternatives OG image
Flotapponnier Jun 25, 2026
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
85 changes: 85 additions & 0 deletions .github/workflows/hf-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: HF dataset publish

# Daily snapshot of the live citable feed pushed to
# https://huggingface.co/datasets/OpenChainBench/benchmarks.
#
# Trigger:
# - 00:00 UTC every day (after the daily Prom roll-up is settled).
# - workflow_dispatch with an optional `dry_run` flag so we can
# validate changes without touching HF.
#
# Required secrets:
# HF_TOKEN write-scoped token for the dataset repo.
# SLACK_WEBHOOK_URL optional, incoming-webhook URL for ops alerts.
# KAGGLE_USERNAME optional, owner of the Kaggle mirror dataset.
# KAGGLE_KEY optional, API key paired with KAGGLE_USERNAME.
#
# When both KAGGLE_USERNAME and KAGGLE_KEY are set, the publisher mirrors
# the snapshot to kaggle.com/datasets/openchainbench/benchmarks right
# after the HF push. A Kaggle-side failure never aborts the run.

on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
inputs:
dry_run:
description: "Stage parquet locally without pushing to HF"
type: boolean
default: false

concurrency:
group: hf-publish
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
KAGGLE_USERNAME: ${{ secrets.KAGGLE_USERNAME }}
KAGGLE_KEY: ${{ secrets.KAGGLE_KEY }}
OCB_API: https://openchainbench.com
HF_REPO_ID: OpenChainBench/benchmarks
KAGGLE_DATASET_ID: openchainbench/benchmarks
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: pip
cache-dependency-path: scripts/hf_publisher/requirements.txt

- name: Install deps
run: pip install -r scripts/hf_publisher/requirements.txt

- name: Run publisher tests (offline)
# Schema/quorum regressions caught here never reach the dataset.
run: |
cd scripts/hf_publisher
python -m unittest test_publish.py -v

- name: Publish snapshot
run: |
cd scripts/hf_publisher
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ]; then
python publish.py --dry-run
else
python publish.py
fi

- name: Summary
if: always()
run: |
{
echo "## HF publish ${{ job.status }}"
echo ""
echo "**Repo:** https://huggingface.co/datasets/${HF_REPO_ID}"
echo "**Mode:** ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run == true && 'dry-run' || 'live' }}"
echo "**Time:** $(date -u +%FT%TZ)"
} >> "$GITHUB_STEP_SUMMARY"
82 changes: 82 additions & 0 deletions .github/workflows/hf-space-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: HF Space deploy

# Pushes scripts/hf_space/ to the HF Space at
# https://huggingface.co/spaces/OpenChainBench/leaderboard.
#
# Trigger:
# - push to main that touches scripts/hf_space/**
# - workflow_dispatch for manual redeploys
#
# Required secrets:
# HF_TOKEN write-scoped token for the Space repo (same token as the
# dataset publisher).

on:
push:
branches: [main]
paths:
- "scripts/hf_space/**"
- ".github/workflows/hf-space-deploy.yml"
workflow_dispatch:

concurrency:
group: hf-space-deploy
cancel-in-progress: false

jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
HF_SPACE_REPO_ID: OpenChainBench/leaderboard
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install huggingface_hub
run: pip install "huggingface_hub>=0.26"

- name: Upload to HF Space
env:
GIT_SHA: ${{ github.sha }}
run: |
python - <<'PY'
import os
from huggingface_hub import HfApi

token = os.environ["HF_TOKEN"]
repo_id = os.environ["HF_SPACE_REPO_ID"]
sha = os.environ.get("GIT_SHA", "manual")
api = HfApi(token=token)
api.create_repo(
repo_id=repo_id,
repo_type="space",
space_sdk="gradio",
exist_ok=True,
private=False,
)
info = api.upload_folder(
folder_path="scripts/hf_space",
repo_id=repo_id,
repo_type="space",
commit_message=f"deploy from {sha}",
)
print("uploaded:", getattr(info, "oid", "ok"))
PY

- name: Summary
if: always()
run: |
{
echo "## HF Space deploy ${{ job.status }}"
echo ""
echo "**Space:** https://huggingface.co/spaces/${HF_SPACE_REPO_ID}"
echo "**Commit:** ${{ github.sha }}"
echo "**Time:** $(date -u +%FT%TZ)"
} >> "$GITHUB_STEP_SUMMARY"
34 changes: 34 additions & 0 deletions .github/workflows/hf-space-keepalive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: HF Space keepalive

# Free HF Spaces fall asleep after a stretch of inactivity, and the
# first visitor after a sleep waits 30 to 60 seconds for the container
# to boot. That looks broken from a tweet. A light curl every 4 hours
# keeps the Space warm without burning meaningful GH Actions minutes
# (~6 runs per day, a few seconds each).

on:
schedule:
- cron: "0 */4 * * *"
workflow_dispatch:

concurrency:
group: hf-space-keepalive
cancel-in-progress: false

jobs:
ping:
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- name: Wake leaderboard Space
run: |
code=$(curl -sLm 60 -o /dev/null -w "%{http_code}" \
"https://openchainbench-leaderboard.hf.space")
echo "leaderboard: $code"
# 200 is a hot hit. 503 means HF is still booting the
# container, which is exactly the case we are warming for, so
# don't fail the workflow on it.
case "$code" in
200|302|503) exit 0 ;;
*) exit 1 ;;
esac
17 changes: 17 additions & 0 deletions .github/workflows/prod-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,23 @@ jobs:
| xargs -P 4 -I{} curl -s -o /dev/null -w "%{http_code} %{time_total}s {}\n" --max-time 120 {} \
|| echo "warm-up failed (non-blocking)"

# Warm /api/citable explicitly: the aggregator cache is independent
# from per-bench caches, and the bench-page warm-up only populates
# the latter. Without this step, /api/citable's first hit after
# deploy runs 26 parallel Prom queries on a cold function instance,
# which has historically produced mostly-placeholder snapshots that
# cached for 60s and shipped status=insufficient to LLM agents.
- name: Warm citable aggregate
run: |
base="https://openchainbench.com"
# /api/mcp is the docs path under /mcp, the live JSON-RPC
# endpoint is /api/mcp/mcp (Streamable HTTP). Warm the real
# endpoint so the first agent request after deploy is hot.
for ep in /api/citable /api/llm-context /api/mcp/mcp; do
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 120 "$base$ep" || echo "000")
echo "$code $base$ep"
done

- name: Summary
run: |
{
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,9 @@ harnesses/*/script
harnesses/*/monitor
harnesses/*/cmd/script/script
harnesses/*/cmd/monitor/monitor

# Python venvs for the HF publisher and Space (created locally for dry-runs)
scripts/hf_publisher/.venv/
scripts/hf_space/.venv/
**/__pycache__/
*.pyc
2 changes: 1 addition & 1 deletion alternatives/alchemy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Multi-chain node + enhanced API provider
benchmark: aggregator-head-lag

intro: |
Alchemy serves RPC endpoints and enhanced data APIs across EVM chains and Solana. For real-time feeds, the metric that matters most is freshness. how long between a transaction landing on chain and the API reflecting it? Below is the live head-lag for each major onchain data provider, measured against a canonical-tip archive node and refreshed every minute. Lower is faster.
Alchemy is an EVM-first node and API provider whose surface is shaped by its enhanced endpoints (`alchemy_getAssetTransfers`, NFT API, webhooks, getTokenBalances, the simulation and debug suite, the account-abstraction bundler) rather than by a raw RPC tuned for edge latency. Pricing is metered in compute units, which charges more for an enhanced call than for a plain `eth_call`, so the ceiling shows up first on teams streaming high-cardinality events into a backend rather than on dapp front-ends issuing single reads. Solana coverage exists but sits on a stack built around Ethereum and its L2s. Teams that need a live view of trades on Base, BNB Chain or Solana usually leave Alchemy at the point where the enhanced API list stops mapping to what the product actually reads from chain.

seo_title: Alchemy alternatives. live head-lag benchmark across data providers
seo_description: Compare Alchemy alternatives on real-time data freshness. Live head-lag against a canonical archive node, refreshed every minute and published openly.
2 changes: 1 addition & 1 deletion alternatives/bitquery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: GraphQL API for blockchain data, multi-chain
benchmark: network-coverage

intro: |
Bitquery is a GraphQL data API covering many chains. If you're sizing alternatives, the first axis is breadth. how many networks does each provider officially support? Below is the live count from each major onchain data provider, scraped from their public supported-networks endpoint and refreshed every six hours.
Bitquery is a GraphQL surface on top of indexed onchain data, with the schema as the actual product: queries declare exactly the fields needed across transfers, trades, DEX events and account state, and the indexer fans those out across chains. Pricing is point-based, with each field, filter and join consuming from a monthly point budget rather than from a flat request quota, which means a single dashboard with many panels can hit the ceiling well before request volume looks high. Chain coverage is broad but uneven in depth: some networks expose full DEX trade indexing, others only basic transfers. The team usually compared next is the one whose chain list either covers a long-tail network Bitquery does not, or covers the same network with a flatter pricing model that does not penalise wide GraphQL fragments on a per-field basis.

seo_title: Bitquery alternatives. live network coverage benchmark
seo_description: Compare Bitquery alternatives on the number of blockchains each major onchain data provider officially supports. Live data, refreshed every six hours.
13 changes: 0 additions & 13 deletions alternatives/blocknative.yml

This file was deleted.

2 changes: 1 addition & 1 deletion alternatives/coingecko.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Crypto price + market data API, multi-chain
benchmark: network-coverage

intro: |
CoinGecko offers a broad price + market data REST API used across thousands of crypto apps. The first axis people compare alternatives on is breadth. how many blockchains does each provider officially support? Below is the live count from each major onchain data API, scraped directly from their public supported-networks endpoint and refreshed every six hours.
CoinGecko is a coin-centric price and market data REST API built around a curated asset list (the `/coins` universe) rather than around on-chain events. Tokens are added through a listing process, prices land on the API after that process completes, and the free tier is famously throttled (around 30 requests per minute on the demo key) which pushes any real product onto a paid plan within days of integration. The on-chain DEX side ships as a separate `/onchain` namespace inherited from GeckoTerminal, with its own quotas. Teams usually leave CoinGecko at one of two points: when the launch cadence of the tokens they care about outpaces the listing pipeline, or when the per-minute cap on the free tier forces a migration before the product is monetised enough to justify the enterprise tier.

seo_title: CoinGecko alternatives. live network coverage benchmark
seo_description: Compare CoinGecko alternatives on the number of blockchains each major onchain data API officially supports. Live data, refreshed every six hours.
4 changes: 2 additions & 2 deletions alternatives/etherscan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ description: Block explorer and gas tracker covering Ethereum and Polygon
benchmark: gas-estimation

intro: |
Etherscan is the most-visited block explorer on the web and publishes a gas tracker exposing `SafeGasPrice`, `ProposeGasPrice` and `FastGasPrice` via the v2 API on Ethereum and Polygon (free tier). The tiering was originally designed for the pre-EIP-1559 single-price world and is now mapped onto a priority-fee comparison alongside dedicated oracles. The question every wallet, swap router and bridge UI faces before sending a transaction is which gas oracle actually matches what the next block will charge on the chain their product runs on, rather than what a marketing page claims. This benchmark polls each oracle at its tier-tolerant cadence (Etherscan every 15 seconds with a global rate-gate enforcing at least 6 seconds between any two Etherscan requests across chains, because the no-key limit is 1 req per 5 s per IP shared), buffers the prediction with the predicted block height, and when that block is mined pulls the full block via `eth_getBlockByNumber(.., true)` on the chain's PublicNode RPC. Realized percentiles are computed from actual `maxPriorityFeePerGas` values, and the absolute error per (oracle, tier, chain) lands on both a gauge and a histogram. The ranking metric is the p99 gap over 24 hours, the worst 1 percent of blocks, because typical-minute gaps sit within fractions of a micro-gwei (economically indistinguishable noise) while gas spikes are where a wrong prediction either overpays or misses the block. A covered-rate column shows the share of time each prediction sat at or above the realized p50, the inclusion-side risk an absolute gap cannot show. The cohort competing with Etherscan includes Blocknative (probability-of-inclusion model), PublicNode `eth_feeHistory` (thin wrapper over EIP-1559 reward percentiles) and Owlracle (multi-oracle aggregator).
Etherscan is the most-visited block explorer on the web and publishes a gas tracker exposing `SafeGasPrice`, `ProposeGasPrice` and `FastGasPrice` via the v2 API on Ethereum and Polygon (free tier). The tiering was originally designed for the pre-EIP-1559 single-price world and is now mapped onto a priority-fee comparison alongside dedicated oracles. The question every wallet, swap router and bridge UI faces before sending a transaction is which gas oracle actually matches what the next block will charge on the chain their product runs on, rather than what a marketing page claims. This benchmark polls each oracle at its tier-tolerant cadence (Etherscan every 15 seconds with a global rate-gate enforcing at least 6 seconds between any two Etherscan requests across chains, because the no-key limit is 1 req per 5 s per IP shared), buffers the prediction with the predicted block height, and when that block is mined pulls the full block via `eth_getBlockByNumber(.., true)` on the chain's PublicNode RPC. Realized percentiles are computed from actual `maxPriorityFeePerGas` values, and the absolute error per (oracle, tier, chain) lands on both a gauge and a histogram. The ranking metric is the p99 gap over 24 hours, the worst 1 percent of blocks, because typical-minute gaps sit within fractions of a micro-gwei (economically indistinguishable noise) while gas spikes are where a wrong prediction either overpays or misses the block. A covered-rate column shows the share of time each prediction sat at or above the realized p50, the inclusion-side risk an absolute gap cannot show. The cohort competing with Etherscan includes PublicNode `eth_feeHistory` (thin wrapper over EIP-1559 reward percentiles) and Owlracle (multi-oracle aggregator).

seo_title: Etherscan alternatives. Live gas oracle accuracy benchmark
seo_description: Compare Etherscan against Blocknative, PublicNode feeHistory and Owlracle on gwei gap between predicted and realized priority fee, ranked on p99 over 24h.
seo_description: Compare Etherscan against PublicNode feeHistory and Owlracle on gwei gap between predicted and realized priority fee, ranked on p99 over 24h.

status: live
Loading