# HTML-форма в Google Таблиці: 2 безкоштовні шляхи

Як надсилати HTML-форму в Google Таблиці безкоштовно: напряму в Apps Script або через вебхук сервісу форм. Робочий код, пастка з редиректом і обмеження.

Author: Formgong
Published: 2026-10-05
Language: uk
Canonical: https://formgong.com/uk/blog/html-form-to-google-sheets/

Відкрийте таблицю й додайте Apps Script із функцією doPost, яка дописує рядок. Розгорніть його як вебзастосунок із доступом для всіх і надсилайте форму на його адресу. Потрібні ще сповіщення на пошту чи в Telegram і фільтр спаму? Надсилайте форму на бекенд для форм, а його вебхук хай викликає такий самий скрипт. Обидва способи безкоштовні.

## Два способи коротко

- **Спосіб 1: форма → Apps Script.** Форма надсилає дані прямо в маленький скрипт у вашій таблиці. Більше нічого не потрібно. Ви отримуєте рядки, але без сповіщень, без фільтра спаму понад те, що напишете самі, і форма потребує JavaScript.

- **Спосіб 2: форма → бекенд для форм → Apps Script.** Форма йде на бекенд. Він відсіює спам, надсилає вам сповіщення, а потім передає кожну справжню заявку у ваш скрипт через вебхук.

Якщо потрібен лише список, почніть зі способу 1. Якщо на заявки треба швидко відповідати, обирайте спосіб 2.

## Спосіб 1: форма надсилає дані в Apps Script

Назви пунктів меню наведено, як в англійському інтерфейсі Google. В українському вони перекладені, але стоять на тих самих місцях.

- Створіть таблицю, назвіть аркуш `Заявки` і впишіть у перший рядок: Дата, Ім'я, Email, Повідомлення.

- Відкрийте **Extensions → Apps Script**, видаліть приклад і вставте скрипт нижче.

- Натисніть **Deploy → New deployment**, оберіть **Web app**. У полі Execute as поставте **Me**, у Who has access — **Anyone**.

- Підтвердьте дозволи й скопіюйте адресу вебзастосунку. Вона закінчується на `/exec`.

- Вставте цю адресу в код форми з наступного блоку й опублікуйте сторінку.

Скрипт пропускає заявки із заповненим полем-пасткою. Він також бере блокування, тож дві одночасні заявки не перезапишуть одна одну. Функція `clean()` не дає значенню на кшталт `=IMPORTXML(…)` спрацювати як формула.

```javascript
// У таблиці: Extensions > Apps Script. У першому рядку аркуша "Заявки" — назви стовпців.
function doPost(e) {
  const p = e.parameter;
  if (p.botcheck) return json({ ok: true }); // поле-пастка: боти його заповнюють, люди не бачать
  const lock = LockService.getScriptLock();
  lock.waitLock(20000); // записуємо по одному, щоб рядки не перезаписали один одного
  try {
    SpreadsheetApp.getActive().getSheetByName("Заявки").appendRow([
      new Date(), clean(p.name), clean(p.email), clean(p.message),
    ]);
  } finally {
    lock.releaseLock();
  }
  return json({ ok: true });
}

// Значення, що починається з = + - або @, спрацювало б як формула. Апостроф лишає його текстом.
function clean(value) {
  const text = String(value || "");
  return /^[=+\-@]/.test(text) ? "'" + text : text;
}

function json(data) {
  return ContentService.createTextOutput(JSON.stringify(data))
    .setMimeType(ContentService.MimeType.JSON);
}
```

**HTML-форма, яка надсилає дані у вебзастосунок**

```html
<form id="lead-form">
  <label>Ім'я <input type="text" name="name" required autocomplete="name"></label>
  <label>Email <input type="email" name="email" required autocomplete="email"></label>
  <label>Повідомлення <textarea name="message" required></textarea></label>
  <div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
    <input type="text" name="botcheck" tabindex="-1" autocomplete="off">
  </div>
  <button type="submit">Надіслати</button>
  <p id="lead-status" role="status"></p>
</form>
<script>
  const form = document.getElementById("lead-form");
  const status = document.getElementById("lead-status");
  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    status.textContent = "Надсилаємо…";
    try {
      // Тіло у форматі форми робить запит простим, тож браузер не надсилає preflight.
      const response = await fetch("https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec", {
        method: "POST",
        body: new URLSearchParams(new FormData(form)),
      });
      if (!response.ok) throw new Error(String(response.status));
      form.reset();
      status.textContent = "Дякуємо, заявку отримано.";
    } catch {
      status.textContent = "Не вдалося надіслати. Спробуйте ще раз або напишіть нам на пошту.";
    }
  });
</script>
```

## Чого не вміє спосіб 1

- **Немає сповіщень.** Рядки з'являються тихо. Щоб побачити нову заявку, треба відкрити таблицю.

- **Слабкий захист від спаму.** Адреса публічна, тож будь-хто, хто її знайде, може щось надіслати. Поле-пастка зупиняє лише простих ботів.

- **Потрібен JavaScript.** Форма використовує `fetch`, бо звичайне надсилання залишило б відвідувача на сторінці Google.

- **Зміни — це нова версія.** Після правок у скрипті відкрийте **Manage deployments**, відредагуйте розгортання й оберіть нову версію. Адреса не зміниться.

- **Квоти.** Google обмежує Apps Script для кожного користувача: наприклад, 30 одночасних запусків і 6 хвилин на один запуск (станом на 05.10.2026). Невеликий сайт цього не помітить.

## Спосіб 2: вебхук бекенду для форм у вашу таблицю

Тут форма — звичайна HTML-форма, яка надсилає дані на Formgong. Вона працює без JavaScript і показує сторінку подяки. Formgong відсіює спам, надсилає заявку на пошту чи в Telegram, а потім передає JSON у ваш скрипт. Безкоштовний тариф включає один вебхук на форму.

- Створіть таблицю й аркуш `Заявки` зі стовпцями: ID, Дата, Ім'я, Email, Повідомлення.

- Вставте скрипт для вебхука нижче, змініть `SECRET` і розгорніть його як вебзастосунок, як у способі 1.

- У Formgong відкрийте налаштування форми й додайте вебхук. Вкажіть адресу вебзастосунку плюс `?key=` і ваш секрет.

- Натисніть тест вебхука в кабінеті, а потім надішліть справжню заявку із сайту.

**Apps Script для вебхука Formgong**

```javascript
// URL вебхука у Formgong: адреса вебзастосунку + "?key=" + той самий SECRET.
// Apps Script не бачить заголовків запиту, тому ключ в адресі замінює перевірку підпису.
const SECRET = "change-me";

function doPost(e) {
  if (e.parameter.key !== SECRET) return reply();
  const body = JSON.parse(e.postData.contents);
  if (body.event !== "submission.created") return reply(); // тест із кабінету надсилає подію "webhook.test"
  const lock = LockService.getScriptLock();
  lock.waitLock(20000);
  try {
    const sheet = SpreadsheetApp.getActive().getSheetByName("Заявки");
    const id = body.submission.id;
    // Повторна спроба має той самий id: пропускаємо, якщо рядок уже є.
    if (!sheet.getRange("A:A").createTextFinder(id).matchEntireCell(true).findNext()) {
      const f = body.submission.fields;
      sheet.appendRow([id, body.submission.created_at, clean(f.name), clean(f.email), clean(f.message)]);
    }
  } finally {
    lock.releaseLock();
  }
  return reply();
}

function clean(value) {
  const text = String(value || "");
  return /^[=+\-@]/.test(text) ? "'" + text : text;
}

// HtmlService, а не ContentService: ContentService відповідає редиректом,
// а відправник вебхуків, який не йде за редиректами, вважає це помилкою.
function reply() {
  return HtmlService.createHtmlOutput("ok");
}
```

## Пастка з редиректом, через яку з'являються дублікати

Google пише, що скрипт, який відповідає через `ContentService`, повертає редирект на одноразову адресу на `script.googleusercontent.com`. Браузер іде за ним, тож для способу 1 усе гаразд. А відправник вебхуків, який не йде за редиректами, бачить помилку, хоча рядок уже записано.

Formgong з міркувань безпеки не йде за редиректами вебхуків. Він вважає редирект невдалою доставкою й пробує ще раз пізніше, до п'яти спроб. Кожна спроба запускає скрипт, тож одна заявка може з'явитися п'ять разів. Скрипт для вебхука запобігає цьому двома способами:

- Відповідає через `HtmlService`. За словами розробників, така відповідь приходить одразу, без редиректу.

- Записує ID заявки в стовпець A і пропускає ID, які вже є. Навіть якщо повтор станеться, рядок буде один.

Після налаштування відкрийте журнал вебхуків у кабінеті. Справжня заявка має показати статус 200 з першої спроби.

## Без коду: Make, n8n або Zapier

Не хочете чіпати Apps Script? Спрямуйте вебхук в інструмент автоматизації й додайте там крок Google Sheets. Покрокові інструкції є для [Make](/uk/integrations/make/) і [n8n](/uk/integrations/n8n/), який можна розгорнути на своєму сервері. Zapier теж підходить, але його тригер для вебхуків потребує платного тарифу Zapier. Тож безкоштовні варіанти — Make або n8n.

Формат JSON і перевірку підпису на власному сервері описано в [документації з вебхуків](/uk/docs/webhooks/).

## Питання та відповіді

### Чи можна надсилати HTML-форму в Google Таблиці без коду?

Напряму — ні. Потрібен або невеликий Apps Script, або посередник, наприклад бекенд для форм із Make чи n8n. Скрипт із цієї статті — близько 20 рядків, які достатньо скопіювати.

### Чому після надсилання відкривається сторінка Google?

Форма надсилає дані прямо у вебзастосунок, і браузер показує його відповідь. Надсилайте форму через fetch, як у способі 1, або через бекенд для форм, який веде на вашу сторінку подяки.

### Чому вебхук створює дублікати рядків?

Відправник побачив помилку й повторив спробу. В Apps Script ContentService відповідає редиректом, і деякі відправники вважають це помилкою. Відповідайте через HtmlService і пропускайте ID заявок, які вже є в таблиці.

### Чи безпечно відкривати вебзастосунок для всіх?

Надсилати дані зможе будь-хто з адресою, але прочитати таблицю через неї не можна. Тримайте скрипт простим, перевіряйте секретний ключ для вебхуків і ніколи не повертайте дані таблиці у відповіді.

## Джерела та документація

- [Apps Script: web apps](https://developers.google.com/apps-script/guides/web)
- [Apps Script: Content service redirects](https://developers.google.com/apps-script/guides/content)
- [Apps Script: quotas](https://developers.google.com/apps-script/guides/services/quotas)
- [Apps Script: Lock service](https://developers.google.com/apps-script/reference/lock/lock-service)
- [Stack Overflow: HtmlService avoids the redirect](https://stackoverflow.com/questions/65873559)
- [Zapier pricing](https://zapier.com/pricing)
- [Вебхуки Formgong](https://formgong.com/uk/docs/webhooks/)

[Отримати ключ](https://formgong.com/uk/#top)
