# イベントやフェスティバル向け、シフトを選べるボランティア募集フォーム

> シフトを選べるボランティア募集フォーム。当日の電話番号を集め、人手が足りないシフトを示してシフト表を作るスクリプト付き。

公開日 2026-10-25 · https://ikiform.com/ja/guides/event-registration/volunteer-signup

ボランティアが 1 つのフォームで参加できるシフトをすべてチェックし、電話番号、T シャツのサイズ、緊急連絡先を入力して Ikiform に送信できるようにします。Ikiform は各申し込みを保存してコーディネーターにメールで通知しますが、シフトを埋めたり締め切ったりはしません。そこで、必要人数に対してシフトごとのボランティア数を数え、シフト表を書き出す短いスクリプトを実行します。足りないシフトは、手の空いているボランティアに直接頼んで埋めます。

## ボランティアならではの違い

出欠確認が尋ねるのは「来ますか？」の 1 つだけです。ボランティア募集が尋ねるのは「いつ」で、その答えは各シフトの必要人数と照らし合わせて初めて意味を持ちます。朝 7 時の設営は 6 人必要なのに 2 人しか集まらず、晴れた午後は 10 人必要なところに 19 人集まります。仕事は人数を数えることではなく、穴を埋めることです。

- **選択は 1 つではなく、参加できる時間帯。** 人は複数のシフトに入れます。何が必要かを推測させるのではなく、入れるシフトをすべて尋ね、そこから割り当ててください。
- **当日の連絡先。** メールは計画用です。当日は携帯電話の番号と、ボランティアごとの緊急連絡先が必要です。
- **発注するもの。** T シャツ、ストラップ、昼食を、サイズと数ごとに。
- **年齢。** 多くのイベントでは、ボランティアごとに成人であることか保護者の同意が必要です。何が適用されるかは所属団体に確認してください。チェックボックスは回答を記録しますが、法的な確認にはなりません。

SignUpGenius などのボランティア向けプラットフォームは、枠ごとに申し込みを受け付け、満員になると締め切ります。枠ごとの厳密な上限が必要なら、それを使ってください。Ikiform は、フォームを自分のサイトに置き、整ったリストから手作業でシフトを割り当てたい主催者に向いています。

図: ボランティアの参加可能時間を、穴が見えるシフト表に変える

1. ボランティアは申し込みフォームで入れるシフトをすべてチェックし、フォームは Ikiform に送信されます。
2. Ikiform は各申し込みを保存し、コーディネーターにメールで通知します。
3. スクリプトが API で申し込みを読み込み、シフトごとのボランティア数を必要人数と比べて数えます。
4. 各シフトの名前と電話番号を載せた rota.csv を書き出します。
5. 6 人中 2 人の設営のように、人手が足りないシフトがすぐにわかるので、他で手の空いているボランティアに頼めます。

Ikiform が参加可能時間を保持し、スクリプトがそれを充足状況に変え、最終的な判断はコーディネーターが行います。

## フォーム

一覧しやすいよう、シフトを日ごとにまとめます。チェックボックスの name は `shifts[]` なので、1 つだけチェックしてもリストとして保存されます。プレーンな HTML として、埋め込みを受け付けるどのサイトやビルダーでも動きます:

`volunteer.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label>Name <input name="name" autocomplete="name" required></label>
  <label>Email <input name="email" type="email" autocomplete="email" required></label>
  <label>Mobile number for the day <input name="phone" type="tel" autocomplete="tel" placeholder="+44 7700 900123" required></label>

  <fieldset>
    <legend>Shifts you can do</legend>
    <p>Saturday</p>
    <label><input type="checkbox" name="shifts[]" value="sat_setup"> 7:00 to 10:00, setup</label>
    <label><input type="checkbox" name="shifts[]" value="sat_day"> 10:00 to 14:00</label>
    <label><input type="checkbox" name="shifts[]" value="sat_late"> 14:00 to 18:00</label>
    <p>Sunday</p>
    <label><input type="checkbox" name="shifts[]" value="sun_day"> 10:00 to 14:00</label>
    <label><input type="checkbox" name="shifts[]" value="sun_pack"> 14:00 to 17:00, pack-down</label>
  </fieldset>

  <label>Where you'd like to help
    <select name="role">
      <option value="anywhere">Anywhere</option>
      <option value="welcome">Welcome desk</option>
      <option value="food">Food stall</option>
      <option value="stewarding">Stewarding</option>
    </select>
  </label>
  <label>T-shirt size
    <select name="tshirt" required>
      <option value="s">S</option><option value="m" selected>M</option><option value="l">L</option>
      <option value="xl">XL</option><option value="xxl">XXL</option>
    </select>
  </label>
  <label>Emergency contact name and number <input name="emergency_contact" required maxlength="160"></label>
  <label><input type="checkbox" name="adult" required> I'm 18 or over, or a parent or guardian is filling this in with me</label>

  <input type="hidden" name="_redirect" value="https://fair.example/volunteers/thanks">
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
  <button type="submit">Sign me up</button>
</form>
```

この定義をフォームの **Fields** タブに貼り付けます。これで、どのページから来た送信でも、シフトが選ばれていない申し込み、電話番号として正しくない番号、年齢のチェックボックスが未チェックの申し込みをサーバーが拒否します:

フォーム: Volunteer signup

- **名前** (`name`, text, 必須)
- **メールアドレス** (`email`, email, 必須)
- **当日連絡のつく携帯電話番号** (`phone`, phone, 必須)
- **参加できるシフト** (`shifts`, multi_select, 必須)
- **手伝いたい場所** (`role`, select)
- **T シャツのサイズ** (`tshirt`, select, 必須)
- **緊急連絡先の氏名と電話番号** (`emergency_contact`, text, 必須)
- **18 歳以上です（または保護者と一緒に入力しています）** (`adult`, checkbox, 必須)

`shifts` は `min_items: 1` の `multi_select` です。`phone` は番号の形式を確認する `phone` フィールドです。`adult` はチェックが必須です。

| フィールド | 尋ねる理由 |
| --- | --- |
| `phone` | シフト変更の連絡と、当日の人探し |
| `shifts` | 割り当ての元になる参加可能時間 |
| `role` | 希望。受付を希望した人を受付に配置するため |
| `tshirt` | 2 週間前に出す発注 |
| `emergency_contact` | 救護チームのためで、マーケティング用ではない |
| `adult` | 団体の年齢ルール。独自の `created_at` を持つ送信データに記録される |

> 電話番号と緊急連絡先は、申し込んだ本人以外の人の個人データも含みます。エクスポートは非公開の場所に保管し、シフト表はシフトリーダーとだけ共有し、イベント後に送信データを削除してください。

## シフト表を作り、穴を確認する

状況を知りたいときはいつでも、Node とシークレット API キーでこれを実行します。各ボランティアの最新の申し込みを使い、シフトごとに充足、不足、余裕を表示し、シフトごとの名前と番号を載せた `rota.csv` を書き出します:

`rota.ts`:

```ts
import { writeFileSync } from "node:fs";
import { createClient } from "@ikiform/sdk";

const NEEDED: Record<string, number> = { sat_setup: 6, sat_day: 10, sat_late: 10, sun_day: 8, sun_pack: 6 };
const ikiform = createClient({ apiKey: process.env.IKIFORM_SECRET_KEY! });
const people = new Map<string, Record<string, unknown>>();

for await (const submission of ikiform.submissions.iterate({ formId: "frm_xxxxxxxxxxxxxxxx", status: "received", limit: 100 })) {
  const email = String(submission.fields.email ?? "").trim().toLowerCase();
  if (email && !people.has(email)) people.set(email, submission.fields);
}

const cell = (value: unknown) => `"${String(value ?? "").replaceAll('"', '""')}"`;
const rows = [["shift", "name", "phone", "role", "tshirt"].join(",")];

for (const [shift, needed] of Object.entries(NEEDED)) {
  const team = [...people.values()].filter((fields) => (fields.shifts as string[] | undefined)?.includes(shift));
  const state = team.length < needed ? `SHORT ${needed - team.length}` : team.length > needed ? "spare" : "ok";
  console.log(`${shift.padEnd(10)} ${team.length}/${needed} ${state}`);
  for (const fields of team) {
    rows.push([shift, fields.name, fields.phone, fields.role, fields.tshirt].map(cell).join(","));
  }
}

writeFileSync("rota.csv", `${rows.join("\n")}\n`);
```

- 一覧は新しい順に返るので、参加可能時間を変えて申し込み直したボランティアは、最新の回答で数えられます。
- 各人はチェックしたすべてのシフトの下に表示されます。これは参加可能時間です。CSV で割り当てに絞り込み、各人に確定したシフトを伝えてください。
- 名前に含まれるカンマや引用符はエスケープされるので、CSV はどのスプレッドシートでも問題なく開けます。

コードなしでざっと見るなら、**Submissions** から CSV をエクスポートし、`shifts` 列を `sat_setup` のようなシフトの値で絞り込みます。エクスポートでは、複数選択の値は 1 つのセルにまとめられます。

## 参加可能時間から割り当てへ

1. 2 週間前にシフト表を作り、`tshirt` の数で T シャツを発注します。
2. 不足しているシフトごとに、手が空いていて、そのシフトにもチェックを入れたボランティアに連絡します。参加できると本人がすでに答えています。
3. 自分のメールやメッセージツールから、各ボランティアに確定したシフトを送ります。通知メールの **Reply** は本人に直接届きます。
4. 前日に、電話番号付きのシフト表をシフトリーダー用に印刷します。

Ikiform はフォームを入力した本人にはメールを送りません。通知メールが届くのはあなたとチームだけなので、自動返信、確認メール、ダブルオプトインはありません。それらは [Webhook](https://ikiform.com/ja/docs/webhooks.md) をきっかけに、自分のメールツールから送ってください。ボランティアは何に申し込んだかを忘れるので、確定したシフト表を 1 週間前と前日の夜に個別に送りましょう。

チームがふだん使っている場所で申し込みを知るには、Webhook を [Slack](https://ikiform.com/blog/form-submissions-to-slack.md) や [Discord](https://ikiform.com/blog/form-submissions-to-discord.md) に送ります。そうすれば、不足していたシフトが埋まっていく様子をコーディネーターがその場で見られます。

## 募集を始める前に確認する

1. フォームの **Allowed domains** に自分のサイトのドメインを追加し、開発中は `localhost` も追加します。空のままにすると、どこからの送信も受け付けます。
2. シフトを 1 つチェックして申し込みます。ダッシュボードでは、`shifts` が値 1 つのリストになっています。
3. シフトを選ばずに、または年齢のチェックボックスをオフにして申し込んでみます。ブラウザーが止め、細工した送信には `422` が返ります。
4. 通知の各受信者の受信トレイを確認します。それぞれにフィールド入りのメールが届き、フォームに `email` フィールドがあれば **Reply** で送信者に返信できます。
5. シフト表のスクリプトを実行します。テストの申し込みがそのシフトの下に表示され、他のシフトはすべて不足と表示されます。
6. `rota.csv` をスプレッドシートで開き、電話番号の列を確認します。

## ハマりどころ

| 問題 | 対処法 |
| --- | --- |
| シフトが 1 つだとリストではなくテキストとして保存される | チェックボックスの name が `[]` なしの `shifts` で、フィールドも定義されていません。name を `shifts[]` に変えるか、`shifts` を `multi_select` として定義してください。 |
| `phone` で `422` | 番号が電話番号の形式になっていません。定義のように、ヘルプテキストで国番号の入力を求めてください。 |
| シフト表に同じボランティアが 2 回出てくる | 2 つの異なるメールアドレスで申し込んでいます。スクリプトはメールアドレスで区別するので、手作業でまとめてください。 |
| `422 validation_failed` | 送信がフォームのフィールド定義に合っていません。`error.fields` に各フィールドと理由が示されます。入力欄の `name` をフィールド ID に合わせてください。 |
| `429 rate_limited` | 1 人の訪問者がフォームのレート制限を超えて送信しました。Standard では訪問者ごとに 1 分あたり 5 件までです。`Retry-After` まで待つか、共有の IP 1 つから送信するフォームには Relaxed か Custom を選んでください。 |

## よくある質問

### Ikiform は満員になったシフトを締め切れますか？

いいえ。Ikiform には選択肢ごとの上限はありません。参加可能時間を尋ね、スクリプトやスプレッドシートでシフトごとのボランティア数を数え、自分で人を割り当ててください。厳密な上限のほうが重要なら、枠ごとに申し込む形式のツールを使ってください。

### 1 人のボランティアから複数のシフトを集めるには？

name が shifts[] のチェックボックスを使い、shifts を multi_select フィールドとして定義します。チェックしたシフトはすべて 1 つのリストに保存され、min_items: 1 で少なくとも 1 つが必須になります。

### ボランティアはシフトを変更できますか？

同じメールアドレスでもう一度申し込んでもらってください。シフト表のスクリプトは各ボランティアの最新の申し込みを使うので、新しい参加可能時間が古いものに置き換わります。

### Ikiform はフォームを送信した本人にメールを送れますか？

いいえ。Ikiform がメールを送るのはあなたとチームで、送信者ではないので、自動返信や確認メールはありません。Webhook をメールツールに送り、そこから確認メールを送ってください。

### Ikiform は無料ですか？

いいえ、無料プランはありません。テストは無料で、支払う前に localhost から月 50 件のテスト送信ができます。本番運用するには、月 $6 で 500 件からの Pro か、1 回払いで 10,000 件 $49 または 50,000 件 $149 のパックを選べます。クレジットに有効期限はありません。

## その他のガイド

- [イベント登録](https://ikiform.com/ja/guides/event-registration.md): 自分のイベントページで出欠を受け付けます。フォーム、同伴者の上限、正確な人数集計、満員時の締め切り、受付リストまで、チケットアプリなしで。
- [Eventbrite なしで](https://ikiform.com/ja/guides/event-registration/without-eventbrite.md): 無料のコミュニティイベントの参加登録を自分のサイトで運営します。セッションの選択、自分のツールからの確認メール、部屋ごとの人数、受付リストまで。
- [結婚式の出欠](https://ikiform.com/ja/guides/event-registration/wedding-rsvp.md): 自作の結婚式サイト用の出欠フォーム。招待ごとに 1 回答、名前のあるゲストごとに料理を選び、締め切りと未回答者のリストも用意します。
