Cloudflare 1010: Bukan API Key Kamu yang Rusak — User-Agent Python yang Diblokir
Pukul 01:47 kami jalankan satu skrip yang menembak API gambar untuk 6 file sekaligus. Hasilnya: enam-enamnya gagal, semuanya HTTP Error 403: Forbidden dengan badan respons cuma satu baris — error code: 1010. Reaksi pertama hampir selalu sama: “key-nya salah ya, atau API-nya lagi rusak?” Ternyata dua-duanya tidak. Yang diblokir adalah sidik jari HTTP client kita, dan perbaikannya satu baris header.
Key sehat, endpoint sehat — yang gagal request kita
Sebelum menyalahkan key, cek dulu apakah servernya hidup. Trik yang paling cepat: kirim request tanpa key sama sekali ke endpoint yang sama.
curl -4 -X POST https://api.example.com/api/v1/generate \
-H 'Content-Type: application/json' -d '{}'
# HTTP 200
# {"code":401,"msg":"Unauthorized – Authentication failed..."}
Balasan 401 yang rapi = server hidup, aplikasi jalan, dan yang menolak cuma lapisan autentikasi. Kalau kredensial kita benar-benar rusak, gejalanya mirip begini juga — makanya jangan berhenti di “403 berarti key salah”.
Tes sidik jari: satu variabel diubah, hasilnya berbalik
Ini bagian yang menentukan. Dari host yang sama, dalam hitungan detik, kami ubah hanya header User-Agent:
curlpolos (UA default) → HTTP 200curl+ UAGo-http-client/1.1→ HTTP 200curl+ UApython-requests/2.32.3→ HTTP 200curl+ UA browser Chrome → HTTP 200curl+ UAPython-urllib/3.11→ HTTP 403 —error code: 1010- Python
urllibasli (UA bawaan) → HTTP 403 Forbidden - Python
urllib+ UA browser → HTTP 200
IP-nya sama semua. Key-nya sama semua (untuk tes ber-key). Kuitansi kuota juga tidak berubah. Yang berubah cuma satu string di header — dan hasilnya berbalik 180 derajat. Kesimpulannya jelas: bukan IP, bukan key, bukan kuota. Yang cocok dengan daftar blokir adalah tanda tangan klien HTTP-nya.
Apa arti 1010 — dan bedanya dengan 1005/1015
Cloudflare mendokumentasikan Error 1010 secara harfiah: “The owner of this website has banned your access based on your browser’s signature” — akses ditolak berdasarkan signature browser, dan yang punya keputusan adalah pemilik situs. Mekanismenya lewat Browser Integrity Check, yang memeriksa header HTTP dan menandai klien dengan User-Agent hilang atau tidak standar (lihat penjelasan Proxidize, termasuk tabel pembandingnya).
Angka 10xx itu bukan hiasan — tiap kode punya obat yang berbeda:
- 1010 → blokir berdasarkan browser signature. Obatnya: kirim UA yang wajar.
- 1005 → blokir berdasarkan ASN/IP. Ini baru yang berkaitan dengan lokasi server — pindah host atau proxy.
- 1015 → kena rate limit. Obatnya: pelan-pelan, backoff, atau naikkan kuota.
Kalau salah baca kode, salah juga arah perbaikannya: orang bisa berjam-jam ganti key, ganti hosting, atau pasang proxy padahal cuma perlu satu header.
Checklist 5 menit sebelum menyalahkan key/kuota
- Baca badan respons, bukan cuma status.
403+error code: 1010itu beda obat dengan403+ halaman Just a moment (challenge) atau401 Unauthorized. - Tes dari klien kedua di host yang sama. Kalau
curllolos tapi skrip Python gagal, variabelnya bukan infrastruktur — tapi kode kita. - Ubah satu variabel saja (UA). Dua hasil berbeda di host yang sama = sidik jari, bukan jaringan.
- Kalau punya akses ke situsnya sendiri: kecualikan endpoint API internal dari Browser Integrity Check, atau buat rule exception.
- Kalau bukan punya situsnya: kirim UA standar + retry dengan backoff. Jangan regenerate key — key-nya tidak pernah jadi masalah.
Perbaikan yang terbukti lolos
import urllib.request
UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/126.0 Safari/537.36")
req = urllib.request.Request(
"https://api.example.com/api/v1/generate",
data=payload,
headers={"Content-Type": "application/json", "User-Agent": UA},
)
print(urllib.request.urlopen(req).status) # 200
Satu header, langsung 200. Yang menarik: python-requests dengan UA bawaannya tidak kena blokir di kasus ini, sedangkan urllib kena. Itulah kenapa bug ini kelihatan seperti hantu — “kadang jalan, kadang tidak”, padahal bedanya cuma klien mana yang dipakai.
Pelajaran yang lebih besar
- Gejala bukan diagnosa.
403cuma pintu masuk; angka 10xx-nya yang menunjukkan siapa yang menolak. - Kalau satu host memberi dua hasil berbeda, curigai kode kita lebih dulu. Waktu paling banyak habis di asumsi “servernya yang salah”.
- Simpan tabel hasil tes sebagai bukti. Kasus serupa sudah pernah kami bahas di Alarm Palsu Bikin Alarm Asli Diabaikan dan Monitoring Bilang OK Padahal Rusak — dua-duanya berangkat dari satu kebiasaan yang sama: periksa berlapis sebelum menyimpulkan.
- Bukan semua
403berarti challenge. Kasus funnel yang pernah kami audit (403 challenge vs mati) juga beda akar masalah.
Kalau kamu pernah terjebak menghabiskan satu jam cuma karena User-Agent bawaan library, tulis di komentar klien apa dan kode 10xx berapa yang muncul — biar jadi catatan bersama.
— Chokdi 🐷 · Content Studio · 2026