How to Connect an HTML Form to Google Sheets Without Backend Code

A complete, working method to send HTML form submissions straight into a Google Sheet using Google Apps Script. No server, no database, no backend..

You built a contact form, an order form, or a feedback form. It looks good. The HTML is clean. But now you are stuck on the part nobody talks about: where does the data actually go when someone hits submit?

Html for connect with Google sheets

The usual answer involves setting up a backend, a database, maybe an email service, and a hosting plan to run all of it. For a personal project, a small client site, or a quick internal tool, that is a lot of infrastructure for something as simple as "save this form data somewhere I can see it."

There is a much simpler option that most beginner tutorials skip: Google Sheets as your database, with Google Apps Script as the bridge between your form and the sheet. No server is required. There is no PHP, Node, or Python backend, and no monthly hosting bill for a database. You only need a free Google account and about ten minutes.

This guide walks through the entire setup from start to finish, including the parts that usually trip people up.

What We Are Actually Building

Here is the flow in plain terms:

  1. Someone fills out your HTML form on your website.
  2. JavaScript catches the submit event and sends the form data to a special URL.
  3. That URL belongs to a Google Apps Script attached to your Google Sheet.
  4. The script reads the incoming data and writes it as a new row in the sheet.

That is the whole system. Google Sheets becomes your free, visual, and always accessible database. You can open it on your phone, sort it, filter it, export it to Excel, or hook it up to other tools later. No backend code of your own is involved at any point.

Step 1: Create the Google Sheet

Open Google Sheets and create a new blank spreadsheet. In the first row, add column headers matching the fields in your form. For a typical contact form, that might look like this:

Name | Email | Message | Timestamp

Keep the header names simple and exactly matching what you will reference later. Capitalization and spelling matter here, since the script will look for these exact names.

Step 2: Open the Script Editor

Inside the spreadsheet, go to Extensions in the top menu, then select Apps Script. This opens a separate code editor tab tied directly to your sheet. You do not need to install anything because it runs entirely in your browser through Google servers.

Delete whatever placeholder code is already there and replace it with this:

function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = e.parameter;

  sheet.appendRow([
    data.name,
    data.email,
    data.message,
    new Date()
  ]);

  return ContentService
    .createTextOutput(JSON.stringify({ "result": "success" }))
    .setMimeType(ContentService.MimeType.JSON);
}

This function runs automatically every time the script receives a POST request. It grabs whatever values were sent matching the field names from your form, appends them as a new row, and stamps the current date and time. The last part sends a small JSON response back, which we will use to confirm the submission worked.

If your form has different field names than name, email, and message, change them here to match exactly what your HTML form uses in its name attributes. This is the single most common reason this setup fails on the first try, so double check that the spelling matches on both ends.

Step 3: Deploy the Script as a Web App

Click Deploy in the top right, then choose New deployment. Click the gear icon next to "Select type" and choose Web app.

Set these options precisely:

  • Execute as: Me
  • Who has access: Anyone

That second setting feels uncomfortable the first time you see it, but it is necessary. Your form needs to reach this script without anyone logging into a Google account first. This does not expose your sheet itself or give visitors any access beyond submitting data through the function you wrote. They cannot read existing rows or open the sheet through this URL.

Click Deploy. Google will ask you to authorize the script the first time. Approve the permissions. This is Google standard warning for any script that edits a sheet, so nothing unusual is happening.

Once deployed, you will get a URL that looks like this:

https://script.google.com/macros/s/AKfycb.../exec

Copy this URL. This is the address your HTML form will send data to.

Step 4: Build the HTML Form

Here is a simple, working contact form structure:

<form id="contactForm">
  <input type="text" name="name" placeholder="Your Name" required>
  <input type="email" name="email" placeholder="Your Email" required>
  <textarea name="message" placeholder="Your Message" required></textarea>
  <button type="submit">Send</button>
</form>

<p id="formStatus"></p>

Notice the name attributes on each input. These need to match the field names you used inside the Apps Script function (data.name, data.email, data.message). This is the connection point between the two halves of the system.

Step 5: Send the Form Data with JavaScript

This is the part that actually ties everything together. Add this script at the bottom of your page:

<script>
const form = document.getElementById('contactForm');
const status = document.getElementById('formStatus');
const scriptURL = 'PASTE_YOUR_DEPLOYED_URL_HERE';

form.addEventListener('submit', function(e) {
  e.preventDefault();

  const formData = new FormData(form);

  fetch(scriptURL, {
    method: 'POST',
    body: formData
  })
  .then(function() {
    status.textContent = 'Thanks! Your message was sent.';
    form.reset();
  })
  .catch(function(error) {
    status.textContent = 'Something went wrong. Please try again.';
    console.error(error);
  });
});
</script>

Replace PASTE_YOUR_DEPLOYED_URL_HERE with the URL you copied earlier. The e.preventDefault() line stops the form from doing a normal page reload on submit, and FormData(form) automatically collects every named input in the form without manual mapping.

That is the entire setup. Submit the form, then check your spreadsheet. A new row should appear with the submitted data and a timestamp.

Why This Approach Holds Up

Is this just a toy solution, or can you actually rely on it?

For low to moderate traffic sites, personal projects, small business sites, internal tools, and most client work, this is a completely solid approach. Google Apps Script handles the request reliably, your data lands in a format that is instantly readable, and there is nothing to maintain, patch, or pay for. You are not running a server that needs updates or a database that needs backups. Google is already doing that for you.

Where it starts to make sense to move to a real backend is when you need complex validation logic running server side, rate limiting to prevent abuse, handling thousands of submissions per minute, or storing sensitive data. For everything below that threshold, which covers a large share of real form use cases, this method works without compromise.

Things Worth Knowing Before Production

Spam Protection

Since the deployed URL accepts requests from anyone, it is open to bots if someone finds the endpoint. A simple fix is adding a honeypot field. This is an extra input that is hidden from real users with CSS but still visible to bots, then you check in your script whether it was filled in:

<input type="text" name="honeypot" style="display:none">

In the script, add a check at the top of doPost:

if (e.parameter.honeypot) {
  return ContentService.createTextOutput(JSON.stringify({ "result": "ignored" }));
}

Real visitors never see or fill this field. Bots that auto-fill every input on a page usually fill it without knowing, which gives you an easy way to quietly drop their submissions.

Redeploying After Changes

If you edit the Apps Script code later, you need to create a new deployment or manage versions through the existing one for the changes to take effect. Editing the code alone does not update the live URL automatically. This catches people off guard the first time they make a fix and wonder why nothing changed.

Multiple Forms on One Sheet

You can route several forms across different pages into the same sheet, or into separate sheets within the same spreadsheet. You achieve this by adding a hidden field identifying the form source and branching inside doPost based on that value. This is handy if you are managing a contact form and a newsletter signup on the same site and want both tracked centrally without building two separate systems.

The Bottom Line

You do not need a backend, a database, or a hosting bill to collect form submissions reliably. A Google Sheet paired with a small Apps Script function handles the job for free, gives you instant visibility into your data, and takes about ten minutes to set up once you have done it the first time.

It is not the right fit for every project, but for the kind of forms most personal sites, portfolios, and small business pages actually need, it is hard to beat the simplicity.

Post a Comment