Writing

10 min read

Web3 Dashboard: Polling, Caching vs Real-Time

When to poll, when to cache, and when to use WebSockets for on-chain data. Trade-offs between speed, cost, and accuracy with practical examples using RPCs, The Graph, and TanStack Query.

Web3PerformanceReact QueryArchitecture

Web3 Dashboard Updates: Polling vs Caching vs Real-Time

Why Live On-Chain Data Is Hard

Blockchains are append-only ledgers, not real-time databases. Every piece of data you show — balances, prices, transaction status — is a snapshot that can become stale after it renders.

RPC nodes have rate limits. Indexers can lag behind the chain head by seconds or minutes. Price APIs can also throttle requests.

The engineering challenge is not simply fetching data once. It is deciding how fresh each data type needs to be, how much infrastructure cost you can afford, and what UX trade-offs your users will accept.

Why Blockchain Data Becomes Stale

Different Web3 data sources update at different speeds.

  • Blockchain state changes when new transactions are confirmed

  • RPC providers have request limits

  • Indexers need time to process new blocks

  • Price APIs update at different intervals

  • Cached data can remain available after the source changes

This means a dashboard needs a deliberate data freshness strategy.

When to Use Polling

Polling is the default choice for many Web3 dashboards.

It is simple, predictable, and works with almost any data source.

Recommended Polling Intervals

A practical starting point is:

  • Token balances: 30–60 seconds

  • Portfolio values: 30–60 seconds

  • Pending transaction status: 3–5 seconds

  • Protocol TVL: 60–120 seconds

// hooks/useProtocolTVL.ts

import { useQuery } from '@tanstack/react-query';

export function useProtocolTVL() {
  return useQuery({
    queryKey: ['protocol-tvl'],

    queryFn: async () => {
      const res = await fetch('/api/tvl');

      return res.json() as Promise<{
        tvl: number;
        updatedAt: string;
      }>;
    },

    staleTime: 60_000,
    refetchInterval: 120_000,
    refetchIntervalInBackground: false,
  });
}

Polling on Mobile Devices

Use refetchIntervalInBackground: false when possible to reduce unnecessary network activity and battery usage.

You can also increase polling intervals during periods when users are less active.

When to Use Caching

Caching is ideal for data that does not change frequently.

Examples include:

  • Token metadata

  • Contract ABIs

  • Historical charts

  • Static protocol configurations

  • Documentation data

Server-Side Caching with Next.js

Next.js can cache server-side data so repeated requests do not always reach the upstream provider.

// app/api/token-metadata/route.ts

import { unstable_cache } from 'next/cache';

const getTokenMetadata = unstable_cache(
  async (address: string) => {
    const res = await fetch(
      `https://api.etherscan.io/api?module=token&action=tokeninfo&contractaddress=${address}`
    );

    return res.json();
  },
  ['token-metadata'],
  {
    revalidate: 3600,
  }
);

export async function GET(request: Request) {
  const address = new URL(request.url)
    .searchParams.get('address')!;

  const data = await getTokenMetadata(address);

  return Response.json(data, {
    headers: {
      'Cache-Control':
        's-maxage=3600, stale-while-revalidate=7200',
    },
  });
}

Use Multiple Cache Layers

A production dashboard can use several caching layers:

  1. React Query: Client-side caching with staleTime and gcTime

  2. Next.js: Server-side caching

  3. CDN: Edge caching for public API responses

Each layer reduces the amount of work required by the layer below it.

When Real-Time Updates Matter

WebSockets or Server-Sent Events (SSE) make sense when sub-second updates genuinely affect user decisions.

Examples include:

  • Live trading interfaces

  • Mempool monitoring

  • Auction countdowns

  • Block-by-block event feeds

  • Real-time market interfaces

Using WebSockets for Live Blocks

// hooks/useLiveBlocks.ts

import { useEffect, useState } from 'react';
import {
  createPublicClient,
  webSocket,
} from 'viem';
import { mainnet } from 'viem/chains';

const wsClient = createPublicClient({
  chain: mainnet,
  transport: webSocket(
    process.env.NEXT_PUBLIC_ALCHEMY_WS_URL!
  ),
});

export function useLiveBlocks() {
  const [latestBlock, setLatestBlock] = useState<
    bigint | null
  >(null);

  useEffect(() => {
    const unwatch = wsClient.watchBlocks({
      onBlock: (block) =>
        setLatestBlock(block.number),
    });

    return () => unwatch();
  }, []);

  return latestBlock;
}

Do You Need WebSockets for Every Dashboard?

No.

For most dashboards, polling every 15–30 seconds can provide most of the UX benefit without the additional infrastructure and connection complexity of WebSockets.

Polling vs Caching vs Real-Time Updates

Approach Latency Cost Complexity Best For
Polling (30s) Medium Low Low Portfolio dashboards
Aggressive polling (3s) Low High Low Pending transactions
CDN + server cache High Very low Medium Static protocol data
The Graph Medium Medium Medium Historical events
WebSocket RPC Very low High High Trading interfaces

Balance Freshness With Infrastructure Cost

Showing data that is 45 seconds old with a clear "Last updated 45s ago" indicator can be better than making a portfolio tracker poll every second.

The goal is not maximum freshness.

The goal is appropriate freshness at a reasonable infrastructure cost.

Common Web3 Data Sources

Different data sources are suited to different dashboard requirements.

RPC Nodes

Providers such as Alchemy, Infura, and QuickNode provide direct access to blockchain data.

They are useful for:

  • Wallet balances

  • Contract state

  • Transaction status

  • Real-time blockchain reads

Batch multiple reads with multicall and cache results where appropriate.

The Graph

The Graph provides indexed blockchain events through GraphQL.

It works well for:

  • Transaction history

  • DEX swaps

  • Governance votes

  • Historical protocol activity

Use pagination when querying large datasets.

query GetSwaps(
  $pool: String!
  $first: Int!
  $skip: Int!
) {
  swaps(
    where: { pool: $pool }
    orderBy: timestamp
    orderDirection: desc
    first: $first
    skip: $skip
  ) {
    id
    timestamp
    amount0In
    amount1Out
    sender
  }
}

Moralis and Alchemy APIs

Higher-level APIs can simplify access to:

  • NFT metadata

  • Token transfers

  • Wallet history

  • Blockchain activity

These services can be useful for MVPs before investing in a custom indexing infrastructure.

DeFiLlama and CoinGecko

These sources can provide price, market, and TVL information.

Cache price and market data for approximately 30–60 seconds depending on the requirements of your application.

Avoid making individual price requests inside loops.

Recommended Data Freshness Strategy

Instead of treating every piece of dashboard data the same, divide it into freshness tiers.

Tier 1: Instant Data

Target freshness: 0 seconds

Use this for:

  • Wallet connection state

  • User-initiated transaction status

  • Signing state

  • Wallet changes

Tier 2: Near-Real-Time Data

Target freshness: 15–30 seconds

Use this for:

  • Token balances

  • Portfolio values

  • Recent wallet activity

Tier 3: Periodic Data

Target freshness: 1–5 minutes

Use this for:

  • Protocol TVL

  • Market capitalization

  • Historical charts

  • General protocol metrics

Tier 4: Static Data

Target freshness: Hours or longer

Use this for:

  • Token metadata

  • Contract ABIs

  • Documentation

  • Static protocol configurations

Choose the Cheapest Strategy That Meets the Requirement

Each freshness tier should use the simplest infrastructure that provides the required user experience.

Do not use WebSockets for data that can comfortably be refreshed through polling or caching.

Web3 Dashboard Performance Checklist

Use these practices when designing a dashboard update strategy.

Configure staleTime Per Data Type

Do not use one global staleTime for every query.

Balances, prices, protocol metrics, and static metadata can all have different freshness requirements.

Use Query Keys for Invalidation

Use predictable query keys so related data can be invalidated after a successful transaction.

Prefetch Data

Prefetch important dashboard queries during navigation or other appropriate interactions so data is ready when users reach the next screen.

Show Cached Data During Refetching

Do not replace the entire dashboard with a loading spinner every time data refreshes.

Show cached data immediately and use an isFetching indicator to communicate that an update is happening.

Rate-Limit API Routes

Protect your own API routes from excessive requests so one user or component cannot consume your upstream provider limits.

Monitor RPC Usage

Monitor RPC usage in production.

A single unbatched loop can generate thousands of requests and quickly exhaust provider limits.

FAQ About Web3 Dashboard Data Updates

How Often Should I Poll Balances?

For most display-focused dashboards, polling every 30–60 seconds is a reasonable starting point.

For active trading applications, shorter intervals such as 10–15 seconds may be appropriate.

Is The Graph Still Relevant in 2026?

Yes. The Graph remains useful for historical indexed blockchain data.

For custom indexing requirements or lower-latency applications, alternatives such as Ponder, Envio, or direct RPC with caching may be worth considering.

Should I Use React Query or SWR?

TanStack Query is a strong choice for Web3 applications because it provides extensive caching, refetching, mutation support, developer tools, and integration with wagmi.

How Should I Handle Data After a Transaction?

Invalidate the related query keys after a successful transaction.

Then refetch important data such as:

  • Wallet balances

  • Token balances

  • Transaction history

  • Portfolio values

This helps the interface reflect the latest state without forcing a complete page reload.

How Should I Handle Offline Users?

Display the last cached data and clearly communicate that it may be outdated.

TanStack Query's gcTime can keep cached data available during short periods of disconnection.

Final Thoughts

Web3 dashboards do not need every piece of data to update in real time.

The better approach is to understand how frequently each type of data changes and match it with the right strategy.

Use polling for predictable updates, caching for slow-changing data, indexers for historical information, and WebSockets only when real-time updates genuinely improve the user experience.

A well-designed freshness strategy reduces RPC costs, improves performance, and gives users data that feels both fast and trustworthy.

Get practical Web3 & frontend tips

Short articles on Next.js, Web3 dashboards, and DeFi interfaces. No spam, unsubscribe anytime.

Want help implementing this on your product?

I work with crypto startups and product teams on Web3 dashboards, DeFi interfaces, and Next.js frontends — from architecture through launch. Hire me for web3 dashboard development.