Pengambilan data statistik resmi secara terprogram sudah menjadi kebutuhan standar bagi tim produk yang membangun dashboard ekonomi, laporan otomatis, maupun fitur analitik berbasis data pemerintah. Badan Pusat Statistik (BPS) menyediakan Web API publik di webapi.bps.go.id yang mengembalikan indikator dalam format JSON, sehingga pekerjaan yang sebelumnya dilakukan dengan scraping tabel HTML bisa digantikan oleh satu permintaan HTTP yang jauh lebih stabil.
Meski terdengar sederhana, ada tiga titik yang paling sering menggagalkan implementasi pertama. Pertama, permintaan diblokir oleh Web Application Firewall (WAF) karena header tidak lengkap. Kedua, parameter tahun (th) tidak memakai format empat digit seperti yang diasumsikan banyak pengembang. Ketiga, struktur respons datacontent berupa kamus dengan kunci komposit yang tidak bisa langsung dibaca sebagai tabel. Panduan ini membahas ketiganya secara berurutan, dilengkapi skrip Python yang bisa langsung dijalankan, contoh keluaran nyata dari penarikan pada 24 September 2026, serta cara menjadwalkannya sebagai pipeline cron di server produksi.
Menyiapkan Kunci Akses dan Memahami Peta Endpoint
Sebelum satu permintaan pun dikirim, aplikasi perlu memiliki App Key resmi. Kunci ini berfungsi sebagai identitas aplikasi sekaligus alat pengendali kuota, sehingga setiap pemanggilan endpoint wajib menyertakannya. Prosedur pendaftarannya relatif singkat:
- Buka portal resmi
https://webapi.bps.go.id/melalui peramban. - Daftarkan akun dengan alamat email yang aktif, lalu selesaikan verifikasi email.
- Masuk ke dashboard pengembang dan pilih menu registrasi aplikasi.
- Isi nama aplikasi, deskripsi tujuan penggunaan data, serta alamat domain atau IP server asal permintaan.
- Sistem menerbitkan App Key unik yang harus disertakan pada setiap pemanggilan.
Model pemanggilan data rinci memakai pola URL berikut:
https://webapi.bps.go.id/v1/api/view/model/data/domain/{kode_wilayah}/var/{kode_variabel}/key/{app_key}/
Nilai {kode_wilayah} mengikuti kode wilayah standar BPS. Untuk agregat nasional dipakai 0000, sedangkan level provinsi memakai kode masing-masing seperti 3100 untuk DKI Jakarta dan 3200 untuk Jawa Barat. Selain model view yang mengembalikan nilai data, tersedia pula model list yang berguna untuk menelusuri daftar variabel dan domain yang tersedia pada katalog. Praktik yang disarankan adalah memakai model list sekali di awal untuk memastikan kode variabel yang dituju memang benar, baru kemudian menarik nilainya secara berkala dengan model view.
Header Wajib agar Tidak Diblokir WAF
Penyebab kegagalan paling umum pada percobaan pertama bukanlah kesalahan logika, melainkan permintaan yang ditolak sebelum diproses. Server BPS dilindungi WAF yang menyaring trafik berdasarkan pola header. Pustaka HTTP yang mengirim permintaan tanpa identitas yang wajar akan menerima HTTP 403 Forbidden atau HTTP 429 Too Many Requests.
Spesifikasi header yang direkomendasikan:
| Header | Nilai yang Disarankan | Alasan |
|---|---|---|
User-Agent |
String peramban modern atau nama bot resmi aplikasi | WAF menolak klien tanpa identitas yang jelas |
Accept |
application/json |
Memprioritaskan payload JSON pada negosiasi konten |
Accept-Encoding |
gzip, deflate |
Menghemat bandwidth dan mempercepat transfer |
Connection |
keep-alive |
Menghindari handshake berulang pada penarikan bertahap |
Kesalahan yang sering terjadi adalah mengirim User-Agent bawaan pustaka, misalnya python-requests/2.x atau curl/8.x. Menggantinya dengan string peramban standar sudah cukup untuk melewati penyaringan dasar, dan menambahkan jeda satu sampai dua detik antar permintaan akan menghindari pembatasan laju.
Skrip Python: Fetch dengan Timeout dan Retry
Skrip berikut memakai modul standar Python sehingga tidak memerlukan paket pihak ketiga. Penanganan galat dibuat eksplisit agar kegagalan satu permintaan tidak menghentikan seluruh pipeline.
```python import json import time import urllib.error import urllib.parse import urllib.request
BASE = "https://webapi.bps.go.id/v1/api/view/model/data" HEADERS = { "User-Agent": ( "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" ), "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", }
def ambil_bps(domain, var_id, app_key, kode_tahun=None, percobaan=3): url = f"{BASE}/domain/{domain}/var/{var_id}/key/{app_key}/" if kode_tahun: url += f"th/{kode_tahun}/"
for ke in range(1, percobaan + 1):
req = urllib.request.Request(url, headers=HEADERS)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as err:
if err.code in (403, 429) and ke < percobaan:
time.sleep(2 ** ke)
continue
print(f"[gagal] HTTP {err.code} pada percobaan {ke}")
return None
except Exception as exc:
if ke < percobaan:
time.sleep(2 ** ke)
continue
print(f"[gagal] koneksi: {exc}")
return None
return None
```
Pola 2 ** ke menghasilkan jeda 2, 4, dan 8 detik antar percobaan, yang cukup untuk melewati pembatasan sementara tanpa membuat pipeline menunggu terlalu lama. Fungsi mengembalikan None alih-alih melempar pengecualian, sehingga pemanggil dapat memutuskan sendiri apakah data yang gagal itu bersifat wajib atau opsional.
Mengurai Struktur datacontent yang Komposit
Bagian yang paling sering membingungkan adalah objek datacontent. Alih-alih array objek dengan kunci dan nilai terpisah, BPS menyajikan nilai pengukuran sebagai kamus satu dimensi dengan kunci gabungan. Kunci tersebut merupakan rangkaian dari ID variabel, ID turunan variabel, ID wilayah, ID tahun, dan ID periode. Contoh bentuknya:
datacontent["1234000012401"] = 9.03
Angka 9.03 pada contoh di atas adalah nilai indikator, sedangkan kuncinya perlu dipecah dengan mencocokkan potongan substring terhadap metadata yang dikirim pada blok var, turvar, vervar, dan period. Pendekatan yang paling aman adalah memetakan setiap ID ke labelnya terlebih dahulu, lalu menyusun baris tabel:
python
def uraikan(payload):
meta_var = {v["val"]: v["label"] for v in payload["var"]}
meta_period = {p["val"]: p["label"] for p in payload["period"]}
baris = []
for kunci, nilai in payload["datacontent"].items():
baris.append({
"kunci": kunci,
"variabel": meta_var.get(kunci[:2]),
"periode": meta_period.get(kunci[-2:]),
"nilai": nilai,
})
return baris
Potongan indeks pada kunci[:2] dan kunci[-2:] mengikuti pola ID dua digit yang dipakai BPS pada respons contoh. Karena panjang segmen dapat berbeda antar katalog, kode produksi sebaiknya memverifikasi panjang kunci terlebih dahulu dan melewati entri yang tidak sesuai pola, bukan mengasumsikan satu format tetap.
Contoh Live: Keluaran Nyata 24 September 2026
Nilai berikut adalah hasil penarikan langsung ke katalog publik BPS pada 24 September 2026, bukan angka contoh yang dikarang. Dua indikator dipakai sebagai studi kasus karena keduanya mewakili jenis data yang berbeda: satu berasal dari survei sosial semesteran, satu lagi dari rangkaian nilai tukar.
Indikator pertama adalah persentase penduduk miskin nasional. Data ini dirilis secara semesteran, dengan periode survei Maret dan September:
- Tahun 2024 Semester 1 (Maret): 9,03 persen.
- Tahun 2024 Semester 2 (September): 8,57 persen.
- Tahun 2025 Semester 1 (Maret): 8,47 persen.
- Tahun 2025 Semester 2 (September): 8,25 persen.
Indikator kedua adalah rata-rata kurs transaksi Bank Indonesia terhadap dolar Amerika Serikat:
- Tahun 2023: Rp 15.416 per USD.
- Tahun 2024: Rp 16.162 per USD.
Perlu dicatat bahwa kode tahun pada permintaan tidak selalu sama dengan tahun kalender. Untuk seri data tertentu, BPS memakai kode internal dua atau tiga digit, misalnya 124 untuk 2024 dan 125 untuk 2025. Menebak kode tahun tanpa memeriksa katalog adalah sumber kesalahan yang paling sering muncul pada implementasi baru, dan gejalanya berupa respons kosong tanpa pesan galat yang jelas.
Selain dua indikator di atas, katalog yang sama juga mengekspos siaran pers resmi lengkap dengan tanggal rilis. Pada penarikan 24 September 2026, entri siaran pers terbaru yang tersedia bertanggal 1 September 2026. Endpoint ini berguna untuk memantau kapan rilis baru muncul, sehingga penjadwalan penarikan data bisa disesuaikan dengan kalender publikasi BPS, bukan ditebak.
Membaca Angkanya: Dua Tren yang Berbeda
Dua indikator di atas memberi gambaran mengapa pemisahan jenis data penting dalam sebuah pipeline. Untuk kemiskinan, selisih antara Semester 1 2024 dan Semester 2 2025 adalah 0,78 poin persen, turun dari 9,03 ke 8,25. Angka tersebut merupakan hasil pengurangan sederhana atas nilai resmi BPS, bukan estimasi. Untuk kurs, rata-rata tahunan bergerak dari Rp 15.416 ke Rp 16.162, selisih Rp 746 per USD atau sekitar 4,84 persen, yang menggambarkan pelemahan nilai tukar rata-rata sepanjang periode itu.
Perbedaan karakter kedua data berdampak langsung pada desain penjadwalan. Indikator semesteran tidak perlu ditarik setiap hari karena nilainya tidak berubah di antara dua rilis. Menariknya setiap hari hanya membebani kuota API dan menambah baris log tanpa informasi baru. Sebaliknya, endpoint daftar siaran pers justru layak diperiksa lebih sering karena fungsinya memberi sinyal kapan data baru tersedia.
Pola yang disarankan adalah memeriksa kalender rilis pada frekuensi tinggi, lalu menarik nilai indikatornya hanya ketika muncul tanda rilis baru. Pendekatan ini menekan jumlah permintaan ke server BPS sekaligus menjaga data pada aplikasi tetap mutakhir.
Tabel Rekap Indikator
| Indikator Resmi | Periode / Tahun | Nilai | Sumber |
|---|---|---|---|
| Kemiskinan nasional | 2024 Semester 1 (Maret) | 9,03 persen | BPS, data ditarik 2026-09-24 |
| Kemiskinan nasional | 2024 Semester 2 (September) | 8,57 persen | BPS, data ditarik 2026-09-24 |
| Kemiskinan nasional | 2025 Semester 1 (Maret) | 8,47 persen | BPS, data ditarik 2026-09-24 |
| Kemiskinan nasional | 2025 Semester 2 (September) | 8,25 persen | BPS, data ditarik 2026-09-24 |
| Kurs transaksi BI terhadap USD | Tahun 2023 (rata-rata) | Rp 15.416 | BPS, data ditarik 2026-09-24 |
| Kurs transaksi BI terhadap USD | Tahun 2024 (rata-rata) | Rp 16.162 | BPS, data ditarik 2026-09-24 |
Tabel ini menunjukkan bahwa hasil penarikan terprogram menghasilkan angka yang presisi dan konsisten, tanpa risiko salah ketik yang biasa terjadi pada input manual ke spreadsheet.
Menyimpan Snapshot dan Memvalidasi Keluaran
Langkah yang sering dilewatkan setelah penarikan berhasil adalah menyimpan hasilnya dalam bentuk yang bisa diaudit. Snapshot bertanggal membuat setiap perubahan dapat ditelusuri, dan ketika sebuah angka terlihat janggal, versi sebelumnya masih tersedia untuk dibandingkan.
```python import json from datetime import datetime, timezone
def simpan_snapshot(hasil, folder="data-cache"): stempel = datetime.now(timezone.utc) nama = f"snapshot-{stempel:%Y-%m-%d}.json" with open(f"{folder}/{nama}", "w", encoding="utf-8") as f: json.dump({ "tanggal": f"{stempel:%Y-%m-%d}", "diambil_utc": stempel.isoformat(), "sumber": hasil, }, f, ensure_ascii=False, indent=1) return nama ```
Setidaknya ada tiga validasi minimum sebelum sebuah snapshot dianggap layak dipakai. Pertama, berkas tidak boleh kosong. Kedua, jumlah sumber yang berhasil harus tercatat dengan benar, bukan disamarkan sebagai sukses total. Ketiga, setiap indikator wajib masih memuat nilai bertipe angka.
Validasi terakhir menangkap kasus yang paling berbahaya, yaitu respons yang tetap berupa JSON valid tetapi berisi pesan galat di dalam field nilai. Tanpa pemeriksaan tipe, nilai seperti itu bisa lolos ke halaman publik dan tampil seolah sebagai data resmi. Pemeriksaan sederhana dengan memastikan isinstance(nilai, (int, float)) sudah cukup untuk menutup celah tersebut.
Ekspektasi vs Realita
| Aspek | Ekspektasi Awal | Realita di Lapangan |
|---|---|---|
| Kecepatan implementasi | Satu jam sampai jalan | Perlu waktu tambahan untuk memahami kode tahun dan struktur kunci |
| Stabilitas permintaan | Selalu HTTP 200 | 403 dan 429 muncul jika header tidak lengkap atau permintaan terlalu rapat |
| Format respons | Array objek siap pakai | Kamus kunci komposit yang harus dipecah dengan metadata |
| Frekuensi data | Terasa seperti data harian | Sebagian besar indikator bersifat semesteran, kuartalan, atau tahunan |
| Biaya | Gratis sepenuhnya | Gratis dari sisi API, tetapi butuh server untuk menjalankan penjadwalan |
Baris terakhir tabel di atas penting untuk dipahami sejak awal. API-nya sendiri tidak memungut biaya, namun pipeline yang berjalan otomatis tetap membutuhkan tempat eksekusi yang menyala 24 jam.
Otomasi Penarikan di Server dan Penjadwalan Cron
Agar data pada aplikasi selalu mengikuti rilis terbaru, penarikan sebaiknya dijalankan sebagai pekerjaan terjadwal, bukan dipicu manual. Skenario yang umum adalah menempatkan skrip fetcher pada sebuah server virtual privat yang memiliki alokasi IP publik bersih dan latensi rendah ke server BPS di Jakarta.
Dalam implementasi pipeline data pemerintah di portal Toolkuy, pekerjaan penarikan dijalankan pada node A924ZV, sebuah konfigurasi server dengan 2 vCPU dan RAM 4 GB. Spesifikasi node A924ZV tersebut dipilih karena beban kerjanya didominasi operasi jaringan dan penulisan berkas kecil, bukan komputasi berat, sehingga kapasitas memori yang tersedia lebih dari cukup untuk menampung antrean cron sekaligus proses validasi snapshot.
Penjadwalan mingguan dapat dipasang dengan entri berikut:
```bash
Jalankan setiap Senin pukul 03:00 WIB
0 3 * * 1 /usr/bin/python3 /opt/pipeline/fetch_bps.py >> /var/log/pipeline_bps.log 2>&1 ```
Beberapa praktik yang terbukti mengurangi kegagalan pipeline:
- Simpan snapshot mentah beserta stempel waktu. Setiap run menulis berkas baru dengan tanggal pada namanya, sehingga data lama tetap bisa dibandingkan ketika terjadi anomali.
- Perlakukan sumber sebagai independen. Ketika satu sumber gagal, pipeline tetap menulis hasil dari sumber yang berhasil dan mencatat kegagalan itu secara eksplisit. Pada run 24 September 2026, satu dari delapan sumber yang ditarik mengalami timeout, dan pipeline tetap menyelesaikan tujuh sumber lainnya dengan status yang tercatat.
- Log dengan stempel waktu pada setiap baris. Tanpa stempel waktu, keluaran lama sulit dibedakan dari keluaran baru, dan kegagalan senyap bisa lolos berhari-hari.
- Pisahkan penarikan dari penulisan. Fetcher hanya mengumpulkan data mentah, sedangkan tahap berikutnya yang mengubah data menjadi artikel atau laporan dijalankan terpisah. Pemisahan ini membuat konsumsi AI token untuk tahap penulisan bisa dikendalikan dan dihitung terpisah dari biaya hosting.
Poin keempat berkaitan langsung dengan anggaran. Menjalankan satu server untuk penarikan data sekaligus hosting aplikasi web biasanya lebih murah daripada memisahkan keduanya, tetapi pemisahan logis antara proses fetch dan proses generasi konten tetap penting agar konsumsi AI token tidak membengkak tanpa terlihat.
Keterbatasan Data
Ada beberapa batasan yang perlu dipahami sebelum menjadikan API BPS sebagai sumber tunggal:
- Bukan data real-time. Angka yang disajikan berasal dari survei dan sensus berkala. Data kemiskinan, misalnya, hanya diperbarui dua kali setahun, sedangkan kurs rata-rata tahunan baru lengkap setelah tahun berjalan berakhir.
- Kuota dan pembatasan laju. WAF akan membatasi permintaan yang datang terlalu rapat. Penarikan massal untuk banyak wilayah sekaligus sebaiknya diberi jeda dan dipecah ke beberapa waktu eksekusi.
- Skema metadata dapat berubah. Ketika BPS memperluas cakupan survei, penamaan variabel dan kode turunan bisa ikut berubah. Skrip yang mengasumsikan format kunci tetap akan rusak tanpa peringatan, sehingga penanganan galat dan validasi panjang kunci wajib ada.
- Ketergantungan pada ketersediaan pihak ketiga. Pada run 24 September 2026, satu sumber data eksternal di luar BPS mengalami timeout. Pipeline yang baik harus menganggap kegagalan sumber sebagai kondisi normal, bukan pengecualian, dan tetap menghasilkan keluaran parsial yang jujur soal apa yang tidak berhasil ditarik.
Kesimpulan
Web API BPS menyediakan jalur yang jauh lebih andal dibandingkan scraping untuk memasukkan data statistik resmi ke dalam aplikasi. Tiga hal yang menentukan keberhasilan implementasi adalah header permintaan yang lengkap agar lolos WAF, pemahaman atas konvensi kode tahun yang tidak selalu memakai empat digit, serta kemampuan mengurai struktur datacontent yang berbentuk kunci komposit. Setelah ketiganya dikuasai, langkah berikutnya adalah memindahkan proses ke penjadwalan otomatis pada server yang stabil, lengkap dengan snapshot bertanggal dan pencatatan kegagalan yang eksplisit.
Sumber
Data dan spesifikasi teknis dalam panduan ini merujuk pada dokumentasi resmi dan katalog data terbuka pemerintah:
- Portal Resmi Web API BPS: https://webapi.bps.go.id/
- Portal Utama Badan Pusat Statistik: https://bps.go.id/
- Portal Satu Data Indonesia: https://data.go.id/
💬 Komentar (0)
Belum ada komentar. Jadilah yang pertama! 💬