Manage Triggers Programmatically

While you can create triggers manually through the Apps Script UI, ScriptApp lets you create and delete triggers in code. This is essential for avoiding duplicates, building self-managing scripts, and maintaining clean trigger setups.

Listing All Active Triggers

function listAllTriggers() { var triggers = ScriptApp.getProjectTriggers(); triggers.forEach(function(trigger) { Logger.log( "Function: " + trigger.getHandlerFunction() + " | Type: " + trigger.getEventType() + " | ID: " + trigger.getUniqueId() ); }); Logger.log("Total triggers: " + triggers.length); }

Creating a Time-Based Trigger Safely (No Duplicates)

Always check before creating a trigger to prevent running the same function multiple times:

function createDailyReportTrigger() { var functionName = "sendDailyReport"; // Check if trigger already exists var existing = ScriptApp.getProjectTriggers().filter(function(t) { return t.getHandlerFunction() === functionName; }); if (existing.length > 0) { Logger.log("Trigger already exists for: " + functionName); return; } ScriptApp.newTrigger(functionName) .timeBased() .everyDays(1) .atHour(8) .inTimezone("America/New_York") .create(); Logger.log("Daily report trigger created."); }

Deleting a Trigger by Function Name

function deleteReportTrigger() { var functionName = "sendDailyReport"; ScriptApp.getProjectTriggers().forEach(function(trigger) { if (trigger.getHandlerFunction() === functionName) { ScriptApp.deleteTrigger(trigger); Logger.log("Deleted trigger: " + functionName); } }); }

Deleting All Triggers

Use with caution — this removes every trigger on the project:

function deleteAllTriggers() { ScriptApp.getProjectTriggers().forEach(function(trigger) { ScriptApp.deleteTrigger(trigger); }); Logger.log("All triggers deleted."); }

Replacing a Trigger (Delete + Recreate)

If you need to change a trigger's schedule, delete the old one and create a new one:

function rescheduleDigest() { var functionName = "sendWeeklyDigest"; // Delete existing ScriptApp.getProjectTriggers().forEach(function(trigger) { if (trigger.getHandlerFunction() === functionName) { ScriptApp.deleteTrigger(trigger); } }); // Recreate on Friday instead of Monday ScriptApp.newTrigger(functionName) .timeBased() .onWeekDay(ScriptApp.WeekDay.FRIDAY) .atHour(17) .create(); Logger.log("Digest rescheduled to Friday at 5pm."); }

Full Setup Script for Acme Corp Automations

A single setupAllTriggers() function that installs the entire suite of automations for the Sales Tracker:

function setupAllTriggers() { var ss = SpreadsheetApp.getActiveSpreadsheet(); // Clear existing triggers to start fresh ScriptApp.getProjectTriggers().forEach(function(t) { ScriptApp.deleteTrigger(t); }); // 1. Daily report at 8am on weekdays ScriptApp.newTrigger("sendDailyReport") .timeBased() .everyDays(1) .atHour(8) .inTimezone("America/New_York") .create(); // 2. Weekly digest every Monday at 9am ScriptApp.newTrigger("sendWeeklyDigest") .timeBased() .onWeekDay(ScriptApp.WeekDay.MONDAY) .atHour(9) .create(); // 3. Installable onEdit for status changes ScriptApp.newTrigger("onEditInstallable") .forSpreadsheet(ss) .onEdit() .create(); // 4. onFormSubmit for new lead entries ScriptApp.newTrigger("onNewDealSubmitted") .forSpreadsheet(ss) .onFormSubmit() .create(); // 5. onOpen for menu and dashboard refresh ScriptApp.newTrigger("onOpenInstallable") .forSpreadsheet(ss) .onOpen() .create(); Logger.log("All Acme Corp Sales Tracker triggers installed."); }

Run setupAllTriggers() once after deploying the script to a new spreadsheet, and the entire automation suite is live.

Trigger Event Types Reference

ScriptApp.EventTypeDescription
ON_EDITSpreadsheet cell edited
ON_OPENFile opened
ON_FORM_SUBMITForm submitted
CLOCKTime-based schedule
ON_CHANGESpreadsheet structural change