// Forms · Sheets · Slack

Log form submissions to a spreadsheet in Google Sheets.

Capture every Google Form response into a Sheet with timestamp + parsed fields, then forward a Slack ping for the ones that matter. Single onFormSubmit trigger, no Zapier.

Every time someone submits my form, I want a row in a sheet and a Slack ping if it's urgent.

The script

copy · paste · trigger
logFormSubmission.gs
Apps Script
// Bound to a Google Form. Writes each submission into a Sheet,
// then pings a Slack webhook for high-priority entries.
const SHEET_ID = 'PASTE-YOUR-SHEET-ID';
const SLACK_WEBHOOK = 'https://hooks.slack.com/services/...';

function onFormSubmit(e) {
  const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName('Responses');
  const responses = e.namedValues;

  const row = [
    new Date(),
    responses['Email'] ? responses['Email'][0] : '',
    responses['Subject'] ? responses['Subject'][0] : '',
    responses['Priority'] ? responses['Priority'][0] : 'normal',
    responses['Body'] ? responses['Body'][0] : '',
  ];
  sheet.appendRow(row);

  if (row[3] === 'urgent') {
    UrlFetchApp.fetch(SLACK_WEBHOOK, {
      method: 'post',
      contentType: 'application/json',
      payload: JSON.stringify({
        text: `Urgent: ${row[2]} from ${row[1]}`,
      }),
    });
  }
}

Need a variant? Gnaw writes a custom version from one sentence — fields, triggers, edge cases handled.

Walkthrough

How it works

Apps Script binds to either the Form or the receiving Sheet. The onFormSubmit handler receives an event object with namedValues — a key-value map of the form's answers, indexed by question text.

The handler appends a row with timestamp + parsed fields. Apps Script's appendRow is atomic and safe under concurrent submissions.

For high-priority entries, the script POSTs to a Slack webhook with UrlFetchApp.fetch. That call counts toward your URL-fetch quota (20K/day free, 100K/day Workspace).

How to set the trigger

In the Apps Script editor for the bound Form, open Triggers and add an installable onFormSubmit trigger on the Form. Apps Script will prompt for the Slack URL-fetch scope on first run.

If your script is bound to the Sheet (not the Form), the same handler works — the event object shape is identical.

Why use Apps Script instead of Zapier

Zapier charges per "task" (one form submission = one task). At 1,000 submissions/month you're on a paid plan. Apps Script is free up to enormous quotas.

Apps Script also runs in the same trust boundary as your Sheet — no third party gets a copy of your data, and there's no second auth surface to manage.

Want a custom version?

Describe your sheet and the rule you want. Gnaw writes the Apps Script — fields, triggers, edge cases — in one shot.

FAQ

4 questions
Where do I find the Sheet ID?
Open the Sheet in your browser. The ID is the long string between /d/ and /edit in the URL. Copy it into SHEET_ID.
How do I add more priority levels?
Replace the row[3] === 'urgent' check with a switch or a lookup table. The bulldo.gs generator can scaffold the new shape from a one-line description.
Will this work without a paid Slack workspace?
Yes. Slack incoming webhooks are free on every tier. The webhook URL is the only credential the script needs.
What happens if the trigger fires twice for one submission?
Google deduplicates onFormSubmit triggers — you'll only see one fire per submission. If you do see duplicates, check that you haven't bound the same handler to both the Form and the Sheet.