How to Build a Contact Form Backend With Google Sheets (No Server Needed)
Every website needs a contact form. But setting one up usually means spinning up a backend, configuring a database, handling email notifications, and deploying somewhere reliable.
What if your contact form could just write directly to a Google Sheet?
With Jsonsheets, you can build a fully functional contact form backend in minutes. Form submissions go straight to a spreadsheet where you or your team can review, respond, and organize them — no server code required.
Why Google Sheets as a Contact Form Backend?
Most contact forms don't need a complex database. You need to:
Collect a name, email, and message
Store submissions somewhere accessible
Let your team review and respond
Google Sheets handles all of this. Your team already knows how to use it. You can sort, filter, add columns for status tracking, and even set up Google Sheets notifications when new rows appear.
Step 1: Create Your Submissions Spreadsheet
Open Google Sheets and create a new spreadsheet called "Contact Form Submissions" with these columns:
| name | subject | message | submitted_at | status | |
| John Doe | john@example.com | Contact us | Hi team This is John and i love Jsonsheets.com | 12-02-2026 | Replied |
Keep the first row as headers — these become your API field names. The submitted_at and status columns are optional but useful for tracking when messages arrived and whether they've been handled.
Step 2: Connect the Sheet to Jsonsheets
Sign in at jsonsheets.com
Click Browse Drive and select your Contact Form Submissions spreadsheet
Jsonsheets creates an API endpoint for your sheet automatically
You'll get an API slug like contact-form-submissions and an endpoint:
POST https://jsonsheets.com/api/v1/contact-form-submissions/Sheet1
Step 3: Create an API Key
Go to the API Keys page in your Jsonsheets dashboard and generate a key. You'll need this to authenticate your form submissions.
Step 4: Build the Contact Form (HTML + JavaScript)
Here's a clean, working contact form you can drop into any website:
<form id="contact-form">
<input type="text" name="name" placeholder="Your name" required />
<input type="email" name="email" placeholder="Your email" required />
<input type="text" name="subject" placeholder="Subject" required />
<textarea name="message" placeholder="Your message" required></textarea>
<button type="submit">Send Message</button>
</form>
<script>
document.getElementById("contact-form").addEventListener("submit", async (e) => {
e.preventDefault();
const form = e.target;
const data = {
name: form.name.value,
email: form.email.value,
subject: form.subject.value,
message: form.message.value,
submitted_at: new Date().toISOString(),
status: "new"
};
try {
const response = await fetch(
"https://jsonsheets.com/api/v1/contact-form-submissions/Sheet1",
{
method: "POST",
headers: {
"Authorization": "Bearer js_your_api_key_here",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}
);
if (response.ok) {
form.reset();
alert("Message sent! We'll get back to you soon.");
} else {
alert("Something went wrong. Please try again.");
}
} catch (error) {
alert("Failed to send message. Please try again later.");
}
});
</script>
That's it. Every form submission creates a new row in your Google Sheet.
Step 5: Build It in React Instead
If you're working with React, here's a component version:
import { useState } from "react";
function ContactForm() {
const [sending, setSending] = useState(false);
const [sent, setSent] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setSending(true);
const formData = new FormData(e.target);
const data = {
name: formData.get("name"),
email: formData.get("email"),
subject: formData.get("subject"),
message: formData.get("message"),
submitted_at: new Date().toISOString(),
status: "new"
};
try {
const res = await fetch(
"https://jsonsheets.com/api/v1/contact-form-submissions/Sheet1",
{
method: "POST",
headers: {
Authorization: "Bearer js_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify(data),
}
);
if (res.ok) setSent(true);
} catch (err) {
alert("Failed to send. Please try again.");
} finally {
setSending(false);
}
};
if (sent) return <p>Thanks! We'll be in touch soon.</p>;
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Your name" required />
<input name="email" type="email" placeholder="Your email" required />
<input name="subject" placeholder="Subject" required />
<textarea name="message" placeholder="Your message" required />
<button type="submit" disabled={sending}>
{sending ? "Sending..." : "Send Message"}
</button>
</form>
);
}
Managing Submissions in Google Sheets
Once submissions start coming in, your spreadsheet becomes a simple CRM:
Sort by date to see the newest messages first
Add a "status" column with values like
new,replied,closedColor code rows to prioritize urgent messages
Use Google Sheets filters to find messages by email or subject
Set up notifications in Google Sheets (Tools > Notification rules) to get an email when new rows are added
Reading Submissions via API
You can also build an admin panel that reads submissions through the API:
Get all new submissions:
GET /api/v1/contact-form-submissions/Sheet1?status=new
Get submissions from a specific person:
GET /api/v1/contact-form-submissions/Sheet1?email=john@example.com
Mark a submission as replied:
curl -X PUT \
-H "Authorization: Bearer js_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"condition": {"email": "john@example.com"}, "set": {"status": "replied"}}' \
https://jsonsheets.com/api/v1/contact-form-submissions/Sheet1
Security Considerations
A few things to keep in mind:
API key exposure: Your API key will be visible in frontend JavaScript. Jsonsheets API keys are scoped to your account, so only your sheets are accessible. For extra security, create a dedicated API key just for the contact form and revoke it if compromised.
Spam protection: Add a honeypot field (a hidden input that bots fill out but humans don't) or integrate with a CAPTCHA service before submitting to the API.
Rate limiting: Jsonsheets tracks request usage per account, which naturally limits abuse.
Here's a simple honeypot example:
<!-- Hidden from real users, bots will fill this in -->
<input type="text" name="website" style="display:none" tabindex="-1" />
<script>
// In your submit handler, check:
if (form.website.value !== "") {
// Bot detected, silently ignore
return;
}
</script>
Use Cases Beyond Contact Forms
This same pattern works for any kind of form submission:
Feedback forms — collect user feedback and feature requests
Survey responses — gather answers and analyze them in Sheets
Event registration — track signups with name, email, and ticket type
Job applications — collect resumes and applicant info
Bug reports — let users submit issues directly to a spreadsheet
Newsletter signups — store email addresses for your mailing list
Wrapping Up
You don't need a backend server, a database, or a form service subscription to collect contact form submissions. With a Google Sheet and Jsonsheets, you get:
A working form backend in under 5 minutes
Submissions stored in a spreadsheet your whole team can access
Full API access to read, update, and manage submissions
Zero infrastructure to maintain
Set up your contact form backend at jsonsheets.com