Learn how to build powerful product analytics using Replit. Follow simple steps to track, analyze, and improve your app’s 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 simple and functional product analytics inside a Replit project, you can create a lightweight tracking system using a Node.js backend (Express) and a small SQLite or JSON-based storage. You’ll collect events (like “signup”, “button click”), store them securely, and later view or export analytics. Everything can run directly in Replit — you don’t need extra cloud accounts unless you want persistent databases. This approach is realistic for prototypes, MVPs, or internal dashboards built inside Replit.
Create or open a Replit project using the Node.js template. Replit will set up a default index.js. This file will serve as your main backend server file. Inside the Replit workspace, you’ll see:
index.js — entry point for a Node server.package.json — dependencies and scripts.Replit Secrets tab — for API keys or environment variables (optional).
// Install dependencies for analytics server
npm install express sqlite3
Inside your Replit project, create a new file called db.js. This file will manage your analytics database (SQLite). SQLite runs in one file and works perfectly inside Replit’s filesystem, though note that if your Repl sleeps or is forked, you might lose the database unless you download or persist it.
// db.js
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('./analytics.db'); // Data stored locally
// Create a table for events if it doesn't exist
db.serialize(() => {
db.run(`CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_name TEXT,
user_id TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)`);
});
module.exports = db;
Open your index.js file and replace or extend the existing Express setup. This code creates an endpoint for collecting analytics events. In Replit, this endpoint will be accessible via your Repl’s web URL.
// index.js
const express = require('express');
const db = require('./db');
const app = express();
app.use(express.json()); // To parse JSON body
// Endpoint to record an event
app.post('/track', (req, res) => {
const { event_name, user_id } = req.body;
if (!event_name) {
return res.status(400).json({ error: 'Missing event_name' });
}
db.run('INSERT INTO events(event_name, user_id) VALUES (?, ?)', [event_name, user_id || null], (err) => {
if (err) return res.status(500).json({ error: err.message });
res.json({ message: 'Event tracked' });
});
});
// Endpoint to view analytics
app.get('/analytics', (req, res) => {
db.all('SELECT event_name, COUNT(*) as count FROM events GROUP BY event_name', [], (err, rows) => {
if (err) return res.status(500).json({ error: err.message });
res.json(rows);
});
});
app.listen(3000, () => console.log('Analytics server running on port 3000'));
If you’re using a frontend (like HTML or React) inside Replit, you can send events using fetch. For a simple HTML example, create a file named index.html and connect it to your backend endpoint. You can deploy this frontend either in the same Repl or separately.
<!DOCTYPE html>
<html>
<head>
<title>Product Analytics Example</title>
</head>
<body>
<button id="signupBtn">Sign Up</button>
<script>
const replBaseUrl = window.location.origin; // Your Repl’s URL
document.getElementById('signupBtn').addEventListener('click', () => {
fetch(`${replBaseUrl}/track`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ event_name: 'signup', user_id: 'user123' })
});
});
</script>
</body>
</html>
https://yourproject.username.repl.co./analytics in the browser — you should see JSON data with the count of each event.
./analytics.db). Before stopping your Repl, download this file if you need long-term storage.process.env.SECRET\_NAME.
With this setup, you’ve built a working product analytics service inside Replit: events tracked via a simple REST API, data stored locally, results visible in your analytics endpoint. It’s lightweight, completely valid, and suitable for testing product ideas right from your browser.
import express from "express";
import bodyParser from "body-parser";
import { Database } from "@replit/database";
const app = express();
const db = new Database();
app.use(bodyParser.json());
// Track product analytics events
app.post("/api/events", async (req, res) => {
const { userId, eventType, productId, metadata } = req.body;
if (!userId || !eventType) return res.status(400).json({ error: "Invalid payload" });
const timestamp = Date.now();
const event = { userId, eventType, productId, metadata, timestamp };
// Store events under daily key for easier rollups
const dateKey = new Date().toISOString().split("T")[0];
const key = `events:${dateKey}`;
const existingEvents = (await db.get(key)) || [];
existingEvents.push(event);
await db.set(key, existingEvents);
res.json({ success: true });
});
// Aggregate daily analytics
app.get("/api/stats/:date", async (req, res) => {
const key = `events:${req.params.date}`;
const events = (await db.get(key)) || [];
const summary = events.reduce((acc, e) => {
acc[e.eventType] = (acc[e.eventType] || 0) + 1;
return acc;
}, {});
res.json({ date: req.params.date, totals: summary });
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Analytics API running on ${port}`));
import express from "express";
import fetch from "node-fetch";
const app = express();
app.use(express.json());
// Example: pushing aggregated product analytics data from Replit to external service (e.g., PostHog, Mixpanel)
app.post("/api/push-analytics", async (req, res) => {
const { productId, metrics } = req.body;
if (!productId || !metrics) return res.status(400).json({ error: "Invalid payload" });
try {
const response = await fetch("https://api.mixpanel.com/import", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Basic ${Buffer.from(process.env.MIXPANEL_TOKEN + ":").toString("base64")}`
},
body: JSON.stringify({
event: "ProductMetrics",
properties: {
distinct\_id: productId,
...metrics,
timestamp: new Date().toISOString()
}
})
});
if (!response.ok) throw new Error(`Push failed with status: ${response.status}`);
const result = await response.text();
res.json({ success: true, result });
} catch (err) {
console.error("Error pushing analytics:", err);
res.status(500).json({ error: "Failed to send analytics data" });
}
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Analytics sync service running on ${port}`));
import express from "express";
import { Database } from "@replit/database";
import crypto from "crypto";
const app = express();
const db = new Database();
app.use(express.json());
// Example: anonymizing and aggregating product analytics before saving
app.post("/api/track", async (req, res) => {
const { userEmail, action, productId } = req.body;
if (!userEmail || !action || !productId) {
return res.status(400).json({ error: "Missing required fields" });
}
const hashedUser = crypto
.createHash("sha256")
.update(userEmail + process.env.SALT)
.digest("hex");
const dateKey = new Date().toISOString().split("T")[0];
const eventKey = `analytics:${dateKey}:${productId}`;
const existing = (await db.get(eventKey)) || {};
existing[action] = (existing[action] || 0) + 1;
await db.set(eventKey, existing);
res.json({ success: true });
});
// Aggregated stats retrieval
app.get("/api/analytics/:date", async (req, res) => {
const allKeys = await db.list(`analytics:${req.params.date}:`);
const summaries = {};
for (const key of allKeys) {
const data = await db.get(key);
const productId = key.split(":")[2];
summaries[productId] = data;
}
res.json({ date: req.params.date, data: summaries });
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Anonymized analytics API running on ${port}`));

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 product analytics on Replit works best when you keep it lightweight, secure, and compatible with the always-on and collaborative nature of the environment. The most practical setup is to use a small Node.js or Python service that sends frontend user events (like clicks, visits, or actions) to a backend endpoint. That backend logs events to a database (e.g., Replit DB or an external one) and optionally visualizes aggregated metrics. Never store secrets (like API keys) in plain code; put them in Replit’s Secrets panel. For frontends (React or Vanilla JS), you’ll track events using small functions that call your analytics API. For backends, handle routes securely and don’t block the main thread.
Create a Node.js Repl for your backend. In Replit, click “Create Repl” → “Node.js”. Then create these new files:
// server.js
import express from "express"
import { saveEvent } from "./analytics.js"
import bodyParser from "body-parser"
const app = express()
app.use(bodyParser.json())
// example endpoint for analytics
app.post("/analytics", async (req, res) => {
const { event, user, metadata } = req.body
await saveEvent(event, user, metadata)
res.json({ success: true })
})
app.listen(3000, () => console.log("Analytics server running on port 3000"))
This file contains a function to store analytics events in your database. In a simple prototype, you can keep them in Replit DB (which is key-value based). Add your secret key in Replit’s Secrets tab as REPLIT_DB_URL.
// analytics.js
import Database from "@replit/database"
const db = new Database()
export async function saveEvent(event, user, metadata) {
const timestamp = new Date().toISOString()
const record = { event, user, metadata, timestamp }
// Store array of events under single key
const allEvents = (await db.get("events")) || []
allEvents.push(record)
await db.set("events", allEvents)
}
In a React project on Replit, you can create a utility file named analytics.js inside your src folder. This sends data to your backend server.
// src/analytics.js
export async function trackEvent(event, user, metadata = {}) {
try {
await fetch("https://your-repl-name.username.repl.co/analytics", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ event, user, metadata }),
})
} catch (error) {
console.error("Analytics tracking failed:", error)
}
}
Then in components, call trackEvent() when something important happens:
// src/App.jsx
import React from "react"
import { trackEvent } from "./analytics.js"
function App() {
const handleSignup = () => {
trackEvent("signup_click", "guest_user")
}
return (
<button onClick={handleSignup}>
Sign Up
</button>
)
}
export default App
Never hardcode database URLs, API keys, or tokens. In Replit:
process.env.REPLIT_DB_URL.
You can add a quick endpoint to see your analytics aggregated:
// Add in server.js
app.get("/analytics/view", async (req, res) => {
const allEvents = (await db.get("events")) || []
const summary = {}
for (const e of allEvents) {
summary[e.event] = (summary[e.event] || 0) + 1
}
res.json(summary)
})
Open your /analytics/view endpoint to quickly see counts per event.
This setup gives you a clear, working, and realistic product analytics foundation inside Replit — sending events from frontend to backend, storing them in a secure lightweight DB, and giving you immediate visibility into how your users interact with your product in development or early production.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.