Два способи коротко
- Спосіб 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(…) спрацювати як формула.
// У таблиці: 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-форма, яка надсилає дані у вебзастосунок
<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
// 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 і n8n, який можна розгорнути на своєму сервері. Zapier теж підходить, але його тригер для вебхуків потребує платного тарифу Zapier. Тож безкоштовні варіанти — Make або n8n.
Формат JSON і перевірку підпису на власному сервері описано в документації з вебхуків.
Питання та відповіді
Чи можна надсилати HTML-форму в Google Таблиці без коду?
Напряму — ні. Потрібен або невеликий Apps Script, або посередник, наприклад бекенд для форм із Make чи n8n. Скрипт із цієї статті — близько 20 рядків, які достатньо скопіювати.
Чому після надсилання відкривається сторінка Google?
Форма надсилає дані прямо у вебзастосунок, і браузер показує його відповідь. Надсилайте форму через fetch, як у способі 1, або через бекенд для форм, який веде на вашу сторінку подяки.
Чому вебхук створює дублікати рядків?
Відправник побачив помилку й повторив спробу. В Apps Script ContentService відповідає редиректом, і деякі відправники вважають це помилкою. Відповідайте через HtmlService і пропускайте ID заявок, які вже є в таблиці.
Чи безпечно відкривати вебзастосунок для всіх?
Надсилати дані зможе будь-хто з адресою, але прочитати таблицю через неї не можна. Тримайте скрипт простим, перевіряйте секретний ключ для вебхуків і ніколи не повертайте дані таблиці у відповіді.
Джерела та документація
Офіційні джерела для цієї інструкції: Apps Script: web apps, Apps Script: Content service redirects, Apps Script: quotas, Apps Script: Lock service, Stack Overflow: HtmlService avoids the redirect, Zapier pricing. Вебхуки Formgong, де зберігаються дані.
Завантажити текст статті (Markdown)Читайте також
- Заявки з форми Lovable на пошту й у Telegram
- Контактна HTML-форма без бекенду: готовий приклад
- Як отримувати заявки з форми сайту в Telegram
- Форма не надсилає листи: як знайти причину
- Як вести ліди із сайту в Telegram без CRM
- Бекенд для форм із AI-білдерів: Lovable, Bolt, v0, Cursor
- Telegram-бот для форми сайту: писати свій чи ні?
- Сервіс форм і GDPR: 7 пунктів перед вибором
- Форма mailto чи бекенд для форм: що обрати
- Ліміт форм Webflow: що робити після 50 заявок
- Turnstile, reCAPTCHA чи hCaptcha для форми
- Contact Form 7 і Elementor: заявки в Telegram
- Форма Squarespace не надсилає листи?
- Контактна форма Shopify: куди йдуть листи?
- Google Форма в Telegram: безкоштовний спосіб
- Форма Wix не надсилає листи? Рішення
- Альтернативи Formspree з даними в ЄС / GDPR
- Форми, що нічого не надсилають: перевірка 793 AI-сайтів