MyBotBoxMyBotBox

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

  1. Google Forms has no native outbound webhook, so the platform uses a small Apps Script forwarder bound to the form's onFormSubmit trigger. Open your form, click the three-dot menu → Script editor, and paste the snippet below into Code.gs.
  2. 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).
  3. 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 with 401 when a token is configured. Read submissions via <googleforms1.answers> (keyed by question title) plus <googleforms1.responseId>, <googleforms1.createTime>.
  4. Verify by submitting the form yourself. Apps Script Executions shows onFormSubmit with Completed status, 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 onFormSubmit with On form submit event type. The first submit after install also surfaces an OAuth consent prompt — accept it.
  • Apps Script execution shows Completed but workflow doesn't fire — token mismatch. Check that TOKEN in the snippet matches the trigger's Token field exactly.
  • UrlFetchApp.fetch 401 in execution log — same — token mismatch on a bearer trigger.
  • 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.