/how-to-build-replit

How to Build a Loyalty program with Replit

Learn how to build a customer loyalty program using Replit. Follow simple steps, code examples, and tips to boost engagement and retention.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

How to Build a Loyalty program with Replit

A working loyalty program on Replit can be built as a small full-stack app, using Node.js + Express as backend API and a JSON file or SQLite database to track users’ points. You can also create a simple frontend (HTML + JS) to display points and let users earn more by completing actions. Replit can host this directly — once running, you can access it via the Replit web preview.

 

Step-by-step Setup on Replit

 

Create a new Replit: Choose the “Node.js” template.

Inside this Repl, you’ll already have a index.js file. That’s your backend entry point.

  • Create a folder called public.
  • Inside public, create index.html and (optionally) script.js.
  • If your loyalty logic needs storage, create db.json in the root folder, or use SQLite if you prefer relational structure.

 

Set Up Express Server

 

In index.js add this code to start your server and serve static frontend files:

 

// index.js

import express from "express";
import fs from "fs";

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json()); // to read JSON request bodies
app.use(express.static("public")); // serve static frontend files

// Utility to read current users data from db.json
function readData() {
  try {
    const data = fs.readFileSync("db.json");
    return JSON.parse(data);
  } catch {
    return { users: [] };
  }
}

// Utility to save updated users
function writeData(data) {
  fs.writeFileSync("db.json", JSON.stringify(data, null, 2));
}

// API endpoint to get all users
app.get("/api/users", (req, res) => {
  const data = readData();
  res.json(data.users);
});

// API endpoint to earn points
app.post("/api/earn", (req, res) => {
  const { username, points } = req.body;
  if (!username || typeof points !== "number") {
    return res.status(400).json({ error: "Invalid input" });
  }

  const data = readData();
  let user = data.users.find(u => u.username === username);
  if (!user) {
    user = { username, points };
    data.users.push(user);
  } else {
    user.points += points;
  }

  writeData(data);
  res.json({ success: true, user });
});

// API endpoint to get a single user's points
app.get("/api/user/:username", (req, res) => {
  const data = readData();
  const user = data.users.find(u => u.username === req.params.username);
  if (!user) return res.status(404).json({ error: "User not found" });
  res.json(user);
});

app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

 

Frontend

 

In public/index.html, you’ll create a simple interface to display and earn points.

 

<!DOCTYPE html>
<html>
<head>
  <title>Loyalty Program</title>
</head>
<body>
  <h1>User Loyalty Program</h1>
  <input id="username" placeholder="Enter your username" />
  <button id="check">Check Points</button>
  <button id="earn">Earn 10 Points</button>
  <p id="result"></p>

  <script src="script.js"></script>
</body>
</html>

 

Then in public/script.js:

 

// public/script.js
const usernameInput = document.getElementById("username");
const resultEl = document.getElementById("result");
const checkBtn = document.getElementById("check");
const earnBtn = document.getElementById("earn");

checkBtn.addEventListener("click", async () => {
  const username = usernameInput.value.trim();
  if (!username) return alert("Enter username first!");
  const res = await fetch(`/api/user/${username}`);
  if (res.ok) {
    const data = await res.json();
    resultEl.textContent = `${data.username} has ${data.points} points.`;
  } else {
    resultEl.textContent = "User not found.";
  }
});

earnBtn.addEventListener("click", async () => {
  const username = usernameInput.value.trim();
  if (!username) return alert("Enter username first!");
  const res = await fetch(`/api/earn`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ username, points: 10 })
  });
  const data = await res.json();
  resultEl.textContent = `${data.user.username} now has ${data.user.points} points.`;
});

 

Database (db.json)

 

Create db.json in root folder with initial content:

 

{
  "users": []
}

 

Running and Testing on Replit

 

  • Replit will automatically install dependencies the first time you run index.js.
  • If Express isn’t installed, open the Shell (bottom tab) and run:

 

npm install express

 

  • Click “Run” — the webview window will open your app.
  • Try entering a username and clicking “Earn 10 Points”. Data will persist in db.json until your container resets.

 

Using Secrets for Production

 

If you later integrate a third-party or real database (like MongoDB Atlas), you can store your connection string securely in the Replit Secrets tab — access it in your code as process.env.MONGO\_URI. Never commit sensitive keys directly in files.

 

Common Replit Pitfalls

 

  • Replit’s filesystem resets after long inactivity, so store persistent data externally if you need reliability.
  • Don’t store keys in code — always use Secrets.
  • Keep your Repl awake using “Always On” if you need an always-running loyalty API (for paid plans).
  • Use console.log extensively during development — Replit’s logs in the Console pane are your main debugging tool.

 

That’s a solid baseline loyalty program. It’s simple, fully working on Replit, and can be extended easily — you can later plug in a proper database, authentication, or even UI frameworks like React directly inside the same Repl if you upgrade to the Nix-enabled templates.

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us

How to Build a Simple Loyalty Points API with Express and Replit Database


<script type="module">
import express from "express";
import Database from "@replit/database";

const app = express();
const db = new Database();

app.use(express.json());

// Issue or redeem loyalty points safely (transaction-like update)
app.post("/api/loyalty/update", async (req, res) => {
  const { userId, change, reason } = req.body;
  if (typeof userId !== "string" || typeof change !== "number") {
    return res.status(400).json({ error: "Invalid input" });
  }

  const userKey = `loyalty:user:${userId}`;
  const currentData = (await db.get(userKey)) || { points: 0, history: [] };

  const updated = {
    points: Math.max(0, currentData.points + change),
    history: [
      { change, reason, date: new Date().toISOString() },
      ...currentData.history.slice(0, 49)
    ]
  };

  await db.set(userKey, updated);
  res.json({ success: true, newPoints: updated.points });
});

app.get("/api/loyalty/:userId", async (req, res) => {
  const data = await db.get(`loyalty:user:${req.params.userId}`);
  res.json(data || { points: 0, history: [] });
});

app.listen(3000, () => console.log("Loyalty service running"));
</script>

How to Sync Your Replit Loyalty Program with an External CRM


<script type="module">
import express from "express";
import fetch from "node-fetch";
import Database from "@replit/database";

const app = express();
app.use(express.json());
const db = new Database();

// example: sync Replit-stored user points with an external CRM (like HubSpot or custom API)
app.post("/api/loyalty/syncCRM", async (req, res) => {
  const { userId } = req.body;
  if (!userId) return res.status(400).json({ error: "userId required" });

  const userData = (await db.get(`loyalty:user:${userId}`)) || { points: 0 };

  // external CRM endpoint saved in Secrets as CRM_WEBHOOK_URL
  try {
    const response = await fetch(process.env.CRM_WEBHOOK_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${process.env.CRM_API_KEY}`
      },
      body: JSON.stringify({
        user\_id: userId,
        loyalty\_points: userData.points,
        source: "replit-loyalty"
      })
    });

    if (!response.ok) {
      const text = await response.text();
      console.error("CRM sync failed:", text);
      return res.status(502).json({ error: "CRM sync failed", detail: text });
    }

    const crmResult = await response.json();
    res.json({ success: true, synced: true, crmResult });

  } catch (err) {
    console.error("Error syncing CRM:", err);
    res.status(500).json({ error: "Server error during sync" });
  }
});

app.listen(3000, () => console.log("Loyalty + CRM sync API running on Replit"));
</script>

How to Securely Redeem Loyalty Rewards with Express and Replit Database


<script type="module">
import express from "express";
import jwt from "jsonwebtoken";
import Database from "@replit/database";

const app = express();
const db = new Database();
const SECRET = process.env.JWT\_SECRET;

app.use(express.json());

// Middleware to verify JWT token before accessing secure loyalty rewards endpoint
function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  try {
    const token = authHeader.split(" ")[1];
    req.user = jwt.verify(token, SECRET);
    next();
  } catch {
    res.status(403).json({ error: "Invalid token" });
  }
}

// Secure endpoint to redeem points for a reward
app.post("/api/loyalty/redeem", authenticate, async (req, res) => {
  const { rewardId, cost } = req.body;
  if (!rewardId || typeof cost !== "number") {
    return res.status(400).json({ error: "Invalid input" });
  }

  const userKey = `loyalty:user:${req.user.id}`;
  const current = (await db.get(userKey)) || { points: 0, rewards: [] };

  if (current.points < cost) {
    return res.status(400).json({ error: "Not enough points" });
  }

  const updated = {
    ...current,
    points: current.points - cost,
    rewards: [
      { id: rewardId, redeemedAt: new Date().toISOString() },
      ...current.rewards
    ]
  };

  await db.set(userKey, updated);
  res.json({ success: true, newBalance: updated.points });
});

app.listen(3000, () => console.log("Secure loyalty redemption API running"));
</script>

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us
Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Best Practices for Building a Loyalty program with Replit

A good loyalty program built on Replit should combine a simple backend (like Node.js + Express with a database) and a small frontend to display user points or rewards. Store sensitive data such as API keys or DB credentials in Replit Secrets, not directly in the code. You should make sure your app has persistent storage — Replit resets the filesystem sometimes, so put user data into a hosted database (like SQLite, Supabase, or MongoDB Atlas). Start small: allow user registration, tracking points, and redeeming rewards. Use routes for updating or reading points, and connect it to a frontend or internal dashboard. Replit’s always-on deployments make testing easy, but don’t expect the free Repl server to handle heavy production load.

 

Step 1: Set up Folder Structure

 

In your Replit project, create these files and folders:

  • index.js — your main Node server file
  • package.json — installs dependencies like Express
  • db.js — handles database connection
  • public/ folder — contains HTML (e.g., public/index.html)

 

// In Replit shell, type this to install Express and SQLite3
npm install express sqlite3

 

Step 2: Configure a Simple Database

 

Use SQLite — it’s easy and works well on Replit. Add this to a new db.js file:

 

// db.js
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('./loyalty.db'); // creates or opens the DB file

// Create users table if it doesn’t exist
db.serialize(() => {
  db.run(`
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT,
      points INTEGER DEFAULT 0
    )
  `);
});

module.exports = db;

 

Step 3: Create the Server

 

Inside index.js, set up your Express server. This will expose routes (endpoints) that handle loyalty logic — adding points, resetting them, etc.

 

// index.js
const express = require('express');
const db = require('./db');
const app = express();

app.use(express.json());
app.use(express.static('public')); // serves HTML in public folder

// Add new user
app.post('/users', (req, res) => {
  const name = req.body.name;
  db.run(`INSERT INTO users (name, points) VALUES (?, ?)`, [name, 0], function (err) {
    if (err) return res.status(500).json({ error: err.message });
    res.json({ id: this.lastID, name, points: 0 });
  });
});

// Add points
app.post('/users/:id/add', (req, res) => {
  const { id } = req.params;
  const { points } = req.body;
  db.run(`UPDATE users SET points = points + ? WHERE id = ?`, [points, id], function (err) {
    if (err) return res.status(500).json({ error: err.message });
    res.json({ message: "Points added!" });
  });
});

// Get user info
app.get('/users/:id', (req, res) => {
  const { id } = req.params;
  db.get(`SELECT * FROM users WHERE id = ?`, [id], (err, row) => {
    if (err) return res.status(500).json({ error: err.message });
    if (!row) return res.status(404).json({ error: "User not found" });
    res.json(row);
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

 

Step 4: Build Simple Frontend UI

 

Inside public/index.html, create a form to add users or view points:

 

<!DOCTYPE html>
<html>
  <body>
    <h1>Loyalty Program</h1>
    <input id="name" placeholder="User name" />
    <button onclick="addUser()">Add User</button>
    <hr>
    <input id="userId" placeholder="User ID">
    <input id="addPoints" type="number" placeholder="Points to add">
    <button onclick="addPoints()">Add Points</button>
    <pre id="result"></pre>

    <script>
      async function addUser() {
        const name = document.getElementById('name').value;
        const res = await fetch('/users', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({ name })
        });
        const data = await res.json();
        document.getElementById('result').textContent = JSON.stringify(data, null, 2);
      }

      async function addPoints() {
        const id = document.getElementById('userId').value;
        const points = parseInt(document.getElementById('addPoints').value);
        const res = await fetch(`/users/${id}/add`, {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({ points })
        });
        const data = await res.json();
        document.getElementById('result').textContent = JSON.stringify(data, null, 2);
      }
    </script>
  </body>
</html>

 

Step 5: Store Secrets Safely

 

If you later use an external service (like Supabase or Stripe) for user authentication or reward payments, don’t put the keys in your code. Use Replit’s Secrets tab (🔒 icon on left sidebar) and access them in code like this:

 

// index.js
const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY;

 

Step 6: Commit and Collaborate

 

Use Replit’s built-in Git integration to version control your loyalty program. You can invite collaborators via the "Invite" button or use multiplayer editing to pair-program in real-time. Before deploying, test connections thoroughly since database paths or ports may differ in deployment environments.

 

Step 7: Deploy with Replit

 

When everything works, click “Deploy” → “Production” to keep your loyalty program always running. Replit will manage hosting, but remember to monitor logs via “Shell” or “Console” for runtime errors. For serious production environments with many users, migrate the database to an external persistent host like Supabase or MongoDB Atlas.

 

Practical Tips & Pitfalls

 

  • Never rely on local files for user data — Replit’s virtual machine resets can wipe them. Always use a real database.
  • Use Secrets for tokens and environment variables.
  • Use lightweight dependencies — avoid large packages; Replit storage is limited.
  • Regularly export your Repls to GitHub for backup.
  • Use logs – add console.log() in DB calls or routes while testing.

 

This approach stays within Replit’s strengths: fast setup, live collaboration, and working web apps without external servers. As your loyalty program grows, you can refactor or migrate to a bigger environment with the same Express and database logic.

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022