The navigator object
window.navigator is a grab-bag of information about the browser, the device and the user's environment. It is the entry point for features like geolocation, clipboard, sharing, media devices and connectivity status. A lot of navigator was historically used to sniff the user agent — a practice you should avoid today. Feature-detect instead.
The userAgent string — and why to ignore it
console.log(navigator.userAgent);
// e.g. "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) AppleWebKit/605.1.15 ..."
// Don't do this:
if (navigator.userAgent.includes("Chrome")) {
enableFancyFeature();
}// Good — test the feature, not the brand:
if ("share" in navigator) {
navigator.share({ title: "Hi", url: "/" });
}
if ("clipboard" in navigator && navigator.clipboard.writeText) {
navigator.clipboard.writeText("copied!");
}Browsers are also shipping User-Agent Client Hints (navigator.userAgentData) as a structured, privacy-respecting replacement. Adoption is mixed, especially on Safari/iOS, so still feature-detect.
Language and locale
navigator.language; // "en-GB" — top preferred language navigator.languages; // ["en-GB", "en", "fr-FR"] — full ordered list // Use these as a *default*, not as a lock: const formatter = new Intl.NumberFormat(navigator.language); formatter.format(1234567.89);
1,234,567.89
Online / offline status
navigator.onLine reports whether the browser thinks it has a network connection. It is a hint — true does not guarantee the internet is reachable; the device could be on a LAN with no upstream. Pair it with the online/offline events and a real request when it matters.
console.log("online?", navigator.onLine);
addEventListener("online", () => render({ banner: null }));
addEventListener("offline", () => render({ banner: "You are offline" }));The Clipboard API
// Write — requires a user gesture (click, key) in most browsers:
async function copy(text) {
try {
await navigator.clipboard.writeText(text);
toast("Copied to clipboard");
} catch {
toast("Copy failed — clipboard permission denied");
}
}
// Read — requires explicit permission, often a permission prompt:
async function paste() {
const text = await navigator.clipboard.readText();
console.log("From clipboard:", text);
}Web Share API
async function shareThis() {
if (!navigator.share) {
fallbackCopyLink();
return;
}
try {
await navigator.share({
title: "Check this out",
text: "Great article on web APIs",
url: location.href,
});
} catch (err) {
// User cancelled — that throws AbortError; ignore.
if (err.name !== "AbortError") console.error(err);
}
}Web Share is well supported on mobile and macOS Safari. On desktop Chrome/Firefox it may be missing — always feature-detect and provide a fallback (copy link, mailto).
Geolocation
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(
(pos) => {
const { latitude, longitude, accuracy } = pos.coords;
console.log(`${latitude}, ${longitude} (±${accuracy}m)`);
},
(err) => console.error("geolocation error", err.message),
{ enableHighAccuracy: true, timeout: 5000, maximumAge: 60_000 }
);
}Detailed coverage on the Geolocation page.
Media devices: camera and microphone
async function startCamera() {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: "user" },
audio: true,
});
document.querySelector("video").srcObject = stream;
}
// List devices (labels are empty until permission is granted):
const devices = await navigator.mediaDevices.enumerateDevices();
console.log(devices.map((d) => `${d.kind}: ${d.label}`));What to sniff (and what not to)
Sniff features, not browsers.
if ("share" in navigator)is good.if (isChrome)is not.Use
navigator.languageonly for defaults. Let users override the locale in your UI.Treat
navigator.onLineas a hint, not a guarantee.Avoid
navigator.userAgentfor capability decisions. Use it at most for analytics, and preferuserAgentDatawhere available.Request permissions on user actions, not on page load. Browsers (especially Safari) will silently deny permissions otherwise.