Learn how to build a KPI dashboard with Replit using simple steps, interactive code, and data visualization to track performance effectively

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
To build a KPI dashboard with Replit, you’ll create a small full-stack app: a backend (Node.js + Express) that serves KPI data, and a frontend (HTML/CSS/React or plain JS) that renders charts. Replit handles both sides easily inside one Repl. The key is to keep data retrieval async, keep secrets in the Replit Secrets tab (not in code), and set up your routes and UI files correctly. You can store your KPIs in memory, a JSON file, or connect to an external database like Replit DB or Supabase. Once the backend serves JSON data, your frontend can fetch it and visualize it with a charting library (like Chart.js). This workflow actually mirrors a real product dashboard deployment on Replit.
From your Replit dashboard, create a new Repl using the Node.js template. This gives you a server.js file and already an Express server environment once you install it. You’ll need to install Express manually once:
npm install express
This backend will provide KPI data to the frontend. Open the server.js file that Replit created for you, remove any placeholder code, and paste this real working snippet:
// server.js
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000
app.use(express.json())
app.use(express.static('public')) // Serve frontend files from 'public' folder
// Example KPI data (in real app you'd fetch this from DB)
let kpis = [
{ name: 'Revenue', value: 12000, unit: '$' },
{ name: 'Users', value: 350, unit: '' },
{ name: 'Conversion Rate', value: 4.3, unit: '%' }
]
// Define a route to send KPI data
app.get('/api/kpis', (req, res) => {
res.json(kpis)
})
// Root route (optional, just to check backend runs)
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html')
})
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
When you press the green “Run” button, Replit starts this server. You’ll see the preview pane show your app at a live URL (something like https://yourapp.username.repl.co).
Now create a public folder in the Replit file tree (right-click → “New Folder”). Inside public, create these two files:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>KPI Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script defer src="script.js"></script>
<style>
body { font-family: Arial, sans-serif; padding: 2rem; }
.chart-container { width: 400px; height: 300px; margin-bottom: 40px; }
</style>
</head>
<body>
<h2>Company KPI Dashboard</h2>
<div class="chart-container">
<canvas id="kpiChart"></canvas>
</div>
</body>
</html>
// script.js
// Wait until DOM is loaded
window.onload = async () => {
try {
// Fetch KPI data from backend
const res = await fetch('/api/kpis')
const data = await res.json()
// Prepare data for chart
const labels = data.map(k => k.name)
const values = data.map(k => k.value)
// Create a bar chart
const ctx = document.getElementById('kpiChart').getContext('2d')
new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'KPI Values',
data: values,
backgroundColor: 'rgba(54, 162, 235, 0.5)',
borderColor: 'rgb(54, 162, 235)',
borderWidth: 1
}]
},
options: {
scales: {
y: { beginAtZero: true }
}
}
})
} catch (error) {
console.error('Error loading KPIs:', error)
}
}
Click Run. Replit automatically serves both frontend and backend since Express is serving public/. The URL that appears in the preview (top-right) will show your KPI dashboard chart in real time. Your data is coming from the backend route /api/kpis you defined earlier.
If your KPIs come from an API or database:
npm install @replit/database) or connect to a remote DB like Supabase or MongoDB Atlas.
// Example with Replit DB
const Database = require('@replit/database')
const db = new Database()
// Store KPI
await db.set('revenue', 12000)
const revenue = await db.get('revenue')
That’s it — you now have a fully functional KPI dashboard on Replit using real Express code and Chart.js on a static frontend. This structure (backend API + public folder frontend) is the exact pattern that scales to more complex dashboards while staying simple and fully valid within Replit’s environment.
<!-- server.js -->
<script type="module">
import express from "express";
import Database from "@replit/database";
const app = express();
const db = new Database();
app.use(express.json());
// Example structure: KPIs stored under team, each KPI has {label, value, updatedAt}
// Update or insert a KPI
app.post("/api/kpi/:team/:label", async (req, res) => {
const { team, label } = req.params;
const { value } = req.body;
const key = `kpis:${team}`;
const teamKPIs = (await db.get(key)) || {};
teamKPIs[label] = { value, updatedAt: Date.now() };
await db.set(key, teamKPIs);
res.json({ success: true, updated: teamKPIs[label] });
});
// Fetch all KPIs for a team
app.get("/api/kpi/:team", async (req, res) => {
const { team } = req.params;
const data = (await db.get(`kpis:${team}`)) || {};
res.json(Object.entries(data).map(([label, d]) => ({ label, ...d })));
});
// Simple aggregation across teams
app.get("/api/summary", async (req, res) => {
const keys = await db.list("kpis:");
const all = {};
for (const k of keys) {
const t = k.replace("kpis:", "");
all[t] = await db.get(k);
}
res.json(all);
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`KPI API running on port ${port}`));
</script>
<!-- server.js -->
<script type="module">
import express from "express";
import fetch from "node-fetch";
const app = express();
app.use(express.json());
// Fetch KPI data from an external analytics API (e.g., Google Analytics or a data warehouse proxy)
app.get("/api/external/kpi", async (req, res) => {
try {
const apiKey = process.env.ANALYTICS_API_KEY;
const externalUrl = `https://api.example-analytics.com/v1/metrics?key=${apiKey}&period=weekly`;
const response = await fetch(externalUrl);
if (!response.ok) throw new Error(`External API error: ${response.status}`);
const data = await response.json();
// Transform data into dashboard-friendly KPIs
const kpis = {
activeUsers: data.metrics.active\_users.total,
avgSessionTime: data.metrics.session\_time.avg,
conversionRate: (data.metrics.conversions.total / data.metrics.visits.total) \* 100
};
res.json({ fetchedAt: new Date().toISOString(), kpis });
} catch (err) {
console.error("KPI fetch failed:", err);
res.status(500).json({ error: "Failed to fetch KPI data" });
}
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`External KPI API running on port ${port}`));
</script>
<!-- server.js -->
<script type="module">
import express from "express";
import Database from "@replit/database";
import cron from "node-cron";
import fetch from "node-fetch";
const app = express();
const db = new Database();
app.use(express.json());
// Cache daily revenue KPIs from external API into Replit DB every midnight
cron.schedule("0 0 _ _ \*", async () => {
try {
const res = await fetch(`https://api.example.com/revenue?apikey=${process.env.REVENUE_API_KEY}`);
const data = await res.json();
const today = new Date().toISOString().split("T")[0];
await db.set(`revenueKPI:${today}`, { amount: data.total, capturedAt: Date.now() });
console.log(`[cron] Stored KPI for ${today}`);
} catch (err) {
console.error("Error fetching daily KPI:", err);
}
});
// Fetch latest N days of cached KPIs for dashboard
app.get("/api/kpi/revenue/latest/:days", async (req, res) => {
const days = parseInt(req.params.days) || 7;
const keys = await db.list("revenueKPI:");
const sorted = keys.sort().slice(-days);
const results = [];
for (const k of sorted) {
results.push({ date: k.replace("revenueKPI:", ""), ...(await db.get(k)) });
}
res.json(results);
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Revenue KPI service running on port ${port}`));
</script>

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Building a KPI dashboard on Replit works best when you keep the structure simple: one Node.js backend for fetching and processing KPI data, and one React (or plain HTML/JS) frontend for displaying charts. Since Replit gives you an instantly running web server and automatic URL, your goal is to make it stable, secure, and easy to view live updates without overloading the single Replit container. You’ll store API keys in Replit’s built-in Secrets panel, use a small Express server to serve KPIs as JSON, and use a frontend (React or plain JS + Chart.js) to visualize them. You’ll also commit everything to Git inside Replit to avoid losing progress when the container restarts.
In your main Repl, keep things clean and structured:
Create a file named server.js (in root of your Repl). It will serve both static files and the KPI API.
// server.js
import express from "express"
import path from "path"
import { fileURLToPath } from "url"
// Boilerplate to get __dirname in ES Modules
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const app = express()
const PORT = process.env.PORT || 3000
// Serve static frontend
app.use(express.static(path.join(__dirname, "public")))
// Example KPI endpoint (could be from DB, API, etc.)
app.get("/api/kpis", async (req, res) => {
// Simulated KPI data - normally, pull from DB or API
const data = {
sales: 12300,
newUsers: 45,
conversionRate: 3.5
}
res.json(data)
})
// Start server
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`)
})
npm install express
node server.js
Inside public/index.html, create a simple UI:
<!DOCTYPE html>
<html>
<head>
<title>KPI Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<h1>KPI Dashboard</h1>
<div>
<p><strong>Sales:</strong> <span id="sales">-</span></p>
<p><strong>New Users:</strong> <span id="users">-</span></p>
<p><strong>Conversion Rate:</strong> <span id="rate">-</span>%</p>
</div>
<canvas id="chart" width="400" height="200"></canvas>
<script src="app.js"></script>
</body>
</html>
Then in public/app.js fetch data from your backend and render a chart:
// public/app.js
async function loadKpis() {
const res = await fetch("/api/kpis")
const kpis = await res.json()
// Update text fields
document.getElementById("sales").textContent = kpis.sales
document.getElementById("users").textContent = kpis.newUsers
document.getElementById("rate").textContent = kpis.conversionRate
// Render chart
const ctx = document.getElementById("chart")
new Chart(ctx, {
type: "bar",
data: {
labels: ["Sales", "New Users", "Conversion Rate"],
datasets: [
{
label: "KPIs",
data: [kpis.sales, kpis.newUsers, kpis.conversionRate],
backgroundColor: ["#007bff", "#28a745", "#ffc107"]
}
]
}
})
}
loadKpis()
If your KPIs come from a third-party API, never hardcode API keys. Instead, open the padlock icon on the left sidebar in Replit (called Secrets), and add a key like API\_KEY.
Then in server.js you can read it safely:
// Inside your /api/kpis endpoint in server.js
const apiKey = process.env.API_KEY // Replit automatically loads this secret!
// Then use it in your API call
console.log for debugging inside the Replit console, but remove noisy logs after tests to save CPU usage.
When you press "Run," your Express server starts and serves the dashboard instantly under the provided Replit URL (something like https://yourname.repl.co). Open it in the browser tab that appears. You’ll see your live KPI dashboard pulling fresh data from your backend each time the page reloads. This architecture is small, secure, and works perfectly inside the Replit environment for real small-scale KPI dashboards.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.