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>How it works
- 1
Create a form
Sign up free and get a unique HTTPS endpoint URL in seconds.
- 2
Paste the snippet
Copy the HTML snippet above and paste it into any page — static site, CMS, or custom build.
- 3
Receive submissions
Every form submission is stored and accessible from your dashboard. No server required.