HTML Service: Communicate with Server Functions

google.script.run is an asynchronousclient-side JavaScript API that allows HTML-service pages to call server-sideApps Script functions. The following example shows the most basic functionalityofgoogle.script.runcalling a function on the serverfrom client-side JavaScript.

Code.gs

function doGet() {  return HtmlService.createHtmlOutputFromFile('Index');}function doSomething() {  Logger.log('I was called!');}

Index.html

<!DOCTYPE html><html>  <head>    <base>    <script>      google.script.run.doSomething();    </script>  </head></html>

If you deploy this script as a web app and visit its URL, you won’t seeanything, but if you view the logs, you'll see that the server functiondoSomething() was called.

Client-side calls to server-side functions are asynchronous: after the browserrequests that the server run the functiondoSomething(), the browser continuesimmediately to the next line of code without waiting for a response. This meansthat server function calls may not execute in the order you expect. If you maketwo function calls at the same time, there is no way to know which function willrun first; the result may differ each time you load the page. In this situation,success handlers andfailure handlershelp control the flow of your code.

Thegoogle.script.run API allows 10 concurrent calls to server functions. Ifyou make an 11th call while 10 are still running, the server function will bedelayed until one of the 10 spots is freed. In practice, you should rarely haveto think about this restriction, especially since most browsers already limitthe number of concurrent requests to the same server at a number lower than 10.In Firefox, for example, the limit is 6. Most browsers similarly delay excessserver requests until one of the existing requests has completed.

Parameters and return values

You can call a server function with parameters from the client. Similarly, aserver function can return a value to the client as a parameter passed to asuccess handler.

Legal parameters and return values are JavaScript primitives like aNumber,Boolean,String, ornull, as well as JavaScript objects and arrays thatare composed of primitives, objects and arrays. Aform element within the pageis also legal as a parameter, but it must be the function’s only parameter, andit is not legal as a return value. Requests fail if you attempt to pass aDate,Function, DOM element besides aform, or other prohibited type,including prohibited types inside objects or arrays. Objects that createcircular references will also fail, and undefined fields within arrays becomenull.

Note that an object passed to the server becomes a copy of the original. If aserver function receives an object and changes its properties, the properties onthe client are not affected.

Success handlers

Because client-side code continues to the next line without waiting for a servercall to complete,withSuccessHandler(function)allows you to specify a client-side callback function to run when the serverresponds. If the server function returns a value, the API passes the value tothe new function as a parameter.

The following example displays a browser alert when the server responds. Notethat this code sample requires authorization because the server-side function isaccessing your Gmail account. The simplest way to authorize the script is to runthegetUnreadEmails() function manually from the script editor once before youload the page. Alternately, when youdeploy the web app, you can chooseto execute it as the “user accessing the web app,” in which case you will beprompted for authorization when you load the app.

Code.gs

function doGet() {  return HtmlService.createHtmlOutputFromFile('Index');}function getUnreadEmails() {  return GmailApp.getInboxUnreadCount();}

Index.html

<!DOCTYPE html><html>  <head>    <base>    <script>      function onSuccess(numUnread) {        var div = document.getElementById('output');        div.innerHTML = 'You have ' + numUnread            + ' unread messages in your Gmail inbox.';      }      google.script.run.withSuccessHandler(onSuccess)          .getUnreadEmails();    </script>  </head>  <body>    <div></div>  </body></html>

Failure handlers

In case the server fails to respond or throws an error,withFailureHandler(function)allows you to specify a failure handler instead of a success handler, with theErrorobject (if any) passed as an argument.

By default, if you don't specify a failure handler, failures are logged to theJavaScript console. To override this, callwithFailureHandler(null) or supplya failure handler that does nothing.

The syntax for failure handlers is nearly identical to success handlers, as thisexample shows.

Code.gs

function doGet() {  return HtmlService.createHtmlOutputFromFile('Index');}function getUnreadEmails() {  // 'got' instead of 'get' will throw an error.  return GmailApp.gotInboxUnreadCount();}

Index.html

<!DOCTYPE html><html>  <head>    <base>    <script>      function onFailure(error) {        var div = document.getElementById('output');        div.innerHTML = "ERROR: " + error.message;      }      google.script.run.withFailureHandler(onFailure)          .getUnreadEmails();    </script>  </head>  <body>    <div></div>  </body></html>

User objects

You can reuse the same success or failure handler for multiple calls to theserver by callingwithUserObject(object)to specify an object that will be passed to the handler as a second parameter.This “user object” — not to be confused with theUser class — lets you respond to thecontext in which the client contacted the server. Because user objects are notsent to the server, they can be almost anything, including functions, DOMelements, and so forth, without the restrictions on parameters and return valuesfor server calls. User objects cannot, however, be objects constructed with thenew operator.

In this example, clicking either of two buttons will update that button with avalue from the server while leaving the other button unchanged, even though theyshare one success handler. Inside theonclick handler, the keywordthisrefers to thebutton itself.

Code.gs

function doGet() {  return HtmlService.createHtmlOutputFromFile('Index');}function getEmail() {  return Session.getActiveUser().getEmail();}

Index.html

<!DOCTYPE html><html>  <head>    <base>    <script>      function updateButton(email, button) {        button.value = 'Clicked by ' + email;      }    </script>  </head>  <body>    <input type="button" value="Not Clicked"      />    <input type="button" value="Not Clicked"      />  </body></html>

Forms

If you call a server function with aform element as a parameter, the formbecomes a single object with field names as keys and field values as values. Thevalues are all converted to strings, except for the contents of file-inputfields, which becomeBlob objects.

This example processes a form, including a file-input field, without reloadingthe page; it uploads the file to Google Drive and then prints the URL for thefile in the client-side page. Inside theonsubmit handler, the keywordthisrefers to the form itself. Note that upon loading all forms in the page havethe default submit action disabled bypreventFormSubmit. This prevents thepage from redirecting to an inaccurate URL in the event of an exception.

Code.gs

function doGet() {  return HtmlService.createHtmlOutputFromFile('Index');}function processForm(formObject) {  var formBlob = formObject.myFile;  var driveFile = DriveApp.createFile(formBlob);  return driveFile.getUrl();}

Index.html

<!DOCTYPE html><html>  <head>    <base>    <script>      // Prevent forms from submitting.      function preventFormSubmit() {        var forms = document.querySelectorAll('form');        for (var i = 0; i < forms.length; i++) {          forms[i].addEventListener('submit', function(event) {            event.preventDefault();          });        }      }      window.addEventListener('load', preventFormSubmit);      function handleFormSubmit(formObject) {        google.script.run.withSuccessHandler(updateUrl).processForm(formObject);      }      function updateUrl(url) {        var div = document.getElementById('output');        div.innerHTML = '<a href="' + url + '">Got it!</a>';      }    </script>  </head>  <body>    <form onsubmit="handleFormSubmit(this)">      <input name="myFile" type="file" />      <input type="submit" value="Submit" />    </form>    <div></div> </body></html>

Script runners

You can think ofgoogle.script.run as a builder for a “script runner.” If youadd a success handler, failure handler, or user object to a script runner, youaren't changing the existing runner; instead, you get back a new script runnerwith new behavior.

You can use any combination and any order ofwithSuccessHandler(),withFailureHandler(), andwithUserObject(). You can also call any of themodifying functions on a script runner that already has a value set. The newvalue simply overrides the previous value.

This example sets a common failure handler for all three server calls, but twoseparate success handlers:

var myRunner = google.script.run.withFailureHandler(onFailure);var myRunner1 = myRunner.withSuccessHandler(onSuccess);var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);myRunner1.doSomething();myRunner1.doSomethingElse();myRunner2.doSomething();

Private functions

Server functions whose names end with an underscore are considered private.These functions cannot be called bygoogle.script and their names are neversent to the client. You can thus use them to hide implementation details thatneed to be kept secret on the server.google.script is also unable to seefunctions withinlibraries and functions which aren'tdeclared at the top level of the script.

In this example, the functiongetBankBalance() is available in the clientcode; a user who inspects your source code can discover its name even if youdon't call it. However, the functionsdeepSecret_() andobj.objectMethod() are completely invisible tothe client.

Code.gs

function doGet() {  return HtmlService.createHtmlOutputFromFile('Index');}function getBankBalance() {  var email = Session.getActiveUser().getEmail()  return deepSecret_(email);}function deepSecret_(email) { // Do some secret calculations return email + ' has $1,000,000 in the bank.';}var obj = {  objectMethod: function() {    // More secret calculations  }};

Index.html

<!DOCTYPE html><html>  <head>    <base>    <script>      function onSuccess(balance) {        var div = document.getElementById('output');        div.innerHTML = balance;      }      google.script.run.withSuccessHandler(onSuccess)          .getBankBalance();    </script>  </head>  <body>    <div>No result yet...</div>  </body></html>

Resizing dialogs in Google Workspace applications

Custom dialog boxes in Google Docs, Sheets, orForms can be resized by calling thegoogle.script.host methodssetWidth(width) orsetHeight(height) inclient-side code. (To set the initial size of a dialog, use theHtmlOutputmethodssetWidth(width)andsetHeight(height).)Note that dialogs do not re-center in the parent window when resized, and it isnot possible to resizesidebars.

Closing dialogs and sidebars in Google Workspace

If you use the HTML service to display adialog box or sidebar in Google Docs, Sheets, orForms, you cannot close the interface by callingwindow.close(). Instead, youmust callgoogle.script.host.close().For an example, see the section onserving HTML as a Google Workspace user interface.

Moving browser focus in Google Workspace

To switch focus in the user's browser from a dialog or sidebar back to theGoogle Docs, Sheets, or Forms editor, simply call the methodgoogle.script.host.editor.focus().This method is particularly useful in combination with theDocument service methodsDocument.setCursor(position)andDocument.setSelection(range).

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-06-04 UTC.