iToverDose/Software· 28 MAY 2026 · 20:03

Free contact forms for static sites using Google Sheets and Apps Script

Static websites can now collect form submissions without paying a monthly fee. Google Apps Script and Sheets provide a no-code backend that handles data storage, spam filtering, and email alerts automatically.

DEV Community4 min read0 Comments

Static websites often struggle with the simplest need: a contact form. Portfolio sites, landing pages, and small business pages typically avoid adding a backend just to store a name, email, and message. Meanwhile, popular hosted form services start charging once you want Google Sheet integration or custom branding. A lightweight Google Apps Script web app changes that by turning Google Sheets into a free, real-time contact form database.

How a zero-cost form backend works

The workflow is straightforward. When a visitor submits a form, the frontend sends a POST request to a Google Apps Script web app instead of a traditional server. The script processes the input, writes the data to a Google Sheet, and sends an email alert to the site owner. No database setup, no SMTP configuration, and no recurring hosting bills.

  • HTML form → Google Apps Script doPost endpoint
  • Data validation and spam filtering inside the script
  • Google Sheet acts as the database
  • MailApp.sendEmail delivers instant notifications
  • Optional autoresponse for website visitors

Deploy the script once, and it runs indefinitely without manual intervention.

Setting up the form handler script

The core of the solution is a doPost function that acts as the API endpoint. It wraps the main logic in error handling so any failure returns a clean JSON response instead of exposing internal errors.

function doPost(e) {
  try {
    return handlePost(e);
  } catch (err) {
    console.error(err);
    return jsonResponse('error', 'Internal server error.');
  }
}

Inside handlePost, the script follows a strict sequence:

  • Parses incoming data whether it arrives as JSON or form-urlencoded
  • Checks a hidden honeypot field for bot activity
  • Validates required fields are present and not empty
  • Rejects submissions with malformed email addresses
  • Filters submissions containing common spam keywords
  • Enforces basic rate limiting to block rapid repeats
  • Appends a new row to the designated Google Sheet
  • Sends a notification email to the site owner
  • Optionally dispatches an auto-reply to the visitor

The honeypot technique is especially effective: bots fill every visible field, while humans ignore hidden ones. If the _gotcha field contains a value, the script returns a fake success message and skips writing to the sheet entirely.

Turning Google Sheets into a live database

For contact forms, a spreadsheet is often a better database than a full-fledged SQL instance. It is immediately searchable, exportable to CSV, and familiar to clients who need to review leads. The script creates a dedicated sheet on first run and ensures the correct columns exist.

function ensureSheet(sheetName) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    sheet = ss.insertSheet(sheetName);
    sheet.appendRow(['Timestamp', 'Name', 'Email', 'Message', 'Source URL']);
    sheet.setFrozenRows(1);
    sheet.getRange('D:D').setWrap(true);
  }
}

New submissions are appended with a single call:

function appendRow(sheetName, row) {
  SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName(sheetName)
    .appendRow(row);
}

Column wrapping keeps long messages readable without truncation.

Sending email alerts without SMTP

Google Apps Script includes MailApp.sendEmail, which removes the need for third-party email services. The script constructs a concise notification containing the visitor’s name, email, and message.

MailApp.sendEmail({
  to: cfg.recipientEmail,
  subject: 'New Contact Form Submission',
  body: `${name} <${email}> sent:\n\n${message}`
});

For many small websites, this level of delivery is sufficient. If higher deliverability is needed later, switching to a transactional email provider is always an option.

Connecting the frontend form

The frontend only needs a minimal JavaScript handler that calls the deployed script URL. The example uses fetch with JSON payload including the honeypot field.

const res = await fetch(SCRIPT_URL, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: form.name.value,
    email: form.email.value,
    message: form.message.value,
    _gotcha: form._gotcha.value
  })
});
const json = await res.json();

Set the Google Apps Script deployment access to “Anyone” and paste the generated URL into your form code. The script handles the rest automatically.

When to use this approach — and when not to

This pattern excels for low-traffic use cases:

  • Portfolio and agency contact forms
  • Landing page lead capture
  • Small business inquiry forms
  • Internal request or waitlist signups
  • Low-volume lead generation without file uploads

It is not designed for:

  • File uploads or large attachments
  • Payment processing or e-commerce orders
  • High-frequency transactional workloads
  • Situations requiring strict GDPR compliance or data deletion workflows

For teams needing a polished setup UI and multi-form management, a paid version of the same script exists, but the open-source version remains fully functional for most needs.

A complete, MIT-licensed implementation with templates, spam filters, rate limiting, and autoresponse logic is available for immediate use. The project balances simplicity with practical features, proving that robust form handling does not require a server or subscription fees.

AI summary

Statik web siteleri için aylık ödeme gerektirmeyen ücretsiz bir iletişim formu arka ucu oluşturmanın yolu: Google Apps Script ve Google E-Tablolar ile nasıl yapılır?

Comments

00
LEAVE A COMMENT
ID #DAG4HP

0 / 1200 CHARACTERS

Human check

5 + 3 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.