OnChainProxy

Stable, cache-friendly URLs for on-chain asset metadata and images. Designed for thumbnails, wallets, and UI.

Built for the EVM. Supports Ethereum and major EVM L2s.

Deploy

This is a reference implementation. Self-hosting is recommended for production use.

Open source on gwendall/onchainproxy (MIT).

You can also use the hosted instance you’re on right now. I might add rate limiting / paid hosted option later; for now, feel free to use it.

Railway note: click “Deploy”, then pick “Deploy from GitHub” and select gwendall/onchainproxy.

Supported chains

Use any of these in the path as /:chain:

ethbasearboppolygonzksynclineascrollpolygon-zkevm

All chains are treated identically: read-only RPC, on-chain metadata resolution, and cacheable HTTP responses.

Tip: you can still override RPC per-request with ?rpcUrl=....

Why OnChainProxy exists

Fetching on-chain images is slow, flaky, and inconsistent (IPFS gateways, huge images, random hosts, on-chain data URLs). The naive solution is an indexer + a database. This is the opposite: a tiny origin that resolves the freshest tokenURI/uri from chain RPC at request time, then lets caching do the heavy lifting.

At a broader level

If digital art and on-chain assets are meant to last, their interfaces need to be more resilient than the platforms that serve them. Today, much of this UX still depends on centralized services sitting between users and the chain. OnChainProxy is a small step toward reducing that dependency - by making on-chain data directly consumable over cacheable HTTP, without introducing new state or infrastructure.

Non-goals: indexing, persistence, analytics, ownership history, or marketplace APIs.

What it does

  • Resolves on-chain metadata at request time (read-only EVM JSON-RPC calls).
  • Normalizes URIs (IPFS + data URLs) into a cacheable HTTP response.
  • Uniformizes images for UI: returns WebP thumbnails when possible (size/quality) so interfaces stay fast and consistent.
  • Gives you stable image URLs for <img>, <picture>, and APIs.
  • Acts like a “hidden CDN”: ETag + Cache-Control enable fast edge/browser caching.

Endpoints

Use OnChainProxy as the src for images or as a metadata fetcher - it resolves on-chain tokenURI at request time and returns a cacheable HTTP response.

By default, the image endpoint returns WebP when possible (UI-friendly thumbnails). Use raw=1 to keep the original bytes (no resize / no WebP).

GET /:chain/:contract/:tokenId
Returns JSON metadata (and the resolved image URL).
Query params: rpcUrl, debug=1
GET /:chain/:contract/:tokenId/image
Returns WebP when possible (thumbnail-optimized).
Query params: raw=1, svg=1, w, h, q, rpcUrl, debug=1, json=1

Cache-friendly responses: ETag + Cache-Control.

Notes (formats)

  • Standards: ERC-721 and ERC-1155 (via tokenURI/uri).
  • Special cases: legacy contracts like CryptoPunks are supported too.

Example (CryptoPunks)

For L2s, just swap /eth/ with e.g. /base/, /arb/, /op/,/polygon/, etc.

Query params

GET /:chain/:contract/:tokenId
  • chain: one of eth, base, arb, op, polygon, zksync, linea, scroll, polygon-zkevm.
  • rpcUrl: override the chain RPC URL (optional)
  • debug=1: extra error details (dev only)
GET /:chain/:contract/:tokenId/image
  • chain: one of eth, base, arb, op, polygon, zksync, linea, scroll, polygon-zkevm.
  • raw=1: return the original image (no resize / no WebP)
  • By default, SVGs are rasterized to WebP (so w/h/q applies). svg=1 is an escape hatch to keep SVG as SVG (vector) while still proxying from this origin (no redirect).
  • w, h: max resize bounds (default 512, min 16, max 2048)
  • q: WebP quality (default 70, min 30, max 90)
  • rpcUrl: override the chain RPC URL (optional)
  • json=1: return JSON on error (otherwise SVG fallback)
  • debug=1: extra error details (dev only)

Config (env)

  • ONCHAIN_RPC_URLS / ONCHAIN_RPC_URL: global RPC fallback (optional)
  • Per-chain: ONCHAIN_RPC_URLS_ETH, ONCHAIN_RPC_URLS_BASE, etc. (optional)
  • IPFS_GATEWAY: IPFS gateway base (default https://ipfs.io/ipfs)
  • NEXT_PUBLIC_SITE_URL / SITE_URL: base URL used in metadata (default http://localhost:3000)