シフト希望フォームの作り方・自動リマインドの設定手順

LINE公式アカウント × エルメ

シフト希望フォームの作り方・自動リマインドの設定手順

紙もLINEのバラバラ連絡もやめて、「回答フォーム」で集めて自動で催促する。手を動かせば同じ仕組みが作れる設定ガイドです。

1. つくる仕組みの全体像

この記事では、架空の「みやこ旅館」を例に、スタッフのシフト希望をLINEのフォームで集め、出していない人には自動で催促(リマインド)する仕組みを作ります。役割分担はシンプルです。

担当役割
エルメシフト希望フォームの受付・回答の記録・タグ付け・リマインド配信
スプレッドシート回答の保存台帳(シフト希望台帳)と、スタッフ名簿
GAS(Google Apps Script)締切後に「誰が出した/出していない」を集計し、管理者へLINEで自動通知

いちばん大事な前提:Webhookは1つ

LINE公式アカウントで「メッセージの受信を通知する先(Webhook〔ウェブフック〕)」は1つしか設定できません。エルメを使うと、その1枠はエルメが占有します。だからこの設計では、受信はすべてエルメに任せ、GASは「こちらから送る(push)」ことしかしません。GASに受信させようとすると、エルメと取り合いになって動かなくなります。

✅ この記事のGASは「時刻がきたら管理者に集計を送るだけ」。受信しないので、エルメと問題なく共存します。
◆ ◆ ◆

2. エルメで「シフト希望フォーム」を作る

エルメにはフォーム作成という機能があり、無料プランでもアンケート形式の入力フォームが作れます。まずシフト希望を入力してもらうフォームを1枚作ります。

設定の手順

操作場所:エルメ管理画面 > フォーム作成 > 新規作成

  1. 「新規作成」をクリックし、フォーム名を「シフト希望(管理用の名前)」とつける
  2. フォームのタイトルを「〇月シフト希望の提出」、説明文に締切日(例:毎月20日)を書く
  3. 下の表のとおり質問項目を追加する(質問名はそのままの文字で作る。あとでシートの見出しになります)
  4. 「メッセージ・アクション設定」タブを開き、回答後のアクションで「タグを付ける」を選び、タグ名を シフト_提出済 にする
  5. 同じ画面で、回答後に表示するお礼メッセージ(下のテンプレ)を設定して保存する

フォームの質問項目

質問名形式補足
氏名自由入力(必須)名簿と突き合わせるので、いつも同じ表記で書いてもらう
対象月選択(必須)選択肢は「2026年8月」の形で作る(詳細は第6章のGASと合わせる)
希望休自由入力例:3日、10日、17日
勤務NGの時間帯自由入力例:平日の朝は不可 など
備考自由入力(任意)連休希望・引き継ぎ事項など
💡「対象月」を選択式にしておくと、第6章のGASが「今月集めているのは何月分か」を正しく判定できます。選択肢の文字(例:2026年8月)は、月をゼロ埋めしない形(08月ではなく8月)で作ってください。

回答後のお礼メッセージ(コピペ用)

シフト希望のご提出ありがとうございます! ご入力いただいた内容で受け付けました。 変更がある場合は、締切(20日)までにもう一度フォームからご提出ください。
(フォームのリンクをタップ → 入力して送信)
シフト希望のご提出ありがとうございます!締切(20日)まで変更できます。
◆ ◆ ◆

3. フォームの回答をスプレッドシートに連携する

エルメのフォームは、Googleスプレッドシートと連携しておくと回答があるたびに1行ずつ自動で記録されます。これが「シフト希望台帳」になります。

連携の手順

操作場所:エルメ管理画面 > フォーム作成(一覧) > スプレッドシート

  1. フォーム作成の一覧ページで、対象フォームの「スプレッドシート」をクリック
  2. 連携したいGoogleアカウントでサインインし、連携を許可する
  3. 連携後、テストで1回フォームに回答してみる(この操作でシートに見出し行が作られます)
  4. 作られたシートのタブ名を シフト希望台帳 に変更する
⚠️ エルメが連携したシートは、直接編集しないでください。列を挿入したり見出しを書き換えると、新しい回答が反映されなくなることがあります。台帳シートは「見るだけ・GASが読むだけ」にしておきます。

できあがる台帳(シフト希望台帳)

エルメはフォームの質問名を、そのまま見出しにして列を作ります。おおよそ次のような並びになります(先頭に回答日時が入ります)。

見出し中身
回答日時エルメが自動記録
氏名フォームの回答(名簿と突き合わせるキー)
対象月例:2026年8月
希望休例:3日、10日、17日
勤務NGの時間帯例:平日の朝は不可
備考任意
💡 第6章のGASは、この見出し(氏名・対象月)を名前で探して読みます。列の位置が多少前後しても動くように作ってありますが、見出しの文字は第2章のフォーム質問名と必ず一致させてください。
◆ ◆ ◆

4. フォームをスタッフに配布する

フォームには「配信用URL」があります。これをスタッフに配るだけで受付が始まります。配り方は2つ用意しておくと便利です。

① 毎月の配布(予約配信で自動化)

操作場所:エルメ管理画面 > メッセージ配信 > 新規作成

  1. 「新規作成」→ 管理用タイトルを「シフト希望フォーム配布」にする
  2. メッセージ本文に、第2章で作ったフォームの配信用URLを貼る(下のテンプレ)
  3. 配信対象は「全員(スタッフのタグを付けているなら、そのタグで絞り込み)」
  4. 「配信予約」を選び、毎月1日など、締切より前の日時を指定して登録する
【〇月シフト希望の受付】 みやこ旅館スタッフのみなさん、来月のシフト希望を受け付けます。 下のフォームから、20日(締切)までにご提出ください。 ▽ フォームはこちら (ここにフォームの配信用URL)

② いつでも出せる入口(リッチメニュー)

操作場所:エルメ管理画面 > リッチメニュー

リッチメニューに「シフト希望を出す」ボタンを作り、タップ先にフォームの配信用URLを設定しておくと、スタッフが思い立ったときにいつでも提出できます。

【8月シフト希望の受付】20日までにフォームからご提出ください▽(フォームURL)
はーい、あとで出します!
◆ ◆ ◆

5. 未提出のスタッフだけに自動リマインド

ここが「自動リマインド」の中心です。第2章で、フォームに回答した人には シフト_提出済 タグが自動で付くようにしました。つまりこのタグが付いていない人=まだ出していない人です。エルメの予約配信で「このタグが付いていない人だけ」に送れば、未提出者への催促が自動化できます。

リマインドの予約配信を作る

操作場所:エルメ管理画面 > メッセージ配信 > 新規作成

  1. 「新規作成」→ タイトルを「シフト未提出リマインド(15日)」にする
  2. 本文に催促メッセージ(下のテンプレ)とフォームURLを入れる
  3. 配信対象の絞り込みで「タグ」を選び、シフト_提出済 が付いていない人を条件にする
  4. 「配信予約」で毎月15日の朝などを指定して登録する
  5. 同じ要領で「19日(締切前日)」用のリマインドをもう1本作っておく
【リマインド】〇月シフト希望はお済みですか? 20日が締切です。まだの方は、下のフォームからご提出をお願いします🙏 ▽ フォームはこちら (フォームの配信用URL)
⚠️ 毎月の運用で1つだけ大事なこと:新しい月の受付を始める前に、前月の「シフト_提出済」タグを全員から外してください(エルメ管理画面 > 友だちリスト の一括操作、または配布メッセージのアクションで一括解除)。外し忘れると、先月出した人が今月の未提出リマインドから漏れます。
【リマインド】8月シフト希望はお済みですか?20日が締切です▽(フォームURL)
忘れてました!今出します🙏
✅ この配信は「提出済タグが付いた瞬間、次回から対象外」になります。出した人にはもう催促が飛ばないので、しつこくならず安心です。
◆ ◆ ◆

6. 締切後の提出状況を管理者に自動通知(GAS)

第5章までで、スタッフ側の受付とリマインドは完成です。最後に管理側の自動化として、締切後に「提出〇名/未提出〇名(+未提出者の名前)」を、店長のLINEへ自動で送る仕組みをGASで足します。誰を追いかければいいか、一目で分かります。

準備1:名簿シートを作る

台帳(エルメ連携シート)とは別のタブで、スタッフ全員の名簿を手で作ります。こちらは自由に編集して構いません。タブ名は 名簿 にします。

列見出し中身
AスタッフID任意の社員番号(同姓同名の区別用。無ければ空でも可)
B氏名フォームで入力してもらう氏名と同じ表記にする

準備2:管理者のLINEユーザーIDと、チャネルアクセストークン

  • 管理者のLINEユーザーID:LINE Developersコンソールの対象チャネルの基本設定に「あなたのユーザーID(Uから始まる文字列)」が表示されます。これを控えます。
  • チャネルアクセストークン:同じくLINE Developersコンソールの「Messaging API設定」で発行します。GASが送信(push)に使います。これはエルメが使う受信(Webhook)とは別物なので、エルメと競合しません。

GASを貼り付ける

操作場所:スプレッドシート > 拡張機能 > Apps Script

  1. Apps Scriptを開き、最初のコードを全部消して、下のコードを丸ごと貼り付ける
  2. 先頭の設定3か所(トークン・管理者ID・リマインド日)を自分の値に書き換える
  3. 保存し、時計マーク(トリガー)>「トリガーを追加」で dailyCheck を「時間主導型 > 日タイマー > 午前9〜10時」に設定する
/**
 * シフト希望の集計を管理者へ自動通知(push専用・時刻トリガー起動)
 * ※このGASは受信しない。Webhookはエルメが占有。時刻でこちらからpushするだけ。
 * ※台帳シートはエルメ連携シート。GASは「読むだけ」で、絶対に書き込み・編集しない。
 */

// ▼ 設定(自分の環境に合わせて3か所を書き換える)
const CHANNEL_ACCESS_TOKEN = 'ここにチャネルアクセストークンを貼る';
const ADMIN_USER_ID        = 'Uxxxxxxxxxxxxxxxx'; // 管理者のLINEユーザーID
const REMIND_DAYS          = [15, 19]; // この日に「未提出者一覧」を管理者へ
const SUMMARY_DAY          = 21;       // 締切(20日)の翌日に「最終集計」を管理者へ

// シート名(第3章・第6章で決めたタブ名)
const SHEET_ROSTER = '名簿';
const SHEET_LEDGER = 'シフト希望台帳';

// 台帳の見出し名(第2章のフォーム質問名と一致させる)
const COL_NAME  = '氏名';
const COL_MONTH = '対象月';

// 集める対象月のラベル(翌月)。例:7月に実行 → 「2026年8月」
function targetMonthLabel_() {
  const now = new Date();
  let y = now.getFullYear();
  let m = now.getMonth() + 2; // getMonthは0始まりなので +2 で翌月
  if (m > 12) { m -= 12; y += 1; }
  return y + '年' + m + '月';
}

// 台帳から「当月の提出済み氏名」を集める(見出しで列を探すので列位置がずれても動く)
function submittedNames_() {
  const sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_LEDGER);
  const v  = sh.getDataRange().getValues();
  const h  = v[0];
  const iName  = h.indexOf(COL_NAME);
  const iMonth = h.indexOf(COL_MONTH);
  const month  = targetMonthLabel_();
  const set = {};
  for (let r = 1; r < v.length; r++) {
    if (v[r][iMonth] === month && v[r][iName]) {
      set[String(v[r][iName]).trim()] = true;
    }
  }
  return set;
}

// 名簿の全氏名(B列)を配列で返す
function rosterNames_() {
  const v = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_ROSTER).getDataRange().getValues();
  const names = [];
  for (let r = 1; r < v.length; r++) {          // A=スタッフID / B=氏名
    const name = String(v[r][1] || '').trim();  // B列=氏名
    if (name) names.push(name);
  }
  return names;
}

// 毎朝この関数をトリガーで起動する(日付で自動的に出し分け)
function dailyCheck() {
  const day = new Date().getDate();
  if (REMIND_DAYS.indexOf(day) !== -1) { notifyAdmin_(false); return; }
  if (day === SUMMARY_DAY)             { notifyAdmin_(true);  return; }
}

// 管理者へ提出状況をpush(final=true なら締切後の最終集計)
function notifyAdmin_(final) {
  const submitted = submittedNames_();
  const names     = rosterNames_();
  const month     = targetMonthLabel_();
  const notYet = names.filter(function(n){ return !submitted[n]; });
  const done   = names.length - notYet.length;
  const head   = final ? '【最終集計】' : '【途中経過】';
  const body   = head + month + ' シフト希望\n'
               + '提出 ' + done + ' / ' + names.length + '名\n'
               + '未提出:' + (notYet.length ? notYet.join('、') : 'なし');
  pushText_(ADMIN_USER_ID, body);
}

// LINE Messaging API の push(受信しない・こちらから送るだけ)
function pushText_(userId, text) {
  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/push', {
    method: 'post',
    contentType: 'application/json',
    headers: { 'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN },
    payload: JSON.stringify({ to: userId, messages: [{ type: 'text', text: text }] }),
    muteHttpExceptions: true
  });
}
【最終集計】2026年8月 シフト希望 提出 8 / 10名 未提出:田中、佐藤
田中さんと佐藤さんに直接声かけますね
💡 GASが送るのは管理者への集計だけなので、必要なユーザーIDは「管理者1人分」で済みます。スタッフ全員のユーザーIDを集める必要はありません。
◆ ◆ ◆

7. 動作テストとよくあるつまずき

公開前のテスト手順

  1. 自分(またはテスト用アカウント)でフォームに1回回答し、台帳シートに行が増えることを確認する
  2. 回答後、自分に シフト_提出済 タグが付いているか、友だち情報で確認する
  3. 第5章のリマインド配信を「テスト配信」で送り、タグ無しの人にだけ届くか確認する
  4. 第6章のGASで dailyCheck を手動実行し、管理者のLINEに集計が届くか確認する(初回は権限の承認を求められます)

よくあるつまずき

症状原因と対処
台帳に回答が増えない連携シートを手で編集した可能性。第3章の注意のとおり編集しない。1回テスト回答すると復旧します。
提出済みの人にも催促が届く前月の シフト_提出済 タグを外し忘れ。第5章の運用注意を確認。
集計の人数が合わないフォームの氏名表記と名簿B列の表記が違う(例:スペースの有無)。表記を揃える。
GASの集計が「対象月」を拾わないフォームの対象月の選択肢が「2026年8月」の形になっているか確認(08月やスペース混入に注意)。
GASでLINEに送れないチャネルアクセストークンの貼り間違い、または管理者ユーザーIDの誤り。両方を再確認。

まとめ

フォームで集める → タグで「出した人/出していない人」を分ける → 未提出者にだけ自動で催促、という流れで、シフト希望集めの声かけがほぼゼロになります。まず最初の一手は、第2章のフォームを1枚作って自分で回答してみること。ここまで動けば、あとは配信予約とGASを足すだけです。集計通知(第6章)は後回しでも、第5章までで十分に回り始めます。

※ 本記事は架空の旅館を想定したサンプルの構築例です。掲載コードはサンプルであり、ご利用は自己責任でお願いします。