The short answer
Running a contact form without a backend means replacing the five jobs a server was doing — receiving the POST, validating it, storing it, notifying you, and blocking spam — with services that already exist. A hosted form endpoint covers all five. RG Forms covers them using infrastructure inside your own Google account: an Apps Script web app receives the POST, appends a row to your Google Sheet, emails you from your own account, and verifies a Turnstile token before saving. You maintain no server, no database and no dependencies, and you still own every submission.
The five jobs, and who does them now
| The job | With a server you run | Without one (RG Forms) |
|---|---|---|
| Receive the POST | Your route handler, on a host you pay for | An Apps Script web app in your Google account, at a permanent HTTPS URL |
| Validate the data | Server-side validation code you wrote | HTML validation in the browser, plus whatever rules you add to the script |
| Store it | A database you provision, back up and patch | A row in a Google Sheet you already own |
| Notify you | An email API with its own key and bill | MailApp sending from your own Google account, with reply-to set to the sender |
| Block spam | Rate limiting and a captcha you wire up | A honeypot field, plus optional Cloudflare Turnstile verified server-side |
The thing you’re really avoiding is operations
Writing the endpoint was never the hard part — it’s twenty lines. The cost is everything that comes after: a host that has to stay up, a runtime that goes end-of-life, dependencies with security advisories, a database that needs backups, a certificate that expires, and a monthly bill for a service that receives four messages a week.
For a contact form on a brochure site, that ratio is indefensible. The whole point of going serverless here is to delete the operational surface, not to be clever.
What “no backend” costs you
Being honest about the trade: because there’s no server of yours in the path, required-field enforcement is a frontend concern. A determined person can POST directly to the endpoint and skip your HTML validation. For a contact form that’s a non-issue — the worst case is a row with empty cells — but it’s the wrong architecture for anything that needs to be authoritative, like a payment or an account signup.
Two other things worth knowing: there are no file uploads (text fields only), and there is no read API — the endpoint accepts submissions but never returns them, so pulling your data into another system means reading the Sheet rather than fetching a URL.
Everything else you’d expect — timestamps, multiple forms, custom fields, notification routing, CC/BCC, custom subjects, spam filtering — is there.
The entire client side
This is the complete integration — there is no server-side counterpart to write.
<form id="contact-form">
<label>Name <input name="name" required /></label>
<label>Email <input type="email" name="email" required /></label>
<label>Message <textarea name="message" required></textarea></label>
<!-- Honeypot: humans never see it, bots fill it in -->
<input type="text" name="_hp" tabindex="-1" autocomplete="off"
style="position:absolute;left:-9999px" aria-hidden="true" />
<button type="submit">Send</button>
<p id="form-status" role="status"></p>
</form>
<script>
const ENDPOINT = "https://script.google.com/macros/s/AKfycb.../exec";
const form = document.getElementById("contact-form");
const status = document.getElementById("form-status");
form.addEventListener("submit", async (event) => {
event.preventDefault();
status.textContent = "Sending…";
const res = await fetch(ENDPOINT, {
method: "POST",
// text/plain avoids the CORS preflight Apps Script can't answer
headers: { "Content-Type": "text/plain" },
body: JSON.stringify({
tab: "contact",
fields: Object.fromEntries(new FormData(form)),
}),
});
const data = await res.json();
status.textContent =
data.result === "success" ? "Thanks — we'll be in touch." : "Something went wrong.";
if (data.result === "success") form.reset();
});
</script>Common questions
Is a serverless function a “backend”?
Functionally yes — it’s your code, running on demand, that you own and maintain. It’s a great choice when you need custom logic. It’s overkill when all you need is “put this message somewhere I’ll see it.”
Can I add server-side validation later?
Yes — the Apps Script is in your own account and fully editable. Open it in the Apps Script editor and add whatever rules you want before the row is written.
Is it slower than a real backend?
The first request after a period of inactivity takes roughly 800ms–2s while Apps Script cold-starts; subsequent ones are fast. For a contact form nobody notices, especially with a “Sending…” state on the button.
What happens if Google is down?
The submission fails, same as any hosted service having an outage. Catch the error and show a fallback email address so the visitor still has a way to reach you.
More answers in the full FAQ.