MENU

GASトリガー完全ガイド|定期実行・イベント駆動を使いこなす【2026年版】

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

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次