Back to Blog
·10 min

Blockchain Explorer: Build Your Own Chain Explorer

A blockchain explorer is the window into on-chain activity. Whether you are building for a public chain, a testnet, or a private enterprise blockchain, having a fast and intuitive explorer is essential for developers and users to verify transactions, track assets, and audit smart contracts. A blockchain explorer template provides a complete frontend for any EVM-compatible chain.

Core Explorer Features

A production blockchain explorer built with the Blockchain Explorer template includes:

  • Block Explorer: View recent blocks with timestamps, gas usage, and transaction counts
  • Transaction Details: Full transaction data including inputs, logs, and status
  • Address View: Token balances, transaction history, and contract interactions
  • Token Tracker: ERC-20 and ERC-721 token transfers and holders
  • Smart Contract Reader: Read contract state and decode function calls
  • Search: Search by block number, transaction hash, address, or token

Setting Up the Explorer Template

git clone https://github.com/breafio/blockchain-explorer.git my-explorer
cd my-explorer
pnpm install
cp .env.example .env.local

API Layer

The explorer needs efficient blockchain data indexing:

// lib/explorer/api.ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'

const client = createPublicClient({
  chain: mainnet,
  transport: http(process.env.RPC_URL || 'https://eth-mainnet.g.alchemy.com/v2/demo'),
})

export interface BlockData {
  number: bigint
  hash: string
  timestamp: bigint
  transactions: string[]
  gasUsed: bigint
  gasLimit: bigint
  miner: string
  size: bigint
}

export async function getBlock(blockNumber: bigint): Promise<BlockData> {
  const block = await client.getBlock({ blockNumber, includeTransactions: false })
  return {
    number: block.number!,
    hash: block.hash!,
    timestamp: block.timestamp,
    transactions: block.transactions as string[],
    gasUsed: block.gasUsed,
    gasLimit: block.gasLimit,
    miner: block.miner,
    size: block.size,
  }
}

export async function getLatestBlocks(count: number = 25): Promise<BlockData[]> {
  const latestBlock = await client.getBlockNumber()
  const blocks: BlockData[] = []

  for (let i = 0; i < count; i++) {
    const block = await getBlock(latestBlock - BigInt(i))
    blocks.push(block)
  }

  return blocks
}

Transaction Details

Displaying transaction data requires decoding input data and parsing logs:

import { createPublicClient, http, decodeFunctionData, formatEther } from 'viem'
import { mainnet } from 'viem/chains'

const client = createPublicClient({ chain: mainnet, transport: http() })

export interface TransactionData {
  hash: string
  from: string
  to: string | null
  value: bigint
  gasPrice: bigint
  gas: bigint
  input: string
  status: 'success' | 'reverted'
  timestamp: bigint
  blockNumber: bigint
  logs: Log[]
}

export async function getTransaction(txHash: string): Promise<TransactionData | null> {
  const tx = await client.getTransaction({ hash: txHash as string })
  const receipt = await client.getTransactionReceipt({ hash: txHash as string })
  const block = await client.getBlock({ blockNumber: tx.blockNumber! })

  if (!tx) return null

  return {
    hash: tx.hash,
    from: tx.from,
    to: tx.to,
    value: tx.value,
    gasPrice: tx.gasPrice!,
    gas: tx.gas,
    input: tx.input,
    status: receipt.status === 'success' ? 'success' : 'reverted',
    timestamp: block.timestamp,
    blockNumber: tx.blockNumber!,
    logs: receipt.logs,
  }
}

Search Functionality

A smart search that detects the type of query:

'use client'

import { useState } from 'react'
import { useRouter } from 'next/navigation'

export function ExplorerSearch() {
  const [query, setQuery] = useState('')
  const router = useRouter()

  const handleSearch = (e: React.FormEvent) => {
    e.preventDefault()
    const q = query.trim()

    if (/^d+$/.test(q)) {
      router.push(`/explorer/block/${q}`)
    } else if (q.length === 66 && q.startsWith('0x')) {
      // Could be a transaction or address
      router.push(`/explorer/search?q=${q}`)
    } else if (q.length === 42 && q.startsWith('0x')) {
      router.push(`/explorer/address/${q}`)
    } else {
      router.push(`/explorer/search?q=${encodeURIComponent(q)}`)
    }
  }

  return (
    <form onSubmit={handleSearch} className="relative">
      <Search className="absolute left-4 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Search by block, tx, address, or token..."
        className="w-full rounded-xl border border-gray-200 bg-white py-3 pl-11 pr-4 text-sm shadow-sm"
      />
    </form>
  )
}

The Bottom Line

A blockchain explorer is essential infrastructure for any EVM-based chain. The Blockchain Explorer template provides a complete, customizable frontend with block viewing, transaction details, address tracking, token analytics, and smart search — all powered by Viem and ready to deploy against any EVM RPC endpoint.

Ready to Build?

Get started with our production-ready starter kits and ship your project faster.

Browse Starter Kits