This content originally appeared on DEV Community and was authored by Cherrypick14
Blockchain developers have long struggled with the complexity of connecting to and querying blockchain networks. Traditional APIs often require extensive boilerplate code, lack type safety, and make real-time data subscriptions cumbersome. Enter Polkadot API (PAPI) - a modern, TypeScript-first API that revolutionizes how we interact with Polkadot and its parachains.
In this article, I'll walk you through building Polkadot Network Pulse, a real-time blockchain monitoring dashboard that showcases PAPI's powerful features. By the end, you'll understand how to leverage PAPI's reactive subscriptions, WebSocket connections, and type-safe queries to build production-ready blockchain applications.
🔗 Live Demo: https://polkadot-network-pulse-q5rhsfj68-cherrypick14s-projects.vercel.app/
📦 Source Code: https://github.com/Cherrypick14/polkadot-network-pulse
What is PAPI?
Polkadot API (PAPI) is the next-generation JavaScript/TypeScript library for interacting with Polkadot and Substrate-based chains. It's a complete rewrite of the legacy @polkadot/api
with several key improvements:
Why PAPI Over Legacy @polkadot/api?
Project Overview: Polkadot Network Pulse
Polkadot Network Pulse is a real-time dashboard that monitors the Polkadot blockchain, displaying:
- Latest block updates (streaming in real-time)
- Finalized block numbers
- Average block time calculations
- Live block feed with animations
- Connection status monitoring
The goal is to demonstrate PAPI's core strengths: reactive subscriptions and WebSocket-based real-time data streaming.
Technical Architecture
Tech Stack
- Frontend: React 19 with TypeScript
- Blockchain API: Polkadot API (PAPI) v1.20+
- Styling: Tailwind CSS v4
- Build Tool: Vite
- Icons: Lucide React
Architecture Diagram
Implementation Deep Dive
1. Setting Up PAPI
First, install the required dependencies:
npm install polkadot-api
npm install @polkadot-api/descriptors
2. Creating the PAPI Client
The foundation of any PAPI application is the client creation:
import { createClient } from "polkadot-api";
import { getWsProvider } from "polkadot-api/ws-provider/web";
// Create WebSocket provider
const provider = getWsProvider("wss://rpc.polkadot.io");
// Initialize PAPI client
const client = createClient(provider);
Key Insight: Unlike the legacy API, PAPI uses a provider pattern that separates connection management from client logic. This makes testing and switching between networks trivial.
3. Real-Time Block Subscriptions
This is where PAPI truly shines. Instead of polling for new blocks, we subscribe to observables:
// Subscribe to best (latest) blocks
client.bestBlocks$.subscribe((blocks) => {
for (const block of blocks) {
const blockInfo = {
number: block.number,
hash: block.hash,
timestamp: Date.now(),
};
setLatestBlock(blockInfo);
// Update block feed
setRecentBlocks((prev) => [blockInfo, ...prev].slice(0, 15));
}
});
// Subscribe to finalized blocks
client.finalizedBlock$.subscribe((block) => {
setFinalizedBlock(block.number);
});
Why Observables?
- Reactive: Automatically updates when new data arrives.
- Memory Efficient: Unsubscribe when component unmounts.
- Composable: Easy to combine multiple data streams.
- Error Handling: Built-in error propagation.
4. Calculating Block Time
One interesting metric is the average block time. We calculate this by comparing timestamps of recent blocks:
const calculateBlockTime = () => {
if (recentBlocks.length < 2) return null;
const timeDiff = recentBlocks[0].timestamp -
recentBlocks[recentBlocks.length - 1].timestamp;
const blockDiff = recentBlocks[0].number -
recentBlocks[recentBlocks.length - 1].number;
return (timeDiff / blockDiff / 1000).toFixed(2); // in seconds
};
This gives us a live, measured block time rather than relying on hardcoded values.
5. Managing Connection State
Proper connection management is crucial for production apps:
const [isConnected, setIsConnected] = useState(false);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const connectToPolkadot = async () => {
try {
setLoading(true);
setError(null);
const provider = getWsProvider("wss://rpc.polkadot.io");
const client = createClient(provider);
setIsConnected(true);
// ... set up subscriptions
} catch (err) {
setError(err instanceof Error ? err.message : "Connection failed");
setIsConnected(false);
} finally {
setLoading(false);
}
};
Key PAPI Concepts Explained
1. Observables vs. Promises
Traditional APIs use promises for async operations:
// Legacy approach (promise)
const block = await api.rpc.chain.getBlock();
PAPI uses observables for continuous data:
// PAPI approach (observable)
client.bestBlocks$.subscribe(blocks => {
// Automatically receives updates
});
Benefits:
- No need to repeatedly poll
- Lower network overhead
- Real-time updates
- Automatic cleanup
2. WebSocket Provider
PAPI's WebSocket provider maintains a persistent connection:
const provider = getWsProvider("wss://rpc.polkadot.io");
Features:
- Automatic reconnection on disconnect
- Connection pooling
- Request queuing
- Error recovery
3. Type Safety
One of PAPI's biggest advantages is full TypeScript support. While we didn't use typed APIs extensively in this project (focusing on subscriptions), here's how they work:
// Get typed API with chain-specific types
const typedApi = client.getTypedApi(chainSpec);
// TypeScript knows all available queries
const validators = await typedApi.query.Session.Validators.getValue();
// validators is properly typed!
Challenges & Solutions
Challenge 1: PAPI API Changes
Problem: PAPI is actively developed, and APIs change between versions.
Solution: Focused on stable core features (subscriptions) rather than experimental typed queries. Always check the official docs - https://papi.how
Challenge 2: Handling Reconnections
Problem: WebSocket connections can drop unexpectedly.
Solution: PAPI's provider handles this automatically. We just need to show connection state to users:
{isConnected && (
<div className="flex items-center gap-2">
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse" />
<span>Live Connected</span>
</div>
)}
Challenge 3: Performance with Rapid Updates
Problem: New blocks every ~6 seconds can cause performance issues.
Solution: Limit the block feed to 15 most recent blocks:
setRecentBlocks((prev) => [blockInfo, ...prev].slice(0, 15));
Performance Considerations
1. Bundle Size
PAPI significantly reduces bundle size compared to legacy API:
- Legacy @polkadot/api: ~500KB+ .
- PAPI: ~100KB base + only what you use.
2. Memory Management
Always unsubscribe from observables when components unmount:
useEffect(() => {
const subscription = client.bestBlocks$.subscribe(/* ... */);
return () => {
subscription.unsubscribe(); // Cleanup
};
}, []);
3. Connection Pooling
PAPI automatically manages connection pooling, so multiple subscriptions share the same WebSocket connection.
Deployment
Build for Production
npm run build
Vercel (Preference):
- Push code to GitHub
- Import project in Vercel
- Deploy automatically
Note: Alternative Deployment When Vercel UI Fails
When I first tried deploying through the Vercel dashboard, I ran into this error:
sh: line 1: vite: command not found
Error: Command "vite build" exited with 127
This happens sometimes when the build environment can’t find your local dev dependencies (like Vite).
Instead of getting stuck, I used a different approach that worked perfectly — deploying through Vercel CLI.
Here’s what I did:
Just for more flexibility and if you want more control, the CLI route is smooth:
npm install -g vercel
vercel login
vercel
During the setup:
- Set the build command to
npm run build
- Output directory:
dist
- Confirm project name or leave defaults
Within seconds, your PAPI app will be live with a URL like:
https://your-app-name.vercel.app
💡 Pro tip: The CLI often works better than the UI if you’re using a custom front-end tool-chain or need to debug build errors locally before deployment.
Netlify:
- Run
npm run build
- Drag
dist
/ folder to Netlify Drop - Done!
Environment Variables:
If using different RPC endpoints, add .env
:
VITE_RPC_ENDPOINT=wss://rpc.polkadot.io
Lessons Learned
1. PAPI is Production-Ready
Despite being newer than the legacy API, PAPI is stable and performant. The developer experience is significantly better.
2. Observables Are Powerful
RxJS observables might seem complex at first, but they're perfect for blockchain data that updates continuously.
3. Type Safety Catches Bugs Early
TypeScript integration means fewer runtime errors and better IDE autocomplete.
4. Start Simple
Focus on core features (subscriptions) before diving into complex queries. PAPI's strength is real-time data.
What's Next?
Potential enhancements for this project:
- Historical Data: Query past blocks and create charts.
- Transaction Monitoring: Subscribe to extrinsics in real-time
- Multi-Chain Support: Connect to parachains (Kusama, Acala, etc.)
- Account Tracking: Monitor specific account balances.
- Governance Dashboard: Track referendums and votes.
- Performance Metrics: Add more network statistics.
Useful Resources
📚 - PAPI Official Documentation - https://papi.how
🔧 - PAPI Github - https://github.com/polkadot-api/polkadot-api
🌐 - Polkadot Network - https://polkadot.network
💬 - Polkadot Discord - https://discord.gg/polkadot
Conclusion
Building Polkadot Network Pulse demonstrated that PAPI is a significant leap forward for Polkadot development. The combination of TypeScript support, reactive subscriptions, and a clean API makes it the ideal choice for modern blockchain applications.
Whether you're building a block explorer, DeFi dashboard, or governance tool, PAPI provides the tools you need to create responsive, type-safe applications with minimal boilerplate.
Key Takeaways:
- PAPI simplifies real-time blockchain data subscriptions
- Observables provide elegant solutions for continuous data streams
- TypeScript integration catches errors at compile-time
- WebSocket providers handle connection management automatically
- Smaller bundle sizes improve application performance
Ready to build with PAPI? Start with the official documentation -https://papi.how and experiment with subscriptions. The future of Polkadot development is here!
About Me:
Hey folks 👋 I’m Cheryl, a Full-Stack and Blockchain Developer. I enjoy turning complex technical concepts into clear, easy-to-grasp content through technical writing.
Let's connect here:
My github: https://github.com/Cherrypick14
X(Twitter) : https://x.com/OwalaCheryl
Found this helpful? Drop a ❤️ and follow for more blockchain development content!
This content originally appeared on DEV Community and was authored by Cherrypick14

Cherrypick14 | Sciencx (2025-10-13T15:18:09+00:00) How to Build a Real-Time Blockchain Dashboard with PAPI. Retrieved from https://www.scien.cx/2025/10/13/how-to-build-a-real-time-blockchain-dashboard-with-papi/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.