Trigger Types in Google Apps Script Explained

Triggers are what make Apps Script truly powerful — they let your code run automatically in response to events, without anyone clicking a button. Here's a complete guide to all trigger types.

Simple triggers

Simple triggers are built-in functions that Apps Script recognises by name and runs automatically. No setup required — just define the function.

// Runs when the spreadsheet is opened function onOpen(e) { SpreadsheetApp.getUi() .createMenu('Custom Menu') .addItem('Run Report', 'runReport') .addToUi(); } // Runs when a cell is edited function onEdit(e) { const range = e.range; Logger.log(`Edited: ${range.getA1Notation()} = ${range.getValue()}`); } // Runs when the spreadsheet is changed (including programmatic changes) function onChange(e) { Logger.log('Change type: ' + e.changeType); } // Runs when a form is submitted (from a bound form) function onFormSubmit(e) { Logger.log('Form submitted: ' + JSON.stringify(e.namedValues)); }

Limitations of simple triggers

  • Cannot perform actions that require authorisation (send email, access Drive, call external APIs).
  • Always run as the user who performed the action.
  • Cannot be used in standalone scripts (only container-bound).

Installable triggers

Installable triggers overcome simple trigger limitations. They run with the script owner's authorisation and can perform any action.

Create programmatically

function createInstallableOnEdit() { const ss = SpreadsheetApp.getActiveSpreadsheet(); ScriptApp.newTrigger('onEditInstallable') .forSpreadsheet(ss) .onEdit() .create(); } function onEditInstallable(e) { // Can now send emails, access Drive, etc. if (e.range.getColumn() === 5 && e.value === 'Done') { GmailApp.sendEmail('[email protected]', 'Task completed', `Row ${e.range.getRow()} marked done.`); } }

Create via the UI

  1. Open the script editor.
  2. Click the Triggers icon (clock) in the left sidebar.
  3. Click + Add Trigger.
  4. Configure the function, event source, and event type.

Time-based triggers

Run code on a schedule — every minute, hourly, daily, or weekly.

function createTimeTriggers() { // Every 5 minutes ScriptApp.newTrigger('checkAlerts') .timeBased() .everyMinutes(5) .create(); // Every hour ScriptApp.newTrigger('syncData') .timeBased() .everyHours(1) .create(); // Every day at 8 AM ScriptApp.newTrigger('sendDailyReport') .timeBased() .everyDays(1) .atHour(8) .create(); // Every Monday at 9 AM ScriptApp.newTrigger('sendWeeklyReport') .timeBased() .onWeekDay(ScriptApp.WeekDay.MONDAY) .atHour(9) .create(); // First of every month at 7 AM ScriptApp.newTrigger('monthlyReport') .timeBased() .onMonthDay(1) .atHour(7) .create(); }

Form submit triggers

function createFormTrigger() { const form = FormApp.openById('YOUR_FORM_ID'); ScriptApp.newTrigger('handleFormSubmit') .forForm(form) .onFormSubmit() .create(); } function handleFormSubmit(e) { const email = e.response.getRespondentEmail(); Logger.log('New submission from: ' + email); }

Calendar triggers

function createCalendarTrigger() { ScriptApp.newTrigger('onCalendarUpdated') .forUserCalendar(Session.getActiveUser().getEmail()) .onEventUpdated() .create(); } function onCalendarUpdated(e) { Logger.log('Calendar updated: ' + e.calendarId); }

List and delete triggers

function listAllTriggers() { const triggers = ScriptApp.getProjectTriggers(); triggers.forEach(t => { Logger.log(`Function: ${t.getHandlerFunction()} | Type: ${t.getEventType()} | Source: ${t.getTriggerSource()}`); }); } function deleteAllTriggers() { ScriptApp.getProjectTriggers().forEach(t => ScriptApp.deleteTrigger(t)); Logger.log('All triggers deleted.'); } function deleteTriggerByFunction(fnName) { ScriptApp.getProjectTriggers() .filter(t => t.getHandlerFunction() === fnName) .forEach(t => ScriptApp.deleteTrigger(t)); }

Comparison summary

TypeAuth requiredMin intervalUse case
Simple onEditNoInstantBasic UI reactions
Installable onEditYesInstantEdits that need email/Drive
Time-basedYes1 minuteScheduled jobs
Form submitYesInstantWorkflow on form response
CalendarYesInstantReact to calendar changes

Tips

  • Run trigger setup functions once — check for duplicates before creating to avoid multiple triggers on the same function.
  • Each trigger counts toward your daily trigger quota. Keep the number of triggers per project low.
  • Enable failure notifications in the trigger settings so you're alerted when a trigger execution fails.