Bikin Form Input Data ke Google Spreadsheet yang Rapi dan Enak di HP
8 menit baca · Diperbarui 2026-07-15
Tim lapangan kamu ngisi data pakai HP, jempolan, sambil jalan. Google Form-nya muat sih, tapi field tanggal minta format aneh, nomor HP masuk tanpa dicek, dan tiap kali mau ganti logika "kalau kategori A munculkan field B" kamu mentok. Form-nya bukan punya kamu. Kamu cuma numpang tinggal di template Google.
Kamu nggak perlu bikin app segede gaban buat lepas dari batasan itu. Cukup satu file HTML sebagai form, satu file Apps Script sebagai jembatan, dan Google Sheet sebagai gudang datanya. Gratis, jalan di HP mana pun, dan validasinya kamu yang atur. Di bawah ini kodenya, tinggal tempel.
Kenapa Google Form sering ga cukup
Google Form itu juara buat survei sekali pakai. Tapi begitu kebutuhannya jadi operasional harian, batasannya kerasa cepat.
- Validasi terbatas. Kamu nggak bisa bilang "nomor HP wajib diawali 08 dan 10-13 digit" lalu tolak yang salah sebelum masuk sheet. Data kotor duluan, bersih-bersihnya belakangan.
- Logika kondisional kaku. Percabangan di Google Form cuma per-section dan ribet. Mau sembunyikan field secara instan berdasarkan pilihan dropdown? Nyaris mustahil.
- Tampilan seragam. Semua Google Form kelihatan sama. Nggak ada logo tim, nggak ada layout yang benar-benar pas buat jempol di layar 5 inci.
- Susah nyambung ke logika lain. Mau kirim notifikasi WhatsApp begitu data masuk, atau hitung nomor antrian otomatis? Google Form berhenti di pengumpulan data mentah.
Begitu kamu pegang HTML dan Apps Script sendiri, semua batasan itu hilang. Dan biayanya tetap nol rupiah.
Arsitektur: HTML + Apps Script + Sheet
Susunannya sederhana dan cuma tiga lapis. Form-nya file HTML yang dilayani Apps Script. Apps Script jadi backend-nya: satu fungsi menyajikan halaman, satu fungsi lagi menerima data dan menulisnya. Sheet-nya murni gudang, satu baris per submit.
- Browser HP membuka URL web app. Apps Script menjalankan doGet() dan mengirim balik halaman form.
- User mengisi form, tekan Simpan. JavaScript di halaman memanggil google.script.run untuk menembak fungsi server.
- Fungsi server memvalidasi data, lalu appendRow ke Sheet. Sukses atau gagal dikembalikan ke halaman buat ditampilkan.
Kalau kamu belum pernah nyentuh Apps Script sama sekali, mampir dulu ke panduan Google Apps Script untuk pemula. Pola web app-nya sendiri dibahas lebih dalam di cara membuat web app dari Google Spreadsheet. Di sini kita fokus ke kasus form input.
Bikin tampilan form mobile-first
Buka editor Apps Script (Extensions > Apps Script dari Sheet kamu), tambahkan file HTML bernama Index. Ini form-nya: input teks, dropdown, tanggal, dan textarea. Viewport-nya kita set lewat addMetaTag di doGet (nanti di Code.gs), jadi nggak perlu ditaruh lagi di head; cukup satu tempat biar nggak dobel. Satu hal lagi: font-size input jangan di bawah 16px, biar Safari iOS nggak zoom-in otomatis pas diketuk.
<!-- File: Index.html -->
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
* { box-sizing: border-box; }
body {
font-family: -apple-system, system-ui, sans-serif;
margin: 0; padding: 20px; background: #f5f6f8;
}
.card {
max-width: 480px; margin: 0 auto; background: #fff;
padding: 20px; border-radius: 12px;
}
label { display: block; margin: 14px 0 4px; font-size: 14px; font-weight: 600; }
input, select, textarea {
width: 100%; padding: 12px; font-size: 16px;
border: 1px solid #d0d4da; border-radius: 8px;
}
button {
width: 100%; margin-top: 18px; padding: 14px;
font-size: 16px; font-weight: 600; color: #fff;
background: #2563eb; border: none; border-radius: 8px;
}
button:disabled { background: #9db4e8; }
#pesan { margin-top: 14px; font-size: 14px; min-height: 18px; }
</style>
</head>
<body>
<div class="card">
<h2>Input Data Kunjungan</h2>
<form id="formData">
<label>Nama</label>
<input type="text" id="nama" required>
<label>Nomor HP</label>
<input type="tel" id="telepon" placeholder="08xxxxxxxxxx" required>
<label>Kategori</label>
<select id="kategori">
<option value="Prospek">Prospek</option>
<option value="Servis">Servis</option>
<option value="Komplain">Komplain</option>
</select>
<label>Tanggal</label>
<input type="date" id="tanggal" required>
<label>Catatan</label>
<textarea id="catatan" rows="3"></textarea>
<button type="submit" id="tombol">Simpan</button>
<div id="pesan"></div>
</form>
</div>
<?!= include('JavaScript'); ?>
</body>
</html>google.script.run: kirim data dari form ke server
Inti dari form ini ada di google.script.run. Ini API bawaan Apps Script yang memanggil fungsi server-mu langsung dari JavaScript halaman, tanpa perlu bikin endpoint atau fetch manual. Kamu pasang withSuccessHandler dan withFailureHandler, lalu panggil nama fungsinya seolah fungsi lokal. Buat file HTML kedua bernama JavaScript:
<!-- File: JavaScript.html -->
<script>
document.getElementById('formData').addEventListener('submit', function (e) {
e.preventDefault();
var data = {
nama: document.getElementById('nama').value,
telepon: document.getElementById('telepon').value,
kategori: document.getElementById('kategori').value,
tanggal: document.getElementById('tanggal').value,
catatan: document.getElementById('catatan').value
};
// Validasi ringan di klien dulu, biar hemat round-trip
// 08 + 8..11 digit = total 10..13 digit
if (!/^08\d{8,11}$/.test(data.telepon)) {
tampilkan('Nomor HP harus diawali 08 dan 10-13 digit.', 'red');
return;
}
setLoading(true);
google.script.run
.withSuccessHandler(function () {
setLoading(false);
tampilkan('Tersimpan. Terima kasih!', 'green');
document.getElementById('formData').reset();
})
.withFailureHandler(function (err) {
setLoading(false);
tampilkan('Gagal: ' + err.message, 'red');
})
.simpanData(data);
});
function setLoading(on) {
var b = document.getElementById('tombol');
b.disabled = on;
b.textContent = on ? 'Menyimpan...' : 'Simpan';
}
function tampilkan(teks, warna) {
var el = document.getElementById('pesan');
el.textContent = teks;
el.style.color = warna;
}
</script>Perhatikan: google.script.run itu asinkron dan nggak balikin Promise. Kamu nggak bisa pakai await di sini. Semua hasil datang lewat handler, jadi taruh logika sukses dan gagal di dalam callback masing-masing. Ini jebakan nomor satu buat yang terbiasa fetch modern.
appendRow: simpan ke sheet plus validasi
Sekarang sisi server. Buat file Code.gs. doGet menyajikan halaman, include menempelkan file HTML lain, dan simpanData memvalidasi lalu menulis baris. Validasi server itu wajib, bukan opsional: validasi klien gampang dilewati, jadi server adalah penjaga terakhir sebelum data masuk Sheet. Regex telepon-nya kita samakan persis dengan pesan di klien, dan tulis-nya dibungkus LockService biar dua submit yang barengan nggak saling injak.
// File: Code.gs
function doGet() {
return HtmlService.createTemplateFromFile('Index')
.evaluate()
.setTitle('Input Data')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
function include(namaFile) {
return HtmlService.createHtmlOutputFromFile(namaFile).getContent();
}
function simpanData(data) {
// Validasi server-side: jangan percaya klien
if (!data.nama || !data.nama.trim()) {
throw new Error('Nama wajib diisi.');
}
// 08 + 8..11 digit = total 10..13 digit
if (!/^08\d{8,11}$/.test(data.telepon)) {
throw new Error('Nomor HP tidak valid.');
}
if (!data.tanggal) {
throw new Error('Tanggal wajib diisi.');
}
// Kunci dulu: Apps Script nggak ngunci sheet sendiri.
// Kalau ada eksekusi lain lagi nulis, tunggu maksimal 10 detik.
var lock = LockService.getScriptLock();
lock.waitLock(10000);
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Data');
if (!sheet) {
sheet = ss.insertSheet('Data');
sheet.appendRow(['Waktu', 'Nama', 'HP', 'Kategori', 'Tanggal', 'Catatan']);
}
sheet.appendRow([
new Date(),
data.nama.trim(),
data.telepon,
data.kategori,
data.tanggal,
data.catatan || ''
]);
} finally {
lock.releaseLock();
}
return 'ok';
}Feedback ke user: loading, sukses, error
Form tanpa feedback bikin orang nekan tombol dua-tiga kali karena ngira nggak jalan, dan data kembar pun masuk. Di kode JavaScript tadi tiga state sudah ditangani: begitu submit, tombol di-disable dan berubah jadi "Menyimpan..." biar nggak bisa diklik dobel; kalau sukses muncul teks hijau dan form di-reset; kalau gagal muncul pesan merah yang isinya persis dari Error yang kamu lempar di server.
Karena pesan error datang dari throw new Error di server, kamu bebas nulis pesan yang manusiawi. "Nomor HP tidak valid" jauh lebih berguna buat orang lapangan daripada stack trace. Anggap teks error sebagai bagian dari UX, bukan sisa buangan.
Deploy sebagai web app dan bagikan link
Kode siap, tinggal terbitkan. Di editor Apps Script, klik Deploy, lalu New deployment.
- Pilih tipe Web app.
- Execute as: Me. Artinya script menulis ke Sheet-mu pakai izinmu, jadi pengisi form nggak perlu punya akses ke Sheet.
- Who has access: pilih Anyone kalau form buat publik, atau Anyone within organization kalau cuma buat tim internal.
- Klik Deploy, setujui izin OAuth sekali, lalu salin URL web app-nya.
- Sebar URL itu ke tim. Buka di HP mana pun langsung jalan, tanpa install apa-apa.
Contoh kasus nyata
Pola yang sama nutup banyak kebutuhan operasional harian, cukup ganti field dan validasinya:
- Absensi lapangan. Field nama, lokasi, dan foto. Timestamp dari new Date() jadi bukti waktu yang nggak bisa dikarang. Soal lokasi otomatis: navigator.geolocation kadang jalan, kadang diblok, karena web app Apps Script hidup di dalam iframe sandbox yang punya permissions-policy sendiri. Sediakan input lokasi manual sebagai cadangan.
- Kasir warung. Dropdown produk, input jumlah, total dihitung di server. Tiap transaksi satu baris, rekap harian tinggal SUM di Sheet.
- Pendataan survei door-to-door. Form panjang dengan field kondisional yang muncul-sembunyi sesuai jawaban, sesuatu yang Google Form nggak sanggup.
Begitu datanya ngumpul rapi di Sheet, langkah lanjutannya jadi gampang. Bikin dashboard realtime dari data itu, atau otomatis terbitkan invoice PDF dari tiap baris yang masuk. Semua nyambung karena sumbernya satu.
Penutup
Form input custom ke Google Spreadsheet itu bukan proyek besar. Tiga file, satu deploy, dan kamu dapat sesuatu yang lebih fleksibel dari Google Form tanpa keluar dari ekosistem Google. Yang bikin lama biasanya bukan ngoding-nya, tapi mikirin field apa saja, validasi mana yang perlu, dan alur data setelah masuk Sheet.
Di situ Skematik lewat mode Web GAS bisa motong waktu: jelaskan form yang kamu mau, dan kamu dapat scaffold Apps Script plus HTML yang tinggal kamu sempurnakan, bukan mulai dari halaman kosong. Kalau mau paham dulu cara nyusun kebutuhannya sebelum ngoding, cara membuat PRD untuk aplikasi ngebantu kamu mikir rapi dulu.
Scaffold app form Web GAS di SkematikBerhenti kompromi sama template. Bikin form yang datanya bener-bener punya kamu.