/how-to-build-replit

How to Build a Reviews & ratings with Replit

Learn how to build a reviews and ratings system using Replit. Follow this step-by-step guide to create, store, and display user feedback easily.

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 Reviews & ratings with Replit

To build a simple and working reviews & ratings system on Replit, you can use a Node.js + Express backend along with a small JSON file (or a database if you prefer) to store reviews. You can then connect it with a frontend (plain HTML or React). Below is a straightforward, working method that runs perfectly on Replit, uses environment variables correctly, handles reviews, and is deployed automatically once you click “Run” in Replit.

 

Setup the Project

 

Create a new Repl using Node.js template (not HTML, CSS, JS). Replit will make files like index.js and package.json for you.

  • Create one new file named reviews.json – this will store your data.
  • Optionally create a public folder that will hold your HTML frontend files (e.g. index.html).

 

Backend Code (API to handle reviews)

 

In index.js, paste the following code. This file runs your Express server. It can read and write reviews from reviews.json.

 

// index.js
const express = require("express")
const fs = require("fs")
const path = require("path")
const app = express()

// Middleware that allows JSON body parsing
app.use(express.json())
app.use(express.static("public")) // serves HTML in /public

const dataFile = path.join(__dirname, "reviews.json")

// Helper to read data
function readReviews() {
  try {
    const data = fs.readFileSync(dataFile)
    return JSON.parse(data)
  } catch (err) {
    return [] // if empty file or not found
  }
}

// Helper to write data
function writeReviews(reviews) {
  fs.writeFileSync(dataFile, JSON.stringify(reviews, null, 2))
}

// GET route - list all reviews
app.get("/api/reviews", (req, res) => {
  const reviews = readReviews()
  res.json(reviews)
})

// POST route - add a review
app.post("/api/reviews", (req, res) => {
  const { name, rating, comment } = req.body

  if (!name || !rating) {
    return res.status(400).json({ message: "Name and rating are required." })
  }

  const reviews = readReviews()
  const newReview = {
    id: Date.now(),
    name,
    rating,
    comment: comment || ""
  }
  reviews.push(newReview)
  writeReviews(reviews)
  res.status(201).json(newReview)
})

// Start the server on Replit port
const port = process.env.PORT || 3000
app.listen(port, () => console.log("Server running on port " + port))

 

Where to put this:

  • Replace all existing index.js content with the snippet above.
  • The file reviews.json (in the root directory) should initially contain: []

 

Frontend Code (HTML to submit and show reviews)

 

Inside the public folder, create a new file named index.html and add:

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Reviews & Ratings</title>
</head>
<body>
  <h1>Leave a Review</h1>
  <form id="reviewForm">
    <input type="text" id="name" placeholder="Your name" required /><br />
    <input type="number" id="rating" placeholder="Rating (1-5)" min="1" max="5" required /><br />
    <textarea id="comment" placeholder="Your comment"></textarea><br />
    <button type="submit">Submit</button>
  </form>

  <h2>All Reviews</h2>
  <ul id="reviewsList"></ul>

  <script>
    const form = document.getElementById("reviewForm")
    const list = document.getElementById("reviewsList")

    async function loadReviews() {
      const res = await fetch("/api/reviews")
      const reviews = await res.json()
      list.innerHTML = ""
      reviews.forEach(r => {
        const item = document.createElement("li")
        item.textContent = `${r.name} (${r.rating}/5): ${r.comment}`
        list.appendChild(item)
      })
    }

    form.addEventListener("submit", async e => {
      e.preventDefault()
      const name = document.getElementById("name").value
      const rating = document.getElementById("rating").value
      const comment = document.getElementById("comment").value

      await fetch("/api/reviews", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name, rating, comment })
      })

      form.reset()
      loadReviews()
    })

    loadReviews() // load reviews on page open
  </script>
</body>
</html>

 

Where to put this:

  • File path should be public/index.html.
  • No need to edit package.json manually; Replit detects Express automatically.

 

Testing on Replit

 

Press Run. Replit starts the Express server automatically and shows a public URL (on the right). Open it in the browser tab. Submit a few sample reviews, then refresh the page — you’ll see them persist (Replit keeps them until container resets).

If you want permanent storage, move from a JSON file to a small hosted database like Replit DB or Supabase. For lightweight use, JSON suffices in developing phase.

 

Useful Replit Tips

 

  • Avoid Hardcoding Paths: Always use path.join(\_\_dirname, ...) to avoid path issues inside Replit.
  • Use .env for any secrets (API Keys, DB Credentials). Add them using the “Secrets” tab on left side of Replit.
  • Replit autosaves: You don’t need to manually save the file; it updates as you type.
  • Check Console Logs: If something isn’t loading, open the “Console” tab to see server logs.

 

This setup gives you a clean, working Reviews & Ratings system that runs fully inside Replit, no external environment needed. As your project grows, you can modularize routes or connect a real database, but this is the solid foundation many production-ready prototypes actually start from on Replit.

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 Product Reviews API with Express and Replit Database


<script type="module">
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());

// Save or update a review for a specific product by a specific user
app.post("/api/reviews/:productId", async (req, res) => {
  const { productId } = req.params;
  const { userId, rating, comment } = req.body;

  if (!userId || !rating) return res.status(400).send("Missing fields");

  let reviews = (await db.get(`reviews_${productId}`)) || [];
  const existing = reviews.find(r => r.userId === userId);

  if (existing) {
    existing.rating = rating;
    existing.comment = comment;
    existing.updatedAt = Date.now();
  } else {
    reviews.push({
      userId,
      rating,
      comment,
      createdAt: Date.now()
    });
  }

  await db.set(`reviews_${productId}`, reviews);

  const avgRating = (
    reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length
  ).toFixed(2);

  await db.set(`avg_${productId}`, avgRating);

  res.send({ success: true, avgRating });
});

// Get product reviews with computed average
app.get("/api/reviews/:productId", async (req, res) => {
  const { productId } = req.params;
  const reviews = (await db.get(`reviews_${productId}`)) || [];
  const avgRating = (await db.get(`avg_${productId}`)) || "0.00";
  res.send({ avgRating, reviews });
});

app.listen(3000, () => console.log("Server running on port 3000"));
</script>

How to Add Sentiment Analysis to Product Reviews with Replit


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

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

app.use(express.json());

// This route syncs local reviews with an external sentiment analysis API
// to enrich user ratings with sentiment scores (useful for moderation or insights)
app.post("/api/reviews-with-sentiment/:productId", async (req, res) => {
  const { productId } = req.params;
  const { userId, rating, comment } = req.body;

  if (!userId || !rating || !comment)
    return res.status(400).json({ error: "Missing fields" });

  try {
    // Example of external API call (replace with your own API key stored in secrets)
    const response = await fetch("https://api.meaningcloud.com/sentiment-2.1", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({
        key: process.env.SENTIMENT_API_KEY,
        txt: comment,
        lang: "en"
      })
    });

    const sentimentData = await response.json();
    const sentiment = sentimentData.score\_tag || "NONE";

    const reviews = (await db.get(`reviews_${productId}`)) || [];
    reviews.push({
      userId,
      rating,
      comment,
      sentiment,
      createdAt: Date.now()
    });

    await db.set(`reviews_${productId}`, reviews);

    res.json({
      message: "Review saved with sentiment",
      sentiment,
      total: reviews.length
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: "Failed to process sentiment" });
  }
});

app.get("/api/reviews-with-sentiment/:productId", async (req, res) => {
  const { productId } = req.params;
  const reviews = (await db.get(`reviews_${productId}`)) || [];
  res.json(reviews);
});

app.listen(3000, () => console.log("Server running on port 3000"));
</script>

How to Show Top-Rated & Trusted Product Reviews with Replit


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

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

app.use(express.json());

// Endpoint to fetch top-rated reviews for a product, filtered by a minimum number of ratings.
// Useful when you want to show only trusted user feedback on the frontend.
app.get("/api/reviews/top/:productId", async (req, res) => {
  const { productId } = req.params;
  const minRatings = parseInt(req.query.minRatings || "3", 10);

  const reviews = (await db.get(`reviews_${productId}`)) || [];

  // Count how many ratings each user has left across all products
  const allKeys = await db.list("reviews\_");
  const userRatingsCount = {};

  for (const key of allKeys) {
    const productReviews = (await db.get(key)) || [];
    for (const r of productReviews) {
      userRatingsCount[r.userId] = (userRatingsCount[r.userId] || 0) + 1;
    }
  }

  // Filter by users who have given more than minRatings across the site
  const filtered = reviews
    .filter(r => userRatingsCount[r.userId] >= minRatings)
    .sort((a, b) => b.rating - a.rating)
    .slice(0, 5);

  res.json({ topReviews: filtered });
});

app.listen(3000, () => console.log("Server listening on port 3000"));
</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 Reviews & ratings with Replit

A solid way to build a Reviews & Ratings feature on Replit is to use a simple Node.js (Express) backend with a lightweight database like SQLite or Replit Database (for simpler projects). The flow should include an API route to submit reviews, one to retrieve them, and basic validation before saving data. On the frontend (like React or plain HTML/JS), you’ll fetch from these endpoints. Remember to use Secrets for private info (like database paths if external), not hard-coded values. The backend code should go into a server.js file, and if using React, create components like ReviewForm.jsx and ReviewsList.jsx.

 

1. Backend Setup (Express + Replit DB)

 

In your main Replit project, make sure you’ve selected the Node.js template. In the file sidebar, create a new file named server.js. This will handle your API routes.

// server.js
import express from "express";
import Database from "@replit/database";
import cors from "cors";

const app = express();
const db = new Database(); // Replit’s built-in key-value database

app.use(cors());
app.use(express.json());

// Route to submit a review
app.post("/api/reviews", async (req, res) => {
  const { username, rating, comment } = req.body;

  if (!username || !rating) {
    return res.status(400).json({ error: "Username and rating are required." });
  }

  // Fetch existing reviews
  let reviews = (await db.get("reviews")) || [];
  
  // Add new review
  const newReview = { username, rating, comment, date: new Date().toISOString() };
  reviews.push(newReview);
  
  // Save to Replit DB
  await db.set("reviews", reviews);

  res.status(201).json({ message: "Review added!", review: newReview });
});

// Route to get all reviews
app.get("/api/reviews", async (req, res) => {
  const reviews = (await db.get("reviews")) || [];
  res.json(reviews);
});

app.listen(3000, () => console.log("Server running on port 3000"));

Explanation: This code sets up a small HTTP API. You can send a POST request to /api/reviews to add a review or a GET request to retrieve them. Replit’s DB is persistent per Repl, so your data stays available.

Make sure in your Replit run command (the small “Run” button behavior), your main file is set to server.js in the .replit configuration if it’s not already.

 

2. Frontend (React or Vanilla JS)

 

If you’re using React, create a folder called components inside src, then two files named ReviewForm.jsx and ReviewsList.jsx.

// src/components/ReviewForm.jsx
import { useState } from "react";

export default function ReviewForm({ onSubmit }) {
  const [username, setUsername] = useState("");
  const [rating, setRating] = useState("");
  const [comment, setComment] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    await onSubmit({ username, rating, comment });
    setUsername("");
    setRating("");
    setComment("");
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        placeholder="Your Name"
        required
      />
      <input
        type="number"
        min="1"
        max="5"
        value={rating}
        onChange={(e) => setRating(e.target.value)}
        placeholder="Rating 1-5"
        required
      />
      <textarea
        value={comment}
        onChange={(e) => setComment(e.target.value)}
        placeholder="Your Review"
      ></textarea>
      <button type="submit">Submit</button>
    </form>
  );
}
// src/components/ReviewsList.jsx
import { useEffect, useState } from "react";

export default function ReviewsList() {
  const [reviews, setReviews] = useState([]);

  useEffect(() => {
    fetch("https://your-repl-name.username.repl.co/api/reviews")
      .then(res => res.json())
      .then(data => setReviews(data));
  }, []);

  return (
    <div>
      <h3>Reviews</h3>
      {reviews.map((r, index) => (
        <div key={index}>
          <strong>{r.username}</strong> rated {r.rating}/5<br/>
          <em>{r.comment}</em><br/>
          <small>{new Date(r.date).toLocaleString()}</small>
          <hr/>
        </div>
      ))}
    </div>
  );
}

In your main React component (App.jsx), import these:

// src/App.jsx
import ReviewForm from "./components/ReviewForm";
import ReviewsList from "./components/ReviewsList";

export default function App() {
  const handleSubmit = async (review) => {
    await fetch("https://your-repl-name.username.repl.co/api/reviews", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(review),
    });
  };

  return (
    <div>
      <ReviewForm onSubmit={handleSubmit} />
      <ReviewsList />
    </div>
  );
}

Make sure to replace your-repl-name.username.repl.co with your actual Repl domain (you can see it in the browser preview URL).

 

3. Best Practices Specific to Replit

 

  • Use Secrets (in the left sidebar → padlock icon) for any credentials or API keys. Never hardcode them in your code.
  • Autosave is continuous — Replit automatically saves files, but before you deploy, confirm all files are committed if you’ve linked Git.
  • Database initialization — Replit DB is simple key-value, not relational. For sorting, pagination, or filters, you’ll need to store an array or use SQLite if your data grows large.
  • Keep server.js persistent by clicking “Always On” if on a paid plan, or use an external ping service (like UptimeRobot) to keep it responsive.
  • Multiplayer debugging — teammates can access logs and edit live; be careful since everyone edits the same environment.
  • Deploying — for lightweight services, the Replit-hosted URL is fine. For production traffic, consider exporting to another host (like Render or Vercel) using git integration.

 

4. Common Pitfalls to Avoid

 

  • Not validating input: Always check required fields before saving reviews; malformed data can crash your front-end rendering.
  • Hardcoding URLs: When developing locally on Replit, URLs change with forks. Use relative URLs like /api/reviews inside the same repl if frontend and backend are served together.
  • Forgetting JSON middleware: Without app.use(express.json()), your POST body won’t parse correctly.
  • Mixing backend/front-end Repls incorrectly: Keep them in one Repl if you use Replit free tier; otherwise, React apps on separate Repls need full HTTPS URLs to talk to the backend.

 

This setup gives you a practical, realistic Reviews & Ratings system that’s light enough for Replit but structured well enough to scale later — all done in a way that matches how real apps behave inside the Replit environment.

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