Browser APIs: window, location, history and Observers

Use the window object, read and change the URL with location and URLSearchParams, update history without reloading, and detect elements entering the screen with IntersectionObserver.

Lesson 43 of 56Intermediate15 min read

JavaScript in a web page doesn't just talk to the HTML. It also talks to the browser itself: the window and its size, the address bar, the back and forward buttons, the clipboard, the user's language and whether they're online. Together these are sometimes called the Browser Object Model (BOM), and they're what let a page behave like an app.

Many everyday features rely on them. A search page reads ?q=shoes from the URL to know what to search for. A filtered product list updates the URL so the filters can be shared and the back button works. A "Copy link" button writes to the clipboard. Images and animations start only when they scroll into view.

In this lesson you'll explore the window object, read and build URLs with location, URL and URLSearchParams, change the address bar without reloading using the History API, use a few handy navigator features, and watch elements appear on screen efficiently with IntersectionObserver.

The window object

window is the global object in the browser. Global variables and functions, document, console, setTimeout and localStorage all live on it, which is why you can write alert() instead of window.alert().

Property or methodGives or does
innerWidth, innerHeightThe size of the visible page area in pixels
scrollX, scrollYHow far the page is scrolled
scrollTo({ top: 0, behavior: "smooth" })Scrolls the page
open(url)Opens a new tab or window
devicePixelRatioScreen density (2 on most phones)
addEventListener("resize" / "scroll", fn)Reacts to size and scroll changes

For reacting to screen size, responsive JavaScript with matchMedia is usually better than reading innerWidth.

location and URLs

For the address https://shop.example.com/search?q=lamp&page=2#reviews:

PropertyValue
location.hrefThe whole URL
location.originhttps://shop.example.com
location.pathname/search
location.search?q=lamp&page=2
location.hash#reviews
JavaScript
const params = new URLSearchParams(location.search);
params.get("q");        // "lamp"
params.set("page", 3);
const url = new URL("/search", location.origin);
url.searchParams.set("q", "desk lamp"); // spaces are encoded for you

Setting location.href = "/basket" navigates to a new page; location.reload() reloads.

The History API

JavaScript
history.pushState({ page: 2 }, "", "?page=2");    // new history entry, no reload
history.replaceState(null, "", "?sort=price");    // change the current entry
window.addEventListener("popstate", (e) => render(e.state)); // back/forward pressed

pushState changes the address bar and adds a step to the back button without loading a new page. When the user presses back or forward, the popstate event fires and your code updates the page to match. This is how single-page apps and filterable lists keep URLs shareable. history.back() and history.forward() move through history in code.

JavaScript Browser APIs Syntax

Browser APIs

window.innerWidth; window.scrollY;
window.scrollTo({ top: 0, behavior: "smooth" });
const q = new URLSearchParams(location.search).get("q");
history.pushState({}, "", `?q=${encodeURIComponent(q)}`);
addEventListener("popstate", () => render());
await navigator.clipboard.writeText(location.href);
new IntersectionObserver(cb, { threshold: 0.5 }).observe(el);

JavaScript Browser APIs Summary

  • window is the global object, with size, scroll and timer features.
  • location describes the current URL; URLSearchParams reads and builds query strings.
  • history.pushState changes the URL without reloading; handle popstate for back and forward.
  • navigator offers clipboard, share, language and online status.
  • IntersectionObserver efficiently detects when elements scroll into view.

JavaScript Browser APIs Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Reading and building URLs

const url = new URL("https://shop.example.com/search?q=desk+lamp&page=2&colour=black#reviews");

console.log("Path:", url.pathname);
console.log("Hash:", url.hash);

const params = url.searchParams;
console.log("Search for:", params.get("q"));
console.log("Page:", Number(params.get("page")));
console.log("Has size?", params.has("size"));

params.set("page", 3);
params.append("colour", "white");
params.delete("q");
console.log("New URL:", url.href);
console.log("All colours:", params.getAll("colour"));

const link = new URL("/products", "https://shop.example.com");
link.searchParams.set("name", "café & bar");
console.log(link.href);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 1URL breaks any address into parts, just like location does for the current page.
  2. Line 7get decodes values, so the + becomes a space.
  3. Line 8Query values are strings; convert numbers yourself.
  4. Lines 11 to 13Change, add and remove parameters.
  5. Line 18Special characters are encoded automatically.
Example 2

Filters that update the URL

Click the filters. Each click adds a history entry, and the new URL is logged.

const state = document.querySelector("#state");

function render(cat) {
  state.textContent = `Showing: ${cat}`;
  for (const b of document.querySelectorAll("#filters button")) {
    b.style.fontWeight = b.dataset.cat === cat ? "bold" : "";
  }
}

document.querySelector("#filters").addEventListener("click", (e) => {
  const cat = e.target.dataset.cat;
  if (!cat) return;
  try {
    history.pushState({ cat }, "", `?cat=${cat}`);
  } catch {
    // some sandboxed previews block URL changes
  }
  render(cat);
  console.log("URL would be ?cat=" + cat);
});

window.addEventListener("popstate", (e) => render(e.state?.cat ?? "all"));
render(new URLSearchParams(location.search).get("cat") ?? "all");
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 3 to 8One function draws the page from a state value.
  2. Line 14Each filter click adds a history entry with the new URL.
  3. Line 22Back and forward buttons fire popstate, and the page redraws from the saved state.
  4. Line 23On load, the page reads its starting state from the URL, so links can be shared.
Example 3

Reveal on scroll with IntersectionObserver

Scroll inside the result panel.

const observer = new IntersectionObserver((entries) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      entry.target.classList.add("visible");
      console.log("Revealed:", entry.target.textContent);
      observer.unobserve(entry.target);
    }
  }
}, { root: document.querySelector("#scroller"), threshold: 0.3 });

document.querySelectorAll(".reveal").forEach((el) => observer.observe(el));
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 1The callback receives entries for elements whose visibility changed.
  2. Lines 3 to 4When a card is at least 30% visible, it fades in.
  3. Line 6Stop watching it once it's revealed.
  4. Line 9root is the scrolling box; leave it out to watch the whole page.
  5. Line 11Start watching every card.

Common JavaScript Browser APIs Mistakes

Building query strings by hand

Don't
location.href = "/search?q=" + query; // "rock & roll" breaks the URL
Do
const url = new URL("/search", location.origin);
url.searchParams.set("q", query);
location.href = url;

pushState without handling popstate

Don't
history.pushState({}, "", "?page=2"); // back button changes the URL but not the page
Do
history.pushState({ page: 2 }, "", "?page=2");
addEventListener("popstate", (e) => showPage(e.state?.page ?? 1));

Checking positions on every scroll

Don't
window.addEventListener("scroll", () => {
  cards.forEach(c => { if (c.getBoundingClientRect().top < innerHeight) c.classList.add("visible"); });
});
Do
const io = new IntersectionObserver(entries => entries.forEach(e => e.isIntersecting && e.target.classList.add("visible")));
cards.forEach(c => io.observe(c));

JavaScript Browser APIs in Real Projects

Browser APIs in practice

Online shops put filters and sort order in the URL so customers can share a search. Single-page apps like Gmail and YouTube use the History API to change pages without full reloads. Blogs lazy-load images and comments with IntersectionObserver, and news sites use it to count articles as read. "Copy link" and "Share" buttons use the clipboard and Web Share APIs.

JavaScript Browser APIs Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Read the id parameter from the URL's query string.

const params = new (location.search);
console.log(params.get("id"));
Predict the outputmedium

What is logged?

const u = new URL("https://a.com/shop?x=1&x=2#top");
console.log(u.pathname, u.searchParams.get("x"), u.hash);
Multiple choiceeasy

Which changes the URL without reloading the page?

Multiple choicemedium

Why use IntersectionObserver instead of a scroll listener?

Fix the bugmedium

buildSearchUrl(base, term, page) should return a URL string with q and page parameters, correctly encoded. readPage(url) should return the page as a number, defaulting to 1. Fix both.

function buildSearchUrl(base, term, page) {
  return base + "?q=" + term + "&page" + page;
}
function readPage(url) {
  return new URL(url).searchParams.get("page");
}
console.log(buildSearchUrl("https://a.com/search", "tea & cake", 2));
console.log(readPage("https://a.com/search?page=4"));
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Builds an encoded URL
  • Reads the page as a number
  • Defaults to page 1

JavaScript Browser APIs Quiz

5 questions to check what you learned.

  1. What is location.pathname for https://site.com/blog/post?id=3?

    • https://site.com
    • /blog/post
    • ?id=3
    • post
  2. Which event fires when the user presses the back button after pushState?

    • load
    • hashchange only
    • unload
    • popstate
  3. What is the global object in the browser?

    • document
    • navigator
    • window
    • global
  4. Which API copies text to the clipboard?

    • document.copy()
    • navigator.clipboard.writeText(text)
    • window.clipboard = text
    • location.copy(text)
  5. What does threshold: 0.5 mean for an IntersectionObserver?

    • Check every half second
    • Watch half of the elements
    • Use half the screen as the root
    • Report when at least half of the element is visible

JavaScript Browser APIs Challenge

Remember a tab in the URL

Make the tabs update the URL and the page:

  1. Write showTab(name) that adds class active to the button whose data-tab is name, removes it from the others, and sets #panel text to `Tab: ${name}`
  2. Clicking a tab button calls showTab and history.replaceState(null, "", "#" + name) (wrap it in try...catch in case the preview blocks it)
  3. On load, read the hash (without #) from location.hash, or use "intro" if there isn't one, and call showTab with it
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Starts on intro
  • Clicking switches tabs
  • Uses replaceState and location.hash