[{"data":1,"prerenderedAt":824},["ShallowReactive",2],{"content-query-myKpOMgfVr":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"layout":10,"author":11,"tags":12,"categories":17,"date":19,"image":20,"faq":21,"body":31,"_type":817,"_id":818,"_source":819,"_file":820,"_stem":821,"_extension":822,"sitemap":823},"/blog/google-forms-webhook","blog",false,"","How to Send a Webhook from Google Forms (Apps Script)","Google Forms has no built-in webhooks, but you can POST every response to a URL with a few lines of Google Apps Script and an on-form-submit trigger. Here's the correct setup — no web-app deployment needed — with copy-paste code.","post","Karolis Rusenas",[13,14,15,16],"google forms","webhooks","apps script","guide",[18],"guides","2026-07-21 10:30:00","/images/generic/webhooks.png",[22,25,28],{"q":23,"a":24},"Does Google Forms support webhooks?","Not natively. Google Forms has no built-in webhook option, but you can add one with Google Apps Script: attach a script to the form, POST the response to your endpoint with UrlFetchApp, and run it from an installable 'On form submit' trigger.",{"q":26,"a":27},"Do I need to deploy the Apps Script as a web app?","No. For sending a webhook when a form is submitted you only need an installable on-form-submit trigger — not a web-app deployment. Deploying as a web app is for a different use case (receiving inbound HTTP requests), and adding it here just creates a public endpoint you don't need.",{"q":29,"a":30},"Why does my Google Forms webhook fail with a permissions error?","A simple trigger (a function literally named onFormSubmit that runs automatically) can't call services that need authorization, like UrlFetchApp. Use an installable trigger instead: Triggers → Add Trigger → choose your function, event source 'From form', event type 'On form submit', then authorize it once.",{"type":32,"children":33,"toc":809},"root",[34,66,73,78,109,129,135,154,160,173,557,575,581,607,677,683,710,716,737,782,803],{"type":35,"tag":36,"props":37,"children":38},"element","p",{},[39,42,48,50,55,57,64],{"type":40,"value":41},"text","Google Forms is great at collecting responses but has ",{"type":35,"tag":43,"props":44,"children":45},"strong",{},[46],{"type":40,"value":47},"no native webhooks",{"type":40,"value":49}," — there's no field where you paste a URL. The fix is a few lines of ",{"type":35,"tag":43,"props":51,"children":52},{},[53],{"type":40,"value":54},"Google Apps Script",{"type":40,"value":56}," that POST each response to your endpoint. This guide shows the correct, minimal setup, and avoids a step you'll see in other tutorials that you don't actually need. (New to webhooks? See ",{"type":35,"tag":58,"props":59,"children":61},"a",{"href":60},"/blog/what-is-webhook",[62],{"type":40,"value":63},"what is a webhook",{"type":40,"value":65},".)",{"type":35,"tag":67,"props":68,"children":70},"h2",{"id":69},"the-approach",[71],{"type":40,"value":72},"The approach",{"type":35,"tag":36,"props":74,"children":75},{},[76],{"type":40,"value":77},"Every Google Form can have a bound Apps Script. We'll:",{"type":35,"tag":79,"props":80,"children":81},"ol",{},[82,97],{"type":35,"tag":83,"props":84,"children":85},"li",{},[86,88,95],{"type":40,"value":87},"Add a function that turns a submitted response into JSON and POSTs it with ",{"type":35,"tag":89,"props":90,"children":92},"code",{"className":91},[],[93],{"type":40,"value":94},"UrlFetchApp",{"type":40,"value":96},".",{"type":35,"tag":83,"props":98,"children":99},{},[100,102,107],{"type":40,"value":101},"Wire it to an ",{"type":35,"tag":43,"props":103,"children":104},{},[105],{"type":40,"value":106},"installable \"On form submit\" trigger",{"type":40,"value":108}," so it runs on every submission.",{"type":35,"tag":36,"props":110,"children":111},{},[112,114,119,121,127],{"type":40,"value":113},"That's it — ",{"type":35,"tag":43,"props":115,"children":116},{},[117],{"type":40,"value":118},"no \"Deploy as web app\"",{"type":40,"value":120}," step. (Deploying as a web app is for ",{"type":35,"tag":122,"props":123,"children":124},"em",{},[125],{"type":40,"value":126},"receiving",{"type":40,"value":128}," HTTP requests, not for sending one on submit; adding it here just exposes an endpoint you don't need.)",{"type":35,"tag":67,"props":130,"children":132},{"id":131},"step-1-open-the-script-editor",[133],{"type":40,"value":134},"Step 1 — open the script editor",{"type":35,"tag":36,"props":136,"children":137},{},[138,140,145,147,152],{"type":40,"value":139},"In the form editor, click the ",{"type":35,"tag":43,"props":141,"children":142},{},[143],{"type":40,"value":144},"⋮ (three dots)",{"type":40,"value":146}," menu (top-right, near Send) → ",{"type":35,"tag":43,"props":148,"children":149},{},[150],{"type":40,"value":151},"Apps Script",{"type":40,"value":153},". This opens a script bound to your form.",{"type":35,"tag":67,"props":155,"children":157},{"id":156},"step-2-add-the-code",[158],{"type":40,"value":159},"Step 2 — add the code",{"type":35,"tag":36,"props":161,"children":162},{},[163,165,171],{"type":40,"value":164},"Replace the default contents with this, and set ",{"type":35,"tag":89,"props":166,"children":168},{"className":167},[],[169],{"type":40,"value":170},"ENDPOINT_URL",{"type":40,"value":172}," to your webhook URL:",{"type":35,"tag":174,"props":175,"children":179},"pre",{"className":176,"code":177,"language":178,"meta":7,"style":7},"language-javascript shiki shiki-themes github-dark","const ENDPOINT_URL = 'https://your-endpoint.example.com/webhook';\n\nfunction onFormSubmit(e) {\n  const payload = {};\n  // e.response is the FormResponse for THIS submission\n  e.response.getItemResponses().forEach(function (item) {\n    payload[item.getItem().getTitle()] = item.getResponse();\n  });\n  payload.submittedAt = e.response.getTimestamp();\n\n  UrlFetchApp.fetch(ENDPOINT_URL, {\n    method: 'post',\n    contentType: 'application/json',\n    payload: JSON.stringify(payload),\n    muteHttpExceptions: true,\n  });\n}\n","javascript",[180],{"type":35,"tag":89,"props":181,"children":182},{"__ignoreMap":7},[183,218,228,259,282,292,338,386,395,422,430,457,476,494,522,540,548],{"type":35,"tag":184,"props":185,"children":188},"span",{"class":186,"line":187},"line",1,[189,195,201,206,212],{"type":35,"tag":184,"props":190,"children":192},{"style":191},"--shiki-default:#F97583",[193],{"type":40,"value":194},"const",{"type":35,"tag":184,"props":196,"children":198},{"style":197},"--shiki-default:#79B8FF",[199],{"type":40,"value":200}," ENDPOINT_URL",{"type":35,"tag":184,"props":202,"children":203},{"style":191},[204],{"type":40,"value":205}," =",{"type":35,"tag":184,"props":207,"children":209},{"style":208},"--shiki-default:#9ECBFF",[210],{"type":40,"value":211}," 'https://your-endpoint.example.com/webhook'",{"type":35,"tag":184,"props":213,"children":215},{"style":214},"--shiki-default:#E1E4E8",[216],{"type":40,"value":217},";\n",{"type":35,"tag":184,"props":219,"children":221},{"class":186,"line":220},2,[222],{"type":35,"tag":184,"props":223,"children":225},{"emptyLinePlaceholder":224},true,[226],{"type":40,"value":227},"\n",{"type":35,"tag":184,"props":229,"children":231},{"class":186,"line":230},3,[232,237,243,248,254],{"type":35,"tag":184,"props":233,"children":234},{"style":191},[235],{"type":40,"value":236},"function",{"type":35,"tag":184,"props":238,"children":240},{"style":239},"--shiki-default:#B392F0",[241],{"type":40,"value":242}," onFormSubmit",{"type":35,"tag":184,"props":244,"children":245},{"style":214},[246],{"type":40,"value":247},"(",{"type":35,"tag":184,"props":249,"children":251},{"style":250},"--shiki-default:#FFAB70",[252],{"type":40,"value":253},"e",{"type":35,"tag":184,"props":255,"children":256},{"style":214},[257],{"type":40,"value":258},") {\n",{"type":35,"tag":184,"props":260,"children":262},{"class":186,"line":261},4,[263,268,273,277],{"type":35,"tag":184,"props":264,"children":265},{"style":191},[266],{"type":40,"value":267},"  const",{"type":35,"tag":184,"props":269,"children":270},{"style":197},[271],{"type":40,"value":272}," payload",{"type":35,"tag":184,"props":274,"children":275},{"style":191},[276],{"type":40,"value":205},{"type":35,"tag":184,"props":278,"children":279},{"style":214},[280],{"type":40,"value":281}," {};\n",{"type":35,"tag":184,"props":283,"children":285},{"class":186,"line":284},5,[286],{"type":35,"tag":184,"props":287,"children":289},{"style":288},"--shiki-default:#6A737D",[290],{"type":40,"value":291},"  // e.response is the FormResponse for THIS submission\n",{"type":35,"tag":184,"props":293,"children":295},{"class":186,"line":294},6,[296,301,306,311,316,320,324,329,334],{"type":35,"tag":184,"props":297,"children":298},{"style":214},[299],{"type":40,"value":300},"  e.response.",{"type":35,"tag":184,"props":302,"children":303},{"style":239},[304],{"type":40,"value":305},"getItemResponses",{"type":35,"tag":184,"props":307,"children":308},{"style":214},[309],{"type":40,"value":310},"().",{"type":35,"tag":184,"props":312,"children":313},{"style":239},[314],{"type":40,"value":315},"forEach",{"type":35,"tag":184,"props":317,"children":318},{"style":214},[319],{"type":40,"value":247},{"type":35,"tag":184,"props":321,"children":322},{"style":191},[323],{"type":40,"value":236},{"type":35,"tag":184,"props":325,"children":326},{"style":214},[327],{"type":40,"value":328}," (",{"type":35,"tag":184,"props":330,"children":331},{"style":250},[332],{"type":40,"value":333},"item",{"type":35,"tag":184,"props":335,"children":336},{"style":214},[337],{"type":40,"value":258},{"type":35,"tag":184,"props":339,"children":341},{"class":186,"line":340},7,[342,347,352,356,361,366,371,376,381],{"type":35,"tag":184,"props":343,"children":344},{"style":214},[345],{"type":40,"value":346},"    payload[item.",{"type":35,"tag":184,"props":348,"children":349},{"style":239},[350],{"type":40,"value":351},"getItem",{"type":35,"tag":184,"props":353,"children":354},{"style":214},[355],{"type":40,"value":310},{"type":35,"tag":184,"props":357,"children":358},{"style":239},[359],{"type":40,"value":360},"getTitle",{"type":35,"tag":184,"props":362,"children":363},{"style":214},[364],{"type":40,"value":365},"()] ",{"type":35,"tag":184,"props":367,"children":368},{"style":191},[369],{"type":40,"value":370},"=",{"type":35,"tag":184,"props":372,"children":373},{"style":214},[374],{"type":40,"value":375}," item.",{"type":35,"tag":184,"props":377,"children":378},{"style":239},[379],{"type":40,"value":380},"getResponse",{"type":35,"tag":184,"props":382,"children":383},{"style":214},[384],{"type":40,"value":385},"();\n",{"type":35,"tag":184,"props":387,"children":389},{"class":186,"line":388},8,[390],{"type":35,"tag":184,"props":391,"children":392},{"style":214},[393],{"type":40,"value":394},"  });\n",{"type":35,"tag":184,"props":396,"children":398},{"class":186,"line":397},9,[399,404,408,413,418],{"type":35,"tag":184,"props":400,"children":401},{"style":214},[402],{"type":40,"value":403},"  payload.submittedAt ",{"type":35,"tag":184,"props":405,"children":406},{"style":191},[407],{"type":40,"value":370},{"type":35,"tag":184,"props":409,"children":410},{"style":214},[411],{"type":40,"value":412}," e.response.",{"type":35,"tag":184,"props":414,"children":415},{"style":239},[416],{"type":40,"value":417},"getTimestamp",{"type":35,"tag":184,"props":419,"children":420},{"style":214},[421],{"type":40,"value":385},{"type":35,"tag":184,"props":423,"children":425},{"class":186,"line":424},10,[426],{"type":35,"tag":184,"props":427,"children":428},{"emptyLinePlaceholder":224},[429],{"type":40,"value":227},{"type":35,"tag":184,"props":431,"children":433},{"class":186,"line":432},11,[434,439,444,448,452],{"type":35,"tag":184,"props":435,"children":436},{"style":214},[437],{"type":40,"value":438},"  UrlFetchApp.",{"type":35,"tag":184,"props":440,"children":441},{"style":239},[442],{"type":40,"value":443},"fetch",{"type":35,"tag":184,"props":445,"children":446},{"style":214},[447],{"type":40,"value":247},{"type":35,"tag":184,"props":449,"children":450},{"style":197},[451],{"type":40,"value":170},{"type":35,"tag":184,"props":453,"children":454},{"style":214},[455],{"type":40,"value":456},", {\n",{"type":35,"tag":184,"props":458,"children":460},{"class":186,"line":459},12,[461,466,471],{"type":35,"tag":184,"props":462,"children":463},{"style":214},[464],{"type":40,"value":465},"    method: ",{"type":35,"tag":184,"props":467,"children":468},{"style":208},[469],{"type":40,"value":470},"'post'",{"type":35,"tag":184,"props":472,"children":473},{"style":214},[474],{"type":40,"value":475},",\n",{"type":35,"tag":184,"props":477,"children":479},{"class":186,"line":478},13,[480,485,490],{"type":35,"tag":184,"props":481,"children":482},{"style":214},[483],{"type":40,"value":484},"    contentType: ",{"type":35,"tag":184,"props":486,"children":487},{"style":208},[488],{"type":40,"value":489},"'application/json'",{"type":35,"tag":184,"props":491,"children":492},{"style":214},[493],{"type":40,"value":475},{"type":35,"tag":184,"props":495,"children":497},{"class":186,"line":496},14,[498,503,508,512,517],{"type":35,"tag":184,"props":499,"children":500},{"style":214},[501],{"type":40,"value":502},"    payload: ",{"type":35,"tag":184,"props":504,"children":505},{"style":197},[506],{"type":40,"value":507},"JSON",{"type":35,"tag":184,"props":509,"children":510},{"style":214},[511],{"type":40,"value":96},{"type":35,"tag":184,"props":513,"children":514},{"style":239},[515],{"type":40,"value":516},"stringify",{"type":35,"tag":184,"props":518,"children":519},{"style":214},[520],{"type":40,"value":521},"(payload),\n",{"type":35,"tag":184,"props":523,"children":525},{"class":186,"line":524},15,[526,531,536],{"type":35,"tag":184,"props":527,"children":528},{"style":214},[529],{"type":40,"value":530},"    muteHttpExceptions: ",{"type":35,"tag":184,"props":532,"children":533},{"style":197},[534],{"type":40,"value":535},"true",{"type":35,"tag":184,"props":537,"children":538},{"style":214},[539],{"type":40,"value":475},{"type":35,"tag":184,"props":541,"children":543},{"class":186,"line":542},16,[544],{"type":35,"tag":184,"props":545,"children":546},{"style":214},[547],{"type":40,"value":394},{"type":35,"tag":184,"props":549,"children":551},{"class":186,"line":550},17,[552],{"type":35,"tag":184,"props":553,"children":554},{"style":214},[555],{"type":40,"value":556},"}\n",{"type":35,"tag":36,"props":558,"children":559},{},[560,562,573],{"type":40,"value":561},"Using the ",{"type":35,"tag":43,"props":563,"children":564},{},[565,567],{"type":40,"value":566},"event object ",{"type":35,"tag":89,"props":568,"children":570},{"className":569},[],[571],{"type":40,"value":572},"e.response",{"type":40,"value":574}," is more reliable than fetching \"the latest response\" from the form — it's exactly the submission that fired the trigger, with no race conditions.",{"type":35,"tag":67,"props":576,"children":578},{"id":577},"step-3-add-an-installable-trigger",[579],{"type":40,"value":580},"Step 3 — add an installable trigger",{"type":35,"tag":36,"props":582,"children":583},{},[584,586,591,593,598,600,605],{"type":40,"value":585},"This is the step that trips people up. Because ",{"type":35,"tag":89,"props":587,"children":589},{"className":588},[],[590],{"type":40,"value":94},{"type":40,"value":592}," needs authorization, a ",{"type":35,"tag":122,"props":594,"children":595},{},[596],{"type":40,"value":597},"simple",{"type":40,"value":599}," trigger won't work — you need an ",{"type":35,"tag":43,"props":601,"children":602},{},[603],{"type":40,"value":604},"installable",{"type":40,"value":606}," one:",{"type":35,"tag":79,"props":608,"children":609},{},[610,622,631,660],{"type":35,"tag":83,"props":611,"children":612},{},[613,615,620],{"type":40,"value":614},"In the Apps Script editor, click the ",{"type":35,"tag":43,"props":616,"children":617},{},[618],{"type":40,"value":619},"Triggers",{"type":40,"value":621}," icon (the alarm clock) in the left sidebar.",{"type":35,"tag":83,"props":623,"children":624},{},[625,630],{"type":35,"tag":43,"props":626,"children":627},{},[628],{"type":40,"value":629},"Add Trigger",{"type":40,"value":96},{"type":35,"tag":83,"props":632,"children":633},{},[634,636,645,647,652,654,659],{"type":40,"value":635},"Choose function ",{"type":35,"tag":43,"props":637,"children":638},{},[639],{"type":35,"tag":89,"props":640,"children":642},{"className":641},[],[643],{"type":40,"value":644},"onFormSubmit",{"type":40,"value":646},", event source ",{"type":35,"tag":43,"props":648,"children":649},{},[650],{"type":40,"value":651},"From form",{"type":40,"value":653},", event type ",{"type":35,"tag":43,"props":655,"children":656},{},[657],{"type":40,"value":658},"On form submit",{"type":40,"value":96},{"type":35,"tag":83,"props":661,"children":662},{},[663,668,670,675],{"type":35,"tag":43,"props":664,"children":665},{},[666],{"type":40,"value":667},"Save",{"type":40,"value":669},", then ",{"type":35,"tag":43,"props":671,"children":672},{},[673],{"type":40,"value":674},"authorize",{"type":40,"value":676}," the script when Google prompts (you'll approve the permissions once).",{"type":35,"tag":67,"props":678,"children":680},{"id":679},"step-4-test-it",[681],{"type":40,"value":682},"Step 4 — test it",{"type":35,"tag":36,"props":684,"children":685},{},[686,688,693,695,701,703,708],{"type":40,"value":687},"First, capture what the form sends by pointing ",{"type":35,"tag":89,"props":689,"children":691},{"className":690},[],[692],{"type":40,"value":170},{"type":40,"value":694}," at a free ",{"type":35,"tag":58,"props":696,"children":698},{"href":697},"/webhook-bin",[699],{"type":40,"value":700},"Webhook Bin",{"type":40,"value":702}," — submit a test response and you'll see the exact JSON arrive. Then switch ",{"type":35,"tag":89,"props":704,"children":706},{"className":705},[],[707],{"type":40,"value":170},{"type":40,"value":709}," to your real handler.",{"type":35,"tag":67,"props":711,"children":713},{"id":712},"where-the-webhook-goes-next",[714],{"type":40,"value":715},"Where the webhook goes next",{"type":35,"tag":36,"props":717,"children":718},{},[719,721,727,729,735],{"type":40,"value":720},"Once your form responses are flowing as webhooks, Webhook Relay can route them anywhere: ",{"type":35,"tag":58,"props":722,"children":724},{"href":723},"/features/transform-webhooks",[725],{"type":40,"value":726},"transform",{"type":40,"value":728}," each submission and ",{"type":35,"tag":58,"props":730,"children":732},{"href":731},"/features/webhook-multiple-destinations",[733],{"type":40,"value":734},"fan it out",{"type":40,"value":736}," to multiple destinations, or deliver to a service on your own machine.",{"type":35,"tag":738,"props":739,"children":740},"ul",{},[741,752,771],{"type":35,"tag":83,"props":742,"children":743},{},[744,750],{"type":35,"tag":58,"props":745,"children":747},{"href":746},"/blog/webhook-to-google-sheets",[748],{"type":40,"value":749},"Webhook to Google Sheets",{"type":40,"value":751}," — log every submission to a sheet.",{"type":35,"tag":83,"props":753,"children":754},{},[755,761,763,769],{"type":35,"tag":58,"props":756,"children":758},{"href":757},"/blog/webhook-to-slack",[759],{"type":40,"value":760},"Webhook to Slack",{"type":40,"value":762}," or ",{"type":35,"tag":58,"props":764,"children":766},{"href":765},"/blog/webhook-to-discord",[767],{"type":40,"value":768},"Discord",{"type":40,"value":770}," — get notified on each response.",{"type":35,"tag":83,"props":772,"children":773},{},[774,780],{"type":35,"tag":58,"props":775,"children":777},{"href":776},"/webhooks",[778],{"type":40,"value":779},"Receive it on localhost",{"type":40,"value":781}," — drive a local handler with real submissions.",{"type":35,"tag":36,"props":783,"children":784},{},[785,787,792,794,802],{"type":40,"value":786},"Ready to turn form submissions into webhooks? ",{"type":35,"tag":58,"props":788,"children":789},{"href":697},[790],{"type":40,"value":791},"Grab a free Webhook Bin",{"type":40,"value":793}," to see your first one, or ",{"type":35,"tag":58,"props":795,"children":799},{"href":796,"rel":797},"https://my.webhookrelay.com/register",[798],"nofollow",[800],{"type":40,"value":801},"start forwarding for free",{"type":40,"value":96},{"type":35,"tag":804,"props":805,"children":806},"style",{},[807],{"type":40,"value":808},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":230,"depth":230,"links":810},[811,812,813,814,815,816],{"id":69,"depth":220,"text":72},{"id":131,"depth":220,"text":134},{"id":156,"depth":220,"text":159},{"id":577,"depth":220,"text":580},{"id":679,"depth":220,"text":682},{"id":712,"depth":220,"text":715},"markdown","content:blog:google-forms-webhook.md","content","blog/google-forms-webhook.md","blog/google-forms-webhook","md",{"loc":4},1784660737306]