# Formulir pendaftaran relawan dengan shift, untuk acara dan festival

> Formulir pendaftaran relawan tempat orang memilih shift, dengan nomor telepon untuk hari H, dan skrip yang menunjukkan shift mana yang kurang orang dan menyusun jadwalnya.

Terbit 2026-10-25 · https://ikiform.com/id/guides/event-registration/volunteer-signup

Biarkan relawan mencentang setiap shift yang bisa mereka ambil dalam satu formulir, dengan nomor telepon, ukuran kaus, dan kontak darurat, lalu kirim ke Ikiform. Ikiform menyimpan setiap pendaftaran dan mengirim email ke koordinator, tetapi tidak mengisi atau menutup shift, jadi jalankan skrip pendek yang menghitung relawan per shift dibandingkan kebutuhan Anda dan menulis jadwalnya. Isi shift yang kurang dengan menghubungi langsung relawan yang masih luang.

## Apa yang berbeda dari relawan

RSVP menanyakan satu hal: apakah Anda datang? Pendaftaran relawan menanyakan kapan, dan jawabannya hanya berarti jika dibandingkan dengan kebutuhan tiap shift. Persiapan pukul 7 pagi butuh enam orang dan hanya dapat dua; sore yang cerah butuh sepuluh dan dapat sembilan belas. Tugasnya bukan menghitung peserta, melainkan memastikan semua shift terisi.

- **Ketersediaan, bukan satu pilihan.** Orang bisa mengambil beberapa shift. Tanyakan semua shift yang bisa mereka ambil lalu tugaskan dari situ, alih-alih membuat mereka menebak apa yang dibutuhkan.
- **Kontak di hari H.** Email untuk perencanaan. Di hari H Anda butuh nomor ponsel, dan kontak darurat untuk setiap relawan.
- **Barang yang perlu dipesan.** Kaus, lanyard, dan makan siang, berdasarkan ukuran dan jumlah.
- **Usia.** Banyak acara mensyaratkan relawan sudah dewasa, atau mendapat persetujuan wali. Tanyakan ke organisasi Anda aturan yang berlaku; checkbox mencatat jawabannya tetapi bukan pemeriksaan hukum.

Platform relawan seperti SignUpGenius menjalankan pendaftaran berbasis slot yang menutup slot saat penuh. Jika Anda butuh batas ketat per slot, pakai salah satunya. Ikiform cocok untuk penyelenggara yang ingin formulir ada di situs mereka sendiri dan tidak keberatan menugaskan shift secara manual dari daftar yang rapi.

Diagram: Mengubah ketersediaan relawan menjadi jadwal yang menunjukkan kekurangannya

1. Relawan mencentang setiap shift yang bisa mereka ambil di formulir pendaftaran, yang mengirim ke Ikiform.
2. Ikiform menyimpan setiap pendaftaran dan mengirim email ke koordinator.
3. Sebuah skrip membaca pendaftaran lewat API dan menghitung relawan per shift dibandingkan kebutuhan tiap shift.
4. Skrip menulis rota.csv berisi nama dan nomor telepon untuk setiap shift.
5. Shift yang kurang orang langsung terlihat, misalnya persiapan dengan 2 dari 6, sehingga Anda bisa meminta relawan yang luang di shift lain.

Ikiform menyimpan ketersediaan. Skrip mengubahnya menjadi cakupan shift, dan koordinator yang membuat keputusan akhir.

## Formulirnya

Kelompokkan shift per hari agar mudah dipindai. Checkbox diberi nama `shifts[]`, jadi satu centang pun tetap disimpan sebagai daftar. Ini berfungsi sebagai HTML biasa di situs atau pembuat situs mana pun yang menerima embed:

`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>
```

Tempel definisi ini di tab **Fields** formulir. Server lalu menolak pendaftaran tanpa shift, nomor telepon yang tidak valid, atau kotak usia yang tidak dicentang, dari halaman mana pun asalnya:

Formulir: Volunteer signup

- **Nama** (`name`, text, wajib)
- **Email** (`email`, email, wajib)
- **Nomor ponsel untuk hari H** (`phone`, phone, wajib)
- **Shift yang bisa Anda ambil** (`shifts`, multi_select, wajib)
- **Bagian yang ingin Anda bantu** (`role`, select)
- **Ukuran kaus** (`tshirt`, select, wajib)
- **Nama dan nomor kontak darurat** (`emergency_contact`, text, wajib)
- **Saya berusia 18 tahun ke atas, atau orang tua atau wali mengisi ini bersama saya** (`adult`, checkbox, wajib)

`shifts` adalah `multi_select` dengan `min_items: 1`. `phone` adalah field `phone`, yang memeriksa format nomor. `adult` wajib dicentang.

| Field | Alasan ada di sini |
| --- | --- |
| `phone` | Mengirim SMS soal perubahan shift dan mencari orang di hari H |
| `shifts` | Ketersediaan sebagai dasar penugasan |
| `role` | Preferensi, agar meja penyambutan diisi orang yang memintanya |
| `tshirt` | Pesanan yang Anda buat dua minggu sebelumnya |
| `emergency_contact` | Untuk tim P3K, bukan untuk pemasaran |
| `adult` | Aturan usia organisasi Anda, dicatat pada kiriman yang menyimpan `created_at`-nya sendiri |

> Nomor telepon dan kontak darurat adalah data pribadi tentang orang yang tidak mendaftar sendiri. Simpan hasil ekspor di tempat privat, bagikan jadwal hanya ke ketua shift, dan hapus kiriman setelah acara.

## Susun jadwal dan lihat kekurangannya

Jalankan ini dengan Node dan secret API key kapan pun Anda ingin melihat gambarannya. Skrip mengambil pendaftaran terbaru tiap relawan, mencetak setiap shift sebagai terisi, kurang, atau berlebih, dan menulis `rota.csv` berisi nama dan nomor untuk setiap shift:

`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`);
```

- Daftar diurutkan dari yang terbaru, jadi relawan yang mendaftar lagi dengan ketersediaan berbeda dihitung dari jawaban terbarunya.
- Satu orang muncul di setiap shift yang dicentangnya. Itu ketersediaan. Pangkas menjadi penugasan di CSV, lalu beri tahu setiap orang shift akhir mereka.
- Koma dan tanda kutip dalam nama di-escape, sehingga CSV terbuka dengan rapi di spreadsheet mana pun.

Untuk melihat cepat tanpa kode, ekspor CSV dari **Submissions** dan filter kolom `shifts` dengan nilai suatu shift, seperti `sat_setup`. Nilai multi-select dalam ekspor digabung dalam satu sel.

## Dari ketersediaan ke penugasan

1. Dua minggu sebelumnya, jalankan jadwal dan pesan kaus dari hitungan `tshirt`.
2. Untuk setiap shift yang kurang, hubungi relawan yang masih luang dan juga mencentang shift itu. Mereka sudah menyatakan bisa.
3. Kirim shift akhir ke setiap relawan dari alat email atau pesan Anda. **Reply** di email notifikasi langsung terkirim ke mereka.
4. Sehari sebelumnya, cetak jadwal untuk ketua shift, lengkap dengan nomor telepon.

Ikiform tidak mengirim email ke orang yang mengisi formulir. Email notifikasi hanya dikirim ke Anda dan tim, jadi tidak ada autoresponder, email konfirmasi, atau double opt-in. Kirim semua itu dari alat email Anda, dipicu oleh [webhook](https://ikiform.com/id/docs/webhooks.md). Relawan sering lupa apa yang mereka daftarkan, jadi kirim jadwal akhir secara personal seminggu sebelumnya, dan sekali lagi malam sebelumnya.

Agar setiap pendaftaran masuk ke tempat tim Anda biasa berdiskusi, kirim webhook ke [Slack](https://ikiform.com/blog/form-submissions-to-slack.md) atau [Discord](https://ikiform.com/blog/form-submissions-to-discord.md). Koordinator lalu melihat shift yang kurang terisi secara langsung.

## Cek sebelum merekrut

1. Di **Allowed domains** formulir, tambahkan domain situs Anda, ditambah `localhost` selama pengembangan. Biarkan kosong untuk menerima kiriman dari mana saja.
2. Daftar dengan satu shift dicentang. Di dashboard, `shifts` berupa daftar dengan satu nilai.
3. Coba daftar tanpa shift, atau dengan kotak usia tidak dicentang. Browser menghentikan Anda, dan kiriman buatan mendapat `422`.
4. Cek inbox setiap penerima notifikasi. Masing-masing mendapat email berisi field, dan **Reply** terkirim ke pengirim formulir jika formulir punya field `email`.
5. Jalankan skrip jadwal. Kiriman uji Anda muncul di bawah shift-nya, dan semua shift lain tampil kurang.
6. Buka `rota.csv` di spreadsheet dan cek kolom nomor telepon.

## Hal yang sering menjebak

| Masalah | Yang harus dilakukan |
| --- | --- |
| Satu shift disimpan sebagai teks, bukan daftar | Checkbox diberi nama `shifts` tanpa `[]`, dan tidak ada field yang didefinisikan. Ganti namanya menjadi `shifts[]`, atau definisikan `shifts` sebagai `multi_select`. |
| `422` pada `phone` | Nomornya tidak terlihat seperti nomor telepon. Minta kode negara di teks bantuan, seperti pada definisinya. |
| Seorang relawan muncul dua kali di jadwal | Mereka mendaftar dengan dua email berbeda. Gabungkan secara manual; skrip memakai email sebagai kunci. |
| `422 validation_failed` | Kiriman tidak cocok dengan definisi field formulir. `error.fields` menyebutkan setiap field dan alasannya. Samakan `name` input dengan ID field. |
| `429 rate_limited` | Satu pengunjung mengirim melebihi rate limit formulir. Standard mengizinkan 5 per menit per pengunjung. Tunggu sesuai `Retry-After`, atau pilih Relaxed atau Custom untuk formulir yang mengirim dari satu IP bersama. |

## Pertanyaan

### Bisakah Ikiform menutup shift saat sudah penuh?

Tidak. Ikiform tidak punya batas per opsi. Tanyakan ketersediaan, hitung relawan per shift dengan skrip atau sheet, lalu tugaskan orang sendiri. Pakai alat pendaftaran berbasis slot jika batas ketat lebih penting.

### Bagaimana mengumpulkan beberapa shift dari satu relawan?

Gunakan checkbox bernama shifts[] dan definisikan shifts sebagai field multi_select. Setiap shift yang dicentang disimpan dalam satu daftar, dan min_items: 1 membuat minimal satu wajib dipilih.

### Bisakah relawan mengubah shift mereka?

Minta mereka mendaftar lagi dengan email yang sama. Skrip jadwal memakai pendaftaran terbaru tiap relawan, sehingga ketersediaan yang baru menggantikan yang lama.

### Bisakah Ikiform mengirim email ke orang yang mengisi formulir?

Tidak. Ikiform mengirim email ke Anda dan tim, bukan ke pengirim formulir, jadi tidak ada autoresponder atau email konfirmasi. Kirim webhook ke alat email Anda dan kirim konfirmasinya dari sana.

### Apakah Ikiform gratis?

Tidak, tidak ada paket gratis. Pengujian gratis: Anda bisa mengirim 50 kiriman uji per bulan dari localhost sebelum membayar. Untuk go live, Pro mulai $6/bln untuk 500 kiriman, atau Anda bisa bayar sekali untuk 10.000 kiriman seharga $49 atau 50.000 kiriman seharga $149, dengan kredit yang tidak pernah kedaluwarsa.

## Panduan lainnya

- [Pendaftaran acara](https://ikiform.com/id/guides/event-registration.md): Terima RSVP di halaman acara Anda sendiri: formulir, batas tamu, jumlah peserta yang jujur, menutup saat penuh, dan daftar check-in, tanpa aplikasi tiket.
- [Tanpa Eventbrite](https://ikiform.com/id/guides/event-registration/without-eventbrite.md): Jalankan pendaftaran acara komunitas gratis di situs Anda sendiri: pilihan sesi, email konfirmasi dari alat Anda sendiri, hitungan per ruangan, dan daftar check-in.
- [RSVP pernikahan](https://ikiform.com/id/guides/event-registration/wedding-rsvp.md): Formulir RSVP untuk website pernikahan yang Anda buat sendiri: satu balasan per undangan, satu menu per tamu yang disebut namanya, tenggat, dan daftar siapa yang belum membalas.
