A browser gives your JavaScript a large set of built-in capabilities: fetching data, storing values, watching elements, reading the clipboard, asking for a location. These are the client-side web APIs.
They share a pattern worth learning once: check it exists, ask permission where needed, and handle refusal.
Fetch — getting data#
async function loadUsers() {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
return response.json();
}The single most important detail: fetch does not throw on a 404 or 500. It only rejects when the request could not be made at all. Check response.ok yourself — see the Fetch API guide.
Storage — remembering things#
localStorage.setItem("theme", "dark");
localStorage.getItem("theme"); // "dark", or null
sessionStorage.setItem("step", "3"); // cleared when the tab closesStorage holds strings only, so objects go through JSON.stringify. It can also throw — in private browsing, or when the quota is full — so wrap writes:
function save(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch {
// Storage unavailable or full. Not fatal.
}
}More in localStorage explained.
Geolocation — needs permission#
function findMe() {
if (!("geolocation" in navigator)) {
return showMessage("Your browser cannot share a location.");
}
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude } = position.coords;
showWeather(latitude, longitude);
},
(error) => {
showMessage(
error.code === error.PERMISSION_DENIED
? "Location access was declined."
: "Could not work out your location."
);
},
{ timeout: 10000 }
);
}Three rules for any permissioned API: only ask after the user clicks something, always handle refusal, and never leave the page in a loading state if they say no.
Clipboard#
async function copy(text, button) {
if (!navigator.clipboard) return;
try {
await navigator.clipboard.writeText(text);
button.textContent = "Copied";
setTimeout(() => (button.textContent = "Copy"), 1400);
} catch {
button.textContent = "Press Ctrl+C";
}
}Writing to the clipboard only works in response to a real user gesture — a click, not a timer.
IntersectionObserver — reacting to scroll#
Far better than listening to scroll and measuring positions, which runs hundreds of times a second.
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src; // load the image
observer.unobserve(entry.target);
}
});
}, { rootMargin: "200px" });
document.querySelectorAll("img[data-src]").forEach((img) => observer.observe(img));rootMargin starts the work slightly before the element is visible, so nothing pops in late.
Other ones worth knowing#
// Where am I in the site?
new URL(location.href).searchParams.get("page");
// Change the URL without reloading
history.pushState({}, "", "/results?q=python");
// Is the tab visible?
document.addEventListener("visibilitychange", () => {
if (document.hidden) pauseTimer();
});
// Notify without blocking
if (Notification.permission === "granted") {
new Notification("Done", { body: "Your export is ready." });
}Feature detection#
Test for the thing itself rather than guessing from the browser name:
if ("IntersectionObserver" in window) {
setUpLazyLoading();
} else {
loadAllImagesNow(); // works everywhere, just less efficient
}
if (navigator.share) {
showShareButton(); // hide it entirely when unsupported
}The goal is that the page still works without the API — it just does less.
Questions people ask#
What is the difference between a web API and a REST API?
A web API here means a capability the browser provides your JavaScript. A REST API is a service on a server you send HTTP requests to. fetch is the browser API you use to call a REST API.
Do these work in Node.js?
Some do — fetch and URL exist in modern Node. Anything about the page, storage or permissions does not, because there is no browser.
How do I know if an API is widely supported?
Check a browser-support reference before relying on anything recent, and feature-detect regardless.