Create One Shot Trigger At

Some jobs should run once: send the reminder Thursday at 9, close the form at midnight, re-check the invoice in two hours. createOneShotTriggerAt(handlerName, when) creates a time-based trigger with .at(date) and returns its unique id. deleteTriggerById(id) then removes that one trigger after it fires. Other triggers for the same handler are left alone.

When to use

  • One-off reminders and follow-ups scheduled from a sheet row or menu
  • “Try again in 30 minutes” retries after a flaky API call
  • Opening / closing something at a specific time (a form, a sheet protection)

How to use this snippet

/** * Create a one-time trigger for handlerName at a specific Date. * @param {string} handlerName top-level function name * @param {Date|string|number} when must be in the future * @return {string} trigger unique id (save it if you need to cancel later) */ function createOneShotTriggerAt(handlerName, when) { var at = when instanceof Date ? when : new Date(when); if (isNaN(at.getTime())) { throw new Error('createOneShotTriggerAt: invalid date'); } if (at.getTime() <= Date.now()) { throw new Error('createOneShotTriggerAt: date is in the past'); } // Typos in handler names otherwise fail silently at fire time if (typeof globalThis[handlerName] !== 'function') { throw new Error('createOneShotTriggerAt: no function named ' + handlerName); } var trigger = ScriptApp.newTrigger(handlerName).timeBased().at(at).create(); return trigger.getUniqueId(); } /** * Delete exactly one trigger by unique id. Returns true if it was found. * @param {string} triggerId * @return {boolean} */ function deleteTriggerById(triggerId) { var all = ScriptApp.getProjectTriggers(); for (var i = 0; i < all.length; i++) { if (all[i].getUniqueId() === triggerId) { ScriptApp.deleteTrigger(all[i]); return true; } } return false; }

Example

// Schedule: one hour from now function scheduleFollowUp() { var id = createOneShotTriggerAt('sendFollowUp', new Date(Date.now() + 60 * 60 * 1000)); console.log('Scheduled trigger ' + id); } // Time-driven event objects include triggerUid, the id of the trigger that fired function sendFollowUp(e) { try { doFollowUp_(); // your work } finally { // Clean up: fired one-shot triggers otherwise linger in the Triggers list if (e && e.triggerUid) deleteTriggerById(e.triggerUid); } }

Tips:

  • A fired .at() trigger won’t run again, but it can stay in the Triggers list and count toward the per-user trigger limit (20 per script). Delete it by id when it fires.
  • Why not deleteTriggersByHandler? It removes every trigger for that function, including other reminders you scheduled. Deleting by id only removes the one that fired.
  • For recurring schedules, use createDailyTrigger instead.
  • Timing is approximate: Apps Script may fire a few minutes after when. Don’t use this for anything that needs to happen on the exact second.
  • Need data for the run (row number, email)? Save it in Script Properties under the trigger id, then read and delete it in the handler.

Tip: NitroGAS Co-Pilot can turn “remind the requester 48 hours after the row goes Pending” into a createOneShotTriggerAt call plus a handler that cleans up after itself.

Happy Coding!

NitroGAS Chrome Extension

Want this snippet handy inside the Apps Script editor? NitroGAS gives you free themes and snippets — plus optional Co-Pilot when you want a boost (1-week, 1-month, or yearly passes — no subscription). Happy Coding!

Get the Extension