Skip to main content
24 Agustus 2026 · 6 min read · go

Membangun KAI Ticket Notifier dengan Go, Chromium, dan Telegram

Studi teknis membangun monitor tiket kereta berbasis Go: antrean Chromium, proxy verification, challenge backoff, webhook Telegram, command operasional, dan bukti notifikasi kursi tersedia.

go browser-automation chromium telegram-bot cloudflare-tunnel monitoring kai
Membangun KAI Ticket Notifier dengan Go, Chromium, dan Telegram

Membangun KAI Ticket Notifier dengan Go, Chromium, dan Telegram

Mengecek tiket kereta satu kali itu mudah. Masalahnya berubah ketika saya perlu memantau kereta tertentu untuk beberapa tanggal, mengulang pencarian secara berkala, lalu mengetahui perubahan ketersediaan tanpa terus membuka halaman pemesanan.

Saya membangun KAI Ticket Notifier, service Go yang menjalankan pencarian resmi BookingKAI melalui Chromium, memfilter hasilnya, dan mengirim notifikasi ke Telegram saat kursi yang cocok muncul. Source code tersedia di GitHub, sedangkan rangkuman produk dan keputusan teknisnya ada di case study KAI Ticket Notifier.

Bukti Hasil Nyata

Pada 24 Agustus 2026, monitor mendeteksi 1 kursi Bengawan kelas Ekonomi (C) untuk rute Lempuyangan–Cikarang tanggal 8 September 2026 dengan harga Rp74.000. Notifikasi dikirim ke Telegram lengkap dengan kereta, kelas, jumlah kursi, harga, provider, rute, dan catatan monitor.

Notifikasi Telegram KAI Ticket Notifier ketika satu kursi Bengawan tersedia seharga Rp74.000

Screenshot ini bukan mockup. Ia berasal dari instance monitor yang berjalan di server dan memeriksa BookingKAI. Kolom avatar dipotong untuk menjaga privasi akun Telegram.

Hasil tersebut juga memperlihatkan masalah produk yang saya temukan setelah sistem benar-benar dipakai: selama satu kursi tetap tersedia, versi ini mengirim notifikasi pada beberapa polling berturut-turut. Itu membuktikan jalur deteksi bekerja, tetapi juga mengungkap kebutuhan deduplication atau cooldown agar alert berikutnya hanya dikirim ketika fingerprint ketersediaan berubah.

Mengapa Menggunakan Browser Automation?

Provider resmi bergantung pada alur browser dan session state. Mengandalkan endpoint privat yang tidak terdokumentasi akan lebih ringan, tetapi kontraknya bisa berubah tanpa pemberitahuan. Karena itu saya memilih Chromium untuk provider BookingKAI.

Konsekuensinya, sistem harus menangani lebih banyak hal daripada HTTP request biasa:

  • lifecycle proses browser;
  • cookie dan session state;
  • challenge atau CAPTCHA;
  • pembatasan concurrency;
  • proxy yang benar-benar digunakan browser;
  • parsing hasil pencarian;
  • cleanup saat service dihentikan.

Bot ini tidak mencoba memecahkan atau melewati CAPTCHA secara otomatis. Ketika challenge muncul, monitor melakukan backoff dan dapat membutuhkan intervensi manual.

Arsitektur

graph LR
  A[YAML Config] --> B[Go Schedulers]
  B --> C[Shared Browser Queue]
  C --> D[Chromium]
  D --> E[BookingKAI]
  C --> F[Train and Price Filters]
  F --> G[Telegram Notifications]
  H[Telegram Commands] --> I[Webhook]
  J[Cloudflare Tunnel] --> I
  I --> B

Ada tiga keputusan utama di desain ini.

1. Satu Shared Browser Queue

Beberapa tanggal dapat dipantau sekaligus, tetapi request BookingKAI diproses serial melalui satu antrean. Scheduler hanya menghasilkan pekerjaan; queue yang memiliki browser dan mengeksekusi pencarian.

Pendekatan ini sengaja menukar throughput dengan stabilitas. Untuk beberapa monitor pribadi, lima pencarian paralel tidak memberi manfaat berarti jika hasilnya justru session corruption atau challenge lebih sering.

2. Staggered Scheduler

Ketika service mulai, monitor tidak semuanya menembak provider pada detik yang sama. Start setiap scheduler diberi jeda bertahap. Pola ini mengurangi burst traffic dan membuat log lebih mudah dibaca.

3. Konfigurasi Operasional di YAML

Rute, tanggal, interval, filter, dan provider berada di config.yml. Menambahkan tanggal baru tidak memerlukan perubahan source code atau rebuild aplikasi.

trains:
  - name: BENGAWAN
    origin: LPN
    destination: CKR
    date: "2026-09-08"
    interval: 60
    notes: "kereta pulang"
    providers:
      - name: bookingkai
        proxy_url: "socks5://127.0.0.1:40000"

Token Telegram dan nilai sensitif tidak pernah ditampilkan di artikel atau dimasukkan ke contoh konfigurasi.

Memastikan Proxy Benar-Benar Dipakai

Mencantumkan proxy di konfigurasi belum membuktikan Chromium memakainya. Saat startup, service membandingkan IP direct server dengan IP yang terlihat dari browser melalui proxy. Monitor baru dianggap siap setelah keduanya berbeda.

Pemeriksaan ini penting karena kegagalan proxy sering bersifat diam-diam: aplikasi tetap berjalan, tetapi seluruh request keluar dari IP server.

Startup Validation

Sebelum polling rutin dimulai, setiap konfigurasi divalidasi dengan pencarian nyata. Service memastikan nama kereta yang diminta memang ditemukan pada rute dan tanggal tersebut. Ini menangkap typo atau konfigurasi basi lebih awal daripada menunggu monitor kosong berjam-jam.

Untuk lima tanggal, runtime akan menginisialisasi lima monitor, menjalankan pencarian masing-masing, lalu mencatat bahwa seluruh kereta berhasil divalidasi.

Telegram sebagai Control Plane Ringan

Telegram bukan hanya tujuan notifikasi. Bot juga menyediakan command untuk melihat dan mengendalikan monitor:

CommandFungsi
/list [n]Daftar monitor atau detail satu monitor
/check [n]Jalankan pemeriksaan manual
/status [n]Ringkasan kesehatan atau detail monitor
/history <n> [count]Riwayat pemeriksaan
/toggle <n>Pause atau resume monitor
/sleep <n> <menit>Pause sementara dengan auto-resume

Command status Telegram menampilkan empat monitor dan statistik 2.591 pemeriksaan

Pada contoh operasional di atas, /status merangkum empat monitor dan 2.591 pemeriksaan: 2.423 sukses dan 168 gagal. Itu setara success rate sekitar 93,5%. Angka tersebut adalah statistik runtime pada saat screenshot diambil, bukan klaim SLA jangka panjang.

Screenshot juga menunjukkan anomali timezone: timestamp internal tertulis 00:53 WIB, sedangkan waktu Telegram menunjukkan 07:53. Selisih tujuh jam mengindikasikan runtime saat itu memformat UTC tetapi memberi label WIB. Ini menjadi temuan observability yang perlu diperbaiki dengan konversi timezone eksplisit.

Webhook Tanpa Membuka Port Publik

Dalam webhook mode, service menjalankan HTTP receiver lokal. Cloudflare Tunnel membuat koneksi outbound dari server dan memberi Telegram URL HTTPS untuk webhook.

Telegram
   │ HTTPS webhook

Cloudflare Tunnel


127.0.0.1:8080


Go bot

Dengan pola ini, saya tidak perlu mempublikasikan port receiver langsung ke internet. Untuk eksperimen cepat, aplikasi dapat memakai quick tunnel. Untuk deployment jangka panjang, named tunnel dengan hostname tetap lebih tepat.

Challenge Backoff dan Notification Noise

Booking flow dapat menampilkan Cloudflare challenge. Bila satu job terkena challenge, request berikutnya tidak langsung dipaksa berulang-ulang. Queue menyimpan kondisi backoff agar monitor lain tidak ikut membanjiri provider.

Saya juga memisahkan dua jenis pesan:

  • availability alert, yang memang perlu dilihat pengguna;
  • operational error, yang perlu dicatat tetapi tidak boleh membanjiri chat setiap polling.

Penggunaan nyata memperlihatkan satu area lanjutan: availability alert membutuhkan state transition. Fingerprint seperti train + date + class + price + seats dapat disimpan, lalu alert dikirim hanya jika fingerprint berubah atau cooldown berakhir.

Menjalankan Service

Repository menyediakan setup Ubuntu untuk memasang dependency dan memeriksa kesiapan host. Untuk development atau operasi langsung dari source, service dapat dijalankan di tmux:

tmux new-session -s kai-notifier
cd ~/projects/Tiket-Kereta-Notifier
go run cmd/main.go -config config.yml

Detach dengan Ctrl-b, lalu d. Untuk kembali:

tmux attach -t kai-notifier

Pada deployment saya, proses dijalankan dengan go run agar perubahan source dapat diuji langsung. Untuk deployment yang immutable dan repeatable, binary terverifikasi atau container image tetap lebih ideal.

Hal yang Saya Pelajari

Loop scheduler adalah bagian termudah. Reliability justru datang dari detail di sekelilingnya:

  1. batasi concurrency pada resource yang stateful;
  2. verifikasi dependency seperti proxy, jangan hanya percaya konfigurasi;
  3. validasi semua monitor saat startup;
  4. perlakukan challenge sebagai state dengan backoff;
  5. bedakan alert pengguna dan error operasional;
  6. ukur hasil melalui status dan history;
  7. gunakan bukti produksi untuk menemukan masalah berikutnya, seperti alert duplikat dan timezone.

KAI Ticket Notifier akhirnya menjadi latihan backend dan operations yang lebih lengkap daripada sekadar bot Telegram: ada browser lifecycle, queue ownership, konfigurasi, webhook, network path, observability, dan feedback loop dari runtime nyata.

Lihat case study KAI Ticket Notifier untuk ringkasan recruiter-friendly atau buka repository GitHub untuk source dan dokumentasi command.