How to Handle GET and POST HTTP Requests in Google Apps Script

With Google Apps Script, you can easily create a Web App that serves HTML, JSON, XML or plain text output using the HTML service. When your publish your Google Script project as a web app, the script gets a public URL (think API) that can be invoked from external applications using either HTTP GET or POST requests with query parameters and request body.

When publishing the script as a web app, make sure to choose “Allow anonymous access” and execute the script as yourself. If you edit the script, create a new version inside the script editor and deploy the latest version.

Here are some examples that demonstrate how you can convert your Google Script into a web API by adding the doGet and doPost methods to your project.

Handling GET Requests

When a script is published as a web app, the doGet callback function handles all GET requests made to the script’s public URL. The Google Script can return plain text content, HTML or JSON data as shown in the examples below:

Return Text Content

const doGet = (event = {}) => {
  const { parameter } = event;
  const { name = 'Anonymous', country = 'Unknown' } = parameter;
  const output = `Hello ${name} from ${country}`;
  return ContentService.createTextOutput(output);
};

Any query parameters added to the Google Script URL, like name and country in our example, become available in the parameter property of the event object of the doGet and doPost methods in Apps Script.

https://script.google.com/macros/s/12345/exec?name=Amit&country=India

If something is not working, you can always log the request object to the StackDrive console logs and easily debug the full request.

console.log(`doGet`, JSON.stringify(event));

Serve JSON Output

The same ContentService can be used to return JSON output by using the setMimeType method with the mime set as ContentService.MimeType.JSON.

const doGet = (event = {}) => {
  const { parameter } = event;
  const { name = 'Anonymous', country = 'Unknown' } = parameter;
  const message = `Hello ${name} from ${country}`;
  const json = { name, country, message };
  return ContentService.createTextOutput(JSON.stringify(json)).setMimeType(ContentService.MimeType.JSON);
};

When testing HTTP requests in Google Script with utilities like CURL or Postman, ensure that that “Automatically follow redirects Follow HTTP 3xx responses as redirects” setting is turned on since the ContentService serves a 301 redirect from the script.googleusercontent.com domain.

Serving HTML Content

Your Google Apps script project can serve HTML web pages with the HtmlService service. The web pages served with App Script included Google warning header at the top but it can be removed if you embed the Google Script in another web page (like Google Sites) with the IFRAME tag.

const doGet = (event = {}) => {
  const { parameter } = event;
  const { name = 'Anonymous', color = 'Black' } = parameter;
  const html = `<p><b>${name}'s</b> favorite color is <font color="${color}">${color}</font></p>`;
  return HtmlService.createHtmlOutput(html)
    .setTitle('Apps Script Webpage')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
};

You should set the X-Frame-Options header of the webpage to XFrameOptionsMode.ALLOWALL to allow other pages to embed your Google Script HTML page.

Handle POST Requests with Google Scripts

The callback function doPost is invoked when an HTTP POST request is make to your Google Script URL that is published as a web app with anonymous access.

const doPost = (request) => {
  console.log(request);
  return ContentService.crateTextOutput(JSON.stringify(request));
};

The request argument of the doPost method can include:

  1. queryString - The name-value pairs sent in the URL of the request (name=Mike&age=12)

  2. parameter - The query string name-value pairs are also accessible inside the parameter object similar to GET requests (e.paremeter.name or e.parameter.age).

  3. postData - The contents property of the postData object includes the POST body and type property of postData specifies the MIME type of the post body. It can have values like application/x-www-form-urlencoded (key-value pairs separated by the ’&’ character and each key is separated from its encoded value by ’=’), application/json for JSON data or text/plain for text body.

For binary data, like file uploads, the HTTP post request is sent with the multipart/form-data mime type. In the case of application/x-www-form-urlencoded, the queryString is set as part of the POST request body.

const doPost = (request = {}) => {
  const { parameter, postData: { contents, type } = {} } = request;
  const { source } = parameter;

  if (type === 'application/json') {
    const jsonData = JSON.parse(contents);
    return ContentService.createTextOutput(JSON.stringify(jsonData));
  }

  if (type === 'application/x-www-form-urlencoded') {
    const json = {};
    contents
      .split('&')
      .map((input) => input.split('='))
      .forEach(([key, value]) => {
        json[decodeURIComponent(key)] = decodeURIComponent(value);
      });
    return ContentService.createTextOutput(JSON.stringify(json));
  }

  return ContentService.createTextOutput(contents);
};

Testing HTTP Requests with Google Scripts

You can use Postman, RequestBin, CURL or any of your favorite dev tool to send GET and POST requests to your Apps Script service. We’ll use Apps Script itself with the built-in UrlFetchApp service to test the request and response.

Working with HTTP GET Requests

In this example, the GET API coverts the query string to JSON. The test function makeHttpGetRequest compares the supplied query string value with the returned object.

const doGet = (event = {}) => {
  const { parameter } = event;
  const { name, country } = parameter;
  return ContentService.createTextOutput(JSON.stringify({ name, country })).setMimeType(ContentService.MimeType.JSON);
};

const makeHttpGetRequest = () => {
  const queryString = '?name=Amit+Agarwal&country=India';
  const apiUrl = ScriptApp.getService().getUrl();
  const url = apiUrl + queryString;

  const options = {
    method: 'GET',
    followRedirects: true,
    muteHttpExceptions: true,
    contentType: 'application/json',
  };

  const response = UrlFetchApp.fetch(url, options);
  if (response.getResponseCode() == 200) {
    const { country } = JSON.parse(response);
    Logger.log('Country', country);
  }
};

Working with HTTP GET Requests

The doPost method returns either the country or the name from the request body depending on the action parameter of the script URL.

const doPost = (request = {}) => {
  const { parameter, postData: { contents, type } = {} } = request;
  const { name, country } = JSON.parse(contents);
  if (parameter.action === 'getCountry') {
    return ContentService.createTextOutput(country);
  } else {
    return ContentService.createTextOutput(name);
  }
};

const makeHttpPostRequest = () => {
  const url = ScriptApp.getService().getUrl() + '?action=getCountrdy';

  const payload = {
    name: 'Amit Agarwal',
    blog: 'www.labnol.org',
    country: 'India',
  };

  const options = {
    method: 'POST',
    followRedirects: true,
    muteHttpExceptions: true,
    payload: JSON.stringify(payload),
  };

  const response = UrlFetchApp.fetch(url, options);
  if (response.getResponseCode() == 200) {
    Logger.log(response.getContentText());
  }
};

POST Request with HTML Forms

The next example uses a simple HTML form that sends a POST request with application/x-www-form-urlencoded mime type.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
  </head>
  <body>
    <form action="https://script.google.com/macros/s/#####/exec" method="POST" target="_blank">
      <input type="text" name="name" />
      <input type="text" name="country" />
      <button type="submit">Submit</button>
    </form>
  </body>
</html>

The POST method returns the POST body of the request.

const doPost = (request = {}) => {
  const { postData: { contents, type } = {} } = request;
  return ContentService.createTextOutput(contents);
};

Using CURL to make HTTP Requests

The POST API returns a parameter from the query string of the URL and the name from the request body.

const doPost = (request = {}) => {
  const { parameter, postData: { contents, type } = {} } = request;
  const data = JSON.parse(contents);
  return ContentService.createTextOutput(parameter.secret + type + data.name);
};

You can use CURL to make a POST request to Google Script. Remember to add the -L flag so that curl follows the redirect from script.google.com to googleusercontent.com.

curl -L \
-H 'Content-Type:application/json' \
-d '{"name": "Amit","country": "India"}' \
"https://script.google.com/macros/s/###/exec?secret=1234"

Also see: AJAX, jQuery and Google Scripts

Amit Agarwal

Amit Agarwal

Google Developer Expert, Google Cloud Champion

Amit Agarwal is a Google Developer Expert in Google Workspace and Google Apps Script. He holds an engineering degree in Computer Science (I.I.T.) and is the first professional blogger in India.

Amit has developed several popular Google add-ons including Mail Merge for Gmail and Document Studio. Read more on Lifehacker and YourStory

Awards & Titles

Digital Inspiration has won several awards since it's launch in 2004.

Google Developer Expert

Google Developer Expert

Google awarded us the Google Developer Expert award recogizing our work in Google Workspace.

ProductHunt Golden Kitty

ProductHunt Golden Kitty

Our Gmail tool won the Lifehack of the Year award at ProductHunt Golden Kitty Awards in 2017.

Microsoft MVP Alumni

Microsoft MVP Alumni

Microsoft awarded us the Most Valuable Professional (MVP) title for 5 years in a row.

Google Cloud Champion

Google Cloud Champion

Google awarded us the Champion Innovator title recognizing our technical skill and expertise.

Email Newsletter

Sign up for our email newsletter to stay up to date.

We will never send any spam emails. Promise.