Service Details
Google Apps Script Blog Topics
Google Apps Script Webhooks
In this tutorial, we'll explore how to implement webhooks using Google Apps Script—a powerful way to connect external services with your custom automation workflows. Webhooks allow your script to respond to incoming HTTP requests in real time, making it ideal for integrations like form submissions, payment notifications, or third-party API triggers. We’ll walk through setting up doGet(e) and doPost(e) handlers, parsing incoming parameters, and returning structured responses. Whether you're building a lightweight endpoint or a more complex event-driven system, understanding how to implement webhooks in Apps Script opens the door to smarter, more responsive applications.
In the context of Google Apps Script (GAS), a webhook is an endpoint — a publicly accessible URL that can receive incoming HTTP requests — designed to trigger script execution. This endpoint can process both GET and POST requests, allowing external systems to interact with your script logic.
While GET requests typically pass data via query parameters, POST requests send payloads in the request body. However, POST webhooks in GAS do not support custom headers, which means any metadata or authentication must be handled through alternative means, such as query strings or embedded tokens within the payload.
Sample 1 shows a simple GET webhook. Although it does absolutely nothing, it is — in essence — a webhook. The function name for a GET webhook must be doGet(), and for a POST webhook, doPost().
function doGet(e)
{
}
Sample 1: GET webhook
function doGet(e)
{
return ContentService.createTextOutput('This is some text...');
}
function doGet(e)
{
var json = JSON.stringify({text:"this is some text..."});
return ContentService.createTextOutput(json).setMimeType(ContentService.MimeType.JSON);
}
Sample 2: GET webhook rendering text and JSON
By setting the MIME type, we can render JSON that can be consumed by any web service. You can even present your Sheet data as JSON, making it accessible for integration, automation, or external API calls.
Now let's take it a step further and render HTML. This allows us to present a custom web page that is hosted by Google. Unfortunately, you'll end up with a rather nasty-looking URL — but functionally, it works just fine for internal tools, prototypes, or lightweight publishing.
In order to render HTML in GAS (Google Apps Script), we need to add an HTML file in the script editor. This allows us to serve custom interfaces using HtmlService
Sample 3 and Sample 4 shows the GAS and HTML to render a simple HTML page. The HTML, JavaScript, and CSS are all contained in a single file, making it easy to deploy and maintain within a Google Apps Script project.
Although easy to deploy, it becomes increasingly unreadable in larger projects. As complexity grows, separating HTML, CSS, and JavaScript into modular files improves maintainability, scalability, and clarity.
Note: There are significant limitations in what GAS will allow you to do, due to strict security restrictions.
function doGet(e)
{
return HtmlService.createHtmlOutputFromFile('test.html');
}
Sample 3: GET webhook rendering HTML
<!DOCTYPE html>
<html>
<head>
<title>Hello Name</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 2rem;
}
label, input, button {
display: block;
margin-bottom: 1rem;
}
#greeting {
font-weight: bold;
margin-top: 1rem;
color: #2a7ae2;
}
</style>
</head>
<body>
<label for="nameInput">Enter your name:</label>
<input type="text" id="nameInput" placeholder="Your name" />
<button onclick="sayHello()">Submit</button>
<div id="greeting"></div>
<script>
function sayHello() {
const name = document.getElementById('nameInput').value.trim();
const greeting = name ? `Hello, ${name}!` : '';
document.getElementById('greeting').textContent = greeting;
}
</script>
</body>
</html>
Sample 4: HTML for Sample 3
Now let's write some code to split the HTML, CSS and JS. We're going to "inject" the CSS and JavaScript into our main HTML using server-side includes. For larger projects, this is a solid approach — it keeps your code modular, readable, and easier to maintain.
Important: Please use a strict naming convention for your files to prevent confusion. For example:
test2.html— your main HTML shelltest2.css.html— your CSS partialtest2.js.html— your JavaScript partial
include('filename') and keeps files neatly grouped together in Apps Script editor. It is not ideal that the HTML extension cannot be changed, but this is the best we can do in GAS.
function doGet(e)
{
return HtmlService.createHtmlOutputFromFile('test2.html');
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
Sample 5: GET webhook with split HTML, JS and CSS
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
<?!= include('test2.css.html'); ?>
</style>
</head>
<body>
<label for="nameInput">Enter your name:</label>
<input type="text" id="nameInput" placeholder="Your name" />
<button onclick="sayHello()">Submit</button>
<div id="greeting"></div>
<script>
<?!= include('test2.js.html'); ?>
</script>
</body>
</html>
Sample 6: test2.html
body {
font-family: Arial, sans-serif;
padding: 2rem;
}
label, input, button {
display: block;
margin-bottom: 1rem;
}
#greeting {
font-weight: bold;
margin-top: 1rem;
color: #2a7ae2;
}
Sample 7: test2.css.html
function sayHello() {
const name = document.getElementById('nameInput').value.trim();
const greeting = name ? `Hello, ${name}!` : '';
document.getElementById('greeting').textContent = greeting;
}
Sample 8: test2.js.html
Lastly, for GET webhooks we need to look at input parameters. Sample 9 shows how to parse input parameters using the e.parameter object in Google Apps Script.
When writing autonomous webhooks — meaning scripts that execute without user interaction or UI — it’s a good idea to accept a key= parameter. Since the script is published and accessible to anyone on the internet, the key gives us the power to limit execution only to key holders.
This simple form of access control helps prevent unauthorized use and ensures that only trusted systems or users can trigger the webhook.
function doGet(e)
{
if (e.parameter.key == '123')
return HtmlService.createHtmlOutputFromFile('test.html')
else
return ContentService.createTextOutput('You are not authorised to access this resource.');
}
Sample 9: Renders html if parameter key=123 is passed, otherwise the no access message is displayed.
We will look into more detail on POST webhooks in the form tutorial. This will include how to capture form submissions and parse payloads with Google Apps Script projects.
This concludes our tutorial on webhooks. You've now seen how to structure GET and POST endpoints, inject modular HTML/CSS/JS, and apply basic access control using query parameters. From here, you can confidently build autonomous, branded, and scalable webhook solutions.
Last Updated: 1 October 2025