vccs
Composable charting components for Vue 3, ported from Recharts
One open-source engine powering independent block explorers across chains. BNBScan and EthScan are live today, more on the way.
DataTypeScript · JavaScriptGitHub @heathermhuangOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Alternative multi blockchain block explorer
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
The open-source, multi-chain block explorer platform.
One codebase powers independent explorers for BNB Chain and Ethereum today — and is built to add more chains over time.
Next.js 15, Drizzle ORM, and ethers.js. Maintained by Measurable Data Token (MDT) .Read the full README ↗Altscan is an open-source, multi-chain block explorer platform. One codebase powers two independent explorers today — BNBScan (bnbscan.com, BNB Chain) and EthScan (ethscan.io, Ethereum) — and is designed to extend to more chains over time. They are fully independent from BscScan, Etherscan, Binance, or the Ethereum Foundation, providing a clean, fast interface for exploring blocks, transactions, addresses, tokens, and on-chain activity.
A single CHAIN environment variable selects which chain a deployment serves — same frontend, same indexer, same schema.
| EthScan homepage, dark mode | Block |
|---|---|
| Transaction | Address |
|---|---|
| Token | Status page |
|---|---|
Captured from production on 12 October 2026, with the sponsored slots switched off.
altscan/
├── apps/
│ ├── explorer/ Unified Next.js 15 frontend + API routes
│ │ CHAIN=bnb → bnbscan.com
│ │ CHAIN=eth → ethscan.io
│ ├── indexer/ Unified block indexer (direct polling loop)
│ │ CHAIN=bnb → indexes BNB Chain
│ │ CHAIN=eth → indexes Ethereum
│ ├── status/ Hono status page for the hosted explorers
│ │ Polls /api/health on bnbscan.com and ethscan.io
│ ├── altscan-site/ altscan.io umbrella site (Astro on Cloudflare Workers)
│ └── admin/ Operator console behind Cloudflare Access (Astro on Cloudflare Workers)
├── packages/
│ ├── chain-config/ getChainConfig() — chain-specific config
│ ├── db/ Drizzle ORM schema + Postgres client
│ ├── explorer-core/ Shared utils (rate limiting, formatting, Redis cache)
│ ├── providers/ Third-party data adapters (Moralis) and their spend budgets
│ ├── settings-schema/ Runtime settings shared by the explorer and the admin console
│ └── types/ Shared TypeScript types
├── render.yaml Render blueprint for the hosted explorers
├── docker-compose.yml Self-host stack: Postgres, Redis, indexer, explorer
├── turbo.json Turborepo pipeline config
└── pnpm-workspace.yaml
| Layer | Technology |
|---|---|
| Frontend | Next.js 15 (App Router), React 19, Tailwind CSS 3 |
| Backend | Next.js API routes, Hono (status page) |
| Database | PostgreSQL (via Drizzle ORM) |
| Indexer | ethers.js, JSON-RPC (direct polling loop, no job queue) |
| Cache | Redis (rate limiting, caching, Moralis CU ledger) |
| Edge sites | Astro on Cloudflare Workers (altscan.io, admin console) |
| Monorepo | pnpm + Turborepo |
| Hosting | Render.com (web services + workers + Postgres + Redis) |
/api/health endpoints every 30 seconds, tracking uptime, block lag, and response time over 24 hours and 30 days. Its targets are fixed in apps/status/src/server.ts, and it is not part of the Docker stack or the Render blueprint.git clone https://github.com/heathermhuang/altscan.git
cd altscan
cp .env.docker.example .env
docker compose up -d
Open http://localhost:3000. That's Postgres, Redis, the indexer, and the explorer —
no configuration required to start, and the indexer creates its own schema on first
boot. Set CHAIN=eth in .env and re-run with --build for Ethereum.
Full guide, including Render deployment, retention tuning, and limitations: docs/SELF_HOSTING.md.
package.json; corepack enable picks up the exact versionREDIS_URL, rate limits and caches fall back to per-process memory# Clone the repo
git clone https://github.com/heathermhuang/altscan.git
cd altscan
# Install dependencies
pnpm install
# Start Postgres from the Docker stack (localhost:5432; user, password and database all "altscan")
docker compose up -d postgres
# Set up the explorer environment (defaults match the local Docker Postgres)
cp apps/explorer/.env.example apps/explorer/.env.local
# Start the BNB explorer
CHAIN=bnb NEXT_PUBLIC_CHAIN=bnb pnpm --filter @altscan/explorer dev
The BNB explorer will be available at http://localhost:3000. The indexer creates the
database schema on its first boot, so run it once (below) before expecting data; the
explorer alone, against an empty database, has no tables to read. pnpm dev starts every
app at once through Turborepo: the explorer, the indexer, the status page, and both
Astro sites.
# BNB Chain explorer only
CHAIN=bnb NEXT_PUBLIC_CHAIN=bnb pnpm --filter @altscan/explorer dev
# Ethereum explorer only
CHAIN=eth NEXT_PUBLIC_CHAIN=eth pnpm --filter @altscan/explorer dev -p 3001
# BNB indexer only — build the packages it imports first (see below)
pnpm --filter @altscan/db build && pnpm --filter @altscan/chain-config build && pnpm --filter @altscan/explorer-core build && pnpm --filter @altscan/providers build
CHAIN=bnb pnpm --filter @altscan/indexer dev
# Status page only (monitors the hosted sites)
pnpm --filter @altscan/status dev
CHAIN drives the server; NEXT_PUBLIC_CHAIN is inlined into the client bundle, so set
both to the same chain. The indexer reads its settings from the environment or from
apps/indexer/.env: at least DATABASE_URL (or ETH_DATABASE_URL), the chain's RPC URL,
and a START_BLOCK near the chain head — its built-in start is millions of blocks back.
The explorer compiles the workspace packages from source, but the indexer loads their
built dist/ output, which is not committed — build them once after cloning and again
after changing them.
These are the variables a deployment needs. apps/explorer/.env.example
adds the optional provider caps, and docs/SELF_HOSTING.md covers the
indexer's retention and disk settings.
| Variable | Required | Description |
|---|---|---|
CHAIN | Yes | bnb or eth — selects which chain to serve/index |
NEXT_PUBLIC_CHAIN | Explorer | Same value as CHAIN; read by client components at build time |
DATABASE_URL | CHAIN=bnb | PostgreSQL connection string (BNB Chain) |
ETH_DATABASE_URL | CHAIN=eth | PostgreSQL connection string (Ethereum) |
BNB_RPC_URL | CHAIN=bnb | BSC JSON-RPC endpoint, or a comma-separated list for failover |
ETH_RPC_URL | CHAIN=eth | Ethereum JSON-RPC endpoint, or a comma-separated list for failover |
REDIS_URL | Recommended | Redis connection string; without it, rate limits and caches are per-process |
MORALIS_API_KEY | No | Moralis API for balance and NFT enrichment |
ADMIN_SECRET | No | Bearer token for the /api/admin/* endpoints; unset, they refuse every request |
GA_MEASUREMENT_ID | No | Google Analytics measurement ID; unset, no analytics script loads |
BINANCE_REF_CODE | No | Referral code for the sponsored Binance placements; unset, they never render |
You can get started without paid RPC providers:
| Chain | Free Endpoint |
|---|---|
| BNB Chain | https://bsc-dataseed1.binance.org/ |
| Ethereum | https://ethereum-rpc.publicnode.com |
These are the Docker stack's defaults. Both serve eth_getBlockReceipts for historical
blocks, which the indexer depends on (checked October 2026). Check any other endpoint the
same way — ask it for the receipts of a block a few thousand deep — before you rely on it.
Some public RPCs answer at the chain tip but lack that method, and some return an empty
list for it; the indexer rejects a block whose receipts don't cover its transactions, so it
cannot make progress on either. Some free plans also cap JSON-RPC batch size:
eth.drpc.org's free tier rejects batches of more than three, so set
RPC_BATCH_MAX_COUNT=1 on the indexer if you use it.
For production, use a paid RPC provider: free endpoints rate-limit under indexer load.
Both explorers expose a v1 REST API. /api-docs on either site is the endpoint reference,
and /developer shows how to mint an API key by signing a message with your wallet. A key
is optional: calls without one are rate-limited by IP.
# Example: query transactions for an address
curl -X POST https://bnbscan.com/api/v1/query \
-H "X-API-Key: bnbs_..." \
-H "Content-Type: application/json" \
-d '{"entity":"transactions","filter":{"address":"0x..."}}'
pnpm test
Runs the Vitest suite for every workspace. Suites that need a real Postgres or Redis are skipped unless their environment variable is set — CONTRIBUTING.md lists them and how to run them. CI runs all of them except the two retention-partition suites, plus lint, typechecks of the indexer and the admin console, and a production build of the explorer.
The hosted explorers run on Render.com from
render.yaml: a web service and an indexer worker per chain, with Postgres
and Redis. To run your own, with Docker or on Render, follow
docs/SELF_HOSTING.md.
The indexer runs a retention pass every 6 hours. Past RETENTION_DAYS (default 7) it
deletes logs, DEX trades and gas history, and drops each transaction's input data, which
is refetched from RPC on demand; the transactions themselves stay queryable. Transactions,
token transfers and blocks are kept forever unless you also set COMPACT_RETENTION_DAYS,
so that is the setting that bounds block history. The addresses table is never pruned
and keeps growing with the chain. See
docs/SELF_HOSTING.md.
There is also a manual prune endpoint. It deletes whole rows — transactions and blocks
included — older than days, then runs VACUUM. Ask for a dry run first:
curl -X POST "https://your-explorer.example/api/admin/db-prune?days=7&dry=true" \
-H "Authorization: Bearer $ADMIN_SECRET"
NEXT_PUBLIC_CHAIN is inlined into the client bundle at
build time, so switching chains requires a rebuild, not just a restart.packages/chain-config, so a public fork edits them there. Analytics and referral ads
are off unless configured. See
docs/SELF_HOSTING.md.Contributions are welcome. Please read CONTRIBUTING.md for development setup, the CHAIN model, and PR conventions, and our Code of Conduct.
git checkout -b feat/my-featuremainFirst-time contributors: add your name to CONTRIBUTORS.md in your first PR to accept the Contributor License Agreement. You keep ownership of your work — the CLA is a licence grant, not a copyright assignment, and it's what lets us offer the commercial licence described below. A CI check confirms you're listed.
Found a security vulnerability? Please follow our Security Policy — do not open a public issue.
Open source under AGPL-3.0 — an OSI-approved licence. Free, forever, for everyone:
AGPL asks one thing in return: if you modify Altscan and offer it to others over a network, offer those users your modified source too. Run it unmodified, or keep your changes internal, and you owe nothing.
A commercial licence is available for organisations that cannot use AGPL code or need warranty and support terms. See LICENSING.md for what that covers and how the terms compare to source-available alternatives.
© Measurable Data Token (MDT).