Menebak bahasa pengunjung menghapus halaman Inggris kami dari Google
2026-08-12
Search Console mendaftar setiap URL marketing berbahasa Inggris di bawah satu status: “Discovered - currently not indexed”. Bukan sebagian. Semuanya, plus padanan bahasa Indonesianya. Google tahu URL-nya ada, sudah mengantrekannya, dan memutuskan semuanya tidak layak disimpan.
Penjelasan biasa untuk status itu adalah konten tipis, halaman duplikat, atau anggaran crawl yang habis untuk sampah. Tidak satu pun berlaku. Halamannya baik-baik saja. Google punya alamatnya dan tidak pernah disuguhi apa yang ada di baliknya.
Apa yang dilakukan kodenya
Layout marketing menjalankan keputusan locale di setiap request. Kalau path tidak membawa awalan locale dan request-nya tampak Indonesia, dia mengeluarkan 302 ke path yang sama di bawah /id. Sinyal yang dia pakai adalah header kode negara yang ditempelkan proxy edge kami ke setiap request masuk. Terlihat masuk akal: pengunjung di Jakarta mendarat di situs dan langsung dapat bahasa Indonesia tanpa mencari-cari tombol.
Crawler tidak bekerja begitu. Crawler meminta /about dari mana pun pengambilnya kebetulan berada hari itu, dan sebagian titik keluarnya ada di Indonesia. Request itu mendapat 302 ke /id/about. Crawler mengikutinya, mengindeks halaman Indonesia, lalu jalan terus. Halaman Inggris di /about tidak pernah disuguhkan kepadanya. Bukan disuguhkan dengan lambat, bukan disuguhkan lalu dinilai lemah. Tidak pernah disuguhkan sama sekali.
Jadi pohon halaman berbahasa Inggris tidak terlihat oleh satu-satunya pengunjung yang pendapatnya menentukan apakah halaman itu ada di pencarian. Setiap tautan internal yang menunjuk ke sana berujung pada pengalihan, dan sitemap mendaftar URL yang berperilaku sama. Dari posisi Google, situs berbahasa Inggris kami adalah sekumpulan alamat yang meneruskan ke tempat lain.
Ada masalah kedua yang menumpuk di atas yang pertama, dan itulah yang mengubah bug menjadi hukuman. Menyuguhkan konten berbeda berdasarkan alamat IP peminta adalah apa yang Google sebut cloaking. Kami tidak sedang berusaha menyembunyikan apa pun, tapi niat tidak ikut dihitung. Yang diklasifikasikan adalah polanya.
Situsnya berdebat dengan dirinya sendiri
Tiap halaman juga mengeluarkan blok hreflang yang menyatakan URL bahasa Inggris sebagai kanoniknya sendiri dan menyebut URL Indonesia sebagai alternatifnya. Blok itu benar. Dan blok itu juga disuguhkan dari sebuah URL yang, bagi peminta yang bersangkutan, menjawab dengan pengalihan menjauh dari dirinya sendiri.
Dua klaim dalam satu respons. Markup-nya bilang alamat ini adalah halaman bahasa Inggris. Baris statusnya bilang alamat ini bukan halaman, pergilah ke tempat lain. Ketika sebuah situs bertentangan dengan dirinya sendiri soal URL mana yang sah, penyelesaiannya tidak berpihak kepada Anda. Google memilih satu, dan yang dipilih adalah yang benar-benar dia terima.
Alihkan berdasarkan pilihan, bukan tebakan
Perbaikannya adalah mengubah apa yang menjadi kunci pengalihan. Alamat IP adalah sinyal lemah tentang niat. Dia memberi tahu di mana sebuah paket masuk ke jaringan, dan itu fakta tentang perutean, bukan tentang orangnya. Klik pada tombol bahasa adalah sinyal kuat, karena seseorang melakukannya dengan sengaja.
Jadi sekarang tombol itu menulis cookie locale, dan hanya cookie itu yang memindahkan pengunjung antara dua pohon halaman:
const preferred = cookies.get('locale');
if (!params.lang && preferred === 'id') {
redirect(302, `/id${url.pathname === '/' ? '' : url.pathname}${url.search}`);
}
if (params.lang === 'id' && preferred === 'en') {
redirect(302, `${url.pathname.replace(/^/id/, '') || '/'}${url.search}`);
} Ada dua sifat yang penting di sini dan tidak satu pun sekadar hiasan.
Yang pertama, aturannya simetris. Kode aslinya cuma mendorong orang masuk ke /id. Dia tidak punya cara mendorong mereka keluar lagi, jadi pengunjung yang lebih suka bahasa Inggris tapi mengikuti tautan berbahasa Indonesia terjebak di pohon itu selama sisa sesinya. Begitu keputusannya menjadi preferensi tersimpan alih-alih sifat jaringan, kedua arah sama-sama murah untuk diimplementasikan, dan melewatkan satu arah cuma berarti cabang yang hilang.
Yang kedua, crawler tidak membawa cookie. Dia tidak punya preferensi untuk dihormati, jadi dia jatuh melewati kedua kondisi dan mendapat 200 berisi halaman yang dia minta. Itu seluruh perbaikannya. Halaman berbahasa Inggris menjadi terjangkau bagi klien yang menentukan apakah halaman itu ada.
Header cache yang dipaksa oleh ini
Begitu cookie yang menentukan respons, responsnya bukan lagi fungsi murni dari URL. Cache bersama mana pun di depan aplikasi, milik kami atau milik perantara, akan dengan senang hati menyimpan respons pertama yang dia lihat untuk /about lalu memutarnya ulang ke semua orang yang meminta URL itu sesudahnya. Satu pengunjung dengan preferensi id mengisi cache, dan seratus request berikutnya mendapat HTML bahasa Indonesia dari alamat berbahasa Inggris.
Jadi handler-nya menambahkan Vary: Cookie ke setiap respons marketing. Cuma satu baris, dan itu tidak opsional begitu cookie ikut menentukan keputusan. Melewatkannya mengubah perbaikan kebenaran menjadi bug yang jauh lebih aneh, yang hanya muncul saat ada trafik.
Apa yang kami tolak
Alternatif yang sempat dipertimbangkan adalah mempertahankan pengalihan berbasis IP lalu melunakkannya dengan spanduk yang bisa ditutup: daratkan pengunjung Indonesia di halaman Indonesia, tampilkan bilah yang menawarkan bahasa Inggris, ingat kalau sudah ditutup.
Kami membuangnya karena dua alasan. Pertama, cara itu tidak menyentuh cacat yang sebenarnya. Crawler tetap mendapat pengalihan, halaman berbahasa Inggris tetap tidak pernah disuguhkan, dan blok hreflang tetap bertentangan dengan baris status. Spanduk itu pesan yang ditunjukkan kepada manusia tentang masalah yang hanya merugikan kami lewat mesin.
Alasan kedua lebih umum. Menambah UI untuk menjelaskan asumsi yang salah adalah cara mempertahankan asumsi itu. Asumsinya di sini adalah bahwa dari mana sebuah request berasal memberi tahu bahasa apa yang diinginkan pengirimnya. Itu cukup sering salah sampai jadi masalah: orang bepergian, memakai VPN, bekerja di satu negara dan membaca dalam bahasa negara lain — dan dalam kasus kami, pengunjungnya bahkan bukan orang. Begitu Anda menuliskan bahwa IP adalah tebakan dan klik adalah fakta, spanduk itu berhenti terlihat seperti perbaikan dan mulai terlihat seperti permintaan maaf atas tebakannya.
Semua halaman sekarang hidup, semuanya menjawab 200 dari asal mana pun, dan halaman harga akhirnya jadi sesuatu yang bisa dibaca crawler tanpa lebih dulu dikirim ke tempat lain. Apakah Google memaafkan pola sebelumnya dengan cepat atau lambat, itu di luar kendali kami.
Bagian yang terus saya pikirkan: ini sudah rilis berbulan-bulan lalu dan terlihat benar di setiap peramban yang kami pakai membukanya. Satu-satunya klien yang bisa melihat bug-nya adalah klien yang tidak pernah kami pakai untuk menguji.