Scriptdrill

Getting started Updated November 2026

Deploy as a web app

A script with a doGet(e) or doPost(e) function can be deployed as a web app (Deploy, New deployment, Web app) and gets a URL. doGet returns HtmlService.createHtmlOutput(...) for a page or ContentService.createTextOutput(JSON.stringify(obj)).setMimeType(ContentService.MimeType.JSON) for an API; e.parameter holds query parameters and e.postData.contents the POST body. Each code change needs a new deployment version.

Syntax

function doGet(e) { return ContentService.createTextOutput(text); } | function doPost(e) { const body = JSON.parse(e.postData.contents); }
PartWhat it is
e.parameterObject of query string parameters, for example e.parameter.id
e.postData.contentsRaw POST body as a string
Execute asMe (script runs with your permissions) or User accessing the web app
Who has accessOnly myself, anyone in the domain, or Anyone (needed for public forms and webhooks)

Examples

function doGet(e) {
  const sheet = SpreadsheetApp.openById("1AbC...xyz").getSheetByName("Prices");
  const rows = sheet.getDataRange().getValues();
  const headers = rows.shift();
  const data = rows.map(r => Object.fromEntries(headers.map((h, i) => [h, r[i]])));
  return ContentService.createTextOutput(JSON.stringify(data)).setMimeType(ContentService.MimeType.JSON);
}

Result: Opening the web app URL returns the sheet as JSON: [{"item":"Pens","price":2.5}, ...]

function doPost(e) {
  const body = JSON.parse(e.postData.contents);
  SpreadsheetApp.openById("1AbC...xyz").getSheetByName("Leads").appendRow([new Date(), body.name, body.email]);
  return ContentService.createTextOutput(JSON.stringify({ok: true})).setMimeType(ContentService.MimeType.JSON);
}

Result: A POST with {"name":"Ana","email":"ana@x.com"} adds a row and gets {"ok":true} back

function doGet(e) {
  const name = e.parameter.name || "there";
  return HtmlService.createHtmlOutput("<h1>Hello " + name + "</h1>");
}

Result: URL?name=Ana shows a page with Hello Ana

Common mistakes

  • The web app still runs the old code: you saved but did not deploy; create a new version under Deploy, Manage deployments, Edit, Version: New.
  • Script function not found: doGet: the function is missing or misspelled; a web app needs doGet for browser visits and doPost for POST requests.
  • External callers get a login page: access is set to Only myself or domain users; for webhooks and public forms set Who has access to Anyone.
  • doPost receives e.postData undefined: the request was sent as GET or with no body; check the method and content type on the client.

Practice Deploy as a web app

These drills check your answer on live data, free, no account needed.

  • Parse a query stringParse a URL query string such as `"?page=2&tag=js&tag=web"` into an object of strings. The leading `?` is optional. `+` means a space and `%XX` escapes are decoded. A key without `=` gets `""`. Only the first `=` separates key from value. Empty pieces (as in `a=1&&b=2`) are skipped. A key that appears more than once maps to an array of its values in order.
  • CSV text to objectsParse simple CSV text (no quoted fields) into an array of objects. The first non-blank line holds the headers. Lines end with `\n` or `\r\n`, and blank lines are skipped. Headers and values are trimmed of surrounding spaces and stay strings. A row with fewer values than headers gets `""` for the missing ones.
  • Pick some keysReturn a new object with only the listed `keys` of `obj`. Skip keys that `obj` does not have, but keep keys it has even when the value is `0`, `false`, `null`, `""` or `undefined`. Do not change `obj`.

Questions

Is the test deployment URL different from the real one?

Yes. The /dev URL always runs the latest saved code and only works for you; the /exec URL runs the deployed version and is the one to share.

Can doPost return a redirect or set CORS headers?

No custom headers. Web apps already respond with permissive CORS for simple requests; for redirects, return HTML with a meta refresh or a script that changes window.top.location.

Related

  • UrlFetchAppCall APIs from Google Apps Script with UrlFetchApp.fetch: GET and POST requests, headers and bearer tokens, JSON payloads, muteHttpExceptions, to a sheet.
  • JSON.parse and JSON.stringifyUse JSON.parse and JSON.stringify in Google Apps Script: turn an API response into objects, write nested fields to a sheet, store objects as properties.
  • appendRowAdd a row to a Google Sheet with Apps Script: appendRow for a single row after the last row with data, and setValues for many rows at once, with examples.
  • Dialogs, prompts and sidebarsShow dialogs in Google Sheets with Apps Script: ui.alert for messages, ui.prompt for text input, Yes No buttons, and HtmlService dialogs and sidebars.

Previous: try, catch and finallyNext: map, filter and reduce