Collecting leads, customer inquiries, or newsletter signups usually requires paying for third-party form builders or embed widgets that slow down your website. But did you know you can build a clean, custom HTML contact form and send submissions straight into a Google Sheet for 100% free?
In this step-by-step tutorial, we will set up a Google Sheet, write a lightweight 10-line Google Apps Script backend endpoint, and build a responsive HTML/CSS form that submits data seamlessly without reloading the page.
Step 1: Set Up Your Google Sheet
First, create the spreadsheet where your form responses will be stored:
- Open Google Sheets and create a blank spreadsheet.
- Name your sheet something clear, like
Website Contact Inquiries. - In row 1, set up the exact headers for the fields you want to collect:
- A1:
Timestamp - B1:
Name - C1:
Email - D1:
Subject - E1:
Message
- A1:
Pro Tip: Make sure the tab name at the bottom is set to Sheet1 (or update the script name in Step 2 to match your custom tab name).
Step 2: Create the Google Apps Script Web App
Google Apps Script acts as our free backend API endpoint to receive submissions and append them as new rows.
- In your spreadsheet, go to Extensions > Apps Script.
- Delete any existing code inside the editor and paste the following script:
const sheetName = 'Sheet1';
function doPost(e) {
const lock = LockService.getScriptLock();
lock.tryLock(10000); // Prevents concurrency data collision
try {
const doc = SpreadsheetApp.getActiveSpreadsheet();
const sheet = doc.getSheetByName(sheetName);
const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
const nextRow = sheet.getLastRow() + 1;
const newRow = headers.map(function(header) {
if (header === 'Timestamp') {
return new Date();
}
return e.parameter[header] || '';
});
sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow]);
return ContentService
.createTextOutput(JSON.stringify({ result: 'success', row: nextRow }))
.setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService
.createTextOutput(JSON.stringify({ result: 'error', error: error.message }))
.setMimeType(ContentService.MimeType.JSON);
} finally {
lock.releaseLock();
}
}
- Click the Save disk icon.
Step 3: Deploy the Script as a Web App
To let your HTML form communicate with this script, you must deploy it with public execution permissions:
- Click the blue Deploy > New deployment button in the top-right corner.
- Click the gear icon next to "Select type" and choose Web app.
- Configure the deployment settings:
- Description:
Contact Form Handler - Execute as:
Me (your Google account) - Who has access:
Anyone(Crucial: do not select "Only myself" or submissions will fail with a 403 authorization error).
- Description:
- Click Deploy.
- Click Authorize access, select your Google account, click Advanced, and proceed (click "Go to Untitled project (unsafe)").
- Copy the provided Web App URL (it looks like
https://script.google.com/macros/s/AKfycb.../exec). Save this for your form!
Step 4: The Standard HTML & JavaScript Form
Here is the clean, baseline HTML form. The name="" attribute on each input matches your spreadsheet column header names letter-for-letter:
<!-- Responsive Contact Form Container -->
<div style="max-width: 520px; margin: 20px auto; padding: 24px; border: 1px solid #e2e8f0; border-radius: 8px; background: #ffffff; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); font-family: sans-serif;">
<h3 style="margin-top: 0; color: #0f172a;">Get in Touch</h3>
<form id="googleSheetForm">
<div style="margin-bottom: 14px;">
<label style="display:block; font-weight: 600; margin-bottom: 5px; font-size: 14px;">Name</label>
<input type="text" name="Name" required placeholder="Jane Doe" style="width: 100%; padding: 10px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display:block; font-weight: 600; margin-bottom: 5px; font-size: 14px;">Email</label>
<input type="email" name="Email" required placeholder="jane@example.com" style="width: 100%; padding: 10px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display:block; font-weight: 600; margin-bottom: 5px; font-size: 14px;">Subject</label>
<input type="text" name="Subject" required placeholder="Quick Question" style="width: 100%; padding: 10px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 18px;">
<label style="display:block; font-weight: 600; margin-bottom: 5px; font-size: 14px;">Message</label>
<textarea name="Message" rows="4" required placeholder="How can we help you?" style="width: 100%; padding: 10px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;"></textarea>
</div>
<button type="submit" id="submitBtn" style="background: #0f766e; color: #fff; border: none; padding: 12px 20px; font-size: 15px; font-weight: 600; border-radius: 6px; cursor: pointer; width: 100%;">
Send Message
</button>
<p id="formResponse" style="margin-top: 14px; text-align: center; display: none; font-size: 14px;"></p>
</form>
</div>
<script>
// REPLACE THIS URL with your deployed Apps Script Web App URL from Step 3
const SCRIPT_URL = "YOUR_APPS_SCRIPT_WEB_APP_URL_HERE";
const form = document.getElementById('googleSheetForm');
const responseMsg = document.getElementById('formResponse');
const btn = document.getElementById('submitBtn');
form.addEventListener('submit', e => {
e.preventDefault();
btn.disabled = true;
btn.innerText = 'Sending...';
fetch(SCRIPT_URL, {
method: 'POST',
body: new FormData(form)
})
.then(res => res.json())
.then(data => {
responseMsg.style.display = 'block';
responseMsg.style.color = '#047857';
responseMsg.innerText = 'Thank you! Your message was submitted successfully.';
form.reset();
btn.innerText = 'Message Sent';
})
.catch(err => {
responseMsg.style.display = 'block';
responseMsg.style.color = '#b91c1c';
responseMsg.innerText = 'Submission failed. Please check connection and try again.';
btn.disabled = false;
btn.innerText = 'Send Message';
});
});
</script>
Bonus: 5 Free Copy-Paste Themes for Your Contact Form
Want a look that fits your site's aesthetic? Below are 5 pre-built design themes. They all use the exact same input names, so they work right away with your Apps Script setup.
Theme 1: Clean Minimalist (SaaS & Tech Startups)
A crisp, neutral layout with slate borders and subtle shadows.
<div style="max-width: 480px; margin: 20px auto; padding: 30px; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; font-family: sans-serif; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05);">
<h3 style="margin: 0 0 6px 0; color: #0f172a; font-size: 20px;">Send us a message</h3>
<p style="margin: 0 0 20px 0; color: #64748b; font-size: 14px;">We usually respond within 24 hours.</p>
<form id="minimalForm">
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #334155; margin-bottom: 4px;">Full Name</label>
<input type="text" name="Name" required placeholder="Alex Morgan" style="width: 100%; padding: 10px; font-size: 14px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #334155; margin-bottom: 4px;">Email Address</label>
<input type="email" name="Email" required placeholder="alex@example.com" style="width: 100%; padding: 10px; font-size: 14px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #334155; margin-bottom: 4px;">Subject</label>
<input type="text" name="Subject" required placeholder="Inquiry" style="width: 100%; padding: 10px; font-size: 14px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 18px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #334155; margin-bottom: 4px;">Message</label>
<textarea name="Message" rows="4" required placeholder="How can we help?" style="width: 100%; padding: 10px; font-size: 14px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;"></textarea>
</div>
<button type="submit" style="width: 100%; background: #2563eb; color: #ffffff; padding: 12px; font-size: 14px; font-weight: 600; border: none; border-radius: 6px; cursor: pointer;">Send Message</button>
</form>
</div>
Theme 2: Dark Slate (Developer Portfolios & Tech Blogs)
A sleek dark theme matching code documentation and night-mode websites.
<div style="max-width: 480px; margin: 20px auto; padding: 30px; background: #0f172a; border: 1px solid #1e293b; border-radius: 12px; font-family: sans-serif; color: #f8fafc;">
<h3 style="margin: 0 0 6px 0; color: #f8fafc; font-size: 20px;">Let's Connect</h3>
<p style="margin: 0 0 20px 0; color: #94a3b8; font-size: 14px;">Drop a message to start a conversation.</p>
<form id="darkForm">
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #cbd5e1; margin-bottom: 4px;">Name</label>
<input type="text" name="Name" required placeholder="Jane Doe" style="width: 100%; padding: 10px; font-size: 14px; background: #1e293b; color: #f8fafc; border: 1px solid #334155; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #cbd5e1; margin-bottom: 4px;">Email</label>
<input type="email" name="Email" required placeholder="jane@example.com" style="width: 100%; padding: 10px; font-size: 14px; background: #1e293b; color: #f8fafc; border: 1px solid #334155; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #cbd5e1; margin-bottom: 4px;">Subject</label>
<input type="text" name="Subject" required placeholder="Project Discussion" style="width: 100%; padding: 10px; font-size: 14px; background: #1e293b; color: #f8fafc; border: 1px solid #334155; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 18px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #cbd5e1; margin-bottom: 4px;">Message</label>
<textarea name="Message" rows="4" required placeholder="Details about your inquiry..." style="width: 100%; padding: 10px; font-size: 14px; background: #1e293b; color: #f8fafc; border: 1px solid #334155; border-radius: 6px; box-sizing: border-box;"></textarea>
</div>
<button type="submit" style="width: 100%; background: #38bdf8; color: #0f172a; padding: 12px; font-size: 14px; font-weight: 700; border: none; border-radius: 6px; cursor: pointer;">Send Message</button>
</form>
</div>
Theme 3: Corporate Emerald (Consulting & B2B)
A structured design with a distinct green header bar for business consulting and financial services.
<div style="max-width: 480px; margin: 20px auto; background: #ffffff; border: 1px solid #d1fae5; border-radius: 10px; overflow: hidden; font-family: sans-serif; box-shadow: 0 4px 6px rgba(0,0,0,0.04);">
<div style="background: #047857; padding: 20px 24px; color: #ffffff;">
<h3 style="margin: 0 0 4px 0; font-size: 18px;">Client Inquiry</h3>
<p style="margin: 0; color: #a7f3d0; font-size: 13px;">Get customized spreadsheet assistance.</p>
</div>
<form id="emeraldForm" style="padding: 24px;">
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #064e3b; margin-bottom: 4px;">Name</label>
<input type="text" name="Name" required placeholder="Robert Taylor" style="width: 100%; padding: 10px; font-size: 14px; background: #f0fdf4; border: 1px solid #a7f3d0; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #064e3b; margin-bottom: 4px;">Email</label>
<input type="email" name="Email" required placeholder="robert@example.com" style="width: 100%; padding: 10px; font-size: 14px; background: #f0fdf4; border: 1px solid #a7f3d0; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #064e3b; margin-bottom: 4px;">Topic</label>
<input type="text" name="Subject" required placeholder="Custom Dashboard" style="width: 100%; padding: 10px; font-size: 14px; background: #f0fdf4; border: 1px solid #a7f3d0; border-radius: 6px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 18px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #064e3b; margin-bottom: 4px;">Message</label>
<textarea name="Message" rows="4" required placeholder="How can we assist you?" style="width: 100%; padding: 10px; font-size: 14px; background: #f0fdf4; border: 1px solid #a7f3d0; border-radius: 6px; box-sizing: border-box;"></textarea>
</div>
<button type="submit" style="width: 100%; background: #047857; color: #ffffff; padding: 12px; font-size: 14px; font-weight: 600; border: none; border-radius: 6px; cursor: pointer;">Submit Inquiry</button>
</form>
</div>
Theme 4: Floating Card (Warm & Creative)
Rounded input borders, soft violet accents, and an elevated shadow ideal for creative blogs.
<div style="max-width: 480px; margin: 20px auto; padding: 30px; background: #ffffff; border-radius: 14px; font-family: sans-serif; box-shadow: 0 10px 25px rgba(79, 70, 229, 0.08); border: 1px solid #ede9fe;">
<h3 style="margin: 0 0 6px 0; color: #312e81; font-size: 20px; text-align: center;">Say Hello! 👋</h3>
<p style="margin: 0 0 20px 0; color: #6b7280; font-size: 14px; text-align: center;">Drop us a line and let's talk.</p>
<form id="floatingForm">
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #4338ca; margin-bottom: 4px;">Name</label>
<input type="text" name="Name" required placeholder="Sam Wilson" style="width: 100%; padding: 10px; font-size: 14px; border: 1.5px solid #e0e7ff; border-radius: 8px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #4338ca; margin-bottom: 4px;">Email</label>
<input type="email" name="Email" required placeholder="sam@example.com" style="width: 100%; padding: 10px; font-size: 14px; border: 1.5px solid #e0e7ff; border-radius: 8px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #4338ca; margin-bottom: 4px;">Subject</label>
<input type="text" name="Subject" required placeholder="Collaboration" style="width: 100%; padding: 10px; font-size: 14px; border: 1.5px solid #e0e7ff; border-radius: 8px; box-sizing: border-box;" />
</div>
<div style="margin-bottom: 18px;">
<label style="display: block; font-size: 13px; font-weight: 600; color: #4338ca; margin-bottom: 4px;">Message</label>
<textarea name="Message" rows="4" required placeholder="Write your message..." style="width: 100%; padding: 10px; font-size: 14px; border: 1.5px solid #e0e7ff; border-radius: 8px; box-sizing: border-box;"></textarea>
</div>
<button type="submit" style="width: 100%; background: #4f46e5; color: #ffffff; padding: 12px; font-size: 14px; font-weight: 700; border: none; border-radius: 8px; cursor: pointer;">Send Message</button>
</form>
</div>
Theme 5: Studio Borderless (Editorial & Minimalist)
An elegant, modern layout with clean underline input borders.
<div style="max-width: 480px; margin: 20px auto; padding: 28px; background: #fafafa; border-radius: 8px; font-family: sans-serif;">
<h3 style="margin: 0 0 6px 0; color: #18181b; font-size: 20px;">Contact Studio</h3>
<p style="margin: 0 0 20px 0; color: #71717a; font-size: 14px;">Leave your details below.</p>
<form id="borderlessForm">
<div style="margin-bottom: 18px;">
<label style="display: block; font-size: 12px; font-weight: 700; text-transform: uppercase; color: #52525b; margin-bottom: 4px;">Name</label>
<input type="text" name="Name" required placeholder="Your Name" style="width: 100%; padding: 8px 0; background: transparent; border: none; border-bottom: 2px solid #d4d4d8; font-size: 14px; box-sizing: border-box; outline: none;" />
</div>
<div style="margin-bottom: 18px;">
<label style="display: block; font-size: 12px; font-weight: 700; text-transform: uppercase; color: #52525b; margin-bottom: 4px;">Email</label>
<input type="email" name="Email" required placeholder="your.email@example.com" style="width: 100%; padding: 8px 0; background: transparent; border: none; border-bottom: 2px solid #d4d4d8; font-size: 14px; box-sizing: border-box; outline: none;" />
</div>
<div style="margin-bottom: 18px;">
<label style="display: block; font-size: 12px; font-weight: 700; text-transform: uppercase; color: #52525b; margin-bottom: 4px;">Subject</label>
<input type="text" name="Subject" required placeholder="Topic" style="width: 100%; padding: 8px 0; background: transparent; border: none; border-bottom: 2px solid #d4d4d8; font-size: 14px; box-sizing: border-box; outline: none;" />
</div>
<div style="margin-bottom: 22px;">
<label style="display: block; font-size: 12px; font-weight: 700; text-transform: uppercase; color: #52525b; margin-bottom: 4px;">Message</label>
<textarea name="Message" rows="3" required placeholder="Your message..." style="width: 100%; padding: 8px 0; background: transparent; border: none; border-bottom: 2px solid #d4d4d8; font-size: 14px; box-sizing: border-box; outline: none;"></textarea>
</div>
<button type="submit" style="background: #18181b; color: #ffffff; padding: 11px 24px; font-size: 14px; font-weight: 600; border: none; border-radius: 4px; cursor: pointer;">Submit Message →</button>
</form>
</div>
Best Practices & Security Considerations
- Exact Field Matching: The
nameattribute in your HTML inputs (e.g.,name="Email") must match the column header in Row 1 of your spreadsheet exactly. - LockService: The script uses
LockService.getScriptLock(). This ensures that if multiple users submit simultaneously, their responses queue up safely instead of overwriting rows. - Data Automation: Once form entries arrive in your sheet, you can connect them to other workflows. For example, automatically categorize respondents using XLOOKUP vs. VLOOKUP in Google Sheets.
Expand Your Spreadsheet Skills
Need to connect your incoming inquiries to a stock list or customer database? Read our step-by-step guide on how to build an automated inventory management sheet.
Comments
Post a Comment