New: 6 free SQL practice datasets with 300+ questions — try the SQL Compiler →
Automations

Google Apps Script for Beginners: A Simple Intro

Google Apps Script for beginners: what it is, how to open the editor in Google Sheets, read and write cells, custom functions and triggers.

Upskly AI Team September 26, 2026 13 min read
Google Apps Script for Beginners: A Simple Intro

Google Apps Script is a way to add your own code to Google Sheets, Docs, Forms and Gmail. It uses JavaScript, it runs on Google’s servers, and it lets you do things a formula cannot: send an email when a row changes, add a custom menu, tidy up data every night, or turn a sheet into a small web app. If you have ever repeated the same clicks in a spreadsheet every day, Apps Script is how you make the computer do them for you.

This is the first post of a series about automating Google Sheets. It explains what Apps Script is, where to write it, and the handful of ideas you need before the rest of the series: reading and writing cells, custom functions, menus and triggers.

In this guide

The short version

  • Apps Script is JavaScript that runs on Google’s servers and controls Google Workspace: Sheets, Docs, Gmail, Calendar, Drive and more.
  • Open it from a sheet with Extensions > Apps Script. A script created this way is bound to that sheet.
  • You work with a sheet through SpreadsheetApp: getRange(), getValues(), setValue(), appendRow().
  • Triggers run your code automatically: when a cell is edited, when the file opens, or on a schedule.
  • Runs are limited: for example 6 minutes per execution and a daily email limit. Check the current limits before you rely on them.

How the results in this post were produced. Apps Script runs only on Google’s servers, so the exact code shown was run against a small simulation of the Sheets service (an in-memory sheet with the same method names). The logic of the script is real, but the sheet and the log are simulated, and the clock was fixed at Monday 16 March 2026, 09:30 India time. Always try a script on a copy of your own sheet first.

What is Apps Script?

Google describes Apps Script as a platform for building business applications that work with Google Workspace, written in modern JavaScript. In practice you can:

  • add custom menus, dialogs and sidebars to Sheets, Docs and Forms;
  • write custom functions that you use in a cell like =SUM();
  • run code automatically with triggers (on edit, on open, on a schedule);
  • talk to other Google services, such as Gmail, Calendar and Drive;
  • publish a web app that anyone with the link can open.

You do not need to install anything. The editor is in your browser, and your code is saved in your Google account.

Where you write it

Open a Google Sheet and choose Extensions > Apps Script. A new browser tab opens with the script editor. A script created this way is container-bound: it belongs to that spreadsheet, and it can use the sheet directly, without any setup. This is what you want for almost everything in this series. The other kind is a standalone script, created from script.google.com, which is not tied to one file.

The editor has a file list on the left, the code in the middle, and a Run button with a function selector at the top. Output appears in the Execution log at the bottom. Any function you write can be run from there.

Your first script

A function is a named block of code. Logger.log() writes a line to the Execution log, which is the Apps Script equivalent of print:

function hello() {
  Logger.log("Hello from Apps Script");
}

Execution log (simulated)

Hello from Apps Script

The first time you run a script that touches your data, Google shows an authorization dialog. Apps Script works out which permissions your code needs, for example access to your spreadsheets, and asks you to approve them. Scripts that use sensitive permissions can show a warning that the app is unverified. For a script you wrote yourself that is expected, because Google has not reviewed it. Read what it asks for before you continue.

Reading a sheet

Everything about the spreadsheet goes through SpreadsheetApp. getActiveSpreadsheet() gives you the file, getSheetByName() gives you a tab, and getDataRange().getValues() reads all the cells that hold data into a two-dimensional array: an array of rows, where each row is an array of cells. Here is a small sales sheet, which we will use in the rest of this post:

Sales (simulated sheet)
ABCD
1OrderProductAmountStatus
21001Notebook250Paid
31002Pen40Pending
41003Bag900Paid

The script below adds up the Amount column. Look at how the array is used: rows[i][2] means “row i, column 3”.

function totalSales() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales");
  const rows = sheet.getDataRange().getValues();   // a 2D array: rows[row][column]
  let total = 0;
  for (let i = 1; i < rows.length; i++) {          // start at 1 to skip the header row
    total += rows[i][2];                           // the third column (index 2) is Amount
  }
  Logger.log("Total: %s", total);
  return total;
}

Execution log (simulated)

Total: 1190

The one confusing thing: 1 or 0?

Beginners trip on this more than anything else. Methods such as getRange(row, column) count from 1, like the row numbers you see in the sheet. But the arrays returned by getValues() are ordinary JavaScript arrays, which count from 0. So the same cell has two different addresses. Look at the cell C3 (row 3, column 3), read in three ways:

function showIndexes() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales");
  const values = sheet.getDataRange().getValues();
  Logger.log(sheet.getRange(3, 3).getValue());    // row 3, column 3: counting starts at 1
  Logger.log(sheet.getRange("C3").getValue());    // the same cell, in A1 notation
  Logger.log(values[2][2]);                       // the same cell in the array: counting starts at 0
}

Execution log (simulated)

40
40
40

Remember: sheet coordinates start at 1, array positions start at 0. When you loop over the array and need to write back to the sheet, add 1 to convert the array index into a row number.

Writing to a sheet

setValue() writes into one cell, and appendRow() adds a whole row after the last row that has data. getLastRow() tells you where that is. This function records a new order and marks it as paid:

function addOrder() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales");
  sheet.appendRow([1004, "Pencil box", 120]);     // adds a row after the last row with data
  const last = sheet.getLastRow();
  sheet.getRange(last, 4).setValue("Paid");       // column 4 = Status
  Logger.log("Added row %s", last);
}

Execution log (simulated)

Added row 5
Sales after addOrder() (simulated sheet)
ABCD
1OrderProductAmountStatus
21001Notebook250Paid
31002Pen40Pending
41003Bag900Paid
51004Pencil box120Paid

Row 5 was created by appendRow() with three values, and then setValue() filled column 4.

Custom functions

A custom function is a normal function that you call from a cell, like a built-in formula. If you write =WITHGST(C2) in a cell, Sheets runs your function with the value of C2 and shows what it returns. Custom functions have rules: the name must not clash with a built-in function or end in an underscore, the call must return within 30 seconds (otherwise the cell shows an error), and the function cannot change other cells. It returns a value, and that is all. The @customfunction line in the comment makes the function show up in Sheets’ autocomplete with its description:

/**
 * Adds 18% tax to an amount.
 *
 * @param {number} amount The price before tax.
 * @return {number} The price with tax.
 * @customfunction
 */
function WITHGST(amount) {
  return Math.round(amount * 1.18 * 100) / 100;
}

Execution log (simulated)

295
47.2

So =WITHGST(250) shows 295, and it works on any cell you point it at.

You can put your own menu in the Sheets toolbar so that people can run a function with a click. A special function named onOpen() runs automatically when the file is opened, and it is where menus are created. This is the smallest example. It gets its own post in this series (see below):

function onOpen() {
  SpreadsheetApp.getUi()
      .createMenu("Upskly Tools")
      .addItem("Add a sample order", "addOrder")
      .addToUi();
}

Execution log (simulated)

Menu "Upskly Tools": Add a sample order -> addOrder()

Triggers: running scripts automatically

Up to now you ran functions by hand. The real power of Apps Script is triggers, which run a function automatically:

Kinds of trigger
TriggerRuns whenCovered in
onOpen()Someone opens the fileonOpen in Apps Script
onEdit(e)Someone edits a cellonEdit in Apps Script
Time-drivenEvery minute, hour, day, week or monthApps Script Time Triggers
doGet(e) and doPost(e)Someone visits, or sends data to, your web appWhat Is doGet in Apps Script?

Some triggers are simple: you just name a function onEdit or onOpen, and it works with no set-up, but with some limits (for example, no sending email). Others are installable: you create them yourself, and they can do more. The next posts explain the difference in detail.

Limits to know about

Apps Script is free to use with a Google account, but it runs within quotas. These are the figures in Google’s documentation at the time of writing (September 2026). They can change, so check the official quotas page before you depend on a number:

Apps Script quotas (from Google's documentation)
LimitPersonal (gmail.com) accountGoogle Workspace account
Email recipients per day1001,500
Total trigger runtime per day90 minutes6 hours
URL Fetch calls per day20,000100,000
One script run6 minutes6 minutes
One custom function call30 seconds30 seconds
Triggers per user per script2020

None of this matters for small automations. It matters when a script loops over thousands of rows or sends many emails. The habit that keeps you inside the limits is to read a range once with getValues() and write it once with setValues(), instead of touching cells one at a time.

Apps Script or a formula?

Choosing a tool
You want to…Use
Calculate something in a cellA formula
Reuse a calculation that formulas make messyA custom function
Do something when a cell changes or a file opensA simple trigger
Run something every morning or every hourA time-driven trigger
Send an email, or call another Google serviceAn installable trigger or a menu item
Give people a form or a page on top of a sheetA web app

Start with a formula. Reach for Apps Script when you need something to happen rather than something to be calculated.

Common mistakes

  • Mixing up 1-based and 0-based. Sheet rows and columns start at 1, and arrays start at 0.
  • Reading or writing one cell at a time in a loop. Every call takes time. Read a whole range with getValues(), work on the array, and write it back with setValues().
  • Skipping the header row. getDataRange() includes it, so start the loop at index 1.
  • Wrong sheet name. getSheetByName("sales") is not "Sales". When the name does not match, it returns null, and the next line fails.
  • Expecting a simple trigger to do everything. Simple triggers cannot use services that need authorization, and they stop after 30 seconds.
  • Testing on the real sheet. Make a copy of your sheet and try the script there first.

The rest of this series

Each next post takes one narrow topic and explains it with use cases:

Apps Script is JavaScript, so if you know Python you will pick the ideas up quickly. If you have not learned to code yet, How to Learn Python: A Step-by-Step Roadmap teaches the same basics (variables, loops, functions) in a language with simpler syntax. The official Apps Script documentation is the place to check details.

Try it yourself

Use the sales sheet from above. Work out each answer first, then open the solution.

1. Write a function that logs how many orders are in the sheet.

Show solution
function countOrders() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales");
  Logger.log(sheet.getLastRow() - 1);              // minus the header row
}

Execution log (simulated)

3

getLastRow() is the number of the last row that has data, and one of those rows is the header.

2. Log the amount of the biggest order.

Show solution
function biggestOrder() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales");
  const rows = sheet.getDataRange().getValues().slice(1);   // drop the header
  const amounts = rows.map(row => row[2]);
  Logger.log(Math.max(...amounts));
}

Execution log (simulated)

900

slice(1) drops the header, map() picks the Amount column, and Math.max(...) finds the largest.

3. Set the Status of every order to “Paid” with a single write.

Show solution
function markAllPaid() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales");
  const count = sheet.getLastRow() - 1;
  const values = [];
  for (let i = 0; i < count; i++) values.push(["Paid"]);
  sheet.getRange(2, 4, count, 1).setValues(values);        // one write for the whole column
}
Sales after markAllPaid() (simulated sheet)
ABCD
1OrderProductAmountStatus
21001Notebook250Paid
31002Pen40Paid
41003Bag900Paid

The values must be a 2D array with one row per order, so [["Paid"], ["Paid"], ["Paid"]]. One setValues() call is much faster than three setValue() calls, and the gap grows with the number of rows.

4. Why is values[2][2] the same cell as getRange(3, 3)?

Show answer

Sheet methods count rows and columns from 1, and JavaScript arrays count from 0, so index 2 is the third row and the third column.

Frequently asked questions

What is Google Apps Script?

It is a platform that lets you write JavaScript to automate and extend Google Workspace: Sheets, Docs, Forms, Gmail, Calendar and Drive. Your code runs on Google’s servers.

Do I need to know JavaScript to use Apps Script?

Basic JavaScript is enough to start: variables, functions, loops and arrays. You can learn the rest as you go, and copying a small working example and changing it is a good way in.

How do I open the Apps Script editor in Google Sheets?

Open the sheet and choose Extensions, then Apps Script. A new tab opens with the editor, and the script is bound to that spreadsheet.

Is Apps Script free?

You can use it with any Google account without paying, within Google’s daily quotas, such as limits on run time and emails sent. Workspace accounts have higher limits.

What is the difference between a bound and a standalone script?

A bound script belongs to one file, such as a spreadsheet, and can use it directly. A standalone script is created on its own and is not tied to a file.

Can Apps Script run automatically?

Yes. Triggers run a function when a cell is edited, when a file opens, on a schedule (every minute up to once a month), or when someone visits a web app.

Upskly AI Team
Learning made simple
Scroll to Top