Absensi Kelas Dengan Google App Script
Panduan Script Absensi Kelas dengan Google Apps Script
Guru: Irfannur Diah, S.Pd, S.Kom Sekolah: School Lab ID, Aceh Tamiang Platform: Google Sheets (Google Workspace versi gratis)
1. Konsep dan Struktur Data
Script ini membuat sistem absensi otomatis di Google Sheets dengan 3 sheet:
| Sheet | Fungsi |
|---|---|
Master Siswa | Daftar tetap siswa (No, NIS, Nama, Kelas) — diisi sekali |
Absensi | Log harian absensi (dibuat otomatis oleh script) |
Rekap Bulanan | Rekap kehadiran per bulan (dibuat otomatis saat dibutuhkan) |
Cara kerja singkat:
- Guru mengisi daftar siswa di sheet
Master Siswa(sekali saja). - Setiap hari, klik menu "Buat Absensi Hari Ini" → script otomatis menambahkan baris absensi untuk semua siswa dengan status default "Hadir".
- Guru tinggal mengubah status siswa yang tidak hadir lewat dropdown (Sakit/Izin/Alpa).
- Kapan saja, klik "Buat Rekap Bulanan" untuk melihat ringkasan kehadiran tiap siswa.
2. Script Lengkap
Salin seluruh kode di bawah ini ke Apps Script Editor (cara install ada di Bagian 3).
/**
* ============================================================
* SCRIPT ABSENSI KELAS - SCHOOL LAB ID
* Dibuat untuk: Irfannur Diah, S.Pd, S.Kom
* Kompatibel dengan Google Workspace versi gratis
* ============================================================
*/
// ---- KONFIGURASI NAMA SHEET (boleh diubah sesuai keinginan) ----
const SHEET_MASTER = "Master Siswa";
const SHEET_ABSEN = "Absensi";
const SHEET_REKAP = "Rekap Bulanan";
// ---- DAFTAR PILIHAN STATUS ABSENSI ----
const STATUS_LIST = ["Hadir", "Sakit", "Izin", "Alpa"];
/**
* onOpen() berjalan OTOMATIS setiap kali file Spreadsheet dibuka.
* Fungsinya membuat menu khusus "Absensi Kelas" di toolbar atas.
*/
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("📋 Absensi Kelas")
.addItem("1️⃣ Buat Absensi Hari Ini", "buatAbsensiHariIni")
.addItem("2️⃣ Cek Siswa Belum Diabsen", "cekBelumDiabsen")
.addItem("3️⃣ Buat Rekap Bulanan", "buatRekapBulanan")
.addSeparator()
.addItem("⚙️ Setup Awal (Jalankan Sekali)", "setupAwal")
.addToUi();
}
/**
* setupAwal() membuat sheet "Master Siswa" dan "Absensi" jika belum ada,
* lengkap dengan header dan 3 baris contoh data dummy.
* Cukup dijalankan SEKALI saat pertama kali pakai.
*/
function setupAwal() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
// --- Buat sheet Master Siswa ---
let masterSheet = ss.getSheetByName(SHEET_MASTER);
if (!masterSheet) {
masterSheet = ss.insertSheet(SHEET_MASTER);
masterSheet.appendRow(["No", "NIS", "Nama Siswa", "Kelas"]);
masterSheet.getRange("A1:D1").setFontWeight("bold")
.setBackground("#4a86e8").setFontColor("#ffffff");
masterSheet.setFrozenRows(1);
masterSheet.setColumnWidths(1, 4, 150);
// Data dummy contoh (boleh dihapus/diganti guru)
masterSheet.appendRow([1, "2024001", "Ahmad Fauzi", "VI A"]);
masterSheet.appendRow([2, "2024002", "Siti Aminah", "VI A"]);
masterSheet.appendRow([3, "2024003", "Budi Santoso", "VI A"]);
}
// --- Buat sheet Absensi ---
let absenSheet = ss.getSheetByName(SHEET_ABSEN);
if (!absenSheet) {
absenSheet = ss.insertSheet(SHEET_ABSEN);
absenSheet.appendRow(["Tanggal", "NIS", "Nama Siswa", "Kelas", "Status", "Keterangan", "Waktu Input"]);
absenSheet.getRange("A1:G1").setFontWeight("bold")
.setBackground("#4a86e8").setFontColor("#ffffff");
absenSheet.setFrozenRows(1);
}
SpreadsheetApp.getUi().alert(
"✅ Setup selesai!\n\nLangkah selanjutnya:\n" +
"1. Buka sheet 'Master Siswa', ganti data dummy dengan data siswa asli.\n" +
"2. Jalankan menu 'Buat Absensi Hari Ini' setiap hari."
);
}
/**
* buatAbsensiHariIni() adalah fungsi utama yang dijalankan SETIAP HARI.
* Mengambil daftar siswa dari Master Siswa, lalu menambahkan baris
* absensi baru di sheet Absensi untuk siswa yang belum diabsen hari itu.
*/
function buatAbsensiHariIni() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const masterSheet = ss.getSheetByName(SHEET_MASTER);
const absenSheet = ss.getSheetByName(SHEET_ABSEN);
if (!masterSheet || !absenSheet) {
SpreadsheetApp.getUi().alert("⚠️ Sheet belum siap. Jalankan menu 'Setup Awal' terlebih dahulu.");
return;
}
const today = formatTanggal(new Date());
const masterData = masterSheet.getDataRange().getValues();
const absenData = absenSheet.getDataRange().getValues();
// Kumpulkan NIS yang SUDAH diabsen hari ini agar tidak dobel
const sudahAbsen = new Set();
for (let i = 1; i < absenData.length; i++) {
if (formatTanggal(absenData[i][0]) === today) {
sudahAbsen.add(String(absenData[i][1]));
}
}
let jumlahDitambah = 0;
for (let i = 1; i < masterData.length; i++) {
const nis = String(masterData[i][1]);
const nama = masterData[i][2];
const kelas = masterData[i][3];
if (nis === "" || sudahAbsen.has(nis)) continue;
absenSheet.appendRow([today, nis, nama, kelas, "Hadir", "", new Date()]);
jumlahDitambah++;
}
// Pasang dropdown pilihan status di kolom E (Status)
const lastRow = absenSheet.getLastRow();
if (lastRow > 1) {
const rule = SpreadsheetApp.newDataValidation()
.requireValueInList(STATUS_LIST, true)
.build();
absenSheet.getRange(2, 5, lastRow - 1, 1).setDataValidation(rule);
}
pewarnaanStatus(); // beri warna otomatis sesuai status
SpreadsheetApp.getUi().alert(
`✅ Absensi hari ini (${today}) sudah dibuat.\n` +
`${jumlahDitambah} siswa baru ditambahkan.\n` +
`Silakan ubah kolom "Status" sesuai kondisi siswa.`
);
}
/**
* pewarnaanStatus() memberi warna latar otomatis pada kolom Status:
* Hijau = Hadir, Kuning = Sakit, Biru = Izin, Merah = Alpa.
* Membuat tampilan absensi lebih mudah dibaca sekilas.
*/
function pewarnaanStatus() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(SHEET_ABSEN);
const lastRow = sheet.getLastRow();
if (lastRow < 2) return;
const range = sheet.getRange(2, 5, lastRow - 1, 1);
// Hapus aturan lama di kolom Status agar tidak menumpuk
const rules = sheet.getConditionalFormatRules().filter(r => {
return !r.getRanges().some(rg => rg.getColumn() === 5);
});
const rHadir = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("Hadir").setBackground("#d9ead3").setRanges([range]).build();
const rSakit = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("Sakit").setBackground("#fff2cc").setRanges([range]).build();
const rIzin = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("Izin").setBackground("#cfe2f3").setRanges([range]).build();
const rAlpa = SpreadsheetApp.newConditionalFormatRule()
.whenTextEqualTo("Alpa").setBackground("#f4cccc").setRanges([range]).build();
rules.push(rHadir, rSakit, rIzin, rAlpa);
sheet.setConditionalFormatRules(rules);
}
/**
* cekBelumDiabsen() menampilkan daftar nama siswa yang kolom
* Status-nya MASIH KOSONG untuk tanggal hari ini.
* Berguna sebagai pengingat sebelum jam pelajaran selesai.
*/
function cekBelumDiabsen() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const absenSheet = ss.getSheetByName(SHEET_ABSEN);
const today = formatTanggal(new Date());
const data = absenSheet.getDataRange().getValues();
let belum = [];
for (let i = 1; i < data.length; i++) {
if (formatTanggal(data[i][0]) === today && data[i][4] === "") {
belum.push(data[i][2]);
}
}
if (belum.length === 0) {
SpreadsheetApp.getUi().alert("✅ Semua siswa sudah diabsen hari ini.");
} else {
SpreadsheetApp.getUi().alert("⚠️ Siswa berikut belum diisi statusnya:\n\n" + belum.join("\n"));
}
}
/**
* buatRekapBulanan() menghitung total Hadir/Sakit/Izin/Alpa per siswa
* untuk bulan tertentu, lalu menampilkannya di sheet "Rekap Bulanan".
* Guru akan diminta memasukkan bulan-tahun (contoh: 06-2026).
*/
function buatRekapBulanan() {
const ui = SpreadsheetApp.getUi();
const response = ui.prompt(
"Rekap Bulanan",
"Masukkan bulan dan tahun (format: MM-YYYY), contoh: 06-2026",
ui.ButtonSet.OK_CANCEL
);
if (response.getSelectedButton() !== ui.Button.OK) return;
const input = response.getResponseText().trim();
const parts = input.split("-");
if (parts.length !== 2 || isNaN(parts[0]) || isNaN(parts[1])) {
ui.alert("⚠️ Format salah. Gunakan format MM-YYYY, contoh: 06-2026");
return;
}
const bulan = parseInt(parts[0]);
const tahun = parseInt(parts[1]);
const ss = SpreadsheetApp.getActiveSpreadsheet();
const absenSheet = ss.getSheetByName(SHEET_ABSEN);
const data = absenSheet.getDataRange().getValues();
const rekap = {}; // { nis: {nama, kelas, Hadir, Sakit, Izin, Alpa} }
for (let i = 1; i < data.length; i++) {
const tgl = data[i][0];
if (!(tgl instanceof Date)) continue;
if (tgl.getMonth() + 1 !== bulan || tgl.getFullYear() !== tahun) continue;
const nis = String(data[i][1]);
const nama = data[i][2];
const kelas = data[i][3];
const status = data[i][4];
if (!rekap[nis]) {
rekap[nis] = { nama: nama, kelas: kelas, Hadir: 0, Sakit: 0, Izin: 0, Alpa: 0 };
}
if (STATUS_LIST.includes(status)) {
rekap[nis][status]++;
}
}
// Hapus sheet rekap lama (jika ada) lalu buat baru
let rekapSheet = ss.getSheetByName(SHEET_REKAP);
if (rekapSheet) ss.deleteSheet(rekapSheet);
rekapSheet = ss.insertSheet(SHEET_REKAP);
rekapSheet.appendRow(["NIS", "Nama Siswa", "Kelas", "Hadir", "Sakit", "Izin", "Alpa", "Total Hari", "% Kehadiran"]);
rekapSheet.getRange("A1:I1").setFontWeight("bold")
.setBackground("#4a86e8").setFontColor("#ffffff");
rekapSheet.setFrozenRows(1);
Object.keys(rekap).forEach(nis => {
const r = rekap[nis];
const total = r.Hadir + r.Sakit + r.Izin + r.Alpa;
const persen = total > 0 ? ((r.Hadir / total) * 100).toFixed(1) + "%" : "0%";
rekapSheet.appendRow([nis, r.nama, r.kelas, r.Hadir, r.Sakit, r.Izin, r.Alpa, total, persen]);
});
rekapSheet.autoResizeColumns(1, 9);
ui.alert(`✅ Rekap bulan ${bulan}-${tahun} berhasil dibuat di sheet "${SHEET_REKAP}".`);
}
/**
* formatTanggal() adalah fungsi bantu (helper) untuk mengubah
* objek Date menjadi teks format dd-MM-yyyy, mengikuti zona waktu
* yang sudah diatur di project Apps Script.
*/
function formatTanggal(date) {
if (!(date instanceof Date)) return "";
const tz = Session.getScriptTimeZone();
return Utilities.formatDate(date, tz, "dd-MM-yyyy");
}
3. Cara Install (Langkah demi Langkah)
-
Buka Google Sheets baru. Buka sheets.google.com → klik Blank/Kosong untuk membuat spreadsheet baru. Beri nama, misalnya "Absensi Kelas VI A - 2026".
-
Buka Apps Script Editor. Di menu atas, klik Extensions (Ekstensi) → Apps Script. Akan terbuka tab baru berisi editor kode dengan file default
Code.gs. -
Hapus kode default. Di dalam editor, akan ada tulisan
function myFunction() { }. Klik di dalam kotak kode, tekan Ctrl+A (pilih semua) lalu Delete. -
Tempel (paste) script. Salin seluruh kode di Bagian 2 di atas, lalu tempel (Ctrl+V) ke editor yang sudah kosong tadi.
-
Simpan project. Klik ikon disket (💾) di pojok kiri atas, atau tekan Ctrl+S. Jika diminta nama project, isi misalnya "Script Absensi".
-
Jalankan fungsi
setupAwaluntuk pertama kali. Di bagian atas editor, ada dropdown daftar fungsi (biasanya bertuliskanonOpen). Klik dropdown itu, pilihsetupAwal, lalu klik tombol ▶ Run (Jalankan). -
Izinkan akses (Authorize). Karena ini pertama kali dijalankan, Google akan menampilkan jendela "Authorization required":
- Klik Review permissions.
- Pilih akun Google guru.
- Akan muncul peringatan "Google hasn't verified this app" — ini wajar karena script buatan sendiri. Klik Advanced (Lanjutan) → Go to [nama project] (unsafe).
- Klik Allow (Izinkan).
-
Cek hasil di Spreadsheet. Kembali ke tab Google Sheets. Akan muncul kotak dialog konfirmasi "Setup selesai!", dan dua sheet baru otomatis terbentuk:
Master SiswadanAbsensi. -
Refresh halaman Spreadsheet (F5) agar menu "📋 Absensi Kelas" muncul di toolbar atas (di sebelah menu Help).
4. Cara Menjalankan Script
Ada 3 cara menjalankan fungsi-fungsi di atas:
A. Lewat Menu (cara paling mudah, dipakai sehari-hari)
Setelah file dibuka, klik menu 📋 Absensi Kelas di toolbar → pilih fungsi yang diinginkan:
- Buat Absensi Hari Ini → dijalankan setiap pagi sebelum pelajaran dimulai.
- Cek Siswa Belum Diabsen → dijalankan kapan saja sebagai pengingat.
- Buat Rekap Bulanan → dijalankan di akhir bulan / saat butuh laporan.
B. Otomatis saat File Dibuka
Fungsi onOpen() berjalan otomatis setiap kali Spreadsheet dibuka — ini hanya memunculkan menu, bukan otomatis mengisi absensi (karena alasan keamanan, Google membatasi fungsi onOpen bawaan/simple trigger tidak boleh menulis data besar tanpa izin eksplisit).
C. Terjadwal Otomatis (Time-driven Trigger) — opsional
Jika ingin sheet Absensi terisi otomatis setiap pagi tanpa diklik manual:
- Di Apps Script Editor, klik ikon jam ⏰ (Triggers) di sisi kiri.
- Klik + Add Trigger di pojok kanan bawah.
- Atur:
- Choose which function to run:
buatAbsensiHariIni - Choose which deployment should run: Head
- Select event source: Time-driven
- Select type of time-based trigger: Day timer
- Select time of day: 06:00 - 07:00 (atau sesuai jam masuk sekolah)
- Choose which function to run:
- Klik Save, lalu lakukan proses Authorize seperti langkah 7 di atas jika diminta.
⚠️ Catatan: Pada akun gratis, fungsi yang dipicu trigger otomatis tidak bisa menampilkan kotak dialog
ui.alert(). Untuk trigger otomatis, hasil cukup dicek langsung di sheetAbsensikeesokan harinya.
5. Pengujian dengan Data Dummy
Sebelum dipakai untuk data siswa asli, uji dulu dengan langkah berikut:
- Jalankan Setup Awal — script akan otomatis mengisi 3 data dummy (Ahmad Fauzi, Siti Aminah, Budi Santoso) di sheet
Master Siswa. - Klik menu Buat Absensi Hari Ini. Periksa apakah:
- Muncul kotak dialog "✅ Absensi hari ini sudah dibuat. 3 siswa baru ditambahkan."
- Sheet
Absensiterisi 3 baris baru dengan status default Hadir.
- Coba ubah salah satu status (misalnya Budi Santoso → Alpa). Periksa apakah warna sel otomatis berubah menjadi merah.
- Jalankan menu Buat Absensi Hari Ini lagi (klik kedua kali di hari yang sama). Pastikan tidak ada baris dobel — seharusnya muncul pesan "0 siswa baru ditambahkan".
- Jalankan Cek Siswa Belum Diabsen — pastikan tampil "Semua siswa sudah diabsen hari ini" (karena semua sudah ada status).
- Jalankan Buat Rekap Bulanan, masukkan bulan-tahun hari ini (contoh
06-2026). Periksa sheetRekap Bulananmuncul dengan angka kehadiran yang sesuai. - Setelah yakin semua berjalan benar, hapus 3 baris data dummy di
Master SiswadanAbsensi, lalu masukkan data siswa kelas yang sebenarnya.
6. Troubleshooting (3 Error Umum)
Error 1: "Exception: You do not have permission to call SpreadsheetApp.getUi()"
Penyebab: Fungsi yang memunculkan kotak dialog (ui.alert, ui.prompt) dijalankan dari luar konteks Spreadsheet — misalnya dijalankan lewat trigger otomatis tengah malam, atau dijalankan langsung dari editor tanpa Spreadsheet aktif.
Solusi: Jalankan fungsi tersebut melalui menu di dalam Spreadsheet (bukan tombol Run di editor), atau jika lewat trigger otomatis, hapus baris ui.alert(...) dari fungsi tersebut karena trigger otomatis tidak bisa menampilkan dialog.
Error 2: Menu "📋 Absensi Kelas" tidak muncul di toolbar
Penyebab: Fungsi onOpen() belum sempat dijalankan ulang, atau halaman belum di-refresh setelah script disimpan.
Solusi: Tutup dan buka kembali file Spreadsheet, atau tekan F5 untuk refresh halaman browser. Jika masih belum muncul, buka Apps Script Editor → pilih fungsi onOpen di dropdown → klik Run secara manual sekali.
Error 3: "Authorization required" muncul berulang kali atau gagal Authorize
Penyebab: Izin akses belum disetujui sepenuhnya, atau menggunakan akun Google yang berbeda dari pemilik file. Solusi: Pastikan login dengan akun Google yang sama dengan pemilik Spreadsheet. Ulangi proses Review Permissions → Advanced → Go to [nama project] (unsafe) → Allow. Jika tetap gagal, coba buka di jendela Incognito/Penyamaran lalu login ulang.
7. Penjelasan Kode (Bahasa Sederhana)
| Bagian Kode | Penjelasan Sederhana |
|---|---|
const SHEET_MASTER, SHEET_ABSEN, SHEET_REKAP | Ini seperti "nama panggilan" untuk tiap sheet, supaya kalau ingin ganti nama sheet, guru cukup ubah di satu tempat ini saja, tidak perlu ubah di seluruh kode. |
const STATUS_LIST | Daftar pilihan status yang bisa dipilih guru (Hadir/Sakit/Izin/Alpa). Bisa ditambah sendiri, misalnya "Terlambat", tinggal tambahkan di dalam tanda kurung siku. |
function onOpen() | Ini "pintu masuk" otomatis — setiap file dibuka, fungsi ini langsung jalan dan membuat menu di toolbar. |
function setupAwal() | Fungsi "instalasi". Mengecek apakah sheet yang dibutuhkan sudah ada; kalau belum, dibuatkan otomatis lengkap dengan header dan contoh data. |
function buatAbsensiHariIni() | Fungsi inti harian. Ia membaca semua nama siswa, mengecek siapa yang belum punya catatan absensi hari ini, lalu menambahkan barisnya satu per satu dengan status awal "Hadir". |
Set (di dalam sudahAbsen) | Seperti "daftar centang" sementara di memori komputer, dipakai supaya script tidak menambahkan nama siswa yang sama dua kali di hari yang sama. |
requireValueInList(...) | Perintah untuk membuat dropdown (menu pilihan) di sel, supaya guru tinggal klik dan pilih, tidak perlu mengetik manual (mengurangi salah ketik). |
function pewarnaanStatus() | Memberi warna otomatis pada sel sesuai isinya — supaya saat sekilas dilihat, guru langsung tahu siapa yang tidak hadir tanpa harus membaca teks satu per satu. |
function cekBelumDiabsen() | Seperti "alarm pengingat" — mengecek kolom Status yang masih kosong hari ini dan menampilkan daftar namanya. |
function buatRekapBulanan() | Fungsi "kalkulator" — menjumlahkan berapa kali tiap siswa Hadir/Sakit/Izin/Alpa dalam satu bulan, lalu menyusunnya menjadi tabel rapi beserta persentase kehadiran. |
function formatTanggal() | Fungsi bantu kecil untuk mengubah format tanggal komputer (yang rumit) menjadi format yang mudah dibaca, yaitu dd-MM-yyyy (contoh: 20-06-2026). |
Tips modifikasi untuk guru:
- Ingin tambah kolom baru (misalnya "Wali Kelas")? Tambahkan di
appendRow([...])padasetupAwal()danbuatAbsensiHariIni()secara konsisten. - Ingin ubah warna status? Cari kode warna hex (contoh
#d9ead3) di fungsipewarnaanStatus()dan ganti sesuai selera (gunakan situs pencari "color picker" untuk memilih kode warna lain). - Ingin tambah status baru seperti "Terlambat"? Cukup tambahkan ke
STATUS_LISTdan buat satu baris aturan warna baru dipewarnaanStatus().
Dirancang & didukung oleh guru.schlab.id