Web

Fix HTML form POST to Google Apps Script Web App (2025)

Fix HTML form POST failures to Google Apps Script web apps after June 2025. Redeploy the web app, reauthorize scopes, update /exec URL, and avoid CORS preflight.

1 answer 1 view

HTML form posting to a Google Apps Script web app URL (action=“https://script.google.com/macros/s/AKfycbyzSs8KWgP6lgtOS83j9LLxJmQ5S8qmOrURFPUM/exec”) stopped working since June 2025 — how can I fix it?

I have used the following HTML form on my personal site since 2014. It worked until June 2025 but now submissions no longer reach the Apps Script web app. What changed in Apps Script deployment/authentication and what steps should I take to redeploy or update the form so POST submissions work again?

Form markup:

html
<form class="gform pure-form pure-form-stacked" method="POST" data-email="toto@toto.fr" action="https://script.google.com/macros/s/AKfycbyzSs8KWgP6lgtOS83j9LLxJmQ5S8qmOrURFPUM/exec">
 <div class="form-elements">
 <fieldset class="pure-group">
 <label for="name">Vos nom et prénom: </label>
 <input id="name" name="name" placeholder="nom et prenom" />
 </fieldset>
 <fieldset class="pure-group">
 <label for="message">Message: </label>
 <textarea id="message" name="message" rows="10" placeholder="votre message"></textarea>
 </fieldset>
 <fieldset class="pure-group">
 <label for="email">Votre adresse Email:</label>
 <input id="email" name="email" type="email" value="" required placeholder="name@email.fr"/>
 <span class="email-invalid" style="display:none">Veuillez mettre une adresse valide</span>
 </fieldset>
 <!-- <fieldset class="pure-group">
 <label for="color">Favourite Color: </label>
 <input id="color" name="color" placeholder="green" />
 </fieldset> -->
 <button class="button-success pure-button button-xlarge"> <i class="fa fa-paper-plane"></i> ENVOI</button>
 </div>
 <!-- Customise the Thankyou Message People See when they submit the form: -->
 <div class="thankyou_message" style="display:none;">
 <h2><em>Merci</em> de m'avoir contacter Je vous répondrais bientôt !</h2>
 </div>
</form>

Any suggestions for troubleshooting (redeploy options, access settings, CORS/authorization changes, or other fixes) to restore form submissions?

Your HTML form stopped reaching the Google Apps Script web app because Apps Script changed deployments, OAuth/granular consent, and runtime behavior in 2025 — old deployment IDs, missing re‑authorization, or access settings (anonymous posts) are the usual culprits. Redeploy the web app (Deploy → New deployment → Web app), set Execute as → Me and Who has access → Anyone, even anonymous, copy the new /exec URL into your form action, re‑authorize required scopes, and test with curl or the Executions log; if you use AJAX, avoid preflight (send text/plain or application/x-www-form-urlencoded) or implement doOptions/doPost parsing.


Contents


What changed in Google Apps Script (June 2025)

Short version: several platform and policy changes in 2024–2025 made older public web‑app setups fragile. In particular:

  • Granular OAuth / consent changes rolled out starting January 2025 that change how scripts request and receive scopes from users and the IDE; scripts that need new scopes may require re‑authorization or verification (Workspace updates blog).
  • Deployment and runtime behavior evolution: the deployment model requires creating and managing explicit deployments and a redeploy is needed when the project changes; old deployment IDs can become invalid if a deployment was removed or recreated (Deployments doc, release notes).
  • Runtime changes (Rhino → V8) and other infra updates were announced; while runtime migration alone usually doesn’t drop POSTs, it can require small code changes and re‑testing (release notes).
  • Finally, community reports in mid‑2025 described platform regressions where POSTs returned 500 or 405 and doPost never ran — hinting at server‑side handling changes that can break older client flows (Google Groups report, Developer forum thread).

So: if your site has been posting to the same /exec URL since 2014, either the deployment behind that URL was changed/deleted, your script now needs scopes/verification, or browser/request behavior (preflight/CORS) is interfering.


Quick‑check checklist (fast path)

Try these checks in order — they fix most breakages in minutes:

    1. Test the endpoint directly with curl or Postman (see Diagnose section).
    1. Open the Apps Script project → Deploy → Manage deployments. If no active web app deployment or the ID changed, redeploy (next section) and copy the new /exec URL (deployments doc).
    1. Set Execute as → Me and Who has access → Anyone, even anonymous if the form is public (then update your form action).
    1. Run any function from the script editor to force the authorization prompt; accept scopes. If your code uses Gmail/Sheets/Drive, reauthorize (authorization doc).
    1. If your front end uses fetch/XHR, confirm you’re not triggering a preflight (see CORS section). If you are, send a “simple” request or implement doOptions/doPost handling.
    1. Check the Executions/Logs for errors after a test submit (troubleshooting doc).

If step 1 returns 405 / 500 or the request never hits doPost, redeploy and re‑test.


Step‑by‑step: redeploy your Apps Script web app

Follow these exact steps in the Apps Script editor (new IDE):

  1. Open the script project.
  2. Click Deploy → Manage deployments → New deployment.
  3. For Deployment type choose “Web app”.
  4. Set “Execute as” → Me (runs with your account’s permissions).
  5. Set “Who has access” → Anyone, even anonymous (if you want public form POSTs).
  6. Click Deploy and copy the Web app URL (it ends with /exec).
  7. Update your HTML form action to that new URL.
  8. Test the form submission.

Why those settings? Running as your account lets the script call services (MailApp, Sheets) using your permissions; setting access to “Anyone, even anonymous” allows a browser POST from a visitor without a Google sign‑in. See the official steps in the deployments guide for screenshots and details: Create and manage deployments. If you edit code later, create a new deployment and update the form again — deployments are versioned, and old IDs can become stale.


Authorization, scopes and consent — reauthorize & verify

If the script uses services that access private data (Sheets, Gmail, Drive, advanced APIs), the platform may now require explicit scopes and re‑consent. Actions:

  • In the script editor, run a simple function (or open Run → Run function) to trigger a consent flow and re‑grant scopes. This forces OAuth prompts so the owner can reauthorize.
  • If you see a “This app isn’t verified” warning and you use sensitive scopes, you may need to configure the OAuth consent screen in the Google Cloud project and (for broad public use) submit for verification; see the troubleshooting auth doc: Troubleshoot authentication & authorization issues.
  • If you prefer not to expose the script publicly, consider moving the form submission to your server (proxy) and forwarding data to the Apps Script using your own credentials.

A quick test: if a manual run from the editor succeeds but web POSTs fail, that points to a permission or access setting rather than code logic.


CORS, AJAX and form submission tips for Apps Script web apps

Important distinction: a plain HTML form POST (method=“POST”, no JavaScript) is a “simple” browser navigation and usually doesn’t trigger a CORS preflight. But if you submit via fetch() or XHR, or set custom headers/content‑types, the browser will send an OPTIONS preflight and the server must respond appropriately.

Options:

  • Keep it simple: submit the form as a regular POST (no fetch). That avoids preflight and usually lands in doPost(e).
  • If you must use fetch/XHR, send a “simple” request to avoid preflight. Example fetch that avoids preflight:
javascript
fetch('https://script.google.com/macros/s/DEPLOY_ID/exec', {
 method: 'POST',
 headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
 body: JSON.stringify({ name, email, message })
});

On the Apps Script side parse JSON with:

javascript
function doPost(e) {
 var data = JSON.parse(e.postData.contents);
 Logger.log(data);
 return ContentService.createTextOutput(JSON.stringify({status: 'ok'}))
 .setMimeType(ContentService.MimeType.JSON);
}
  • If you can’t avoid preflight, implement doOptions(e) to handle the OPTIONS request. Note: Apps Script has limited ways to set arbitrary response headers, and many community posts recommend avoiding preflight where possible. See practical guidance on CORS in community answers and how to avoid preflight: StackOverflow CORS thread, IITH blog on CORS, and a pragmatic workaround (send text/plain) described in community posts (Medium example).

If you see console errors like “No ‘Access-Control-Allow-Origin’ header is present”, that usually means your AJAX request triggered preflight or the response did not include the header. For many static sites the fastest fix is to avoid AJAX or to send a simple request.


Diagnosing errors: curl, Executions log, and common HTTP codes

Start with a direct POST from your machine:

  • Test with curl (replace DEPLOY_ID):
bash
curl -v -X POST -d "name=Jean&email=jean@example.com&message=Hello" \
 "https://script.google.com/macros/s/DEPLOY_ID/exec"
  • HTTP 200 — good. Check response body.
  • HTTP 405 — Method Not Allowed (server not accepting POST at that URL; usually wrong endpoint or platform redirect behavior).
  • HTTP 500 — server runtime error; open the Apps Script Executions panel to see the exception trace.

To view server-side logs: open the Apps Script project → left menu “Executions” (or View → Executions in older UI) and click the failing run to see stack traces and logged data. Add diagnostic logging:

javascript
function doPost(e) {
 Logger.log(JSON.stringify(e)); // inspect parameters and postData
 // ... your processing ...
}

The official troubleshooting page walks through common failure modes: Troubleshooting | Apps Script.


Advanced fixes & when it’s a platform regression

If you’ve redeployed, reauthorized, avoided preflight and the POST still never reaches doPost (or you get consistent 500/405 responses), this could be a platform regression — several developers reported this around June 2025. Actions:

  • Search the public thread reports (example: Google Groups report, Developer forum thread).
  • If you confirm widespread reports, either: (a) file feedback/issue from the Apps Script editor, (b) post to the Google Apps Script community, or © use a small server proxy (on your domain) to receive the form and forward to the Apps Script (this avoids relying on the script endpoint during outages).
  • If you have Google Workspace support (paid), open a support ticket with the execution logs and curl output.

Community posts and GitHub issues document real cases where POST data was lost across redirects or script.googleusercontent.com endpoints mishandled POST — keep that in mind if logs show no incoming execution even though curl gets a 200/500.


Sample doPost / doOptions code and form examples

Minimal doPost for a regular form (application/x-www-form-urlencoded):

javascript
function doPost(e) {
 Logger.log(JSON.stringify(e)); // helpful when debugging
 var name = e.parameter.name || '';
 var email = e.parameter.email || '';
 var message = e.parameter.message || '';
 // e.g., append to a Sheet or send an email
 // return a simple confirmation page
 return HtmlService.createHtmlOutput('<p>Thanks — received.</p>');
}

If you accept JSON via text/plain (AJAX workaround):

javascript
function doPost(e) {
 var body = e.postData && e.postData.contents ? e.postData.contents : '{}';
 var data = JSON.parse(body);
 Logger.log(data);
 return ContentService.createTextOutput(JSON.stringify({ok: true}))
 .setMimeType(ContentService.MimeType.JSON);
}

Simple doOptions stub (attempt to handle preflight — behaviour can vary):

javascript
function doOptions(e) {
 // Apps Script has limited control over headers; success depends on platform support
 return ContentService.createTextOutput('')
 .setMimeType(ContentService.MimeType.TEXT);
}

Finally, update your form action to the new URL you copied after redeploy:

html
<form method="POST" action="https://script.google.com/macros/s/NEW_DEPLOY_ID/exec">
 <!-- your fields -->
</form>

Sources


Conclusion

Brief recap: your form stopped reaching the Google Apps Script web app because of deployment, OAuth/consent, and runtime changes (plus possible mid‑2025 platform regressions). Redeploy the web app, set Execute as → Me and Who has access → Anyone, even anonymous, update the form action to the new /exec URL, reauthorize required scopes, and test with curl and the Executions log. If you use AJAX, either send a simple request (text/plain or application/x-www-form-urlencoded) to avoid preflight or handle OPTIONS/remove custom headers; if all else fails, check community reports and file an issue.

Authors
Verified by moderation
Moderation
Fix HTML form POST to Google Apps Script Web App (2025)