GASトリガー完全ガイド|定期実行・イベント駆動を使いこなす【2026年版】
GAS(Google Apps Script)のトリガー機能を使えば、スクリプトを自動で実行できます。毎日決まった時間に動かす「定期実行」から、シートが編集されたら動く「イベント駆動」まで、さまざまな自動化が可能です。
目次
この記事でわかること
- トリガーとは何か、どんな種類があるか
- 時間主導型トリガー(定期実行)の設定方法
- イベント駆動型トリガーの使い方
- GUI操作 vs コードでの設定方法
- 実践的な活用例(毎朝レポート、編集時処理)
- 6分制限の回避テクニック
- トリガー管理のベストプラクティス
トリガーとは何か
トリガーの基本概念
トリガーとは、GASのスクリプトを自動実行するためのきっかけを設定する機能です。
通常、GASスクリプトは手動で「実行」ボタンを押す必要がありますが、トリガーを設定すると、特定のタイミングで自動的に実行されます。
【手動実行】
あなた → 「実行」ボタンをクリック → スクリプト実行
【トリガー実行】
トリガー(時間 or イベント)→ 自動でスクリプト実行
トリガーの種類一覧
GASのトリガーは大きく2種類に分かれます。
| 種類 | 説明 | 例 |
|---|---|---|
| 時間主導型 | 指定した時間間隔で実行 | 毎日9時、1時間ごと |
| イベント駆動型 | 特定のイベント発生時に実行 | シート編集時、フォーム送信時 |
時間主導型トリガー
| トリガータイプ | 実行タイミング | 用途例 |
|---|---|---|
| 分ベース | 1分/5分/10分/15分/30分ごと | リアルタイム監視 |
| 時間ベース | 1時間/2時間/4時間/6時間/8時間/12時間ごと | 定期データ取得 |
| 日ベース | 毎日(時間帯指定可) | 日次レポート |
| 週ベース | 毎週(曜日指定可) | 週次レポート |
| 月ベース | 毎月(日付指定可) | 月次処理 |
イベント駆動型トリガー
| トリガータイプ | 発火タイミング | 対象 |
|---|---|---|
| onOpen | ファイルを開いたとき | スプレッドシート、ドキュメント |
| onEdit | セルを編集したとき | スプレッドシート |
| onChange | ファイルに変更があったとき | スプレッドシート |
| onFormSubmit | フォームが送信されたとき | Googleフォーム |
| onSelectionChange | 選択範囲が変わったとき | スプレッドシート |
時間主導型トリガーの設定方法
GUI(画面操作)で設定する
- Apps Scriptエディタを開く
- 左メニューの「トリガー」(時計アイコン)をクリック
- トリガーを追加をクリック
- 以下を設定:
| 設定項目 | 選択内容 |
|---|---|
| 実行する関数 | 実行したい関数名を選択 |
| 実行するデプロイ | 「Head」を選択 |
| イベントのソース | 「時間主導型」を選択 |
| 時間ベースのトリガーのタイプ | 希望する間隔を選択 |
| 時刻(日次の場合) | 実行したい時間帯を選択 |
- 保存をクリック
コードで設定する
トリガーはコードでも設定できます。プログラムで動的に管理したい場合に便利です。
// ===================================================
// 時間主導型トリガーをコードで設定
// ===================================================
/**
* 毎日午前9時に実行するトリガーを作成
*/
function createDailyTrigger() {
// 既存のトリガーを削除(重複防止)
deleteTriggers('dailyReport');
// 新しいトリガーを作成
ScriptApp.newTrigger('dailyReport')
.timeBased()
.atHour(9) // 午前9時
.everyDays(1) // 毎日
.create();
console.log('日次トリガーを作成しました');
}
/**
* 1時間ごとに実行するトリガーを作成
*/
function createHourlyTrigger() {
deleteTriggers('hourlyCheck');
ScriptApp.newTrigger('hourlyCheck')
.timeBased()
.everyHours(1) // 1時間ごと
.create();
console.log('時間トリガーを作成しました');
}
/**
* 毎週月曜日に実行するトリガーを作成
*/
function createWeeklyTrigger() {
deleteTriggers('weeklyReport');
ScriptApp.newTrigger('weeklyReport')
.timeBased()
.onWeekDay(ScriptApp.WeekDay.MONDAY) // 月曜日
.atHour(9) // 午前9時
.create();
console.log('週次トリガーを作成しました');
}
/**
* 毎月1日に実行するトリガーを作成
*/
function createMonthlyTrigger() {
deleteTriggers('monthlyReport');
ScriptApp.newTrigger('monthlyReport')
.timeBased()
.onMonthDay(1) // 毎月1日
.atHour(9) // 午前9時
.create();
console.log('月次トリガーを作成しました');
}
/**
* 指定した関数のトリガーを削除
*/
function deleteTriggers(functionName) {
const triggers = ScriptApp.getProjectTriggers();
triggers.forEach(trigger => {
if (trigger.getHandlerFunction() === functionName) {
ScriptApp.deleteTrigger(trigger);
console.log('トリガーを削除しました: ' + functionName);
}
});
}
イベント駆動型トリガーの設定方法
シンプルトリガー(簡易版)
特定の関数名を使うだけで、自動的にイベントに反応するようになります。
// ===================================================
// シンプルトリガー(関数名を合わせるだけで動作)
// ===================================================
/**
* スプレッドシートを開いたときに実行
* ※関数名は必ず「onOpen」にする
*/
function onOpen() {
// カスタムメニューを追加
const ui = SpreadsheetApp.getUi();
ui.createMenu('自動化ツール')
.addItem('レポート生成', 'generateReport')
.addItem('データ更新', 'updateData')
.addToUi();
console.log('スプレッドシートが開かれました');
}
/**
* セルが編集されたときに実行
* ※関数名は必ず「onEdit」にする
*/
function onEdit(e) {
const sheet = e.source.getActiveSheet();
const range = e.range;
const value = e.value;
console.log('編集されました: ' + sheet.getName() +
' セル: ' + range.getA1Notation() +
' 値: ' + value);
// 例: 特定の列が編集されたら処理
if (range.getColumn() === 3) { // C列
range.offset(0, 1).setValue(new Date()); // D列にタイムスタンプ
}
}
インストーラブルトリガー(高機能版)
シンプルトリガーでは権限が制限されるため、メール送信やカレンダー操作にはインストーラブルトリガーが必要です。
// ===================================================
// インストーラブルトリガー(高機能版)
// ===================================================
/**
* 編集時トリガーを作成(インストーラブル)
* ※メール送信など高度な操作が可能
*/
function createOnEditTrigger() {
const ss = SpreadsheetApp.getActive();
deleteTriggers('onEditAdvanced');
ScriptApp.newTrigger('onEditAdvanced')
.forSpreadsheet(ss)
.onEdit()
.create();
console.log('編集トリガーを作成しました');
}
/**
* フォーム送信時トリガーを作成
*/
function createFormSubmitTrigger() {
const ss = SpreadsheetApp.getActive();
deleteTriggers('onFormSubmitHandler');
ScriptApp.newTrigger('onFormSubmitHandler')
.forSpreadsheet(ss)
.onFormSubmit()
.create();
console.log('フォーム送信トリガーを作成しました');
}
/**
* 編集時の処理(インストーラブル版)
*/
function onEditAdvanced(e) {
const sheet = e.source.getActiveSheet();
const range = e.range;
// 例: ステータスが「完了」になったらメール送信
if (sheet.getName() === 'タスク一覧' && range.getColumn() === 2) {
if (e.value === '完了') {
const taskName = sheet.getRange(range.getRow(), 1).getValue();
sendCompletionEmail(taskName);
}
}
}
/**
* フォーム送信時の処理
*/
function onFormSubmitHandler(e) {
const responses = e.values;
console.log('フォームが送信されました: ' + responses.join(', '));
// 例: 自動返信メール送信
const email = responses[1]; // 2番目の質問がメールアドレスの場合
if (email) {
GmailApp.sendEmail(
email,
'お問い合わせありがとうございます',
'お問い合わせを受け付けました。\n担当者より折り返しご連絡いたします。'
);
}
}
function sendCompletionEmail(taskName) {
GmailApp.sendEmail(
'manager@example.com',
'タスク完了通知',
'タスク「' + taskName + '」が完了しました。'
);
}
シンプルトリガー vs インストーラブルトリガー
| 項目 | シンプル | インストーラブル |
|---|---|---|
| 設定方法 | 関数名を合わせるだけ | コードまたはGUIで設定 |
| 権限 | 制限あり | フルアクセス |
| メール送信 | ❌ 不可 | ✅ 可能 |
| 外部API呼び出し | ❌ 不可 | ✅ 可能 |
| 実行時間 | 30秒以内 | 6分以内 |
| イベントオブジェクト | 一部制限 | 完全取得 |
実践例
実践例①: 毎朝のレポート自動送信
毎朝9時に、前日のデータを集計してメールで送信する例です。
// ===================================================
// 実践例①: 毎朝のレポート自動送信
// ===================================================
/**
* 日次レポートを生成してメール送信
* ※createDailyTrigger()でトリガー設定
*/
function dailyReport() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('売上データ');
const today = new Date();
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
const dateStr = Utilities.formatDate(yesterday, 'Asia/Tokyo', 'yyyy/MM/dd');
// 前日のデータを集計
const data = sheet.getDataRange().getValues();
let totalSales = 0;
let count = 0;
data.forEach((row, index) => {
if (index === 0) return; // ヘッダースキップ
const rowDate = Utilities.formatDate(new Date(row[0]), 'Asia/Tokyo', 'yyyy/MM/dd');
if (rowDate === dateStr) {
totalSales += row[2]; // C列が売上金額
count++;
}
});
// レポート作成
const report = `
【日次売上レポート】
対象日: ${dateStr}
件数: ${count}件
売上合計: ¥${totalSales.toLocaleString()}
---
このメールは自動送信されています。
`.trim();
// メール送信
GmailApp.sendEmail(
'sales-team@example.com',
`【日次レポート】${dateStr}の売上報告`,
report
);
console.log('日次レポートを送信しました');
}
実践例②: シート編集時の自動処理
特定のセルが編集されたら、自動でタイムスタンプを記録し、ログシートに履歴を残す例です。
// ===================================================
// 実践例②: シート編集時の自動処理
// ===================================================
/**
* 編集時の自動処理
* ステータス変更を検知してログを記録
*/
function onEditAdvanced(e) {
const sheet = e.source.getActiveSheet();
const range = e.range;
// 対象シートのみ処理
if (sheet.getName() !== 'タスク管理') return;
// ステータス列(B列)が編集された場合
if (range.getColumn() === 2) {
const row = range.getRow();
const taskName = sheet.getRange(row, 1).getValue();
const newStatus = e.value;
const oldStatus = e.oldValue || '(空)';
// タイムスタンプを記録(E列)
sheet.getRange(row, 5).setValue(new Date());
// 更新者を記録(F列)
sheet.getRange(row, 6).setValue(Session.getActiveUser().getEmail());
// ログシートに履歴を追加
logStatusChange(taskName, oldStatus, newStatus);
// 完了時は通知
if (newStatus === '完了') {
notifyCompletion(taskName);
}
}
}
/**
* ステータス変更をログに記録
*/
function logStatusChange(taskName, oldStatus, newStatus) {
const logSheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('変更ログ');
if (!logSheet) return;
logSheet.appendRow([
new Date(),
Session.getActiveUser().getEmail(),
taskName,
oldStatus,
newStatus
]);
}
/**
* 完了通知を送信
*/
function notifyCompletion(taskName) {
// Slackに通知(Webhook URLは別途設定)
const webhookUrl = PropertiesService.getScriptProperties()
.getProperty('SLACK_WEBHOOK_URL');
if (webhookUrl) {
const payload = {
text: `✅ タスク「${taskName}」が完了しました!`
};
UrlFetchApp.fetch(webhookUrl, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
});
}
}
実践例③: 6分制限の回避テクニック
GASのスクリプトは最大6分で強制終了されます。大量データを処理する場合は、以下のテクニックを使います。
// ===================================================
// 実践例③: 6分制限の回避テクニック
// ===================================================
/**
* 大量データを分割処理
* 5分経過したら一旦停止し、続きを次回実行
*/
function processLargeData() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('大量データ');
const props = PropertiesService.getScriptProperties();
// 前回の処理位置を取得(初回は0)
const startRow = parseInt(props.getProperty('PROCESS_ROW') || '2');
const data = sheet.getDataRange().getValues();
const totalRows = data.length;
// 開始時刻を記録
const startTime = new Date().getTime();
const MAX_RUNTIME = 5 * 60 * 1000; // 5分(余裕を持って)
let currentRow = startRow;
for (let i = startRow; i < totalRows; i++) {
// 5分経過したら中断
if (new Date().getTime() - startTime > MAX_RUNTIME) {
console.log(`時間切れ: ${i}行目で中断`);
props.setProperty('PROCESS_ROW', i.toString());
createContinueTrigger(); // 1分後に再開
return;
}
// === ここに実際の処理を書く ===
processRow(data[i], i);
currentRow = i;
}
// 処理完了
console.log('全データの処理が完了しました');
props.deleteProperty('PROCESS_ROW');
deleteTriggers('processLargeData'); // 継続用トリガーを削除
}
/**
* 1分後に再開するトリガーを作成
*/
function createContinueTrigger() {
deleteTriggers('processLargeData');
ScriptApp.newTrigger('processLargeData')
.timeBased()
.after(1 * 60 * 1000) // 1分後
.create();
console.log('1分後に処理を再開します');
}
/**
* 1行分の処理(サンプル)
*/
function processRow(rowData, rowIndex) {
// 実際の処理をここに記述
Utilities.sleep(100); // 処理時間のシミュレーション
console.log(`${rowIndex}行目を処理しました`);
}
トリガー管理のベストプラクティス
1. トリガーの確認・削除
/**
* 現在設定されているトリガーを一覧表示
*/
function listAllTriggers() {
const triggers = ScriptApp.getProjectTriggers();
console.log('=== トリガー一覧 ===');
triggers.forEach((trigger, index) => {
console.log(`${index + 1}. 関数: ${trigger.getHandlerFunction()}`);
console.log(` タイプ: ${trigger.getEventType()}`);
console.log(` ID: ${trigger.getUniqueId()}`);
console.log('---');
});
console.log(`合計: ${triggers.length}件`);
}
/**
* すべてのトリガーを削除
*/
function deleteAllTriggers() {
const triggers = ScriptApp.getProjectTriggers();
triggers.forEach(trigger => {
ScriptApp.deleteTrigger(trigger);
});
console.log(`${triggers.length}件のトリガーを削除しました`);
}
2. エラーハンドリング
トリガー実行時のエラーは通知されないことがあるため、try-catchで囲んでメール通知を設定しましょう。
/**
* エラーハンドリング付きの処理
*/
function safeExecution() {
try {
// メインの処理
mainProcess();
} catch (error) {
// エラー時にメール通知
GmailApp.sendEmail(
'admin@example.com',
'【GASエラー】スクリプト実行エラー',
`エラーが発生しました:\n\n${error.message}\n\nスタックトレース:\n${error.stack}`
);
console.error(error);
}
}
3. トリガー設定時の注意点
| 注意点 | 対策 |
|---|---|
| 重複トリガー | 作成前に既存トリガーを削除 |
| トリガー上限 | 1プロジェクト20個まで |
| 時間のズレ | ±15分程度のズレは正常 |
| エラー通知 | try-catchでエラーハンドリング |
| 実行ログ | console.logで処理状況を記録 |
トラブルシューティング
よくあるエラーと解決法
| エラー | 原因 | 解決法 |
|---|---|---|
Authorization required |
権限未承認 | 手動で一度実行して承認 |
Exceeded maximum execution time |
6分超過 | 分割処理を実装 |
Service invoked too many times |
API呼び出し上限 | 間隔を空ける、バッチ処理 |
Trigger not firing |
トリガー設定ミス | トリガー一覧で確認 |
デバッグのコツ
- 実行ログを確認: 「実行数」メニューで過去の実行履歴を確認
- console.log活用: 処理の進捗を記録
- 手動実行でテスト: トリガー設定前に手動で動作確認
- 小さく始める: まず1件のデータで動作確認してからスケール
まとめ
ポイントまとめ
| 項目 | 内容 |
|---|---|
| トリガー種類 | 時間主導型・イベント駆動型の2種類 |
| 設定方法 | GUI(画面操作)またはコード |
| シンプル vs インストーラブル | 高度な操作にはインストーラブル必須 |
| 6分制限回避 | 分割処理+継続トリガー |
| ベストプラクティス | 重複削除、エラーハンドリング |
次のステップ
- 日次レポートの自動化を試してみる
- イベント駆動でリアルタイム処理を実装
- ChatGPT連携で高度な自動化に挑戦
関連記事
- GAS入門ガイド
- GAS×ChatGPT連携入門
- GASエラー解決ガイド
作成日: 2026-02-02
公開予定日: 2026-03-10
コメント