Home/Templates/Feedback & NPS

Free Feedback & NPS Backend

Gather structured feedback from your users.

<form action="YOUR_ENDPOINT_URL" method="POST">
  <div>
    <label for="rating">Rating (1–10)</label>
    <select id="rating" name="rating" required>
      <option value="">Select a rating</option>
      <option value="1">1 – Very poor</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4">4</option>
      <option value="5">5 – Neutral</option>
      <option value="6">6</option>
      <option value="7">7</option>
      <option value="8">8</option>
      <option value="9">9</option>
      <option value="10">10 – Excellent</option>
    </select>
    <span class="fd-error" data-fd-error="rating"></span>
  </div>
  <div>
    <label for="what_worked">What worked well?</label>
    <textarea id="what_worked" name="what_worked" required minlength="10" maxlength="5000" rows="4" placeholder="Tell us what you liked..."></textarea>
    <span class="fd-error" data-fd-error="what_worked"></span>
  </div>
  <div>
    <label for="what_didnt">What could be improved?</label>
    <textarea id="what_didnt" name="what_didnt" required minlength="10" maxlength="5000" rows="4" placeholder="Tell us what could be better..."></textarea>
    <span class="fd-error" data-fd-error="what_didnt"></span>
  </div>
  <div>
    <label for="email">Your Email</label>
    <input type="email" id="email" name="email" required placeholder="you@example.com" />
    <span class="fd-error" data-fd-error="email"></span>
  </div>
  <button type="submit">Submit Feedback</button>
</form>

<style>
  .fd-error { color: #dc2626; font-size: 0.875rem; margin-top: 0.25rem; display: none; }
  .fd-success { color: #16a34a; padding: 1rem; border: 1px solid #16a34a; border-radius: 4px; display: none; }
  .fd-fail { color: #dc2626; padding: 1rem; border: 1px solid #dc2626; border-radius: 4px; display: none; }
  button[type="submit"]:disabled { opacity: 0.6; cursor: not-allowed; }
</style>

<div class="fd-success" id="fd-success">Thanks! Your message has been received.</div>
<div class="fd-fail" id="fd-fail">Something went wrong. Please try again.</div>

<script>
  (function () {
    const form = document.currentScript.closest("form") || document.querySelector("form");
    if (!form) return;

    const fields = {
      rating:     { required: true,                                  label: "Rating" },
      what_worked:{ required: true, minlength: 10, maxlength: 5000, label: "What worked" },
      what_didnt: { required: true, minlength: 10, maxlength: 5000, label: "What didn’t work" },
      email:      { required: true, type: "email",                   label: "Email" },
    };

    function validate(name, value) {
      const rule = fields[name];
      if (!rule) return null;
      if (rule.required && !value.trim()) return `${rule.label} is required.`;
      if (rule.type === "email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
        return "Enter a valid email address.";
      if (rule.minlength && value.trim().length < rule.minlength)
        return `${rule.label} must be at least ${rule.minlength} characters.`;
      if (rule.maxlength && value.trim().length > rule.maxlength)
        return `${rule.label} must be under ${rule.maxlength} characters.`;
      return null;
    }

    function showError(name, message) {
      const el = form.querySelector(`[data-fd-error="${name}"]`);
      if (!el) return;
      el.textContent = message;
      el.style.display = message ? "block" : "none";
    }

    form.querySelectorAll("input, textarea, select").forEach((input) => {
      input.addEventListener("blur", () => {
        showError(input.name, validate(input.name, input.value) || "");
      });
    });

    form.addEventListener("submit", async (e) => {
      e.preventDefault();
      let hasErrors = false;
      form.querySelectorAll("input, textarea, select").forEach((input) => {
        const error = validate(input.name, input.value);
        showError(input.name, error || "");
        if (error) hasErrors = true;
      });
      if (hasErrors) return;

      const btn = form.querySelector("button[type='submit']");
      const originalText = btn.textContent;
      btn.disabled = true;
      btn.textContent = "Sending…";

      try {
        const res = await fetch(form.action, { method: "POST", body: new FormData(form) });
        if (res.ok) {
          form.reset();
          form.style.display = "none";
          document.getElementById("fd-success").style.display = "block";
        } else throw new Error();
      } catch {
        document.getElementById("fd-fail").style.display = "block";
        btn.disabled = false;
        btn.textContent = originalText;
      }
    });
  })();
</script>
Get your free endpoint →

How it works

  1. 1

    Create a form

    Sign up free and get a unique HTTPS endpoint URL in seconds.

  2. 2

    Paste the snippet

    Copy the HTML snippet above and paste it into any page — static site, CMS, or custom build.

  3. 3

    Receive submissions

    Every form submission is stored and accessible from your dashboard. No server required.