Google Forms
Trigger workflows on Google Form submissions via an Apps Script forwarder.
The Google Forms trigger fires on every form submission. Google Forms has no native outbound webhook, so MyBotBox uses a small Apps Script forwarder bound to the form's onFormSubmit trigger. Each submission becomes one workflow run with question titles as keys in <googleforms1.answers>.
How to configure
- Google Forms has no native outbound webhook, so the platform uses a small Apps Script forwarder bound to the form's
onFormSubmittrigger. Open your form, click the three-dot menu → Script editor, and paste the snippet below intoCode.gs. - In the Apps Script editor, open Triggers (clock icon in the left rail) → Add Trigger. Set: function =
onFormSubmit, event source =From form, event type =On form submit. Save and grant the OAuth consent (Apps Script will prompt the first time). - If you set a Token on this trigger, the snippet sends it as
Authorization: Bearer <token>(or as the custom header you configured). MyBotBox will reject unsigned requests with401when a token is configured. Read submissions via<googleforms1.answers>(keyed by question title) plus<googleforms1.responseId>,<googleforms1.createTime>. - Verify by submitting the form yourself. Apps Script Executions shows
onFormSubmitwithCompletedstatus, and the workflow execution log shows the matching fire within ~5 seconds. Re-paste the snippet whenever you change the trigger's token or webhook URL.
Apps Script forwarder snippet
// Code.gs — paste into Apps Script editor, set WEBHOOK_URL + TOKEN.
const WEBHOOK_URL = 'https://mybotbox.com/api/webhooks/trigger/<path>';
const TOKEN = 'paste-your-trigger-token-here'; // matches trigger's Token field
function onFormSubmit(e) {
const namedValues = e.namedValues || {};
const answers = {};
for (const [k, v] of Object.entries(namedValues)) {
answers[k] = Array.isArray(v) ? v[0] : v;
}
const payload = {
provider: 'googleforms',
formId: FormApp.getActiveForm().getId(),
responseId: e.response ? e.response.getId() : null,
createTime: new Date().toISOString(),
lastSubmittedTime: new Date().toISOString(),
answers,
raw: { namedValues },
};
UrlFetchApp.fetch(WEBHOOK_URL, {
method: 'post',
contentType: 'application/json',
headers: { Authorization: `Bearer ${TOKEN}` },
payload: JSON.stringify(payload),
muteHttpExceptions: true,
});
}Authentication
The trigger supports the same auth modes as the Generic Webhook: none, bearer, custom_header, or hmac_sha256. The Apps Script snippet above uses bearer — the simplest production-safe option for Apps Script callers.
responseId (when present) is used as the webhook_event_dedup key so a re-run of the Apps Script trigger is idempotent.
Sample payload
{
"provider": "googleforms",
"formId": "1FAIpQLSe-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"responseId": "2_ABaOnudaaQ9k1m9q1L8z",
"createTime": "2026-04-26T21:00:00.000Z",
"lastSubmittedTime": "2026-04-26T21:00:00.000Z",
"answers": {
"Full Name": "Alex Chen",
"Email Address": "alex@example.com",
"How did you hear about us?": "Twitter",
"Rating": "5"
},
"raw": {
"namedValues": {
"Full Name": ["Alex Chen"],
"Email Address": ["alex@example.com"],
"How did you hear about us?": ["Twitter"],
"Rating": ["5"]
}
}
}Downstream blocks read submission fields by question title: <googleforms1.answers["Full Name"]>, <googleforms1.answers["Email Address"]>, etc.
Verify with the bundled scripts
bun apps/sat/tests/staging/triggers/googleforms/verify.ts \
https://mybotbox.com/api/webhooks/trigger/<path> \
--secret=<bearer-token>python3 apps/sat/tests/staging/triggers/googleforms/verify.py \
https://mybotbox.com/api/webhooks/trigger/<path> \
--secret=<bearer-token>Source: apps/sat/tests/staging/triggers/googleforms/.
Troubleshooting
- No fire on form submit — Apps Script trigger isn't installed. Open Apps Script → Triggers, confirm one row for
onFormSubmitwithOn form submitevent type. The first submit after install also surfaces an OAuth consent prompt — accept it. - Apps Script execution shows
Completedbut workflow doesn't fire — token mismatch. Check thatTOKENin the snippet matches the trigger's Token field exactly. UrlFetchApp.fetch401 in execution log — same — token mismatch on abearertrigger.- Question titles change after deploy — the answer map is keyed by question title as it appears at submit time. Renaming a question breaks downstream references; rename then re-deploy the workflow.