Error navigator is not defined muncul karena kode memanggil navigator.geolocation saat komponen masih dirender di server. Solusi tercepat: pindahkan pemanggilan ke event handler atau useEffect di Client Component, lalu pasang guard typeof navigator !== "undefined".
Penyebab Navigator Is Not Defined di App Router
Next.js App Router merender Server Component di server secara default. Objek navigator hanya tersedia di browser, jadi pemanggilan langsung saat prerender pasti gagal.
- Server Component tidak punya akses ke browser API seperti geolocation, clipboard, dan
mediaDevices. - Client Component tetap dirender sekali di server untuk HTML awal, lalu dihydrate di browser.
- Pola pemicu umum:
navigator.geolocation.getCurrentPosition()ditulis langsung di body render. - Pola lain: dipakai di initializer
useState(() => navigator...)atau dijalankan library peta, fingerprint, dan clipboard saat import.
Tabel Troubleshooting Cepat Navigator Error
Baca stack trace dulu. Nama file dan nomor baris biasanya menunjuk baris pemanggil navigator.
| Masalah | Penyebab | Solusi |
|---|---|---|
Error saat next build |
Geolocation dipanggil saat prerender | Pindah ke useEffect atau event click |
| Error saat refresh halaman | Client Component akses navigator saat render | Tambah guard typeof navigator |
| Error dari library pihak ketiga | Library membaca navigator saat import | Muat dengan dynamic ssr: false |
| Error hanya saat navigasi tertentu | Kode clipboard/mediaDevices jalan sebelum mount | Tunda sampai user berinteraksi |
Solusi Aman untuk Akses Navigator di Client
Tambahan "use client" saja tidak cukup. Kode tetap perlu memastikan browser sudah siap.
- Buat komponen kecil bertanda
"use client"khusus kebutuhan lokasi atau clipboard. - Jangan panggil
navigatordi body render atau initializer state. - Pasang guard
typeof navigator !== "undefined"plus cek fitur, misalnya"geolocation" in navigator. - Panggil geolocation di dalam
useEffectatau handler tombol. - Pakai dynamic import
ssr: falsehanya untuk komponen yang sepenuhnya browser-only.
"use client";
import { useState } from "react";
export default function TombolLokasi() {
const [status, setStatus] = useState("");
function mintaLokasi() {
if (typeof navigator === "undefined" || !("geolocation" in navigator)) {
setStatus("Geolocation tidak didukung browser ini");
return;
}
navigator.geolocation.getCurrentPosition(
(pos) => setStatus(`${pos.coords.latitude}, ${pos.coords.longitude}`),
() => setStatus("Izin lokasi ditolak")
);
}
async function salinTeks() {
if (typeof navigator === "undefined" || !navigator.clipboard) return;
await navigator.clipboard.writeText("Halo");
}
return <button onClick={mintaLokasi}>{status || "Minta lokasi"}</button>;
}
FAQ
Apakah semua kode navigator harus memakai useEffect?
Tidak. Event handler seperti onClick juga aman karena hanya berjalan di browser.
Kenapa guard typeof window saja belum cukup?
window ada belum tentu fitur tersedia, jadi cek juga "geolocation" in navigator atau navigator.clipboard.
Kapan memakai dynamic import untuk komponen navigator?
Pakai saat library langsung membaca navigator ketika modul diimpor dan tidak bisa diperbaiki dengan guard biasa.